Pregunta

Me gustaría pasar argumentos a un método que se define usando define_method, ¿cómo lo haría?

¿Fue útil?

Solución

El bloque que pasa a define_method puede incluir algunos parámetros.Así es como su método definido acepta argumentos.Cuando defines un método, en realidad simplemente estás poniendo un apodo al bloque y manteniendo una referencia a él en la clase.Los parámetros vienen con el bloque.Entonces:

define_method(:say_hi) { |other| puts "Hi, " + other }

Otros consejos

...y si quieres parámetros opcionales

 class Bar
   define_method(:foo) do |arg=nil|                  
     arg                                                                                          
   end   
 end

 a = Bar.new
 a.foo
 #=> nil
 a.foo 1
 # => 1

...tantos argumentos como quieras

 class Bar
   define_method(:foo) do |*arg|                  
     arg                                                                                          
   end   
 end

 a = Bar.new
 a.foo
 #=> []
 a.foo 1
 # => [1]
 a.foo 1, 2 , 'AAA'
 # => [1, 2, 'AAA']

...combinación de

 class Bar
   define_method(:foo) do |bubla,*arg|
     p bubla                  
     p arg                                                                                          
   end   
 end

 a = Bar.new
 a.foo
 #=> wrong number of arguments (0 for 1)
 a.foo 1
 # 1
 # []

 a.foo 1, 2 ,3 ,4
 # 1
 # [2,3,4]

...todos ellos

 class Bar
   define_method(:foo) do |variable1, variable2,*arg, &block|  
     p  variable1     
     p  variable2
     p  arg
     p  block.inspect                                                                              
   end   
 end
 a = Bar.new      
 a.foo :one, 'two', :three, 4, 5 do
   'six'
 end

Actualizar

Ruby 2.0 introdujo el doble símbolo ** (dos estrellas) que (Yo cito) hace:

Ruby 2.0 introdujo argumentos de palabras clave y ** actúa como *, pero para argumentos de palabras clave.Devuelve un Hash con pares clave/valor.

...y por supuesto también puedes usarlo en el método define :)

 class Bar 
   define_method(:foo) do |variable1, variable2,*arg,**options, &block|
     p  variable1
     p  variable2
     p  arg
     p  options
     p  block.inspect
   end 
 end 
 a = Bar.new
 a.foo :one, 'two', :three, 4, 5, ruby: 'is awesome', foo: :bar do
   'six'
 end
# :one
# "two"
# [:three, 4, 5]
# {:ruby=>"is awesome", :foo=>:bar}

Ejemplo de atributos con nombre:

 class Bar
   define_method(:foo) do |variable1, color: 'blue', **other_options, &block|
     p  variable1
     p  color
     p  other_options
     p  block.inspect
   end
 end
 a = Bar.new
 a.foo :one, color: 'red', ruby: 'is awesome', foo: :bar do
   'six'
 end
# :one
# "red"
# {:ruby=>"is awesome", :foo=>:bar}

Estaba intentando crear un ejemplo con argumento de palabra clave, splat y doble splat, todo en uno:

 define_method(:foo) do |variable1, variable2,*arg, i_will_not: 'work', **options, &block|
    # ...

o

 define_method(:foo) do |variable1, variable2, i_will_not: 'work', *arg, **options, &block|
    # ...

...pero esto no funcionará, parece que hay una limitación.Cuando lo piensas, tiene sentido ya que el operador splat está "capturando todos los argumentos restantes" y el doble splat está "capturando todos los argumentos de palabras clave restantes", por lo que mezclarlos rompería la lógica esperada.(¡No tengo ninguna referencia para probar este punto!)

actualización de agosto de 2018:

Artículo resumido: https://blog.eq8.eu/til/metaprogramming-ruby-examples.html

Además de la respuesta de Kevin Conner:Los argumentos de bloque no admiten la misma semántica que los argumentos de método.No puede definir argumentos predeterminados ni bloquear argumentos.

Esto sólo se solucionó en Ruby 1.9 con la nueva sintaxis alternativa "stabby lambda" que admite la semántica completa de los argumentos del método.

Ejemplo:

# Works
def meth(default = :foo, *splat, &block) puts 'Bar'; end

# Doesn't work
define_method :meth { |default = :foo, *splat, &block| puts 'Bar' }

# This works in Ruby 1.9 (modulo typos, I don't actually have it installed)
define_method :meth, ->(default = :foo, *splat, &block) { puts 'Bar' }

Con 2.2 ahora puedes usar argumentos de palabras clave:https://robots.thinkbot.com/ruby-2-keyword-arguments

define_method(:method) do |refresh: false|
  ..........
end
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top