2016-05-13 2 views
-2

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

data = [ 
    ["value", true], 
    ["any value here", true], 
    ["Value", true], 
] 

def test_value_1(string) 
    string == "value" 
end 

def test_value_2(string) 
    string.gsub(/.*?value.*?/, "\\1") 
end 

def test_value_3(string) 
    string.downcase == "value" 
end 

#tests 
[:test_value_1, :test_value_2, :test_value_3].each do |method| 
    data.each do |test| 
    value = test[0] 
    expected_result = test[1] 
    puts "#{method}: #{method.to_proc.call(value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'" 
    end 
end 

Важный бит конечный блок, следуя #tests комментарий. Методы data и test_value_* - это просто примеры того, как использовать блок тестирования и не имеют собственного значения, поэтому нет необходимости копать в них.

Что я на самом деле пытаюсь сделать сводится к этому фрагменту кода:

method.to_proc.call(value) 

И в этом случае value является символьным именем метода в глобальном пространстве имен (непосредственно не метод объект).

Это выход ошибка, что я получаю:

>$ ruby symbol_methods.rb 
symbol_methods.rb:33:in `call': private method `test_value_1' called for "value":String (NoMethodError) 
    from symbol_methods.rb:33:in `block (2 levels) in <main>' 
    from symbol_methods.rb:30:in `each' 
    from symbol_methods.rb:30:in `block in <main>' 
    from symbol_methods.rb:29:in `each' 
    from symbol_methods.rb:29:in `<main>' 

Я в тупик. Я пробовал public_send(method, value) и method.to_proc.call(value), но оба результата приводят к ошибке private method.

Что было бы правильным способом вызова метода, названного в качестве символа в этом случае? Я ищу и объяснение, и синтаксически правильный ответ.

ответ

0

После изрядных поисков, я нашел альтернативный ответ, чем Object#send, который имеет непредвиденное преимущество функции. Решение состоит в том, чтобы использовать Object#method для возврата объекта Method для обозначения имени символа.

A Method объект является Proc-подобным вызываемым объектом, поэтому он реализует интерфейс #call, который прекрасно подходит к счету. Object имеет много таких полезных помощников, определенных в его интерфейсе.

В контексте первоначального вопроса, это то, как он работает:

#tests 
[:test_value_1, :test_value_2, :test_value_3].each do |method| 
    data.each do |test| 
    value = test[0] 
    expected_result = test[1] 
    puts "#{method}: #{self.method(method).call(value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'" 
    end 
end 

важные биты:

self.method(method).call(value) 

Это преобразует имя символа в Method объекта, а затем вызвать в качестве параметра указан метод с value. Это работает примерно эквивалентно до send method solution, в функциональном выражении. Однако есть некоторые отличия.

send будет несколько более эффективным, так как нет никаких накладных расходов при преобразовании в Method. Method#call и send используют различные внутренние механизмы вызова, и оказывается, что send имеет меньшую нагрузку на вызов.

непредвиденное особенность использования Object#method является то, что Method объект легко преобразуется в Proc объекта (с использованием Method#to_proc). Таким образом, он может быть сохранен и передан как объект первого класса. Это означает, что он может быть поставлен вместо блока или предоставлен в качестве обратного вызова, что делает его полезным для реализации гибких диспетчерских решений.

4

send вместо этого.

puts "#{method}: #{send(method, value) == expected_result ? 'Pass' : 'Fail'}: '#{value}'" 
+1

@mudasobwa Здесь нужно позвонить частному методу. 'public_send' именно то, что не будет работать. – sawa

+0

@sawa ой, действительно, извините за это. – mudasobwa

+0

@delta это эквивалентно 'send (method, value == expected_result? 'Pass': 'Fail')' - это должно быть 'send (method, value) == expected_result? «Pass»: «Fail». Парсенс. –

Смежные вопросы