Можно ли определить блок с необязательными аргументами в Ruby? - PullRequest
7 голосов
/ 16 января 2009

Я пытаюсь динамически определить функции, которые обращаются к другой функции, которая принимает параметр параметров:

class MyClass
  ["hour", "minute", "second"].each do |interval|
    define_method "get_#{interval}" do |args|
      some_helper(interval, args)
    end
  end
  def some_helper(interval, options={})
    # Do something, with arguments
  end
end

Я бы хотел иметь возможность вызывать разные методы в MyClass двумя способами (с необязательными аргументами и без них):

mc = MyClass.new
mc.get_minute( :first_option => "foo", :second_option => "bar")
mc.get_minute  # This fails with: warning: multiple values for a block parameter (0 for 1)

При втором вызове минуты я вижу это предупреждение:

предупреждение: несколько значений для параметра блока (0 для 1)

  1. Есть ли способ написать блок для метода "get_ *", чтобы это предупреждение не появлялось?
  2. Я злоупотребляю define_method?

Ответы [ 3 ]

16 голосов
/ 16 января 2009

Единственное изменение, которое вам нужно сделать, это изменить args на *args. * указывает, что args будет содержать массив необязательных аргументов для блока.

5 голосов
/ 25 марта 2011

Два года спустя ... Я не знаю, является ли это новая функция с ruby ​​1.9.2, или это было возможно в прошлом, но это работает:

class MyClass
    ["hour", "minute", "second"].each do |interval|
        define_method "get_#{interval}" do |args = {:first_option => "default foo", :second_option => "default  bar"}|
           some_helper(interval, args)
        end
    end
    def some_helper(interval, options={})
        # Do something, with arguments
        p options
    end
end

mc = MyClass.new
mc.get_minute( :first_option => "foo", :second_option => "bar")
mc.get_minute  

Результат:

{:first_option=>"foo", :second_option=>"bar"}
{:first_option=>"default foo", :second_option=>"default  bar"}
0 голосов
/ 17 января 2009

Я согласен с Гордоном, добавление * к вашим аргументам заставит его исчезнуть.

Еще один способ сделать это - использовать method_missing ()

Примерно так:

class MyClass

  def method_missing(m, *args)  
    if /get_(.+)/.match(m.to_s)
      some_helper($1, args) 
    else
      raise 'Method not found...'
    end
  end  

  def some_helper(interval, *args)
    puts interval + ' -> ' + args.inspect
  end

end

m = MyClass.new
m.get_minute( :first_option => "foo", :second_option => "bar" )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...