From: Alex Stahl on
Thanks again, yermej's suggestion actually worked out. I've now got
send doing exactly what I wanted to accomplish.

Going into my thinking on this problem, I knew I wanted dynamic
execution, and being relatively new to ruby, thought that eval would be
the right tool. Wasn't aware of send. Great thing is it caused me to
look up the Object and see all the cool things it can do for me.

So my original question probably should have been, "is eval even the
right tool for this?". Of course, that's not always obvious considering
there's always more than one way to do something in ruby.

On Sun, 2010-07-11 at 16:58 -0500, Ammar Ali wrote:
> On Mon, Jul 12, 2010 at 12:41 AM, Alex Stahl <astahl(a)hi5.com> 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



From: Brian Candler on
Alex Stahl wrote:
> So my original question probably should have been, "is eval even the
> right tool for this?". Of course, that's not always obvious considering
> there's always more than one way to do something in ruby.

Certainly. You should also be aware that 'send' is also not without its
security problems:


$ irb --simple-prompt
>> RUBY_DESCRIPTION
=> "ruby 1.8.7 (2010-01-10 patchlevel 249) [x86_64-linux]"
>> foo = "system"
=> "system"
>> bar = "rm /tmp/nonexistent*"
=> "rm /tmp/nonexistent*"
>> send(foo,bar)
rm: cannot remove `/tmp/nonexistent*': No such file or directory
=> false


$ irb19 --simple-prompt
>> RUBY_DESCRIPTION
=> "ruby 1.9.2dev (2009-07-18 trunk 24186) [i686-linux]"
>> foo = "system"
=> "system"
>> bar = "rm /tmp/nonexistent*"
=> "rm /tmp/nonexistent*"
>> send(foo,bar)
rm: cannot remove `/tmp/nonexistent*': No such file or directory
=> false


So it may be a good idea to give all your callable methods a prefix
("do_xxx"), and/or only call public methods:

send(foo,bar) if respond_to?(foo)
--
Posted via http://www.ruby-forum.com/.

From: Robert Klemme on
On 11.07.2010 23:00, 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.

I wouldn't even use eval here - it's unsafe and slow. Something like
this should work

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

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
From: Josh Cheek on
[Note: parts of this message were removed to make it a legal post.]

Eval is also a wonky work flow.

You have data serialized as JSON in a String
You parse it into a Ruby hash
You then serialize it as Ruby code in a String
You then eval the string to get the hash back out of it...


I don't know what types JSON supports, but if it supports anything that
doesn't have a literal, then that second converting to String and evaling
will break. Also explains why Amir's solution breaks on 1.8, because, as
David A. Black pointed out, Hash#to_s changed, and that is what is being
used to serialize it (which implies to me that this may not be realized)

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