I have the following:
class Test @@a = 10 def show_a() puts "a: #{@@a}" end class << self @@b = '40' def show_b puts "b: #{@@b}" end end end Why does following work:
Test.instance_eval{show_b} b: 40 => nil But I can't access @@b directly?
Test.instance_eval{ @@b } NameError: uninitialized class variable @@b in Object Likewise, the following works
t = Test.new t.instance_eval{show_a} a: 10 => nil but the following fails
t.instance_eval{ @@a } NameError: uninitialized class variable @@a in Object I don't understand why I can't access the Class Variables directly from the instance_eval blocks.
Ruby Class VariablesClass variables begin with @@ and must be initialized before they can be used in method definitions. Referencing an uninitialized class variable produces an error. Class variables are shared among descendants of the class or module in which the class variables are defined.
class_eval(array_second) adds the method second to any instance of Array by passing a String that will be evaluated in the context of the class Array . The call to String. class_eval with a block will evaluate the content of the block in the context of the class String .
In Ruby OOP, class << self is a syntax you would often encounter. It's usually used to define class methods.
A variable itself is not an object. "A variable in Ruby is just a label for a container. A variable could contain almost anything - a string, an array, a hash. A variable name may only contain lowercase letters, numbers, and underscores.
I just asked the same question to Matz during the RubyKaigi party. I was half-drunk, but he was perfectly sober, so you can take this as the definitive answer.
Anton is right - the reason why you cannot access class variables through instance_eval() is "just because". Even class_eval() shares the same issue (Matz himself wasn't totally sure about class_eval() until I told him I'd already tried it). More specifically: scope-wise, class variables are more like constants than instance variables, so switching self (as instance_eval() and class_eval() do) is not going to make any difference when it comes to accessing them.
In general, it might be a good idea to avoid class variables altogether.
EDIT: below code was tested with 1.8.7 and 1.9.1...it seems the situation is different again with 1.9.2 :/
The situation actually isn't that straight forward. There are differences in behaviour depending on whether you're using 1.8 or 1.9 and whether you're using class_eval or instance_eval.
The examples below detail the behaviour in most situations.
I also included the behaviour of constants, for good measure, as their behaviour is similar to, but not exactly the same as, class variables.
class_eval in Ruby 1.8:
class Hello @@foo = :foo end Hello.class_eval { @@foo } #=> uninitialized class variable class_eval in Ruby 1.9:
Hello.class_eval { @@foo } #=> :foo So class variables are looked up in 1.9 (but not in 1.8) when using class_eval
instance_eval in Ruby 1.8 and 1.9
Hello.instance_eval { @@foo } #=> uninitialized class variable Hello.new.instance_eval { @@foo } #=> uninitialized class variable It appears class variables are not looked up in 1.8 or 1.9 when using instance_eval
What is also interesting is the case for constants:
class_eval in Ruby 1.8
class Hello Foo = :foo end Hello.class_eval { Foo } #=> uninitialized constant class_eval in Ruby 1.9
Hello.class_eval { Foo } #=> :foo So, as with class variables, constants are looked up in 1.9 but not in 1.8 for class_eval
instance_eval in Ruby 1.8
Hello.instance_eval { Foo } #=> uninitialized constant Hello.new.instance_eval { Foo } #=> uninitialized constant instance_eval in Ruby 1.9
Hello.instance_eval { Foo } #=> uninitialized constant Hello.new.instance_eval { Foo } #=> :foo It appears that constant lookup is not quite analogous to class variable look up for Ruby 1.9. A Hello instance does get access to the constant while the Hello class does not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With