Strange behavior when class_eval'ing a Class object

Just for the sake of learning more about the Ruby object model, I’ve
been doing some experiments, and the following behavior surprised me:

Let’s say we have a class Test:

class Test;end

Then, we class_eval Test.class in order to add a method to the Test
object:

Test.class.class_eval do
def foo
puts ‘foo called!’
end
end

(equivalent to calling Test.class.send(:define_method,:foo) … )

Then:

irb(main):076:0> Test.foo
=> foo called!

But sending foo to class also works:

irb(main):006:0> Test.class.foo
=> foo called!

I still can’t figure out why, though. The Class’ singleton_class doesn’t
contain it (the only possible explanation that came to my mind was that
somehow the method was added to the Class’ singleton class):

Test.class.singleton_methods
=> [:nesting, :constants]

How does the method lookup work in this case? Why does sending :foo to
Test.class also calls the method ? Am I missing something ?


As a reference, I did the same thing with an instance of Test:

irb(main):001:0> class Test;end
=> nil
irb(main):002:0> _foo = Test.new
=> #Test:0x007fa2c39e2f38
irb(main):003:0> _foo.class.class_eval do
irb(main):004:1* def foo
irb(main):005:2> puts ‘foo called!’
irb(main):006:2> end
irb(main):007:1> end
=> :foo
irb(main):008:0> _foo.foo
foo called!
=> nil
irb(main):009:0> _foo.class.foo
NoMethodError: undefined method `foo’ for Test:Class

This worked the way I expected it to.

Thanks in advance!

Because Test.class == Class and Class.class == Class

It’s kind of swirly.

class A
def foo()…;end
end
B.is_a? A # so B.foo works
C.is_a? A # so C.foo works

thus:

class Class
def foo()…;end
end
Test.is_a? Class # Test.foo works
Class.is_a? Class # Class.foo works

Matthew K.

Yep! I just figured out that a few minutes before you sent the message!
Eureka :slight_smile:

Thank you very much for taking the time to answer.

Cheers,


Marcelo Serpa
Sent with Sparrow (http://www.sparrowmailapp.com/?sig)