2010-07-01 9 views
5

En este código Ruby:¿Es posible llamar a una función del módulo desde el interior de una clase que también se encuentra en ese módulo

Module M 
    Class C < Struct.new(:param) 
    def work 
     M::helper(param) 
    end 
    end 

    def helper(param) 
    puts "hello #{param}" 
    end 
end 

consigo un "método no definido 'ayudante' para 'M: módulo'" error cuando trato de ejecutar

c = M::C.new("world") 
c.work 

pero llamar M::helper("world") directamente de otra clase funciona bien. ¿Las clases no pueden llamar a las funciones del Módulo que están definidas en el mismo Módulo en el que están definidas? ¿Hay alguna forma de evitar esto aparte de mover la clase fuera del módulo?

Respuesta

4

Con el fin de invocar M::helper es necesario definir como def self.helper; end Para efectos de comparación, echar un vistazo a ayudante y helper2 en el siguiente fragmento modificado

module M 
    class C < Struct.new(:param) 
    include M  # include module to get helper2 mixed in 
    def work 
     M::helper(param) 
     helper2(param) 
    end 
    end 

    def self.helper(param) 
    puts "hello #{param}" 
    end 

    def helper2(param) 
    puts "Mixed in hello #{param}" 
    end 
end 

c = M::C.new("world") 
c.work 
+0

gracias por la explicación de la diferencia entre usar uno mismo. e incluyendo el módulo. –

3

debe anteponer método módulo con self:

module M 
    class C < Struct.new(:param) 
    def work 
     M::helper(param) 
    end 
    end 

    def self.helper(param) 
    puts "hello #{param}" 
    end 
end 
+0

Estos no estaban en la pregunta, pero 'C.work' se llama como un método de clase en lugar de método de instancia. ¿Has intentado llamar a 'M.helper (" foo ")'? – Eimantas

2

C está intentando llamar helper en M cuando helper no está en M 's clase singleton. Además, sigues diciendo que helper es una función de módulo, cuando es solo un método. Haciendo helper una función módulo hará que el trabajo código:

module M 
    class C < Struct.new(:param) 
    def work 
     M::helper(param) 
    end 
    end 

    module_function 

    def helper(param) 
    puts "hello #{param}" 
    end 
end 

Incluyendo el módulo en la clase también trabajará:

module M 
    class C < Struct.new(:param) 
    include M 

    def work 
     helper(param) 
    end 
    end 

    def helper(param) 
    puts "hello #{param}" 
    end 
end 

En el primer ejemplo, helper se pone en M 's de clase singleton con module_function. El segundo ejemplo importa los métodos de M en C para que C pueda usarlos. Otra diferencia es que en el primero, podrá llamar al M.helper desde cualquier lugar de su código. En el segundo, podrá llamar al helper desde cualquier instancia de C en su código. Para solucionar este problema, crea helper privada:

module M 
    class C < Struct.new(:param) 
    include M 

    def work 
     helper(param) 
    end 
    end 

    private 
    def helper(param) 
    puts "hello #{param}" 
    end 
end 
1

Aquí es una explicación:

De ruby docs.

Un módulo es una colección de métodos y constantes. Los métodos en un módulo pueden ser métodos de instancia o métodos de módulo. Los métodos de instancia aparecen como métodos en una clase cuando se incluye el módulo, los métodos de módulo no. Por el contrario, se pueden llamar a los métodos de módulo sin crear un objeto de encapsulado, mientras que los métodos de instancia pueden no serlo. (Véase el módulo # module_function.)

self.methodname dentro de un módulo crea un método módulo.

En este caso, cuando invoca M::helper, realmente hace M.helper cuando lo mira desde el punto de vista de un desarrollador C++. El receptor es el objeto Módulo (una instancia del módulo tipo ruby ​​incorporado) en este caso.


Otra manera de mirar esto es para entender un concepto receptor, cada llamada al método consiste en un nombre del receptor y el método (+ params opcionalmente y el bloque de código). El receptor puede ser Module object, Class object o instancia de una clase definida por el usuario.

Solo puede invocar métodos de módulo (o clase) en un objeto de módulo (o clase). Puede invocar cualquier método (Módulo/Clase/instancia) en una instancia.

Si desea invocar un método de instancia definido en un módulo, debe darle un receptor por including ese módulo en alguna clase y crear una instancia de este.

Así que en este caso otra solución puede ser:

module MM 
    def helper(param) 
    puts "hello #{param}" 
    end 

    class ReceiverClass 
    include MM   # add helper() to ReceiverClass 
    end 

    class C < Struct.new(:param) 
    def work 
     ReceiverClass.new.helper(param) 
    end 
    end 
end 

c = MM::C.new("world") 
c.work 
Cuestiones relacionadas