30 votes

Comment obtenir des constantes définies par la classe Module de Ruby via la réflexion?

J'ai essayé d'obtenir Matz-n-Flanagan RPL du livre de la métaprogrammation chapitre dans ma tête. Cependant, je ne pouvais pas comprendre la sortie de l'extrait de code suivant que j'ai rêvé.

p Module.constants.length           # => 88
$snapshot1 = Module.constants       
class A
  NAME=:abc

  $snapshot2 = Module.constants
  p $snapshot2.length               # => 90
  p $snapshot2 - $snapshot1         # => ["A", "NAME"]

end
p Module.constants.length           # => 89
p Module.constants - $snapshot1     # => ["A"]
p A.constants                       # => ["NAME"]

Le livre affirme que la méthode de la classe 'constantes' retourne la liste des constantes de la classe (comme vous pouvez le voir dans la sortie de A. constantes) J'ai essayé d'obtenir la liste des constantes définies pour le Module de classe quand je suis tombé sur le dessus de comportement étrange.
Une des constantes apparaissent dans le Module.les constantes. - comment puis-je obtenir la liste des constantes définies par le Module de classe? Les docs de l'état que " le Module.les constantes retourne toutes les constantes définies dans le système. incl. les noms de toutes les classes et méthodes" Depuis Un hérite de sa mise en œuvre dans le Module.constantes, comment ça se comportent différemment dans la base et les types dérivés?

p A.class               # => Class
p A.class.ancestors       # => [Class, Module, Object, Kernel]

Remarque: Si vous utilisez Ruby 1.9, les constantes serait de retourner un tableau de symboles à la place de chaînes de caractères.

35voto

Marc-André Lafortune Points 34140

Bonne question!

Votre confusion est due au fait que la méthode de la classe Module.constants masque la méthode d'instance Module#constants pour Module.

En Ruby 1.9, cette question a été traitée par l'ajout d'un paramètre facultatif:

# No argument: same class method as in 1.8:
Module.constants         # ==> All constants
# One argument: uses the instance method:
Module.constants(true)   # ==> Constants of Module (and included modules)
Module.constants(false)  # ==> Constants of Module (only).

Dans l'exemple ci-dessus, A.constants des appels Module#constants (la méthode d'instance), tandis que l' Module.constants des appels, eh bien, Module.constants.

En Ruby 1.9, vous voulez appeler Module.constants(true).

En Ruby 1.8, il est possible d'appeler la méthode d'instance #constants sur Module. Vous avez besoin pour obtenir la méthode d'instance et les lier comme une méthode de classe (à l'aide d'un nom différent):

class << Module
  define_method :constants_of_module, Module.instance_method(:constants)
end

# Now use this new class method:
class Module
   COOL = 42
end
Module.constants.include?("COOL")  # ==> false, as you mention
Module.constants_of_module         # ==> ["COOL"], the result you want

Je voudrais être en mesure de rétroporter le 1.9 fonctionnalité complètement à 1,8 pour ma backports gem, mais je ne peux pas penser à un moyen pour obtenir uniquement les constantes d'un Module, à l'exclusion de celles héritées, en Ruby 1.8.

Edit: Juste changé la documentation officielle afin de refléter correctement cette...

2voto

Gishu Points 59012

Il fallait que je retourne dans ma grotte de la pensée pendant un certain temps après Marc réponse. Bricolé avec plus de fragments de code et puis un peu plus. Enfin, quand Ruby méthode de résolution ne semble faire sens, écrit comme un billet de blog afin que je n'oublie pas.

Notation: Si A" est le eigenclass d' Un

Lors de l' A.constants est appelée, la méthode de résolution (voir l'image dans mon blog pour avoir une aide visuelle) recherche les emplacements suivants dans l'ordre

  • MyClass", Object", BasicObject" (singleton méthodes)
  • Class (méthodes d'instance)
  • Module (méthodes d'instance)
  • Object (méthodes d'instance) et le Noyau
  • BasicObject (méthodes d'instance)

Ruby trouve la méthode d'instance Module#constants

Lors de l' Module.constants est appelé, Ruby regarde

  • Module", Object", BasicObject" (singleton méthodes)
  • Class (méthodes d'instance)
  • Module (méthodes d'instance)
  • Object (méthodes d'instance) et le Noyau
  • BasicObject (méthodes d'instance)

cette fois, Ruby trouve le singleton/méthode de classe à l' Module".constants comme Marc l'a dit.

Module définit un singleton méthode qui masque la méthode d'instance. Le singleton méthode renvoie tous connus des constantes alors que la méthode d'instance renvoie les constantes définies dans la classe actuelle et de ses ancêtres.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X