2009-01-16 26 views
7

estoy tratando de definir de forma dinámica a través de funciones que llaman a otra función que toma un parámetro de opciones:¿Es posible definir un bloque con argumentos opcionales en Ruby?

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 

Me gustaría ser capaz de llamar a los diferentes métodos en MiClase en estas dos maneras (con y sin argumentos opcionales):

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) 

en la segunda llamada a minuto, veo esta advertencia:

advertencia: varios valores para un parámetro de bloque (0 para 1)

  1. ¿Hay una manera de escribir el bloque para el método de "get_ *" para que esta advertencia no se van a plantear?
  2. ¿Estoy abusando de define_method?

Respuesta

16

El único cambio que necesita hacer es cambiar args a *args. El * indica que args contendrá una matriz de argumentos opcionales para el bloque.

+0

¡Gracias por señalar eso! – Readonly

0

Estoy de acuerdo con Gordon agregar * a sus argumentos hará que desaparezca.

Otra forma de hacer esto es utilizar method_missing()

Algo como esto:

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") 
+1

Prefiero llamar 'super' en el método que falta en lugar de 'subir' para que realice una acción predeterminada de Ruby cuando el método realmente falta. – Priit

5

Dos años más tarde ... No sé si es una característica nueva es con el rubí 1.9.2, o si también era posible en el pasado, pero esto funciona:

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 

el resultado es:

{:first_option=>"foo", :second_option=>"bar"} 
{:first_option=>"default foo", :second_option=>"default bar"} 
+2

Sí, los argumentos opcionales con valores predeterminados son nuevos para Ruby 1.9 –

Cuestiones relacionadas