constant annoyance

Jared Carroll

Recently Ive been running into some strange behavior with Ruby and its class constants and methods.

For example, the following works:

class User

  def self.blah
    puts 'blah'
  end

end

User.blah => 'blah'
User::blah => 'blah'

Somebody tell me why that works.

My only idea is that its some implementation bug about the way Ruby stores its class methods.

Either way, invoking a class method like you’d reference a class or module is too confusing, so don’t use it.

Another one is that defining a class constant via #class_eval, really declares a top level constant:

class User
end

TYPES => uninitialized constant TYPES

User.class_eval do
  TYPES = ['admin', 'non-admin']
end

TYPES => ['admin', 'non-admin']
User::TYPES => warning toplevel constant TYPES referenced by
  User::TYPES ['admin', 'non-admin']

In some Ruby I was trying to do the following:

User.class_eval do
  TYPES = ['admin', 'non-admin']
end

Event.class_eval do
  TYPES = ['meeting', 'interview']
end

TYPES => ['meeting', 'interview']

In other words I wanted to define a constant with the same name via #class_eval in 2 different classes (nevermind why I was doing this via #class_eval, just know it was necessary and for a good reason). Of course the problem is there’s only ever going to be 1 constant named TYPES defined, there won’t be 2 (1 scoped to User and 1 scoped to Event).

Now how else could I do this?

How about class variables?

User.class_eval do

  @@types = ['admin', 'non-admin']

  def self.types
     @@types
  end

end

Event.class_eval do

  @@types = ['meeting', 'interview']

  def self.types
     @@types
  end

end

No.

Those are ugly. I never use class variables in Ruby.

How about class methods who’s name’s are in uppercase?

User.class_eval do

  def self.TYPES
    ['admin', 'non-admin']
  end

end

Event.class_eval do

  def self.TYPES
    ['meeting', 'interview']
  end

end

User.TYPES => ['admin', 'non-admin']
Event.TYPES => ['meeting', 'interview']

That’s a little better but invoking a class method who’s name is in all caps is bizarre.

Wait, how about that above hack I mentioned. According to that I should be able to invoke a class method using a syntax like referencing a class constant.

Order::TYPES

Nope, it doesn’t work. It looks like that hack only works if the class method name is in all lower case, it can’t even be capitalized either.

What a total waste of time.

About thoughtbot

We've been helping engineering teams deliver exceptional products for over 20 years. Our designers, developers, and product managers work closely with teams to solve your toughest software challenges through collaborative design and development. Learn more about us.