ruby module_function vs y compris le module
En ruby, je comprends que les fonctions du module peut être mis à disposition sans mélange dans le module en utilisant module_function
comme illustré ici. Je peux voir comment cela est utile si vous pouvez utiliser la fonction sans mélange dans le module.
module MyModule
def do_something
puts "hello world"
end
module_function :do_something
end
Ma question est que pourquoi vous devriez avoir la fonction définie à la fois de ces moyens.
Pourquoi ne pas simplement avoir
def MyModule.do_something
OU
def do_something
Dans ce genre de cas, il serait utile de disposer de la fonction disponible pour être mélangés dans des, ou pour être utilisé comme une méthode statique?
Vous devez vous connecter pour publier un commentaire.
Pense Énumérable.
C'est le parfait exemple de quand vous avez besoin de l'inclure dans un module. Si votre classe définit
#each
, vous obtenez beaucoup de bonté en incluant un module (#map
,#select
, etc.). C'est le seul cas où j'utilise les modules mixin - lorsque le module fournit des fonctionnalités en termes de quelques méthodes définies dans la classe que vous incluez le module. Je peut dire que cela devrait être le cas en général.Comme pour la définition de "statique" des méthodes, une meilleure approche serait:
Vous n'avez pas vraiment besoin de faire appel
#module_function
. Je pense que c'est juste bizarre héritage des trucs.Vous pouvez même le faire:
...mais il ne fonctionne pas bien si vous aussi vous souhaitez inclure le module quelque part. Je suggère de les éviter jusqu'à ce que vous apprendre les subtilités de l'Ruby métaprogrammation.
Enfin, si vous venez de le faire:
...il ne va pas finir comme une fonction globale, mais comme une méthode privée sur
Object
(il n'y a pas de fonctions en Ruby, juste des méthodes). Il y a deux inconvénients. Tout d'abord, vous n'avez pas namespacing - si vous définissez une autre fonction avec le même nom, c'est celle qui est évaluée plus tard que vous obtenez. Deuxièmement, si vous avez des fonctionnalités mises en œuvre en termes de#method_missing
, avoir une méthode privée dansObject
va ombre. Et enfin, monkey patchingObject
est juste mal affaires 🙂EDIT:
module_function
peut être utilisé d'une manière similaire àprivate
:De cette façon, vous pouvez appeler
Something.bar
, mais non pasSomething.foo
. Si vous définissez toutes les autres méthodes après cet appel à lamodule_function
, ils seraient également disponible sans mélange dans.Je ne l'aime pas, pour deux raisons, cependant. Tout d'abord, les modules qui sont à la fois mixte et "statique" méthodes ont l'air un peu louche. Il pourrait y avoir des cas valides, mais il ne sera pas très souvent. Comme je l'ai dit, je préfère utiliser un module comme un espace de noms ou de mélanger, mais pas les deux.
Deuxième, dans cet exemple,
bar
serait également disponible pour les classes/modules qui se mélangent dansSomething
. Je ne suis pas sûr quand c'est souhaitable, étant donné que soit la méthode utiliseself
et il doit être mélangé dans, ou ne l'est pas et puis il n'a pas besoin d'être mélangé dans.Je pense que l'utilisation
module_function
sans passer le nom de la méthode est utilisé le plus souvent avec. En va de même pourprivate
etprotected
.module_function
: Le "privé" de la fonctionfoo
ne peut pas être accessible à partir de l'intérieur debar
, parce quefoo
est alors une méthode d'instance (il n'a pasself
), et il peut être appelé que lorsque ce module est mélangé à un peu de classe. Impossible quand on est un module autonome juste pour namespacing fins. Alors, comment avoir les deux? Comment utiliser le module juste pour namespacing et cacher certaines de mise en œuvre des fonctions d'assistance à partir de l'extérieur, mais de leur permettre d'être appelé par ses méthodes d'interface?C'est un bon moyen pour un Ruby bibliothèque pour offrir une fonctionnalité qui n'utilise pas (beaucoup) d'état interne. Donc, si vous (par exemple) vous voulez offrir un
sin
fonction et ne veux pas polluer le "global" (Object
) de l'espace de noms, vous pouvez le définir en tant que méthode de classe en vertu d'une constante (Math
).Cependant, un développeur d'application, qui veut écrire une application mathématique, peut-être besoin
sin
tous les deux lignes. Si la méthode est également une méthode d'instance, elle peut simplement d'inclure lesMath
(ouMy::Awesome::Nested::Library
) module et vous pouvez maintenant appeler directementsin
(stdlib exemple).C'est vraiment le fait de faire une bibliothèque de plus confortable pour ses utilisateurs. Ils peuvent choisir eux-mêmes, s'ils veulent la fonctionnalité de votre bibliothèque sur le niveau supérieur.
Par la manière, vous pouvez obtenir une fonctionnalité similaire comme
module_function
en utilisant:extend self
(dans la première ligne du module). À mon avis, c'est mieux et rend les choses un peu plus faciles à comprendre.Mise à jour: Plus d'informations de fond dans cet article de blog.
module_function
surextend self
module_function
pourrait être plus convivial pour les débutants, mais tout le monde qui est en train de faire de graves Ruby devrait être en mesure de lire et de comprendre leextend self
version.extend self
est moins l'abstraction. Il utilise Ruby de base du jeu d'outils, tout enmodule_function
pourrait être retiré de Ruby, sans perdre de fonctionnalités importantes.self.method
etclass << self
.Si vous voulez voir un exemple de travail, découvrez la chronique de la gemme:
https://github.com/mojombo/chronic/blob/master/lib/chronic/handlers.rb
et des Gestionnaires est d'être inclus dans l'Analyseur de classe ici:
https://github.com/mojombo/chronic/blob/master/lib/chronic/parser.rb
Il utilise module_function pour envoyer les méthodes de Gestionnaires de cas spécifiques de Gestionnaire à l'aide de cette instance de la méthode invoke.