Extendiendo clases

Hola gente,
Tengo unos cuantos modelos y controladores que comparten una serie de
metodos y estoy viendo la manera de ser mas DRY y no tener el código
repetido con todos los problemas para mantenerlo que esto acarrea.
Tengo curiosidad por saber que patrones usais vosotros en este tipo de
situaciones.

Tras darle vueltas yo estoy haciendolo de la siguiente manera:

Me creo uno modulo:

module foo

 def self.included(base)
   base.extend ClassMethods
 end

 module ClassMethods

def my_foo
belongs_to :bar

       include foo::InstanceMethods
      extend  foo::SingletonMethods

end

 end

 module InstanceMethods
        def example_method end
 end

 module SingletonMethods
        def example_method end
end

end

luego con un initializer lo cargo:

ActiveRecord::Base.send(:include, foo)

para luego en el modelo:

class Article < ActiveRecord::Base
my_foo
end

Y bueno lo mismo para los controladores.
El único inconveniente que le encuentro es que cada vez que haces un
cambio tienes que reiniciar el servidor o relanzar el irb.
¿Alguien sabe alguna manera de evitar esto y hacer que se cargen los
cambios en “caliente”?¿ideas para mejorar el patron?

saludos
Felipe

On Sun, Sep 21, 2008 at 9:39 PM, Felipe T. Armero <
[email protected]> wrote:

module SingletonMethods
       def example_method end

end

end

luego con un initializer lo cargo:

ActiveRecord::Base.send(:include, foo)

A mi no me gusta ese modelo, entre otros, por el hecho de usar send, que
si
mal no recuerdo, en ruby 1.9, send no es capaz de llamar a métodos
privados
como include.
Personalmente, prefiero algo parecido, pero que no toque activerecord:

class User < AR::Base
include my_module

end

Me gusta también más por lo que se me pega de Merb. Un modelo de
datamaper:
class User
include DM::Resource
include my_module
end

El único inconveniente que le encuentro es que cada vez que haces un
cambio tienes que reiniciar el servidor o relanzar el irb.
¿Alguien sabe alguna manera de evitar esto y hacer que se cargen los
cambios en “caliente”?¿ideas para mejorar el patron?

Mira si te puede ser útil el reload_application
http://github.com/rails/rails/tree/master/actionpack/lib/action_controller/dispatcher.rb

saludos
Felipe

saludos

On 21 Sep 2008, at 22:26, Guillermo wrote:

luego con un initializer lo cargo:

ActiveRecord::Base.send(:include, foo)

A mi no me gusta ese modelo, entre otros, por el hecho de usar send,
que si mal no recuerdo, en ruby 1.9, send no es capaz de llamar a
métodos privados como include.

Es cierto que ‘send’ no es capaz de llamar a métodos privados en Ruby
1.9.

La alternativa (la que usan en Rails, si no me equivoco) es:

ActiveRecord::Base.class_eval { include Foo }

-christos

Hubo un tiempo en el que #send se quito en el desarrollo de Ruby 1.9,
pero regreso:

Mon Nov 5 00:32:32 2007 Yukihiro M. [email protected]

* eval.c (rb_f_send): allow send/__send__ to call methods of all
  visibility again.  we no longer provide __send, __send!.

¡Ah!

Esto explica porque hay commits como estos:

http://github.com/rails/acts_as_list/tree/master/init.rb

pero no en todos lo sitios donde deberia:

http://github.com/rails/acts_as_tree/tree/master/init.rb

:slight_smile:

-christos

2008/9/21 Guillermo [email protected]:

A mi no me gusta ese modelo, entre otros, por el hecho de usar send, que si
mal no recuerdo, en ruby 1.9, send no es capaz de llamar a métodos privados
como include.

#send se usa sin reparos en Rails:

fxn@feynman:~/prj/rails$ ack ‘.send(’ | wc -l
465

Hubo un tiempo en el que #send se quito en el desarrollo de Ruby 1.9,
pero regreso:

Mon Nov 5 00:32:32 2007 Yukihiro M. [email protected]

 * eval.c (rb_f_send): allow send/__send__ to call methods of all
   visibility again.  we no longer provide __send, __send!.

En 1.9 finalmente #send sigue ahi como en 1.8, y se añade #public_send
por si el caller quiere respetar visibilidad a proposito.

Dicho esto, para una cuestion asi los cambios de API que pudieran
haber en la 1.9 en general no me parecerian muy relevantes con
respecto al diseño en si de la solucion.