2010-02-22 2 views
38

Ich habe versucht, Matz und Flanagans „Ruby-Programmiersprache“ metaprogramming Kapitel in meinen Kopf zu bekommen, aber ich konnte die Ausgabe aus dem folgenden Code-Snippet, das ich geträumt nicht verstehen:Wie bekomme ich Konstanten von Rubys Modul-Klasse über Reflektion definiert?

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"] 

Das Buch besagt, dass Die Klassenmethode constants gibt die Liste der Konstanten für die Klasse zurück (wie Sie in der Ausgabe für A.constants sehen können). Ich habe versucht, die Liste der Konstanten zu erhalten, die für die Modul-Klasse definiert sind, als ich auf das obige merkwürdige Verhalten stieß.

A Konstanten werden in Module.constants angezeigt. Wie bekomme ich die Liste der Konstanten, die von der Module-Klasse definiert sind?

Die docs Zustand

Module.constants kehrt alle Konstanten in dem System definiert. einschließlich der Namen aller Klassen und Methoden

Seit A erbt seine Implementierung von Module.constants, wie es anders in der Basis und abgeleitete Typen verhält?

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

Hinweis: Wenn Sie Ruby 1.9 verwenden sind, constants würde eine Reihe von Symbolen anstelle von Strings zurück.

+0

Habe ich Ihre Frage beantwortet? Ich frage, weil meine Antwort nicht "akzeptiert" wurde, aber keine zusätzlichen Informationen verlangte ... –

+0

@Marc - Ihre Antwort führte mich zu mehr Fragen und mehr Kritzeln und Löschen. Ich habe diese Woche damit verbracht, meinen Kopf über die Methode der Methodenauflösung zu legen ... Ich bin immer noch nicht klar, was die Möglichkeiten sind - aber ich denke, ich bin mir zu 90% sicher, wie es funktioniert. Siehe meinen Beitrag unten. – Gishu

Antwort

47

Gute Frage!

Ihre Verwirrung liegt daran, dass die Klassenmethode Module.constants die Instanzmethode Module#constants für Module versteckt.

# 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). 

In Ihrem Beispiel oben, A.constants Anrufe Module#constants (die Instanz-Methode), während Module.constants Anrufe, na ja, Module.constants:

In Ruby 1.9, dies wird durch das Hinzufügen eines optionalen Parameters angesprochen.

In Ruby 1.9 möchten Sie also Module.constants(true) aufrufen. In Ruby 1.8 ist es möglich, die Instanzmethode #constants unter Module aufzurufen. Sie müssen die Instanz-Methode zu erhalten und es als Klassenmethode binden (unter einem anderen Namen):

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 

Ich wünschte, ich in der Lage war für mein backports Juwel der 1.9 Funktionalität vollständig auf 1,8 zurückzuportieren, aber ich kann‘ Ich denke an einen Weg, um nur die Konstanten eines Moduls, ausgenommen die vererbten, in Ruby 1.8 zu erhalten.

bearbeiten: änderte einfach die offizielle Dokumentation dies korrekt widerspiegeln ...

+0

@Marc - ich würde es begrüßen, wenn Sie mein Verständnis der Methodenauflösung nachvollziehen und bestätigen könnten. Blog-Post-Link in meinem Post unten. Danke und Angenommen :) – Gishu

3

ich für eine Weile nach Marcs Antwort zurück in mein Denken Höhle zu gehen hatte. Gebastelt mit mehr Code-Schnipsel und dann noch etwas mehr. Schließlich, als Rubys Methodenauflösung sinnvoll erschien, schrieb sie es als Blogpost auf, damit ich es nicht vergesse.

Notation: Wenn A“ ist die Eigenklasse von A

Wenn A.constants genannt wird, Verfahren Auflösung (in my blog post auf das Bild beziehen eine Sehhilfe haben) sieht in den folgenden Orten auf, um

  • MyClass", Object", BasicObject" (Singleton-Methoden)
  • Class (Instanz Verfahren)
  • Module (instance methods)
  • Object (instance methods) und Kernel
  • BasicObject (instance methods)

Ruby die Instanzmethode wird Module#constants

Wenn Module.constants findet genannt, Rubin Blick auf

  • Module", Object", BasicObject" (Singleton-Methoden)
  • Class (instance methods)
  • Module (instance methods)
  • Object (instance methods) und Kernel
  • BasicObject (instance methods)

Dieses Mal findet Ruby die Singleton/Class-Methode bei , wie Marc sagte.

Modul definiert eine Singleton-Methode, die die Instanzmethode schattiert. Die Singleton-Methode gibt alle bekannten Konstanten zurück, während die Instanzmethode die in der aktuellen Klasse und ihren Vorfahren definierten Konstanten zurückgibt.

Verwandte Themen