Syntaxe du module imbriqué Ruby (et Rails)
Je me demande quelle est la différence entre les deux modules suivants
# First Example
module Parent
module Child
end
end
Et
# Second Example
module Parent::Child
end
En utilisant la 2ème méthode, il semble que le module Parent doit être préalablement défini, sinon j'obtiens une erreur 'constante non initialisée'
Compte tenu de cela, quelle est la manière préférée de définir des modules comme celui-ci, puis d'ajouter des enfants imbriqués en ce qui concerne la syntaxe et la structure de fichier (ie. les dossiers etc). La référence à un chemin de Rails serait grandement apprécier.
Ces deux exemples sont-ils équivalents à toutes fins utiles?
4 réponses
Dans le premier exemple, il définit les Parent
module, puis le Child
module. Le deuxième exemple, comme vous le dites vous-même, doit avoir le module Parent
défini avant la main. Au détriment d'une ligne de code supplémentaire, vous vous assurez que le module que vous imbriquez en utilisant votre premier exemple sera toujours défini.
Pour un exemple Rails regardons dans le railties / lib / rails / engine.rb fichier ré-ouvre le Rails
module, puis définit un Engine
classe à l'intérieur de celui-ci. Cela aurait pu être fait avec simplement:
class Rails::Engine
Mais peut-être pour les raisons indiquées ci-dessus et peut-être aussi pour des raisons de clarté, le module a été défini en premier, puis la classe à l'intérieur.
Je préfère la deuxième méthode (si je suis sûr que le Parent est déjà défini) car il semble plus propre, esp. lorsque la nidification est très profonde.
Cependant, la 1ère méthode a quelques avantages, un pas encore discuté est qu'un module imbriqué a accès à toutes les constantes lexicalement disponibles dans le module englobant.
De manière générale, vous ne voulez pas définir un module en utilisant la syntaxe du module Parent::Child sauf si vous pouvez être absolument certain que Parent est déjà là. Un sous-Module ne peut être défini en utilisant la syntaxe:: que si le module parent est défini. Dans votre exemple, si vous procédez comme suit, vous n'obtiendrez pas d'erreur constante non initialisée.
module Parent
end
module Parent::Child
end
Il semble que la réponse de Banister soit aussi la raison de ce comportement:
ruby-1.9.2-p290 :001 > module A; module A; A.ancestors; end; end
=> [A::A]
ruby-1.9.2-p290 :002 > module A::A; A.ancestors; end
=> [A]
Le module interne A est une constante à l'intérieur du module externe A, et donc il n'est pas visible en utilisant la deuxième méthode.
Modification de mon commentaire précédent:
Ceci est expliqué dans 7.9 "recherche constante" de "le langage de programmation Ruby" (première édition). La partie pertinente ici est le Module.imbrication, qui ne contient pas le module externe dans le deuxième exemple, donc A ne peut être trouvé que dans le global portée.