Take me home

Constant lookup and blocks

Published August 19, 2008

class HelperHandler
  def foo_exists
    Foo.exists
  end
  
  module Foo
    def self.exists
      puts "Foo does indeed exist"
    end
  end
end


h = HelperHandler.new
h.foo_exists
# => "Foo does indeed exist"

No surprises here. This, however, is quite surprising:

class HelperHandler
  def initialize(&block)
    instance_eval(&block)
  end
end

HelperHandler.new do
  foo_exists
  # => "Foo does indeed exist"
  Foo.exists
  # => NameError: uninitialized constant Foo
end

Doing instance_eval is quite common in Ruby libraries. Sinatra, for example, which is what this website is built on, uses it. It evals the block in the context of the instance in question.

Calling the method worked, but referring to the Foo constant is not OK.

That's because Ruby doesn't care about instance_eval when it comes to constants. Constants are looked up in the calling scope. Nothing you can do about it.

Unless you want to be evil and use strings.

class HelperHandler
  def initialize(evil)
    eval(evil)
  end
end

HelperHandler.new "Foo.exists"
# => Foo does indeed exist

Questions or comments?

Feel free to contact me on Twitter, @augustl, or e-mail me at august@augustl.com.