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?

28
demandé sur brad 2010-05-19 23:44:36

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.

31
répondu Ryan Bigg 2010-05-19 21:38:36

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.

13
répondu horseyguy 2010-05-20 07:07:25

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
7
répondu jamin4jc 2010-05-20 00:34:43

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.

3
répondu TauPan 2011-11-22 09:57:01