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:
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?
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:
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’
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?
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.
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.
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:
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)