2012-07-18 12 views
39

En ruby, entiendo que las funciones del módulo pueden estar disponibles sin mezclar en el módulo usando module_function como se muestra aquí. Puedo ver cómo esto es útil para que pueda usar la función sin mezclar en el módulo.ruby ​​module_function vs including module

module MyModule 
    def do_something 
    puts "hello world" 
    end 
    module_function :do_something 
end 

Mi pregunta es por qué es posible que desee tener la función definida de estas dos maneras.

¿Por qué no tienen

def MyModule.do_something 

O

def do_something 

En qué tipo de casos podría ser útil tener la función disponible para ser mezclado en, o para ser utilizado como un método estático ?

Respuesta

35

Piense en Enumerable.

Este es el ejemplo perfecto de cuándo debe incluirlo en un módulo. Si su clase define #each, obtiene mucha bondad con solo incluir un módulo (#map, #select, etc.). Este es el único caso cuando uso módulos como mixins, cuando el módulo proporciona funcionalidad en términos de unos pocos métodos, definidos en la clase en la que se incluye el módulo. Puedo argumentar que este debería ser el único caso en general.

En cuanto a la definición de métodos "estáticos", un mejor enfoque sería:

module MyModule 
    def self.do_something 
    end 
end 

Usted realmente no necesita llamar #module_function. Creo que es solo un legado extraño.

incluso Usted puede hacer esto:

module MyModule 
    extend self 

    def do_something 
    end 
end 

... pero no va a funcionar bien si también desea incluir el módulo en alguna parte. Sugiero evitarlo hasta que aprenda las sutilezas de la metaprogramación de Ruby.

Por último, si usted acaba de hacer:

def do_something 
end 

, ... no terminan como una función global, sino como un método privado en Object (no hay ninguna función en Ruby, a métodos). Hay dos desventajas. En primer lugar, no tiene espacio de nombres: si define otra función con el mismo nombre, es la que se evalúa más adelante. En segundo lugar, si tiene la funcionalidad implementada en términos de #method_missing, tener un método privado en Object lo sombreará. Y, por último, mono parches Object es sólo el mal negocio :)

EDIT:

module_function se puede utilizar de una manera similar a private:

module Something 
    def foo 
    puts 'foo' 
    end 

    module_function 

    def bar 
    puts 'bar' 
    end 
end 

De esta manera, se puede llamar Something.bar, pero no no Something.foo. Si define otros métodos después de esta llamada al module_function, también estarían disponibles sin mezclar.

No me gusta por dos razones.En primer lugar, los módulos que están mezclados y tienen métodos "estáticos" suenan un poco dudosos. Puede haber casos válidos, pero no será tan seguido. Como dije, prefiero usar un módulo como espacio de nombres o mezclarlo, pero no ambos.

En segundo lugar, en este ejemplo, bar también estaría disponible para las clases/módulos que se mezclan en Something. No estoy seguro de cuándo es deseable, ya que el método usa self y debe mezclarse, o no, y luego no necesita mezclarse.

Creo que usar module_function sin pasar el El nombre del método se usa con bastante más frecuencia que con. Lo mismo vale para private y protected.

+0

gracias por la explicación. Entiendo por qué querría mezclar en un módulo, mi pregunta era más acerca de cuándo podría usar realmente la función module_function. ¿Hay algún momento en que puedas usarlo? –

+2

Hay una captura más en este último ejemplo con 'module_function': La función" privada "' foo' no se puede acceder desde dentro de 'bar', porque' foo' es entonces un método de instancia (no tiene 'self') , y solo se puede invocar cuando este módulo está mezclado en alguna clase. Imposible cuando es un módulo independiente solo para propósitos de creación de espacios de nombres. Entonces, ¿cómo tener ambas cosas? ¿Cómo se usa el módulo solo para el espaciado de nombres y se ocultan algunas funciones de ayuda de implementación del mundo exterior, pero se les permite llamar por sus métodos de interfaz? – SasQ

12

Es una buena forma de que una biblioteca de Ruby ofrezca funcionalidades que no usan (mucho) el estado interno. Por lo tanto, si (por ejemplo) desea ofrecer una función sin y no desea contaminar el espacio de nombres "global" (Object), puede definirlo como método de clase bajo una constante (Math).

Sin embargo, un desarrollador de aplicaciones que desee escribir una aplicación matemática puede necesitar sin cada dos líneas. Si el método también es un método de instancia, puede simplemente incluir el módulo Math (o My::Awesome::Nested::Library) y ahora puede llamar directamente al sin (ejemplo de stdlib).

Se trata realmente de hacer una biblioteca más cómoda para sus usuarios. Pueden elegir ellos mismos, si quieren la funcionalidad de su biblioteca en el nivel superior.

Por cierto, puede lograr una funcionalidad similar como module_function usando: extend self (en la primera línea del módulo). En mi opinión, se ve mejor y hace las cosas un poco más claras para comprender.

Actualización: Más información general en this blog article.

+3

El [ruby styleguide] (https://github.com/bbatsov/ruby-style-guide#classes--modules) prefiere '' module_function'' sobre '' extends self'' – zhon

+3

Gracias por el puntero. No estoy de acuerdo con eso, sin embargo. 'module_function' podría ser más amigable para principiantes, pero todos los que estén haciendo Ruby en serio deberían poder leer y comprender la versión de' extenderse uno mismo '. 'extender self' es menos abstracción.Utiliza el conjunto de herramientas base de Ruby, mientras que 'module_function' se puede eliminar de Ruby, sin perder funcionalidad importante. –

+0

Gracias por dar tus razones. Antes de leer este Q/A, estaba usando '' self.method'' y '' class << self''. – zhon