DEV Community

RobL
RobL

Posted on

Fun with classes and constants

Ruby is somewhat versatile at times. Suppose you want to define a class dynamically, and I do….

class Thing; end 
Enter fullscreen mode Exit fullscreen mode

Ok, that’s not dynamic

# still not dynamic but getting there. def define_a_class Thing = Class.new end # ok then I see def define_a_class(name) Object.const_set(name, Class.new) end define_a_class('Thing') => Thing 
Enter fullscreen mode Exit fullscreen mode

This is great but what if you wanted to define a class within a module

define_a_class('Nigel::Thing') NameError: wrong constant name Nigel::Thing from (pry):19:in `const_set' 
Enter fullscreen mode Exit fullscreen mode

Oh. That sucks. What you’re actually trying to do here is

Object.const_set('Thing', Class.new) #=> Thing Nigel.const_set('Thing', Class.new) #=> Nigel::Thing 
Enter fullscreen mode Exit fullscreen mode

Object is for root namespace, and the module name for the nested namespace.

So today we had an issue. We normally define a Permit class if one doesn’t already exist like so.

def define_permit_class name = "#{self.name}Permit" Object.const_get(name) rescue NameError Object.const_set(name, Class.new(Permit)) end 
Enter fullscreen mode Exit fullscreen mode

This works for

Thing.define_permit_class 
Enter fullscreen mode Exit fullscreen mode

But obviously not for

Nigel::Thing.define_permit_class 
Enter fullscreen mode Exit fullscreen mode

Well, easily fixed. A class can find it’s parent module, or if it is doesn’t have one it’s Object.

Thing.parent #=> Object Nigel::Thing.parent #=> Nigel 
Enter fullscreen mode Exit fullscreen mode

So we just refactor this a little and bingo

def define_permit_class name = "#{self.name.demodulize}Permit" parent.const_get(name) rescue NameError parent.const_set(name, Class.new(Permit)) end 
Enter fullscreen mode Exit fullscreen mode

Ok, it now seems that parent is deprecated in Rails 6.1. module_parent it is.

DEPRECATION WARNING: `Module#parent` has been renamed to `module_parent`. `parent` is deprecated and will be removed in Rails 6.1. 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)