[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

instance_exec

Ara.T.Howard

7/7/2006 5:23:00 PM

27 Answers

Marcel Molina Jr.

7/7/2006 5:27:00 PM

0

On Sat, Jul 08, 2006 at 02:22:31AM +0900, ara.t.howard@noaa.gov wrote:
>
> i seems to recall someone came up with an impl of instance_exec
> (instance_eval
> that takes args) a while back - might have even been me! ;-) anyone
> remember?

There is one in Rails' ActiveSupport:

class Object
unless defined? instance_exec # 1.9
def instance_exec(*arguments, &block)
block.bind(self)[*arguments]
end
end
end

class Proc
def bind(object)
block, time = self, Time.now
(class << object; self end).class_eval do
method_name = "__bind_#{time.to_i}_#{time.usec}"
define_method(method_name, &block)
method = instance_method(method_name)
remove_method(method_name)
method
end.bind(object)
end
end

marcel
--
Marcel Molina Jr. <marcel@vernix.org>

Sean O'Halpin

7/7/2006 5:32:00 PM

0

On 7/7/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:
>
> i seems to recall someone came up with an impl of instance_exec (instance_eval
> that takes args) a while back - might have even been me! ;-) anyone remember?
>
> -a
> --

You did indeed! And so did I. However, Mauricio Fernandez came up with
what seems to be a fairly complete implementation (thread safe,
handles frozen objects, etc.) at:

http://eigenclass.org/hiki.rb?cmd=view&p=instance_exec&key=ins...

Regards,
Sean

Ara.T.Howard

7/7/2006 5:37:00 PM

0

Sean O'Halpin

7/7/2006 5:47:00 PM

0

On 7/7/06, Marcel Molina Jr. <marcel@vernix.org> wrote:
> On Sat, Jul 08, 2006 at 02:22:31AM +0900, ara.t.howard@noaa.gov wrote:
> >
> > i seems to recall someone came up with an impl of instance_exec
> > (instance_eval
> > that takes args) a while back - might have even been me! ;-) anyone
> > remember?
>
> There is one in Rails' ActiveSupport:
>
> class Object
> unless defined? instance_exec # 1.9
> def instance_exec(*arguments, &block)
> block.bind(self)[*arguments]
> end
> end
> end
>
> class Proc
> def bind(object)
> block, time = self, Time.now
> (class << object; self end).class_eval do
> method_name = "__bind_#{time.to_i}_#{time.usec}"
> define_method(method_name, &block)
> method = instance_method(method_name)
> remove_method(method_name)
> method
> end.bind(object)
> end
> end
>
> marcel
> --
> Marcel Molina Jr. <marcel@vernix.org>
>
>
This is not thread-safe - relying on time.usec may not work on
sufficiently fast or clock-impaired machines.

Regards,
Sean

Trans

7/7/2006 6:23:00 PM

0


Marcel Molina Jr. wrote:
> On Sat, Jul 08, 2006 at 02:22:31AM +0900, ara.t.howard@noaa.gov wrote:
> >
> > i seems to recall someone came up with an impl of instance_exec
> > (instance_eval
> > that takes args) a while back - might have even been me! ;-) anyone
> > remember?
>
> There is one in Rails' ActiveSupport:
>
> class Object
> unless defined? instance_exec # 1.9
> def instance_exec(*arguments, &block)
> block.bind(self)[*arguments]
> end
> end
> end
>
> class Proc
> def bind(object)
> block, time = self, Time.now
> (class << object; self end).class_eval do
> method_name = "__bind_#{time.to_i}_#{time.usec}"
> define_method(method_name, &block)
> method = instance_method(method_name)
> remove_method(method_name)
> method
> end.bind(object)
> end
> end

Huh. That looks like the one I wrote a while back (minus the time
stamp).

Mauricio Fernandez's looks better though --think I'll have to rip it
for Facets ;-)

T.


Sean O'Halpin

7/8/2006 2:12:00 AM

0

On 7/7/06, transfire@gmail.com <transfire@gmail.com> wrote:
> Huh. That looks like the one I wrote a while back (minus the time
> stamp).
>
> Mauricio Fernandez's looks better though --think I'll have to rip it
> for Facets ;-)
>
> T.
>
Do - it's the best version for 1.8 so far (IMHO).

Regards,
Sean

Ara.T.Howard

7/9/2006 6:10:00 AM

0

Mauricio Fernández

7/9/2006 8:15:00 AM

0

On Sun, Jul 09, 2006 at 03:09:52PM +0900, ara.t.howard@noaa.gov wrote:
> >Mauricio Fernandez's looks better though --think I'll have to rip it
> >for Facets ;-)
>
> i just came across a bug in it (it's not re-entrant) - here's the fix:
>
[#instance_exec implementation]

The example you gave does work with my implementation too:

RUBY_VERSION # => "1.8.5"
RUBY_RELEASE_DATE # => "2006-06-24"
class Object
module InstanceExecHelper; end
include InstanceExecHelper
def instance_exec(*args, &block)
mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
InstanceExecHelper.module_eval{ define_method(mname, &block) }
begin
ret = send(mname, *args)
ensure
InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil
# ==========
# thx to this
end
ret
end
end

a = []

a.instance_exec 42 do |x|
instance_exec x do |y|
push y
p size
end
end

a # => [42]
a.size # => 1
# >> 1


I had actually a test for that (see test_instance_exec_nested below). Do you
have any additional assertions handy?
(So far test_instance_exec_with_frozen_obj fails in all the other
implementations I've seen.)

require 'test/unit'
class TestInstanceEvalWithArgs < Test::Unit::TestCase
def test_instance_exec
# Create a block that returns the value of an argument and a value
# of a method call to +self+.
block = lambda { |a| [a, f] }

assert_equal [:arg_value, :dummy_value],
Dummy.new.instance_exec(:arg_value, &block)
end

def test_instance_exec_with_frozen_obj
block = lambda { |a| [a, f] }

obj = Dummy.new
obj.freeze
assert_equal [:arg_value, :dummy_value],
obj.instance_exec(:arg_value, &block)
end

def test_instance_exec_nested
i = 0
obj = Dummy.new
block = lambda do |arg|
[arg] + instance_exec(1){|a| [f, a] }
end

# the following assertion expanded by the xmp filter automagically from:
# obj.instance_exec(:arg_value, &block) #=>
assert_equal([:arg_value, :dummy_value, 1], obj.instance_exec(:arg_value, &block))
end
end


--
Mauricio Fernandez - http://eige... - singular Ruby

Trans

7/9/2006 11:07:00 AM

0

Thanks Ara.

Do you have a testcase I can use?

T.


Erik Veenstra

7/10/2006 10:13:00 AM

0

> The example you gave does work with my implementation too:
>
> RUBY_VERSION # => "1.8.5"
> RUBY_RELEASE_DATE # => "2006-06-24"
> class Object
> module InstanceExecHelper; end
> include InstanceExecHelper
> def instance_exec(*args, &block)
> mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"

If instance_exec is called recursively, like in the example,
the mname for the outer method is reused for defining the inner
method. This isn't really a problem, but conceptually not very
"clean"...

Did it work "by accident", or did you really intent to reuse
the name? ;]

> InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil

This "rescue nil" might have been an indication of this "bad
design"... ;]

I wonder, why did you use a module for the context, instead of
the good old meta class?

gegroet,
Erik V. - http://www.erikve...