Refactor eval (some_variable) .is_a? (Pro c), чтобы не использовать eval - PullRequest
0 голосов
/ 08 апреля 2020

У меня есть старый код, который выглядит следующим образом:

some_variable = "-> (params) { Company.search_by_params(params) }"
if eval(some_variable).is_a?(Proc)
...

Rubocop жалуется на использование eval. Есть идеи как убрать использование eval?

Я на самом деле не понимаю Proc s, поэтому любые рекомендации по этому поводу будут оценены.

Ответы [ 2 ]

2 голосов
/ 08 апреля 2020

Simple. Не определяйте ваш переменный объект как строку, а как лямбда Proc

my_lamda = -> (params) { Company.search_by_params(params) }
if my_lambda.is_a?(Proc)
  #do stuff
end

Но зачем вам создавать экземпляр строкового объекта, который содержит то, что выглядит как нормальная лямбда , что является Proc, когда вместо него можно определить Proc?

1 голос
/ 08 апреля 2020

Я собираюсь ответить на вопрос «Если я хочу запустить код позже, в чем разница между использованием строки * pro c и eval 'd?» (что, я думаю, является частью вашего вопроса и путаницы):

Что eval делает, это берет строку, анализирует ее в коде и затем запускает. Эта строка может прийти откуда угодно, включая ввод пользователя. Но eval очень небезопасен и проблематичен c, , особенно при использовании с необработанным пользовательским вводом.

Проблемы с eval обычно таковы:

  • Почти всегда есть лучший способ сделать это
  • Очень опасно и небезопасно
  • затрудняет отладку
  • медленно

Использование eval позволяет полностью контролировать процесс ruby, и если у вас есть высокие разрешения, предоставленные процессу ruby потенциально даже 1041 * acmes к машине. Таким образом, общая рекомендация - использовать 'eval' только в том случае, если у вас совершенно нет других опций, особенно если речь не идет о пользовательском вводе.

Procs / lambdas / blocks также позволяет сохранять код на потом (и решить большинство проблем. проблемы с eval, они являются «лучшим способом»), но вместо хранения произвольного кода в виде строки для последующего чтения, они уже являются кодом, уже проанализированы и готовы к go. В некоторых случаях это методы, которые вы можете передать позже. Создание proc / lambda дает вам объект с #call методом. Затем, когда вы позже захотите запустить proc / block / lambda, вы вызываете call([arguments...]). Что вы не можете сделать с procs, так это позволить пользователям писать произвольный код (и в целом это хорошо). Вы должны написать код для профи c в файле ruby загрузки (большую часть времени). Eval справляется с этим, но вам действительно следует переосмыслить, если вы действительно хотите, чтобы это было возможно.

В вашем примере кода странным образом сочетаются оба этих метода: он оценивает строку как лямбду. Итак, здесь происходит то, что eval сразу же запускает код в строке и возвращает (последний) результат, который в данном случае является лямбда / pro c. (Обратите внимание, что это будет происходить каждый раз, когда вы запускаете eval, что приведет к нескольким копиям про c, с разными удостоверениями, но с одинаковым поведением). Поскольку код внутри строки создает лямбду, возвращаемое значение равно Proc, которое позже может быть #call 'd. Таким образом, когда запускается eval, код анализируется, и создается новая лямбда-код с сохраненным в ней лямбда-кодом для запуска в более позднее время. Если код внутри строки не создает лямбду, весь этот код будет запущен немедленно, когда eval будет вызван со строкой.

Такое поведение может быть желательным, но, вероятно, есть лучший способ сделайте это, и это, безусловно, пушечное оружие: есть по крайней мере полдюжины хитрых способов, которыми этот код мог бы делать непреднамеренные вещи, если вы не были действительно осторожны с ним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...