Warning pasando parámetros con define _method


#1

Hola,
me da que esta pregunta es mas apropiada para la lista de ruby que de
rails, pero la lanzo por aquí porque supongo que a alguno os ha pasado
currando con rails.

Estoy creando un metodo de una clase dinamicamente y necesito que
reciba parámetros opcionales osea necesito definir dinamicamente un
metodo que haga esto:

def foo( args = {} )
args[:type] = value

end

Pues este metodo recibe un hash de opciones o un hash vacío y
necesito que esté inicializado, he probado de varias maneras y la
única manera de que funcione correctamente es
así:
define_method( :foo ) do |args|
args ||= {}
args[:type]=value

end

Pero claro pega un horrendo warning cuando no le paso parámetros,
aunque si funciona bien.

warning: multiple values for a block parameter (0 for 1)

¿ Ideas u otras maneras para solucionar el warning ?

Saludos
Felipe


#2

2008/10/28 Felipe T. Armero removed_email_address@domain.invalid:

     args[:type] = value

end


Ror-es mailing list
removed_email_address@domain.invalid
http://lists.simplelogica.net/mailman/listinfo/ror-es

No es un bug, es una feature =;-)

Vamos, que es que es así, no se pueden hacer opcionales los parámetros
de un bloque (en Ruby 1.9 sí).

Pero, aunque es un poco hack, sí hay algo que puedes hacer, que es
usar el splat operator (el asterisco, vamos), que sí que se puede
hacer en 1.8:

class Hola

así lo tienes tú

define_method(:foo) do |arg|
“foo #{arg}”
end

#así lo puedes hacer
define_method(:bar) do |*args|
“bar #{args.first}”
end
end

puts Hola.new.foo(‘hey’)

imprime “foo hey”

puts Hola.new.foo

imprime “foo” y tira un warning

puts Hola.new.bar(‘tolo’)

imprime “bar tolo”

puts Hola.new.bar

imprime “bar”

Es un poco feo y pierdes el control total sobre el número de
parámetros (te pueden pasar lo que quieran, que menos el primero te
los comes) a no ser que lo hagas a mano (mirando el tamaño de args,
que es un array con todos los parámetros). Pero sigue funcionando y el
warning no aparece :wink:


Sergio Gil Pérez de la Manga
e-mail > removed_email_address@domain.invalid
blog > http://www.lacoctelera.com/porras
now > http://twitter.com/porras


#3

Siempre te quedará la opción de eval, donde tienes todas las libertades
de
la metaprogramación

class A
def new_method(meth)
instance_eval <<-END
def #{meth.to_s}(args = {})
puts args[:type]
end
END
end
end

irb(main):011:0* a = A.new
=> #<A:0xb7c1d2b8>
irb(main):012:0> a.new_method(:salute)
=> nil
irb(main):013:0> a.salute
nil
=> nil
irb(main):014:0> a.salute(:type=>“good”)
good
=> nil
irb(main):015:0>

Un Saludo.


#4

On Oct 28, 2008, at 11:36 PM, Sergio Gil Pérez de la Manga wrote:

Es un poco feo y pierdes el control total sobre el número de
parámetros (te pueden pasar lo que quieran, que menos el primero te
los comes) a no ser que lo hagas a mano (mirando el tamaño de args,
que es un array con todos los parámetros). Pero sigue funcionando y el
warning no aparece :wink:

Estuve probando con el splat operator sin llegar a afinarlo del todo
y preferí quedarme con el warning, aparte que supuse que habría algo
mas “elegante” de solucionarlo.
Finalmente lo he solucionado
así:
define_method( :foo ) do |*args|
args=args.first
args ||= {}
raise(ArgumentError, “wrong number of arguments 3 is the
maximum.”) if args.size > 3
args.merge! :type => value

end

El control de parámetros lo hago comprobando a manubrio el tamaño del
hash que me llega en primer lugar y si es mas de los que necesito
salto la excepción, pues el metodo lo uso con un hash foo(:bar =>
1, :foobar => 2)

si me viene a nil lo inicializo y punto, es un hack un poco raro, pero
soluciona el asunto osea que así se queda hasta que rulemos con la
versión 1.9 :smiley:

Gracias

Saludos
Felipe