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?
答案 0 :(得分:3)
In this particular case, getting what you want is quite easy, and doesn't even involve a call to load
:
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
.
More generally, if you want to specify an arbitrary context, that's basically the exact situation you'd want to use the optional Binding
argument to Kernel#eval
in:
bnd = 'Hello'.instance_exec { x = 3; binding }
eval('length + x',bnd) #=> 8