[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

eval? instance_eval?? hmm

Steve Hull

6/1/2009 7:54:00 AM

Hey ruby wizards. I got a question for you. I want to call a method on
my object instance, with the method name specified by a string. I want
to *pass in* a hash to my method.

I tried:

myMethodName = "doSomeStuff"
myObject.instance_eval "#{myMethodName}(#{myHash})"

But it complained that it didn't have a method named #{myHash.to_s}.

So I tried myObject.instance_eval { myMethodName(myHash) }

But it compalined that it didn't have a method named "myMethodName"
(which is obvious -- the method I wanted to call is doSomeStuff).

I'm new to metaprogramming in ruby. What am I missing here?

Last thought: I guess I could assign a transient local var
"@input_hash", then call the method which would use @input_hash instead
of requiring an input. That just seems a little ugly though. Any
prettier solution?

-Steve
--
Posted via http://www.ruby-....

4 Answers

James Coglan

6/1/2009 8:46:00 AM

0

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

2009/6/1 Steve Hull <p.witty@gmail.com>

> Hey ruby wizards. I got a question for you. I want to call a method on
> my object instance, with the method name specified by a string. I want
> to *pass in* a hash to my method.
>
> I tried:
>
> myMethodName = "doSomeStuff"
> myObject.instance_eval "#{myMethodName}(#{myHash})"
>
> But it complained that it didn't have a method named #{myHash.to_s}.
>
> So I tried myObject.instance_eval { myMethodName(myHash) }
>
> But it compalined that it didn't have a method named "myMethodName"
> (which is obvious -- the method I wanted to call is doSomeStuff).
>
> I'm new to metaprogramming in ruby. What am I missing here?



myObject.__send__(myMethodName, myHash) is a more appropriate idiom for what
you seem to be doing.

Brian Candler

6/1/2009 8:52:00 AM

0

Steve Hull wrote:
> Hey ruby wizards. I got a question for you. I want to call a method on
> my object instance, with the method name specified by a string. I want
> to *pass in* a hash to my method.
>
> I tried:
>
> myMethodName = "doSomeStuff"
> myObject.instance_eval "#{myMethodName}(#{myHash})"
>
> But it complained that it didn't have a method named #{myHash.to_s}.

You can easily see what you've done wrong if you just use 'puts' instead
of 'myObject.instance_eval'

Here's it's because you turned the hash into a string, and then inserted
the string into your code, and then tried to run it.

irb(main):001:0> myHash={"one"=>1}
=> {"one"=>1}
irb(main):002:0> def showit(x); puts "got #{x.inspect}"; end
=> nil
irb(main):003:0> myMethodName = "showit"
=> "showit"
irb(main):004:0> puts "#{myMethodName}(#{myHash})"
showit(one1)
=> nil

Imagine what happens if you type "showit(one1)" at the command line.

What you needed was just to pass literally 'myHash' as the argument,
whilst still interpolating the method name, i.e.

irb(main):005:0> instance_eval "#{myMethodName}(myHash)"
got {"one"=>1}
=> nil

However there are better ways to achieve this, without using the string
version of eval. Probably all you want is this:

myObject.send(myMethodName, myHash)

> I'm new to metaprogramming in ruby. What am I missing here?

This isn't metaprogramming (metaprogramming = programs which write
programs). This is just dynamic method dispatch.

Regards,

Brian.
--
Posted via http://www.ruby-....

Steve Hull

6/2/2009 12:13:00 AM

0

James -- perfect. Thanks!

Brian Candler wrote:
> You can easily see what you've done wrong if you just use 'puts' instead
> of 'myObject.instance_eval'
>
> Here's it's because you turned the hash into a string, and then inserted
> the string into your code, and then tried to run it.

Believe it or not, I did realize that. I just couldn't find any docs
showing me the proper usage of the string form of "instance_eval" (ie,
passing an argument).

> irb(main):005:0> instance_eval "#{myMethodName}(myHash)"
> got {"one"=>1}
> => nil

See I thought about trying this, but didn't even bother, as I expected
it to fail. Anyway I'm glad to see it does indeed work like this.

> However there are better ways to achieve this, without using the string
> version of eval. Probably all you want is this:
>
> myObject.send(myMethodName, myHash)

Yup. This works perfectly, thanks!!

> This isn't metaprogramming (metaprogramming = programs which write
> programs). This is just dynamic method dispatch.

Hah yeah I realize that now... cut me some slack, it was ~1:30am my
time and the wife was harassing me to come to bed! ;)
Anyway, as you may have guessed, I'm new to Ruby in general. Only been
working with the language for about 3 months. So far I'm loooooving it.
:)

Thanks for the helpful replies! I got it working exactly how I wanted.

-Steve
--
Posted via http://www.ruby-....

Brian Candler

6/2/2009 7:32:00 AM

0

Steve Hull wrote:
>> Here's it's because you turned the hash into a string, and then inserted
>> the string into your code, and then tried to run it.
>
> Believe it or not, I did realize that. I just couldn't find any docs
> showing me the proper usage of the string form of "instance_eval" (ie,
> passing an argument).

I wouldn't expect there to be any. eval or instance_eval with a string
just parses and runs Ruby code, so the proper usage is "just put some
valid Ruby code in there" :-)

That's why it's useful to use puts for debugging - you can see at a
glance whether that code would be valid or not, if you had just inserted
it into your program at that point.

> Thanks for the helpful replies! I got it working exactly how I wanted.

No problem, glad it's all making sense.

Cheers,

Brian.
--
Posted via http://www.ruby-....