From: Alex Stahl on
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


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

On Sun, Jul 11, 2010 at 10:57 PM, Alex Stahl <astahl(a)hi5.com> 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

From: Alex Stahl on
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 <astahl(a)hi5.com> 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



From: Brian Candler on
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/.

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

On Sun, Jul 11, 2010 at 11:29 PM, Alex Stahl <astahl(a)hi5.com> 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