DEV Community

RobL
RobL

Posted on

1

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

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs