modules define_method ruby module mixins

define_method - ruby module_function vs módulo incluido



ruby define_method (3)

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

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

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

Por cierto, puedes 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 de entender.

Actualización: Más información de fondo en este artículo del blog .

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.

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

Mi pregunta es, sin embargo, por qué es posible que desee tener la función definida de ambas maneras.

¿Por qué no solo tener

def MyModule.do_something

O

def do_something

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


Piense en Enumerable .

Este es el ejemplo perfecto de cuándo necesitas incluirlo en un módulo. Si su clase define #each , obtendrá mucha bondad simplemente al 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 algunos 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

Realmente no necesitas llamar a #module_function . Creo que son solo cosas extrañas del legado.

Incluso puedes hacer esto:

module MyModule extend self def do_something end end

... pero no funcionará bien si también desea incluir el módulo en algún lugar. Sugiero evitarlo hasta que aprendas las sutilezas de la metaprogramación de Ruby.

Finalmente, si solo haces:

def do_something end

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

EDITAR:

module_function puede usarse de una manera similar a la private :

module Something def foo puts ''foo'' end module_function def bar puts ''bar'' end end

De esa manera, puedes llamar a Something.bar , pero no a Something.foo . Si define otros métodos después de esta llamada a module_function , también estarán disponibles sin mezclarse.

Sin embargo, no me gusta por dos razones. Primero, 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 a menudo. Como dije, prefiero usar un módulo como espacio de nombres o mezclarlo, pero no ambos.

Segundo, en este ejemplo, la 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 se usa a self y debe mezclarse, o no, y entonces no es necesario mezclarlo.

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