Я пишу постоянно, что я рассматриваю как ненужный код в Ruby при использовании параметров, передаваемых по имени для методов.
Возьмите, например, следующий код:
def my_method(args)
orange = args[:orange]
lemon = args[:lemon]
grapefruit = args[:grapefruit]
# code that uses
# orange, lemon & grapefruit in this format which is way prettier & concise than
# args[:orange] args[:lemon] args[:grapefruit]
puts "my_method variables: #{orange}, #{lemon}, #{grapefruit}"
end
my_method :orange => "Orange", :grapefruit => "Grapefruit"
То, что мне действительно не нравится приблизительно этот код, - то, что я должен взять args и передать значения в локальные переменные, идущие вразрез с принципами DRY и просто обычно занимающие место в моих методах. И если я не использую локальные переменные и просто обращаюсь ко всем переменным с args [: символ] синтаксис тогда код становится несколько неразборчивым.
Я попытался обработать решение этого, но продолжать врезаться в кирпичную стену, поскольку я не знаю, как определить локальные переменные с помощью оценки в пределах метода, или с помощью любой другой техники. Вот одна из многих попыток ниже, которая приводит к ошибке
def my_method_with_eval(args)
method_binding = binding
%w{ orange lemon grapefruit}.each { |variable| eval "#{variable} = args[:#{variable}]", method_binding; }
# code that uses
# orange, lemon & grapefruit in this format which is way prettier & concise than
# args[:orange] args[:lemon] args[:grapefruit]
puts "my_method_with_eval variables: #{orange}, #{lemon}, #{grapefruit}"
end
my_method_with_eval :orange => "Orange", :grapefruit => "Grapefruit"
При выполнении того кода я просто добираюсь
NameError: undefined local variable or method ‘orange’ for main:Object method my_method_with_eval in named_args_to_local_vars at line at top level in named_args_to_local_vars at line 9
Любой получил любые идеи, как я мог упростить это вниз так или иначе так, чтобы я не запускал свои методы параметра, передаваемого по имени с загрузок var=args [: var] код?
Спасибо, Matthew O'Riordan
Я не верю, что есть какой-либо способ сделать это в Ruby (если кто-то придумает такой, сообщите мне, и я обновлю или удалю этот ответ, чтобы отразить его!) - если локальная переменная еще не определена, невозможно динамически определить ее с помощью привязки. Возможно, вы могли бы сделать что-то вроде апельсин, лимон, грейпфрут = nil
перед вызовом eval, но вы можете столкнуться с другими проблемами - например, если args [: orange] - это строка «Апельсин», вы в конечном итоге оцените orange = Orange
с вашей текущей реализацией.
Вот кое-что, что могло бы сработать, используя класс OpenStruct из стандартной библиотеки (под «может работать» я имею в виду «это зависит от вашего стиля, a.orange
лучше, чем args [: orange]
"):
require 'ostruct'
def my_method_with_ostruct(args)
a = OpenStruct.new(args)
puts "my_method_with_ostruct variables: #{a.orange}, #{a.lemon}, #{a.grapefruit}"
end
Если вам не нужен легкий доступ к какому-либо состоянию или методам на приемнике этого метода, вы можете использовать instance_eval следующим образом.
def my_method_with_instance_eval(args)
OpenStruct.new(args).instance_eval do
puts "my_method_with_instance_eval variables: #{orange}, #{lemon}, #{grapefruit}"
end
end
Вы можете даже сделать что-нибудь хитрое с помощью method_missing (подробнее см. здесь ), чтобы разрешить доступ к «первичному» объекту, но производительность, вероятно, будет невысокой.
В целом, я думаю, что, вероятно, наиболее просто / удобно использовать менее СУХИЕ первоначальное решение, которое вас беспокоило.
Я нашел дискуссию по этому поводу на рубин-так-гугле и похоже, что это оптимизация парсера. Локальные переменные уже вычисляются во время выполнения, так что локальные_переменные уже установлены в начале метода.
def meth
p local_variables
a = 0
p local_variables
end
meth
# =>
[:a]
[:a]
Таким образом, Ruby не нужно решать, является ли a
методом или локальной переменной, или нет во время выполнения, но можно смело предположить, что это локальная переменная.
(Для сравнения: В Python localals()
будет пустой в начале функции.)