8

I'm greatly confused by Ruby's behavior when defining const_missing and other class methods inside a class << self definition as opposed to using the def self.foo syntax.

I was trying to do something like this:

class Foo
  class << self
    def foo
      puts MISSING
    end

    def const_missing(name)
      puts "#{name} missing"
    end
  end
end

Foo.foo

I mostly use the the class << self syntax to define class methods. However, it did not work as expected. const_missing is never called. The above results in a NameError.

Defining both methods like this works as expected:

def self.foo
  puts MISSING
end

def self.const_missing(name)
  puts "#{name} missing"
end

I thought that the class << self syntax is just another way to define class methods, but completely equivalent to def self.foo? I've tested the above with MRI 1.8.7, 1.9.2 and JRuby 1.5.6. So obviously I'm missing something here?

Any hint is greatly appreciated.

Thanks, Martin

martido
  • 373
  • 2
  • 9

1 Answers1

12

class << self is not a shortcut to define class methods. This syntax (I don't know the exact naming) opens the eigenclass from a object (in your case, a class). With that you can define methods to the object (not instance methods). But when you call a constant into the eigenclass, you are calling a constant from the eigenclass, not from the class. In this case you have to define a class method on the eigenclass to the const_missing, two ways to do that:

class Test
  class << self
    def foo
      p MISSING
    end

    # First way: (syntax sugar for the second way)
    def self.const_missing(name)
      name
    end

    # Second way:
    class << self # eigenclass of the eigenclass of the class
      def const_missing(name)
        name
      end
    end

  end
end

Test.foo #=> :MISSING
diveintohacking
  • 4,783
  • 6
  • 29
  • 43
Guilherme Bernal
  • 8,183
  • 25
  • 43
  • Thanks a lot, LBg. I knew that `class << self` opens up the eigenclass of a class. But since class methods are just instance methods of the eigenclass I thought it would work this way. It makes perfectly sense, however, that a constant referred to from the eigenclass is not the same as a constant referred to from the class itself. Sometimes this whole thing makes my head spin :) – martido Mar 14 '11 at 21:11