2013-02-27 9 views
32

Dies ist eine Fortsetzung diese ursprüngliche SO Frage: Using "::" instead of "module ..." for Ruby namespacingRubin - lexikalischer Umfang vs Vererbung

In der ursprünglichen Frage SO, hier ist das Szenario vorgestellt, das ich habe immer noch nicht verstehen:

FOO = 123 

module Foo 
    FOO = 555 
end 

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

class Foo::Bar 
    def glorf 
    puts FOO 
    end 
end 

puts Foo::Bar.new.baz # -> 555 
puts Foo::Bar.new.glorf # -> 123 

Kann jemand eine Erklärung liefern, warum der erste Anruf zurückkehrt und warum der zweite Anruf 123 zurückgibt?

+1

Willson, zugeordnet, die unten beantworten denken Sie, würdig der Prämie ist? Danke – rainkinz

+0

Hinweis: fügen Sie "puts Module.nesting" nach den beiden puts in Ihrem Code. Siehe auch: http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/ –

Antwort

33

Sie können module Something, jedes Auftreten von class Something oder def something als „Gateway“ in einen neuen Bereich denken gefunden. Wenn Ruby nach der Definition eines Namens sucht, auf den verwiesen wurde, sucht er zuerst im aktuellen Bereich (der Methode, der Klasse oder des Moduls), und wenn er dort nicht gefunden wird, wird er durch jeden mit "Gateway" und Suche zurückgehen der Umfang dort.

In Ihrem Beispiel das Verfahren baz ist definiert als

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

Also, wenn der Wert von FOO zu bestimmen versucht, zuerst die Klasse Bar wird geprüft, und da Bar enthält keine FOO die Suche nach oben bewegt über das "class Bar Gateway" in das Modul Foo, das den enthaltenen Bereich enthält. Foo enthält eine Konstante FOO (555), also ist dies das Ergebnis, das Sie sehen.

Verfahren glorf ist definiert als:

class Foo::Bar 
    def glorf 
    puts FOO 
    end 
end 

Hier wird das „Gateway“ class Foo::Bar ist, so dass, wenn nicht innerhalb FOOBar gefunden wird das „Tor“ durchläuft das Modul Foo und gerade in der obersten Ebene , wo es eine andere FOO (123) gibt, was angezeigt wird.

Hinweis, wie class Foo::Bar Verwendung erzeugt ein einzelnes „Gateway“, über den Umfang der Foo Skipping, aber module Foo; class Bar ... öffnet zwei separate „Gateways“

+3

BTW. der Gateway-Begriff. In den Ruby-Quellen scheint es, was man einen "Scope-Stack" nennen könnte. Jedes Mal, wenn Sie 'class' oder' module' eingeben, wird ein neuer Bereich auf diesen Stapel geschoben. Wenn Ruby dann nach Variablen oder Konstanten sucht, konsultiert es diesen Stapel von unten nach oben und endet in der obersten Ebene "main", wenn es die Variable nicht auf dem Weg nach oben gefunden hat. Im Fall von 'Klasse Foo :: Bar' sollte es wirklich ZWEI Bereiche auf den Stapel schieben (sowohl' Foo' als auch 'Bar'), aber es drückt nur eins, daher bekommen wir das" Problem ". – Casper

+0

Wie unterscheidet sich das von der ursprünglichen Antwort? – rainkinz

+1

@Casper das macht Sinn. Ich lese irgendwo über die "Gateway" Idee (kann mich nicht erinnern, wo leider) als eine Art zu denken, was vor sich geht, aber ich habe die Implementierung nicht betrachtet. Ich denke, eine Erklärung für dieses Verhalten ist, dass Sie eine verschachtelte Klasse öffnen können (um es zu affen), ohne dass Sie befürchten müssen, dass der umschließende Bereich interferiert. – matt

5

wow, große Frage. Die beste Antwort, die ich mir vorstellen kann, ist, dass Sie in diesem Fall ein Namespace definieren. diese

Check out:

FOO = 123 

module Foo 
    FOO = 555 
end 

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 

    def glorf3 
     puts ::FOO 
    end 
    end 
end 

class Foo::Bar 
    def glorf2 
    puts Foo::FOO 
    end 

    def glorf 
    puts FOO 
    end 
end 

puts Foo::Bar.new.baz # -> 555 
puts Foo::Bar.new.glorf # -> 123 
puts Foo::Bar.new.glorf2 # -> 555 
puts Foo::Bar.new.glorf3 # -> 123 

Also mein Gedanke ist, dass, wenn Sie definieren:

module Foo 
    FOO = 555 
end 

Sie FOO im Namensraum von Foo erstellen. Also, wenn Sie es hier verwenden:

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

Sie im Foo Namespace sind. Wenn Sie jedoch darauf verweisen in:

class Foo::Bar 
    def glorf 
    puts FOO 
    end 
end 

FOO wird aus dem Standard-Namespace kommt (wie durch ::FOO dargestellt).

+0

danke für die Beispiele! das macht Sinn außer für einen Punkt: Wenn Sie die Klasse Foo :: Bar definieren, nennen Sie es nicht Foo? Bedeutet der "Foo ::" - Teil von "Foo :: Bar" nicht, dass Sie diese Klasse namespacen? – wmock

+0

Foo :: Bar.new.glorf Rückkehr 123 ist schwierig für mich zu verstehen, wenn Foo :: Bar.new.baz 555 zurückgibt. – wmock

+1

Ich hätte das auch gedacht, aber es sieht so aus, was passiert ist, ist Sie Namespacing Bar (unter Foo) explizit von Foo :: Bar und alles andere in diesem Kontext kommt immer noch aus dem Standard-Namespace. – rainkinz

0

der erste Anruf:

puts Foo::Bar.new.baz # -> 555 

druckt das Ergebnis der Methode aufgerufen baz einer Instanz der Klasse Foo :: Bar

Hinweis, dass Foo :: Bar # baz Definition ist eigentlich ein Verschluss auf FOO.Nach Rubys Bereichsregeln:

  1. FOO wird in Foo :: Bar (die Klasse, nicht die Instanz) gesucht Umfang, ist es nicht gefunden wird,
  2. FOO in gesucht wird der umschließenden Umfang Foo (denn wir sind in der Moduldefinition) und es wird festgestellt (555)

der zweite Anruf:

druckt das Ergebnis des Aufrufens Methode glorf einer Instanz der Klasse Foo :: Bar

Hinweis, dass Foo :: Bar # glorf Definition diesmal ist auch eine Schließung auf FOO, aber wenn wir Rubys Bereichsregeln folgen werden Sie feststellen, dass der Wert auf dieser Zeit geschlossen ist :: FOO (Top-Level-Umfang FOO) auf folgende Weise:

  1. FOO wird in Foo :: Bar (die Klasse, nicht die Instanz) gesucht Namespace, ist es nicht
  2. FOO gesucht im umgebenden Gültigkeitsbereich ('Top-Level') gefunden, und es ist dort (123)
0

glorf ist eine Methode der Klasse Foo, in => [Foo, Module, Object, Kernel, BasicObject]

innerhalb dass Rahmen (dh in default/Hauptmodul) wird FOO 123

zugeordnet Modul Foo ist definiert als

module Foo 
    FOO = 555 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

wo das Verfahren baz Klasse Bar in Modul Foo gehört => [Bar, Foo, Object, Kernel, BasicObject]

und in diesem Umfang FOO wurde 555

+0

Das oben erwähnte 'main' ist ein Artefakt von irb, eigentlich ist 'FOO = 123' eine Methode auf oberster Ebene, die in die Klasse Object eingeht. – aug2uag