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
--
Posted via http://www.ruby-forum.com/.
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
···
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?
#
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
--
Mauricio Fernandez
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] Guido
--
Posted via http://www.ruby-forum.com/\.
Mauricio Fernandez 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.
···
On Thu, Feb 09, 2006 at 07:33:53AM +0900, Jim Weirich wrote:
--
-- Jim Weirich
--
Posted via http://www.ruby-forum.com/\.