2012-03-27 9 views
8
auto

tengo el siguiente código:No entender las clases, módulos y el método de la clase <<

class MyClass 
    module MyModule 
    class << self 

     attr_accessor :first_name 

     def myfunction 
     MyModule.first_name = "Nathan" 
     end 

    end 
    end 
end 

Cuando llamo el método myfunction como tal, funciona bien:

> me = MyClass::MyModule.myfunction 
=> "Nathan" 
> me 
=> "Nathan" 

Pero si eliminé el class << self y agregué un prefijo self. a myfunction, no funciona.

Por ejemplo:

class MyClass 
    module MyModule 

    attr_accessor :first_name 

    def self.myfunction 
     MyModule.first_name = "Nathan" 
    end 

    end 
end 


> me = MyClass::MyModule.myfunction 
NoMethodError: undefined method `first_name=' for MyClass::MyModule:Module 

estoy tratando de entender el método class << self. Pensé que era una manera de agregar el prefijo self. a todos los métodos dentro de él, pero si eso era cierto, ¿por qué no funciona si lo elimino y prefijo cada método con self. manualmente?

Gracias de antemano por su ayuda.

+2

Si realmente quieres aprender los detalles de Ruby metaprogramming, recomiendo el [libro Metaprogramación Rubí por Paolo Perrotta] (http://pragprog.com/book/ppmetr/metaprogramming-ruby) . – sarnold

Respuesta

7

Esto es porque su attr_accessor :first_name también está envuelto por el class << self.

Para hacerlo de la manera que usted sugiere, puede utilizar mattr_accessor así:

require 'active_support' 

class MyClass 
    module MyModule 

    mattr_accessor :first_name 

    def self.myfunction 
     MyModule.first_name = "Nathan" 
    end 

    end 
end 
+0

¿Esto es algo específico de los rieles que se basa en active_support? ¿Asumo que el mattr_accessor es un método específico de setter/getter? – Nathan

+0

Eso es correcto. Para bien o para mal, 'mattr_accessor' solo se puede acceder a través de Rails. – jnevelson

+0

Hay un montón de cosas que a veces desearía que también estuvieran disponibles en Ruby regular, no solo en Rails o ActiveRecord. –

4

Para comprender mejor cómo se puede lograr lo que quiere, echar un vistazo al siguiente ejemplo:

module PrintingModule 

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

    module ClassMethods 

    def class_method_of_class 
     puts "I am class #{self.name}" 
    end 

    end 

    def instance_method_of_class 
    puts "My name is: #{@name}" 
    end 

    class << self 
    def static_module_method 
     puts "Printer version 1.0" 
    end 
    end 
end 

class SomeObject 
    include PrintingModule 
    def initialize(name) 
    @name = name 
    end 
end 

object = SomeObject.new("Something") 
object.instance_method_of_class 
SomeObject.class_method_of_class 
PrintingModule.static_module_method 

espero que sea más claro ahora, tenga en cuenta que esto es sólo una de las posibles vías (hay otros)

ACTUALIZACIÓN: Trataré de ser más específico. Cuando define métodos de instancia/singleton en el módulo, lo que realmente está haciendo es definir los métodos de instancia de clase que incluirán ese módulo y, por otro lado, los métodos de clase definidos en el módulo se convertirán en métodos de clase de ese módulo. Lo segundo que se debe saber es que attr_accessor crea un método de instancia para getter y setter del parámetro dado.

Ahora, para responder una parte de su pregunta, en el primer ejemplo está creando 3 métodos de clase en la clase del módulo. En el segundo, está creando 1 método de clase donde está intentando acceder a otro método de clase (setter), pero sus getters y setters se definen como métodos de instancia = se convertirán en instancia de método de clase que incluirá su módulo, usted no puede llegar a ellos de esta manera = no tiene acceso a sus getters y setters. En cuanto a la explicación de sí mismo, bueno, no soy tan habilidoso, pero hasta donde yo sé, cuando usas "clase < < self" estás abriendo eigenclass (cada objeto tiene su propia anynonymous) del objeto (nota que La clase, los módulos o las instancias de las clases también son, por supuesto, objetos) en los que está definiendo métodos de instancia. Método de clase de objeto en Ruby = método de instancia de la clase de usuario del objeto. Así que usted puede hacer esto por ejemplo:

text = "something" 
class << text 
    def say_hi 
    puts "Hi!" 
    end 
end 

text.say_hi 

Al crear instancia de la clase (String en ese ejemplo), esa instancia recibe su propia clase anónima única que es subclase de esta clase. En el ejemplo, ha definido el método de instancia en la clase de creación de la subclase anónima de clase String. Entonces puede usar el método "say_hi" en el objeto de texto pero no en la clase String. Entonces, "clase < < self" está abriendo esas clases propias.

Por otro lado, "solo" solo representa un objeto en el contexto actual, lo que significa lo mismo en algunos escenarios (por ejemplo, el suyo). En cuanto al método self.included, es solo un método de devolución de llamada que se llama cuando el módulo se incluye en la clase con un parámetro que representa el objeto (aquí clase SomeObject).

Espero que haya respondido al menos parte de su pregunta. Más información aquí: Difference between 'self.method_name' and 'class << self' in Ruby

+0

Veo cómo estás usando mixins, y la mayoría todo tiene sentido, excepto para la parte superior del 'autodefinido (objeto) ... '. Lo que pasa es que no estoy buscando tanto lograr tanto como tratar de comprender el comportamiento. No estoy seguro de que tu ejemplo haya explicado por qué la 'clase << self 'funcionaba con un módulo mixto pero el prefijo' .self' no lo hacía cuando intentabas acceder al método de la clase. En realidad, estoy confundido en mis ejemplos sobre cómo el método de instancia: first_name está disponible con una llamada de clase. – Nathan

+0

He actualizado mi respuesta, espero que responda al menos parte de sus preguntas. Que tengas un buen día. – Giron

Cuestiones relacionadas