I'm prototyping a DSL and came across a situtation where I have a lambda
that I would like to give to instance_eval, but the lambda takes
arguments. Instance_eval will not supply any arguments when evaluating
the lambda and I don't see a straightforward way around this.
Any suggestions?
Here's a test case ...
class Dummy
def f
:dummy_value
end
end
def instance_eval_with_args(obj, *args, &block)
# Magic goes here to evaluate +block+ in the scope of
# +obj+, yet pass a list of argument values to the block.
end
class TestInstanceEvalWithArgs < Test::Unit::TestCase
def test_instance_eval_with_args
# Create a block that returns the value of an argument and a value
# of a method call to +self+. This is the basic functionality I
need.
block = lambda { |a| [a, f] }
assert_equal [:arg_value, :dummy_value],
instance_eval_with_args(Dummy.new, :arg_value, &block)
end
end
--
-- Jim Weirich
on 08.02.2006 23:33
on 08.02.2006 23:58
On Thu, Feb 09, 2006 at 07:33:53AM +0900, Jim Weirich wrote: > I'm prototyping a DSL and came across a situtation where I have a lambda > that I would like to give to instance_eval, but the lambda takes > arguments. Instance_eval will not supply any arguments when evaluating > the lambda and I don't see a straightforward way around this. > > Any suggestions? This is what 1.9's Object#instance_exec does: http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9#l10 One way to implement it in 1.8: # The following script was annotated with my xmp filter # http://eigenclass.org/hiki.rb?Enhanced+xmp+code+evaluation+and+annotation # class Object def instance_exec(*args, &block) mname = "__instance_exec_#{Thread.current.object_id.abs}" class << self; self end.class_eval{ define_method(mname, &block) } begin ret = send(mname, *args) ensure class << self; self end.class_eval{ undef_method(mname) } rescue nil end ret end end # your test case class Dummy def f :dummy_value end end def instance_eval_with_args(obj, *args, &block) # Magic goes here to evaluate +block+ in the scope of # +obj+, yet pass a list of argument values to the block. obj.instance_exec(*args, &block) end require 'test/unit' class TestInstanceEvalWithArgs < Test::Unit::TestCase def test_instance_eval_with_args # Create a block that returns the value of an argument and a value # of a method call to +self+. This is the basic functionality I need. block = lambda { |a| [a, f] } assert_equal [:arg_value, :dummy_value], instance_eval_with_args(Dummy.new, :arg_value, &block) end end __END__ # >> Loaded suite - # >> Started # >> . # >> Finished in 0.000561 seconds. # >> # >> 1 tests, 1 assertions, 0 failures, 0 errors
on 09.02.2006 00:00
Hi,
In message "Re: how to do instance_eval with arguments"
on Thu, 9 Feb 2006 07:33:53 +0900, Jim Weirich
<jim@weirichhouse.org> writes:
|
|I'm prototyping a DSL and came across a situtation where I have a lambda
|that I would like to give to instance_eval, but the lambda takes
|arguments. Instance_eval will not supply any arguments when evaluating
|the lambda and I don't see a straightforward way around this.
|
|Any suggestions?
CVS HEAD (1.9) has instance_exec method that works exactly what you
want.
matz.
on 09.02.2006 01:46
Yukihiro Matsumoto wrote: > <jim@weirichhouse.org> writes: > | > |I'm prototyping a DSL and came across a situtation where I have a lambda > |that I would like to give to instance_eval, but the lambda takes > |arguments. Instance_eval will not supply any arguments when evaluating > |the lambda and I don't see a straightforward way around this. > | > |Any suggestions? > > CVS HEAD (1.9) has instance_exec method that works exactly what you > want. Excellent! I think Matz's time machine is every bit as good as Guido's[1]. -- -- Jim Weirich [1] http://www.catb.org/jargon/html/G/Guido.html
on 09.02.2006 01:49
Mauricio Fernandez wrote: > On Thu, Feb 09, 2006 at 07:33:53AM +0900, Jim Weirich wrote: >> Any suggestions? [...] > One way to implement it in 1.8: [... solution elided ...] Thanks! That should be good enough for my prototype ... at least until 1.9 features become standard. -- -- Jim Weirich