[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Works in irb but not elsewhere

Patrick Li

8/8/2008 7:26:00 PM

Hi i'm creating a DSL, and would like to use the following
functionality.It works fine in irb but when I run it from the
commandline. Does it look like my fault or a ruby bug?

class A
def method
puts "a"
end
def A.create
A.new.instance_eval { yield }
end
end

A.create{method}

PS: I'm on "ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32]"
--
Posted via http://www.ruby-....

9 Answers

Patrick Li

8/8/2008 7:27:00 PM

0

Oh and I get:

Temp.rb:11:in `method': wrong number of arguments (0 for 1)
(ArgumentError)
from Temp.rb:11
from Temp.rb:7:in `create'
from Temp.rb:7:in `instance_eval'
from Temp.rb:7:in `create'
from Temp.rb:11

When i run it from commandline.
Thanks a lot for your insight.
-Patrick
--
Posted via http://www.ruby-....

cardboard42@gmail.com

8/8/2008 7:55:00 PM

0

On Aug 8, 3:26 pm, Patrick Li <patrickli_2...@hotmail.com> wrote:
> Hi i'm creating a DSL, and would like to use the following
> functionality.It works fine in irb but when I run it from the
> commandline. Does it look like my fault or a ruby bug?
>
> class A
> def method
> puts "a"
> end
> def A.create
> A.new.instance_eval { yield }
> end
> end
>
> A.create{method}

Maybe I'm missing something, but shouldn't that be:

class A
def method
puts "a"
end
def A.create &block
A.new.instance_eval &block
end
end

Adam Shelly

8/8/2008 8:08:00 PM

0

On 8/8/08, cardboard42@gmail.com <cardboard42@gmail.com> wrote:
> On Aug 8, 3:26 pm, Patrick Li <patrickli_2...@hotmail.com> wrote:
> > Hi i'm creating a DSL, and would like to use the following
> > functionality.It works fine in irb but when I run it from the
> > commandline. Does it look like my fault or a ruby bug?
> >
> > class A
> > def method
> > puts "a"
> > end
> > def A.create
> > A.new.instance_eval { yield }
> > end
> > end
> >
> > A.create{method}

I think the issue is in the last line:
you are calling Object#method', which expects one parameter. You
ought to be using the String "method" to send to instance_eval.

-Adam

Patrick Li

8/8/2008 8:12:00 PM

0

Hey that works. Thanks that's a suitable workaround for me. Though I see
nothing wrong with my version. I think it's probably a bug. Can someone
confirm for me?

Thanks again for the workaround.
-Patrick
--
Posted via http://www.ruby-....

Patrick Li

8/8/2008 8:17:00 PM

0

Thanks for all your comments:

I think there's a bug in how ruby treats block parameters.

ie. the following works
def myMethod &block
A.new.instance_eval &block
end

but this doesn't
def myMethod
A.new.instance_eval{yield}
end

Thanks goes to cardboard42 for noticing that.
--
Posted via http://www.ruby-....

Mikael Høilund

8/8/2008 8:37:00 PM

0


On Aug 8, 2008, at 22:16, Patrick Li wrote:

> Thanks for all your comments:
>
> I think there's a bug in how ruby treats block parameters.
>
> ie. the following works
> def myMethod &block
> A.new.instance_eval &block
> end
>
> but this doesn't
> def myMethod
> A.new.instance_eval{yield}
> end
>

For reasons I cannot quite understand at the moment, the block for =20
instance_eval is executed in the scope of the receiver, but yield =20
inside that block will cause the block given to the *caller* to =20
execute, not raise a LocalJumpError as one would expect (since there's =20=

no block to yield inside the object). That block is executed at its =20
original scope:

>> @foo =3D :outside
=3D> :outside
>> class Klass
>> def initialize
>> @foo =3D :inside
>> end
>> end
>> Klass.new.instance_eval { @foo }
=3D> :inside # As expected
>> def lol; Klass.new.instance_eval { yield } end
>> lol do puts @foo end
=3D> :outside # o.O

I might be completely missing something here, but I would expect that =20=

last line to raise that darn LocalJumpError. This shows that the =20
=93current block=94 inside the instance_eval is indeed what's passed to =20=

the caller.

=85
>> def lol; Klass.new.instance_eval { Proc.new } end # Proc.new with =20=

no block returns the current block, cf. http://bit...
>> my_proc =3D proc { :test }
=3D> #<Proc:0x0004fb28@(irb):15>
>> lol &my_proc
=3D> #<Proc:0x0004fb28@(irb):15>
>> lol(&my_proc) =3D=3D my_proc
=3D> true

This might be a bug.

--=20
# Mikael H=F8ilund
def method_missing(m, a=3D0) a +
m.to_s[/[a-z]+/].size * 2; end
p What is the meaning of life?


cardboard42@gmail.com

8/8/2008 9:01:00 PM

0

I think what's happening is that yield is calling the block passed to
the caller of instance_eval so method is being called on self in that
block's closure. Since it was executed at the top level that would be
Object. Object.method takes 1 parameter, thus causing the error you're
seeing. The reason the code I posted works because it takes the block
passed to create and passes it directly to instance_eval as it's
block. This means that method will be called on self in instance_eval,
where it is set to the object instance_eval is called on, in this case
the result of A.new.

Sorry if my explanation is hard to understand, but I'm positive this
is not a bug in ruby. instance_eval { yield } simply has very
different semantics from instance_eval &block.

Ken

Calamitas

8/8/2008 9:18:00 PM

0

On Fri, Aug 8, 2008 at 10:36 PM, Mikael H=F8ilund <mikael@hoilund.org> wrot=
e:
>
> On Aug 8, 2008, at 22:16, Patrick Li wrote:
>
>> Thanks for all your comments:
>>
>> I think there's a bug in how ruby treats block parameters.
>>
>> ie. the following works
>> def myMethod &block
>> A.new.instance_eval &block
>> end
>>
>> but this doesn't
>> def myMethod
>> A.new.instance_eval{yield}
>> end
>>
>
> For reasons I cannot quite understand at the moment, the block for
> instance_eval is executed in the scope of the receiver, but yield inside
> that block will cause the block given to the *caller* to execute, not rai=
se
> a LocalJumpError as one would expect (since there's no block to yield ins=
ide
> the object). That block is executed at its original scope:

The only effect of instance_eval on the block it gets as parameter is
that self is changed. It influences only instance variables and method
calls without explicit receiver, nothing else. yield is tied to the
method it is in, not what self is at that point, so it is not affected
by instance_eval.

This should also answer the OP's question: since yield is unaffected,
it doesn't change self in the block it calls. So it's definitely not a
bug. You're calling #method on the toplevel object, which is an
instance of Object, and Object#method expects 1 parameter.

Peter

Robert Klemme

8/9/2008 8:26:00 AM

0

On 08.08.2008 23:01, cardboard42@gmail.com wrote:
> I think what's happening is that yield is calling the block passed to
> the caller of instance_eval so method is being called on self in that
> block's closure. Since it was executed at the top level that would be
> Object. Object.method takes 1 parameter, thus causing the error you're
> seeing. The reason the code I posted works because it takes the block
> passed to create and passes it directly to instance_eval as it's
> block. This means that method will be called on self in instance_eval,
> where it is set to the object instance_eval is called on, in this case
> the result of A.new.
>
> Sorry if my explanation is hard to understand, but I'm positive this
> is not a bug in ruby. instance_eval { yield } simply has very
> different semantics from instance_eval &block.

Absolutely correct, there is no bug - at least not in Ruby. You can
also see it from this:

$ ruby <<XXX
> class A
> def method
> puts "a"
> end
> def A.create
> A.new.instance_eval { yield }
> end
> end
>
> A.create{ p self; method}
>
> XXX
main
-:10:in `method': wrong number of arguments (0 for 1) (ArgumentError)
from -:10
from -:6:in `create'
from -:6:in `instance_eval'
from -:6:in `create'
from -:10

Note the output of "p self": it's main. And this is the case because
self is not changed for the block invoked via "yield".

Note also that this does not work in IRB as well:

$ irb
irb(main):001:0> class A
irb(main):002:1> def method
irb(main):003:2> puts "a"
irb(main):004:2> end
irb(main):005:1> def A.create
irb(main):006:2> A.new.instance_eval { yield }
irb(main):007:2> end
irb(main):008:1> end
=> nil
irb(main):009:0>
irb(main):010:0* A.create{ p self; method}
main
ArgumentError: wrong number of arguments (0 for 1)
from (irb):10:in `method'
from (irb):10
from (irb):6:in `create'
from (irb):6:in `instance_eval'
from (irb):6:in `create'
from (irb):10
irb(main):011:0>


Kind regards

robert