Mixing instance_eval and block with arguments


R

Robert Klemme

Hi,

here's what I'd like to do in a silly example:

S = Struct.new :foo, :bar

init = lambda do |a, b|
self.foo = b
self.bar = a + 10
end

s = S.new # or create an instance otherwise

# now comes the fun part which does not work
s.instance_eval(1, 2, &init)
=> #<struct S foo=2, bar=11>

In other words: I like to define a block as an initializer which I can
store away somewhere and invoke that initializer later on in the
context of "self" and pass arguments at the same time. Any ideas how
I can accomplish this elegantly?

Kind regards

robert
 
Ad

Advertisements

J

Jesús Gabriel y Galán

Hi,

here's what I'd like to do in a silly example:

S =3D Struct.new :foo, :bar

init =3D lambda do |a, b|
=A0self.foo =3D b
=A0self.bar =3D a + 10
end

s =3D S.new # or create an instance otherwise

# now comes the fun part which does not work
s.instance_eval(1, 2, &init)
=3D> #<struct S foo=3D2, bar=3D11>

In other words: I like to define a block as an initializer which I can
store away somewhere and invoke that initializer later on in the
context of "self" and pass arguments at the same time. =A0Any ideas how
I can accomplish this elegantly?

Probably not exactly what you want (can't make self to not be main
inside the lambda), but what about:

irb(main):001:0> S =3D Struct.new :foo, :bar
=3D> S
irb(main):003:0> s =3D S.new
=3D> #<struct S foo=3Dnil, bar=3Dnil>
irb(main):040:0> def s.init(*args,&blk) #you can put this in a module
and extend s with it, or add it to S
irb(main):041:1> blk[self,*args]
irb(main):042:1> end
irb(main):043:0> init =3D lambda do |o,a,b|
irb(main):044:1* o.foo =3D b
irb(main):045:1> o.bar =3D a + 10
irb(main):046:1> end
=3D> #<Proc:[email protected](irb):43>
irb(main):047:0> s.init(1,2,&init)
=3D> 11
irb(main):048:0> s
=3D> #<struct S foo=3D2, bar=3D11>

Don't know if this is good enough.

Jesus.
 
T

Tony Arcieri

[Note: parts of this message were removed to make it a legal post.]

In other words: I like to define a block as an initializer which I can
store away somewhere and invoke that initializer later on in the
context of "self" and pass arguments at the same time. Any ideas how
I can accomplish this elegantly?

Sounds like you need instance_exec, which is a 1.9 feature but there are
implementations for 1.8:

http://eigenclass.org/hiki.rb?instance_exec
 
R

Robert Klemme

[Note: parts of this message were removed to make it a legal post.]

In other words: I like to define a block as an initializer which I can
store away somewhere and invoke that initializer later on in the
context of "self" and pass arguments at the same time. Any ideas how
I can accomplish this elegantly?

Sounds like you need instance_exec, which is a 1.9 feature but there are
implementations for 1.8:

http://eigenclass.org/hiki.rb?instance_exec

1.9 is OK.

irb(main):001:0> l = lambda {|a| self + a}
=> #<Proc:[email protected](irb):1 (lambda)>
irb(main):002:0> 1.instance_exec(2,&l)
=> 3

Perfect! This is _exactly_ what I need. Thanks a bunch!

This article is so old, I can't believe I missed this completely.
Amazing: learn something new every day.

Kind regards

robert
 
Ad

Advertisements

R

Robert Klemme

Hi,

here's what I'd like to do in a silly example:

S = Struct.new :foo, :bar

init = lambda do |a, b|
self.foo = b
self.bar = a + 10
end

s = S.new # or create an instance otherwise

# now comes the fun part which does not work
s.instance_eval(1, 2, &init)
=> #<struct S foo=2, bar=11>

In other words: I like to define a block as an initializer which I can
store away somewhere and invoke that initializer later on in the
context of "self" and pass arguments at the same time. Any ideas how
I can accomplish this elegantly?

Probably not exactly what you want (can't make self to not be main
inside the lambda), but what about:

irb(main):001:0> S = Struct.new :foo, :bar
=> S
irb(main):003:0> s = S.new
=> #<struct S foo=nil, bar=nil>
irb(main):040:0> def s.init(*args,&blk) #you can put this in a module
and extend s with it, or add it to S
irb(main):041:1> blk[self,*args]
irb(main):042:1> end
irb(main):043:0> init = lambda do |o,a,b|
irb(main):044:1* o.foo = b
irb(main):045:1> o.bar = a + 10
irb(main):046:1> end
=> #<Proc:[email protected](irb):43>
irb(main):047:0> s.init(1,2,&init)
=> 11
irb(main):048:0> s
=> #<struct S foo=2, bar=11>

Don't know if this is good enough.

Thank you! Unfortunately I tried to avoid explicit passing of the
reference.

Kind regards

robert
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top