Forum: Ruby how to do instance_eval with arguments

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jim W. (Guest)
on 2006-02-09 00:33
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 W.
Mauricio F. (Guest)
on 2006-02-09 00:58
(Received via mailing list)
On Thu, Feb 09, 2006 at 07:33:53AM +0900, Jim W. 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+ev...
#
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
Yukihiro M. (Guest)
on 2006-02-09 01:00
(Received via mailing list)
Hi,

In message "Re: how to do instance_eval with arguments"
    on Thu, 9 Feb 2006 07:33:53 +0900, Jim W.
<removed_email_address@domain.invalid> 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.
Jim W. (Guest)
on 2006-02-09 02:46
Yukihiro M. wrote:
> <removed_email_address@domain.invalid> 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 W.

[1] http://www.catb.org/jargon/html/G/Guido.html
Jim W. (Guest)
on 2006-02-09 02:49
Mauricio F. wrote:
> On Thu, Feb 09, 2006 at 07:33:53AM +0900, Jim W. 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 W.
This topic is locked and can not be replied to.