Доступ к локальным переменным в контексте вызова - PullRequest
0 голосов
/ 11 января 2019

В моем коде у меня есть несколько методов, использующих следующий шаблон

def my_method only: [], ignore: []
  something('textvalue') if (only.empty? && ignore.empty?) || (only.any? && only.include?('textvalue')) || (ignore.any? && !ignore.include?('textvalue'))
end

Другими словами, я могу отфильтровать результаты, указав only или ignore, в зависимости от того, какой из них более удобен в контексте.

Я хотел бы объявить помощника want, который обращается к локальным параметрам only и ignore без необходимости каждый раз указывать их, в идеале результат будет выглядеть следующим образом:

def my_method only: [], ignore: []
  something('textvalue') if want('textvalue')
end

Этот помощник будет использоваться в нескольких различных методах, классах и т. Д. Он будет каким-то образом проверять локальные переменные в вызывающей точке, проверять, существуют ли only и ignore, а затем проверять, нужен ли параметр или нет .

Можно ли получить доступ к стеку вызовов и посмотреть там локальные переменные?

Ответы [ 3 ]

0 голосов
/ 11 января 2019

Для этого можно использовать определение метода ruby ​​

def my_method val, only: [], ignore: [], want: ->(val) { ((only.empty? && ignore.empty?) || (only.any? && only.include?(val))) }
 something(val) if want.call(val)
end

my_method 'value', only: ['value2']
=> false
0 голосов
/ 11 января 2019

При таких обстоятельствах, не могли бы вы просто передать аргументы want?

def my_method only: [], ignore: []
  something('textvalue') if want?('textvalue', only, ignore)
end

def want?(string, only, ignore)
  (only.empty? && ignore.empty?) || (only.any? && only.include?(string)) || (ignore.any? && !ignore.include?(string))
end

Кажется, нет необходимости, чтобы он был более сложным?

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

0 голосов
/ 11 января 2019

Существует драгоценный камень binding_of_caller, который может это сделать. Установите драгоценный камень, а затем выполните

require 'binding_of_caller'

def my_method only: [], ignore: []
  something('textvalue') if want('textvalue')
end

def want(value)
  only = binding.of_caller(1).local_variable_get(:only)
  ignore = binding.of_caller(1).local_variable_get(:ignore)
  (only.empty? && ignore.empty?) || (only.any? && only.include?(value)) || (ignore.any? && !ignore.include?(value))
end

Но это плохо, так как создает очень высокую связь. Это действительно не очень хороший дизайн. Если вы хотите сделать это для экспериментов и экспериментов, достаточно честно, но не делайте это в производстве.

...