nPn nPn - 4 months ago 10
Ruby Question

In Ruby is there a way to define the context for load?

I would like to load a file in a block and evaluate the statements in the context of an instance of a object. For example something like this:

I have a file called foo_file that contains just this one line (statement)

some_method


I would like this "statement" to be called in the context of an instance of Foo, as shown below.

class Foo
def some_method
puts "hello"
end
end

foo = Foo.new

foo.instance_eval do
load "foo_file" # load and execute statement some_method from a foo_file.
end


This fails with:

foo_file:1:in `<top (required)>': undefined local variable or method `some_method' for main:Object (NameError)


while this works fine:

foo.instance_eval do
some_method
end


So it seems that while I call load in the block passed to instance_eval, the statements are loaded into the top context, not the instance foo.

I can get around this with the code shown below. I create a top level method that wraps a call to the instance method. I still need to provide the context, which I accomplish with a singleton.

require 'singleton'

class Context
include Singleton
attr_accessor :ctx
end

def some_method
ctx = Context.instance.ctx
ctx.some_method
end

Context.instance.ctx = foo
load "bar_file"


I think this will work, but it seems like there should be a better way (like just loading into the correct context to begin with). Any suggestions?

Answer

UPDATE: Actually, there is an even simpler way to do this:

foo.instance_eval(File.read(file))

For example, if file just had the text length, then

"Hello".instance_eval(File.read(file))

would return 5.


ORIGINAL SUGGESTION

This is exactly the sort of situation you'd want to use Kernel#eval with the optional Binding argument in:

foo.instance_eval do
  eval(File.read(file),binding)
end