2009-11-24 14 views
17

Considere el siguiente código:Los métodos de instancia en módulos

module ModName 
    def aux 
    puts 'aux' 
    end 
end 

Si reemplazamos module con class, podemos hacer lo siguiente:

ModName.new.aux 

Los módulos no pueden ser instanciadas, sin embargo. ¿Hay alguna manera de llamar al método aux en el módulo?

+3

para un solo uso desechable, que puede hacer 'Object.new.extend (ModeName) .aux' – AJcodez

Respuesta

22

Piensa en qué es aux. ¿Qué objeto responderá al aux? Es un método de instancia, lo que significa que las instancias de las clases que incluyen ModName responderán a él. El módulo ModName en sí mismo no es una instancia de dicha clase. Esto tampoco funcionaría si hubiera definido ModName como una clase; no puede llamar a un método de instancia sin una instancia.

Los módulos se parecen mucho a las clases que se pueden combinar en otras clases para agregar un comportamiento. Cuando una clase se mezcla en un módulo, todos los métodos de instancia del módulo se convierten en métodos de instancia de la clase. Es una forma de implementar herencia múltiple.

También sirven como sustitutos para los espacios de nombres, ya que cada módulo define un espacio de nombres. Pero eso es algo sin relación. (Por cierto, las clases también tienen sus propios espacios de nombres, pero lo que es una clase implica que vamos a crear instancias de ella, por lo que son conceptualmente equivocado para ese propósito.)

+2

Un caso de uso del mundo real para esto es con el método 'helper' de Sinatra que toma un módulo y lo mezcla en las solicitudes. Si los métodos de su módulo no dependen del estado (por ejemplo, una función que formatea una cadena pasada), también pueden ser apropiados llamados externamente como 'MyHelperModule.foo (bar)'. El uso de 'module_function' (por la respuesta de @ JPabloFernández a continuación) permite el acceso a un método de 'instancia' de un solo módulo a medida que las solicitudes de OP. – Phrogz

5

la definición del módulo se evalúa como 'esto es ...', ¿por qué?

En Ruby, todo es una expresión, no hay declaraciones o declaraciones. Lo que significa que todo evalúa a un valor. (Sin embargo, esto no significa necesariamente que se evalúa como un valor útil . Por ejemplo, el método puts da siempre como resultado nil, al igual que una expresión definición def método (excepto en Rubinius, donde la expresión se evalúa como un defCompiledMethod objeto para el método que se está definiendo).)

Por lo tanto, si todo se evalúa a un valor, ¿qué debería evaluar una expresión de definición de módulo? Bueno, hay un par de candidatos: podría evaluar a nil, al igual que una expresión de definición de método. O podría evaluar el objeto del módulo en sí, después de todo, este es lo que estamos definiendo, ¿verdad? Pero en realidad, Matz eligió una tercera opción: las expresiones de definición de módulo (y clase) realmente evalúan a lo que sea la última expresión dentro del cuerpo de definición de módulo evaluado. (Esto le permite simular fácilmente las otras dos posibilidades simplemente poniendo nil o self como la última expresión dentro de un cuerpo de definición de módulo.)

En su caso, la última expresión dentro del cuerpo de definición del módulo es una asignación. Pero, ¿una tarea? ¿Qué diablos hace que devolver? ¿No es eso una declaración? No, no en Ruby. Todo es una expresión y las asignaciones no son una excepción: las expresiones de asignación se evalúan según lo que evalúa el lado derecho. Aquí, el lado derecho de la expresión de asignación es un literal de cadena, que se evalúa como un objeto de cadena.

Por lo tanto, toda la expresión de definición de módulo evalúa la cadena 'this is a const in module'.

+0

gracias Jörg W Mittag, lo tengo. – freenight

+6

La pregunta fue muy editada desde la respuesta de Joerg, si alguien está un poco confundido sobre lo que está hablando. –

0
class Foo 
    include ModName 
end 
Foo.new.aux 
# output: aux 
19

Puede hacerlo de esta manera:

module ModName 
    def aux 
    puts 'aux' 
    end 
    module_function :aux 
end 

y luego simplemente llamarlo:

ModName.aux 
+4

También: si está utilizando el módulo * exclusivamente * como espacio de nombres, 'extender self' es una opción más clara para definir todos y cada uno de los métodos como una función module_. – yaauie

+1

@yaauie Si no pasa un argumento a 'module_funciton', cualquier función que se encuentre debajo se convertirá en una función de módulo. Funciona de la misma manera que 'privado '. – LandonSchropp

14

También se puede decir

module ModName 
    extend self 

    def aux 
    puts 'aux' 
    end 
end 

Entonces puede incluir el módulo normalmente, pero también los métodos de llamada a través de ModName.

2

Y un poco más ...

module Y 
    def Y.a 
    puts "a" 
    end 

    def Y.b 
    c 
    end 

    def self.c 
    puts "b -- c" 
    end 
end 

llamada (sin '.new'):

Y.a #=> "a" 
Y.b #=> "b -- c" 
Y.C#=> "b -- c" 
+1

'Y.c' funciona también. También puedes hacer 'módulo Y; clase << uno mismo; def c; pone "b - c"; fin; end; 'y define' :: c' en su clase propia. –

Cuestiones relacionadas