ara.t.howard wrote:
blocks form closures, which is what makes them useful, when you are
defining methods via blocks you need to consider the enclosing scope as
it will be the primary namespace lookup. understanding closures is
step one to metaprogramming bliss.
Careful. Putting @@aa at the top level makes it into a kind of global,
so there’s no need for a closure to access it:
class A; end
@@aa = ‘this is sorta global’
A.class_eval{ define_method(:foo){
A.send :class_variable_get, ‘@@aa’ } }
p A.new.foo # ==> “this is sorta global”
p Object.send(:class_variable_get, “@@aa”)
# ==> “this is sorta global”
It’s global in the sense that @@aa is defined at the root of the class
tree (Object), and class var lookup wanders along this tree towards the
root, until it finds a class with @@aa defined.
An example that works only because class vars are affected by
closures:
class A; @@bb = 3 end
class B
@@bb = “belongs to B, yet visible in closure”
A.send(:define_method, :bar){ @@bb }
end
p A.new.bar
# ==> “belongs to B, yet visible in closure”
begin
p Object.send(:class_variable_get, “@@bb”)
rescue => ex
puts ex
# ==> uninitialized class variable @@bb in Object
end
p A.send(:class_variable_get, “@@bb”) # ==> 3
(Note that the @bb=3 is hidden when inside the scope of class B…end.)
But note that the behavior of instance vars in closures is different:
the lookup rules for @foo are dynamic, based on which object is the self
when the code is executed.
class A; end
@@aa = ‘this is what is meant by closure’
@a = “bar”
A.send(:define_method, :foo){ @@aa }
A.send(:define_method, :bar){ @a }
p A.new.foo # ==> “this is what is meant by closure”
p A.new.bar # ==> nil
It is a good idea to avoid class vars, for the following reason:
class A
@@one_by_this_name = 42
end
class B < A
@@one_by_this_name = 43
@@two_by_this_name = “zap”
end
class A
@@two_by_this_name = “pow”
end
class A
p @@one_by_this_name # == > 43 <-- surprise!
p @@two_by_this_name # == > “pow”
end
class B
p @@one_by_this_name # == > 43
p @@two_by_this_name # == > “zap”
end
The order of assignment determines whether a class and subclass share
the class variable!