I think we need a RubyBlackMagic page on the Wiki
I am probably being obtuse, but in order to decipher this I had to go the
long way round, starting with an analogy with with the normal usage of the
'class <<obj' pattern:
class Foo
# here, the current object (self) is 'Foo', of class 'Class'
end
a = Foo.new # 'a' is of class 'Foo'
class <<a
# the current object (self) is now a new Class which is a
# singleton subclass of 'Foo'; and 'a' has been changed so that it
# belongs to this new Class
def bar; puts "hello"; end
end
puts a.bar #>> "hello" ('a' is of singleton class which includes 'bar')
b = Foo.new
puts b.bar #>> NameError ('b' is of class Foo which doesn't include 'bar')
So in the above, 'a' has been changed from an instance of 'Foo' to an
instance of an anonymous (singleton) class derived from 'Foo'.
Now, taking what you wrote:
class C
# the current object (self) is 'C' of class 'Class'
class <<self
# the current object (self) is now a new Class which is a
# singleton subclass of 'Class'; and 'C' is changed so that it
# belongs to this new class
attr_accessor :instances
end
end
So, 'C' is no longer an instance of a regular 'Class', but an instance of an
anonymous subclass of 'Class' which has a counter.
Therefore, C.new generates an instance of an object whose class is this
'enhanced' class.
Consistent? Yes. Predictable? Perhaps, if you've seen it before
<aside>
Question: does the code you wrote (subclassing Class) have the same effect
as adding class methods? i.e.
class C
def C.instances
@instances
end
def C.instances=(val)
@instances=val
end
end
</aside>
Anyway, taking the original example which was something like:
class Tree
@data = nil
@kids = nil
def initialize(data)
@data = data
@kids =
end
end
then I don't think it's immediately obvious at a glance that:
1. the first uses of '@data' and '@kids' are something completely different
to the second uses
2. the things that you've created by the first assignments to '@data' and
'@kids' are actually fairly well hidden; the only way you can get at
them is via subclassing Class, or through class methods
3. even if you realise that the first uses of '@data' and '@kids' belong
to the class and not to an instance of an object of that class, they
are still not the same thing as '@@data' and '@@kids', which belong to
the class but in a different way:
class Tree
@count = 0
@@count = 50
def Tree.inc
@count += 1
end
def Tree.inc2
@@count += 1
end
end
puts Tree.inc #>> 1
puts Tree.inc #>> 2
puts Tree.inc2 #>> 51
puts Tree.inc2 #>> 52
puts Tree.instance_variables #>> @count
puts Tree.class_variables #>> @@count
If you saw those things at a first glance, then I'd say you are a RubyWizard
Regards,
Brian.
···
On Sat, Feb 22, 2003 at 04:05:59PM +0900, dblack@candle.superlink.net wrote:
It's probably most useful in an accessor. For example, if you want to
keep a running tally of how many instances of a class have been
created:
class C
class << self; protected; attr_accessor :instances; end
@instances = 0
def initialize
self.class.instances += 1
end
end