我有一些看起来像旧的代码:
some_variable = "-> (params) { Company.search_by_params(params) }"
if eval(some_variable).is_a?(Proc)
...
Rubocop is complaining about the use of eval
. Any ideas on how to remove the usage of eval
?
I don't really understand Proc
s so any guidance on that would be appreciated.
I am going to answer the question "If I want to run code at a later time, What is the difference between using a proc and a
eval
'd string?" (which I think is part of your question and confusion):What
eval
does is take a string and parses it to code, and then runs it. This string can come from anywhere, including user input. But eval is very unsafe and problematic, especially when used with raw user input.The problems with eval are usually:
Using
eval
allows full control of the ruby process, and if you have high permissions given to the ruby process, potentially even root acmes to the machine. So the general recommendation is use 'eval' only if you absolutely have no other options, and especially not with user input.Procs/lambdas/blocks also let you save code for later, (and solve most of the problems with eval, they are the "better way") but instead of storing arbitrary code as a string to read later, they are code already, already parsed and ready to go. In someways, they are methods you can pass around later. Making a proc/lambda gives you an object with a
#call
method. Then when you later want to run the proc/block/lambda, you callcall([arguments...])
. What you can't do with procs though is let users write arbitrary code (and generally that's good). You have to write the code for the proc in a file ruby loads (most of the time). Eval does get around that, but you really should rethink if you really want that to be possible.Your code sample oddly combines both these methods: it evaluates a string to a lambda. So what's happening here is eval is running the code in the string right away and returning the (last) result, which in this case happens to be a lambda/proc. (Note that this would happen every time you ran
eval
, which would result in multiple copies of the proc, with different identities, but the same behavior). Since the code inside the string happens to make a lambda, the value returned is aProc
which can later be#call
'd. So when eval is run, the code is parsed, and a new lambda is created, with the code in the lambda stored to be run at a later time. If the code inside the string did not create a lambda, the all that code would be run immediately wheneval
was called with the string.可能需要这种行为,但是可能有更好的方法来执行此操作,这绝对是步枪:如果您不太谨慎,则至少有六种微妙的方法可以执行此代码的意外操作。
Simple. Don't define your variable object as a string but as a lambda
Proc
But why would you instantiate a string object which contains what appears to be a normal lambda which is a
Proc
, when you can define aProc
instead?