David Unric
David Unric

Reputation: 7719

class_eval and context of class variables?

Looking for an explanation why in the following example in Module.class_eval block, class variables lookup does not work:

class MyClass
  @@myvar = 123
  def self.myvar_getter
    @@myvar
  end
end

class MyClass
  p "#{self}, #{self.object_id}, #{singleton_class.object_id}"
  # output: "MyClass, 21055520, 21055500"
  p myvar_getter  # class method lookup working
  # output: 123
  p @@myvar       # class variable lookup working
  # output: 123
end

MyClass.class_eval do
  p "#{self}, #{self.object_id}, #{singleton_class.object_id}"
  # output: "MyClass, 21055520, 21055500"
  p myvar_getter  # class method lookup working as expected
  # output: 123
  p @@myvar       # class variable lookup NOT working (why ?)
  # output: -- following exception --
  #   a.rb:47: warning: class variable access from toplevel
  #   a.rb:47:in `block in <main>': uninitialized class variable
  #   @@myvar in Object (NameError)
end

As you may see the scope seems to be identical, self is the same, class method :myvar_getter is found in both cases, but class variable @@myvar is unexpectedly looked up in Object class within class_eval block. Can anybody explain this behavior other than because ?

Upvotes: 0

Views: 624

Answers (1)

David Unric
David Unric

Reputation: 7719

I've had to experience some weak moment, as the answer is quite clear & obvious.

From the Module.class_eval documentation:

Evaluates the string or block in the context of mod, except that when a block is given, constant/class variable lookup is not affected. This can be used to add methods to a class. module_eval returns the result of evaluating its argument.

So if I would need directly access class variables from eval block (ie. without use of class variable getter/setter methods), I'd just pass the code as a string:

MyClass.class_eval <<-EOS
  p @@myvar       # class variable lookup is working from a string
  # output: 123  voila!
  EOS

Upvotes: 1

Related Questions