Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > How to pass a hash as a param to a method called through eval?

Reply
Thread Tools

How to pass a hash as a param to a method called through eval?

 
 
Alex Stahl
Guest
Posts: n/a
 
      07-11-2010
Hi Folks - I've got a data-driven app I'm building, and I'd like to be
able to read a set of data from a json file, pass that to eval, and have
it executed:

json:
{
"action": "someFunc",
"params": {
"a": "foo",
"b": "bar",
"c": "etc"
}
}

call = JSON.parse(json)
eval("#{call['action']} #{call['params']}")


Problem is that 'call['params']' is treated as a string by the receiver,
not the hash I intended to pass. Tried using casting operations first,
like .to_s and then .to_hash, but the to_hash call fails w/ no method
error. Instead the hash comes through as a string. How can I pass it
so that it remains a hash, and retains its structure for key/val reading
in the receiver?

Thanks,
Alex


 
Reply With Quote
 
 
 
 
Ammar Ali
Guest
Posts: n/a
 
      07-11-2010
[Note: parts of this message were removed to make it a legal post.]

On Sun, Jul 11, 2010 at 10:57 PM, Alex Stahl <(E-Mail Removed)> wrote:

> How can I pass it
> so that it remains a hash, and retains its structure for key/val reading
> in the receiver?
>
> Thanks,
> Alex
>



Adding parentheses around #{call['params']} should do it:

eval("#{call['action']}(#{call['params']})")

Ammar

 
Reply With Quote
 
 
 
 
Alex Stahl
Guest
Posts: n/a
 
      07-11-2010
Thanks, but... tried that already and it fails without even calling the
method:

"...undefined method `com' for nil:NilClass (NoMethodError)"

So I tried that w/ single quotes too:

eval("#{call['action']}('#{call['params']}')")

and that works, but still passes the params as a string, not a hash.

-Alex


On Sun, 2010-07-11 at 15:18 -0500, Ammar Ali wrote:
> On Sun, Jul 11, 2010 at 10:57 PM, Alex Stahl <(E-Mail Removed)> wrote:
>
> > How can I pass it
> > so that it remains a hash, and retains its structure for key/val reading
> > in the receiver?
> >
> > Thanks,
> > Alex
> >

>
>
> Adding parentheses around #{call['params']} should do it:
>
> eval("#{call['action']}(#{call['params']})")
>
> Ammar




 
Reply With Quote
 
Brian Candler
Guest
Posts: n/a
 
      07-11-2010
Alex Stahl wrote:
> Hi Folks - I've got a data-driven app I'm building, and I'd like to be
> able to read a set of data from a json file, pass that to eval, and have
> it executed:
>
> json:
> {
> "action": "someFunc",
> "params": {
> "a": "foo",
> "b": "bar",
> "c": "etc"
> }
> }
>
> call = JSON.parse(json)
> eval("#{call['action']} #{call['params']}")


I'm pretty sure that what you really want is this:

send(call['action'], call['params'])

For simple cases you might be able to work with eval, like this:

eval("#{call['action']} #{call['params'].inspect}")

But that's fragile, slow, and fraught with security dangers. If what you
want is to call a method whose name is in a variable, then the tool is
provided to do that: 'send'
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Ammar Ali
Guest
Posts: n/a
 
      07-11-2010
[Note: parts of this message were removed to make it a legal post.]

On Sun, Jul 11, 2010 at 11:29 PM, Alex Stahl <(E-Mail Removed)> wrote:

> Thanks, but... tried that already and it fails without even calling the
> method:
>
> "...undefined method `com' for nil:NilClass (NoMethodError)"
>
> So I tried that w/ single quotes too:
>
> eval("#{call['action']}('#{call['params']}')")
>
> and that works, but still passes the params as a string, not a hash.
>



The argument should be a string, that's what eval expects. The problem with
the first version (without the parentheses) was syntax. I don't know where
the "com" or the nil:NilClass are coming from. Is there something missing
from your code sample?

Here's what I get in irb:

mini:~ ammar$ rvm use 1.9.1
info: Using ruby 1.9.1 p378
mini:~ ammar$ irb
ruby-1.9.1-p378 > require 'json'
=> true
ruby-1.9.1-p378 > def some_func(hash); puts "from function:
#{hash.inspect}"; end
=> nil
ruby-1.9.1-p378 > j = '{ "action": "some_func", "params": { "a": "foo", "b":
"bar" } }'
=> "{ \"action\": \"some_func\", \"params\": { \"a\": \"foo\", \"b\":
\"bar\" } }"
ruby-1.9.1-p378 > call = JSON.parse(j)
=> {"action"=>"some_func", "params"=>{"a"=>"foo", "b"=>"bar"}}
ruby-1.9.1-p378 > eval("#{call['action']}(#{call['params']})")
from function: {"a"=>"foo", "b"=>"bar"}
=> nil

Ammar

 
Reply With Quote
 
Brian Candler
Guest
Posts: n/a
 
      07-11-2010
Just use 'puts' instead of 'eval' to see what's happening.

>> json = <<EOS

{
"action": "someFunc",
"params": {
"a": "foo",
"b": "bar",
"c": "etc"
}
}
EOS
=> "{\n \"action\": \"someFunc\",\n \"params\": {\n \"a\":
\"foo\",\n \"b\": \"bar\",\n \"c\": \"etc\"\n }\n}\n"
>> require 'rubygems'

=> true
>> require 'json'

=> true
>> call = JSON.parse(json)

=> {"action"=>"someFunc", "params"=>{"a"=>"foo", "b"=>"bar",
"c"=>"etc"}}
>> puts "#{call['action']} #{call['params']}"

someFunc afoobbarcetc
=> nil
>> puts "#{call['action']}('#{call['params']}')"

someFunc('afoobbarcetc')
=> nil
>>


Should be pretty obvious now, remember that eval is just interpreting
that string as a piece of ruby code.
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
yermej
Guest
Posts: n/a
 
      07-11-2010
On Jul 11, 2:57*pm, Alex Stahl <(E-Mail Removed)> wrote:
[...]
> Problem is that 'call['params']' is treated as a string by the receiver,
> not the hash I intended to pass. *Tried using casting operations first,
> like .to_s and then .to_hash, but the to_hash call fails w/ no method
> error. *Instead the hash comes through as a string. *How can I pass it
> so that it remains a hash, and retains its structure for key/val reading
> in the receiver?
>


This will do it:

eval("#{call['action']}(call['params'])")

Depending on context, you can probably completely avoid using eval:

method(call['action']).call(call['params'])

When you use #{call['params']}, I think that calls #to_s on the Hash
which causes what you're seeing.

Jeremy
 
Reply With Quote
 
David A. Black
Guest
Posts: n/a
 
      07-11-2010
Hi --

On Mon, 12 Jul 2010, Brian Candler wrote:

> Just use 'puts' instead of 'eval' to see what's happening.
>
>>> json = <<EOS

> {
> "action": "someFunc",
> "params": {
> "a": "foo",
> "b": "bar",
> "c": "etc"
> }
> }
> EOS
> => "{\n \"action\": \"someFunc\",\n \"params\": {\n \"a\":
> \"foo\",\n \"b\": \"bar\",\n \"c\": \"etc\"\n }\n}\n"
>>> require 'rubygems'

> => true
>>> require 'json'

> => true
>>> call = JSON.parse(json)

> => {"action"=>"someFunc", "params"=>{"a"=>"foo", "b"=>"bar",
> "c"=>"etc"}}
>>> puts "#{call['action']} #{call['params']}"

> someFunc afoobbarcetc
> => nil
>>> puts "#{call['action']}('#{call['params']}')"

> someFunc('afoobbarcetc')
> => nil
>>>

>
> Should be pretty obvious now, remember that eval is just interpreting
> that string as a piece of ruby code.


Footnote: in 1.9, Hash#to_s has changed such that (like Array#to_s) it
returns more of an inspect string:

>> puts "#{call['action']}(#{call['params']})"

someFunc({"a"=>"foo", "b"=>"bar", "c"=>"etc"})

(I concur however in your point that send is almost certainly a better
choice anyway.)


David

--
David A. Black, Senior Developer, Cyrus Innovation Inc.

The Ruby training with Black/Brown/McAnally
Compleat Stay tuned for next event announcement!
Rubyist http://www.compleatrubyist.com

 
Reply With Quote
 
Alex Stahl
Guest
Posts: n/a
 
      07-11-2010
Thanks. You're actually the second response to suggest doing it that
way (w/ eval). But it doesn't work for me.

Though, the first respondent is using 1.9.1, and I've got 1.8.7 at the
moment. Are you by chance also on 1.9.1?

-Alex

On Sun, 2010-07-11 at 16:05 -0500, yermej wrote:
> On Jul 11, 2:57 pm, Alex Stahl <(E-Mail Removed)> wrote:
> [...]
> > Problem is that 'call['params']' is treated as a string by the receiver,
> > not the hash I intended to pass. Tried using casting operations first,
> > like .to_s and then .to_hash, but the to_hash call fails w/ no method
> > error. Instead the hash comes through as a string. How can I pass it
> > so that it remains a hash, and retains its structure for key/val reading
> > in the receiver?
> >

>
> This will do it:
>
> eval("#{call['action']}(call['params'])")
>
> Depending on context, you can probably completely avoid using eval:
>
> method(call['action']).call(call['params'])
>
> When you use #{call['params']}, I think that calls #to_s on the Hash
> which causes what you're seeing.
>
> Jeremy
>




 
Reply With Quote
 
Ammar Ali
Guest
Posts: n/a
 
      07-11-2010
[Note: parts of this message were removed to make it a legal post.]

On Mon, Jul 12, 2010 at 12:41 AM, Alex Stahl <(E-Mail Removed)> wrote:

> Thanks. You're actually the second response to suggest doing it that
> way (w/ eval). But it doesn't work for me.
>
> Though, the first respondent is using 1.9.1, and I've got 1.8.7 at the
> moment. Are you by chance also on 1.9.1?



On 1.8.7 use yermej's suggestion, without the interpolation, if you choose
to stick with eval despite the excellent suggestions to use send instead:

eval("#{call['action']}(call['params'])")

Cheers,
Ammar

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
hash of hash of hash of hash in c++ rp C++ 1 11-10-2011 04:45 PM
HTML::Template->param() : You gave me an odd number of parameters to param()! Dave Perl Misc 5 04-26-2011 02:44 AM
Overload by deriv class param; call w base class param ectoplasm C++ 12 07-28-2005 08:20 AM
XSLT: How to replace param name with this param's value ? Geathaa XML 2 07-30-2003 06:48 AM



Advertisments