Navindra said:
Why does the first one work but not the second one?
As mathew said, def is just a command to define a method, it runs when
the interpreter gets to that line. What makes the first one work and the
second one not, however, is a matter of scope. When 'def' is called, it
defines a method in a certain place. That place is determined by what
'class' or 'module' it's in. So class Test; def foo; end end defines a
method on Test objects.
#1: def moo; puts 'moo' end is *not inside a 'class' or 'module' block*.
This is important. You may be defining a class method boo on Test (well,
a singleton method on the Test object), but your @@class_variables won't
actually be class variables of Test, because it's outside the class
block. It's out in the wild. Here's what the PickAxe2 (p. 346) has to
say about that:
"Outside a class or module definition, a definition with an unadorned
method name is added as a private method to class Object, and hence may
be called in any context without an explicit receiver."
So what's happening here?
Test.boo calls the Test.boo method you defined, which defines a private
method moo on Object. The 'def' keyword, as you've seen returns nil. So
Test.boo returns nil. Test.boo.moo tries to invoke the moo method on the
nil object. Since nil.is_a? Object, it has the moo method that you just
defined.
(I'm thinking the PickAxe may be wrong? about the private thing since
you can call #moo with an explicit receiver -- sounds more like public.
Can somebody explain?)
#2: When Test.boo is called, moo is defined as an instance method on
Test. Test.boo returns nil, as before, but nil is not a Test object, so
the moo method does not exist.
---
So... The best way to do what you actually want depends on what you
actually want. Are you just trying to group a bunch of similar methods
inside a subcomponent of Test, or do you want the Test.boo.moo method to
be dynamically generated based on what Test.boo does? If the latter,
then keep in mind that every method call returns an Object. What you
want to do is make Test.boo return an Object that has a moo method on it.
Devin