2013-05-07 4 views
16

ich dachte, dass es innerhalb eines class << self Block und diejenigen, erklärt mit einem self. Präfix, aber es gibt deklariert keine Unterschiede zwischen den Verfahren waren:Warum sind Konstanten aus dem erweiterten Modul in Klassenmethoden, die mit self deklariert sind, nicht verfügbar?

module A 
    VAR = 'some_constant' 
end 

class B 
    extend A 

    class << self 
    def m1 
     puts VAR 
    end 
    end 

    def self.m2 
    puts VAR 
    end 
end 

B.m1 # => OK 
B.m2 # => uninitialized constant B::VAR 

Warum sind Konstanten von A in m1 aber nicht in m2?

Antwort

20

In Ruby ist das konstante Nachschlagen nicht das gleiche wie das Nachschlagen nach Methoden. Bei Methodenabfragen ist das Aufrufen von foo immer dasselbe wie das Aufrufen von self.foo (vorausgesetzt, es ist nicht privat). Der Aufruf einer Konstanten FOO ist sehr unterschiedlich zu self::FOO oder singleton_class::FOO.

Mit einer nicht qualifizierten Konstante (z. B. FOO) wird in den aktuell geöffneten Modulen nachgeschlagen. Ein Modul wird mit module Mod, class Klass, class << obj oder module_eval und Varianten geöffnet. Bei der Definition von m1 sind dies B und dann B.singleton_class. Bei der Definition von m2 wird nur B geöffnet.

module Foo 
    X = 42 
    class Bar 
    def self.hello 
     X 
    end 
    end 
end 

In diesem Code wird Foo::Bar.hello 42 zurückkehren, obwohl X keine Konstante von Bar, seine Singletonklasse oder Vorfahr ist. Wenn Sie später eine Konstante X zu Bar hinzufügen, wird dieser Wert zurückgegeben. Schließlich ist die folgende Definition nicht äquivalent:

module Foo 
    X = 42 
end 

class Foo::Bar 
    def self.hello 
    X 
    end 
end 

Foo::Bar.hello # => uninitialized constant Foo::Bar::X 

der Tat, wenn hello definiert ist, nur die Klasse Foo::Bar geöffnet ist, während in dem vorherigen Beispiel, sowohl Foo und Foo::Bar wo geöffnet.

Ein letztes Beispiel den Unterschied ein expliziter Umfang zu zeigen mit Vererbung haben:

class Base 
    X = 42 
    def self.foo 
    X 
    end 
    def self.bar 
    self::X 
    end 
end 

class Parent < Base 
    X = :other 
end 

Parent.foo # => 42 
Parent.bar # => :other 

In Ihrem Fall Sie wahrscheinlich Ihr Modul include wollen, statt extending es, nicht wahr?

Andernfalls könnten Sie singleton_class::VAR verwenden, Ihr Code wird so funktionieren, wie Sie es erwarten.

module A 
    VAR = 'some_constant' 
end 

class B 
    extend A 

    class << self 
    def m1 
     puts singleton_class::VAR # not necessary here, as singleton_class is opened 
    end 
    end 

    def self.m2 
    puts singleton_class::VAR # necessary here! 
    end 
end 

B.m1 # => OK 
B.m2 # => OK 
+0

was ist 'f1' und' f2'? Kannst du da einfach ein paar Zeilen hinzufügen? Was ist "momentan geöffnete Module"? –

+0

@Priti: Antwort bearbeitet, tks –

Verwandte Themen