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.