[Ror-es] #include en ruby
Esteban
ecorrales at mercedessoftware.com
Tue Sep 26 00:20:36 GMT 2006
Entonces forzando la sintaxis de Ruby se podría escribir
class User < ActiveRecord::Base
User.has_many :posts
end
(no garantizo que compile)
Asi queda más claro que "has_many" se ejecuta sobre (la clase) "User" y
una única vez, en tiempo de la definición de la clase, el momento idoneo
para ampliarla por medio de metaprogramación.
Agradezco tu extensa explicación, me haz aclaro conceptos teóricos de
Ruby que antes aceptaba por pura fé ;-)
Me pregunto si en los seminarios de RoR se aprende tanto con en esta
lista. :-D
Lo que sigue ahora es aplicar la metaprogramación en mis proyectos, una
forma elegante de reducir la cantidad y complejidad del código.
Saludos
Xavier Noria wrote:
>On Sep 25, 2006, at 8:03 PM, Esteban wrote:
>
>
>
>>Magnífica solución: funcional, sencilla, elegante, ruby-idiomática
>>
>>
>
>Estupendo, me alegro de que te guste :-).
>
>
>
>>Claro también me gustaría entender por qué funciona, un poco de
>>teoría de Ruby ya sabes, así que te disparo unas preguntas si no te
>>molesta
>>
>>1. self.abstract_class, le asigna un valor a una variable de clase
>>(o un setter de clase), es este un atributo de ActiveRecord o de
>>Object?
>>
>>
>
>abstract_class es un atributo de la clase ActiveRecord::Base, esta
>definido en el archivo activerecord/lib/active_record/base.rb:
>
> # Set this to true if this is an abstract class (see
>#abstract_class?).
> attr_accessor :abstract_class
>
>Dada un clase persistente, klass, AR necesita determinar de donde
>leer su metadata, para ello usa el metodo de clase base_clase, y como
>se ve ignora las clases abstractas:
>
> # Returns the base AR subclass that this class descends from. If A
> # extends AR::Base, A.base_class will return A. If B descends from A
> # through some arbitrarily deep hierarchy, B.base_class will
>return A.
> def base_class
> class_of_active_record_descendant(self)
> end
>
> # Returns the class descending directly from ActiveRecord in the
>inheritance hierarchy.
> def class_of_active_record_descendant(klass)
> if klass.superclass == Base || klass.superclass.abstract_class?
> klass
> elsif klass.superclass.nil?
> raise ActiveRecordError, "#{name} doesn't belong in a
>hierarchy descending from ActiveRecord"
> else
> class_of_active_record_descendant(klass.superclass)
> end
> end
>
>
>
>>2. A has_* y validates_* les llamas métodos estáticos, vengo de C++
>>y Java, ahí eso equivale a un método de clase, que significa en Ruby
>>
>>
>
>Eso mismo, son metodos de clase. Cuando en Ruby defines un metodo
>"foo" de este modo
>
> class Foo
> def self.foo
> # ...
> end
> end
>
>estas definiendo un metodo de clase y puedes invocarlo de este modo:
>
> Foo.foo
>
>Hay idiomas alternativos para definir metodos de clase pero ese es
>para mi el mas evidente. Hay todo un tema aqui muy chulo para
>estudiar para saber exactamente como va esto, ahi intervienen los
>conceptos de metodo singleton, que las clases son instancias de
>Class, que todo esta basado en envio de mensajes, etc. Eso esta muy
>bien explicado en el Pickaxe y en Ruby for Rails.
>
>Por cierto, una de las diferencias con los metodos estaticos de Java
>es que no puedes invocar metodos de clase sobre instancias de dicha
>clase:
>
> irb(main):001:0> class Foo; def self.foo; true; end; end
> => nil
> irb(main):002:0> Foo.foo
> => true
> irb(main):003:0> f = Foo.new
> => #<Foo:0x35a618>
> irb(main):004:0> f.foo
> NoMethodError: undefined method `foo' for #<Foo:0x35a618>
> from (irb):4
> from :0
>
>OK, pues sucede que ActiveRecord::Base define montones de metodos de
>clase, por ejemplo has_many es uno.
>
>Cuando el codigo que define una clase se evalua, "self" es la clase
>misma, y cuando se esta en la definicion de un metodo, "self" es el
>objeto al cual se esta enviando el mensaje. Si el metodo es de clase
>"self" dentro del metodo sigue siendo la clase, siempre es el
>receptor del mensaje.
>
>Un dato importante es que el codigo que define una clase se ejecuta
>*al interpretar la definicion de la clase*:
>
> irb(main):005:0> class Foo; puts "foo"; end
> foo
> => nil
>
>Ves que se imprime "foo"? En Java se podria medio emular eso con
>bloques static { ... }.
>
>Por ello, cuando escribes
>
> class User < ActiveRecord::Base
> has_many :posts
> end
>
>se ejecuta el metodo de clase has_many, con el simbolo :posts como
>argumento, al procesarse la definicion de la clase User. Como no se
>explicita el receptor este es self por definicion, y en ese punto
>self es User. Lo interesante de esto es que como justamente has_many
>se evalua al interpretar la definicion de User tenemos ahi la
>oportunidad de realizar metaprogramacion. Para cuando vayamos a usar
>la clase todos los metodos de coleccion existen como si los hubieras
>picado de verdad.
>
>Todo eso junto explica como funciona la solucion que envie:
>
> class Abstract < ActiveRecord::Base
> self.abstract_class = true
>
> def self.setup_common_associations
> has_many :foos
> has_one :bar
> end
> end
>
> class X < Abstract
> setup_common_associations
> end
>
>Hemos definido un metodo de clase en Abstract. Como en cualquier
>metodo su cuerpo se ejecuta solo al ser invocado.
>
>Al interpretarse la definicion de X hay una llamada a
>setup_common_associations en el top-level, por tanto dicha llamada se
>realiza. La ejecucion del metodo tiene as su vez una llamada has_many
>(:foos), cuyo receptor es self, que en ese momento es X. Por lo
>tanto, la metaprogramacion se realiza sobre X, del mismo modo que se
>haria si hubieras escrito ese has_many normal en el top-level de X.
>Lo verdaderamente importante es que conseguimos que X sea el receptor
>de ese codigo.
>
>Que tal explicado asi?
>
>-- fxn
>
>_______________________________________________
>Ror-es mailing list
>Ror-es at lists.simplelogica.net
>http://lists.simplelogica.net/mailman/listinfo/ror-es
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.simplelogica.net/pipermail/ror-es/attachments/20060926/a5ec285a/attachment-0001.htm
More information about the Ror-es
mailing list