Forum: Rails-ES warning pasando parámetros con define _method

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Felipe T. Armero (Guest)
on 2008-10-29 00:14
(Received via mailing list)
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
Sergio Gil Pérez de la Manga (Guest)
on 2008-10-29 00:36
(Received via mailing list)
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 ;)

--
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
Felipe T. Armero (Guest)
on 2008-10-29 02:20
(Received via mailing list)
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 ;)

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 :-D

Gracias

Saludos
Felipe
Guillermo (Guest)
on 2008-10-29 03:54
(Received via mailing list)
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.
This topic is locked and can not be replied to.