2013-02-27 16 views
32

Si tratta di questo originale domanda SO una continuazione: Using "::" instead of "module ..." for Ruby namespacingRubino - scope lessicale vs Inheritance

Nella domanda iniziale SO, qui è lo scenario presentato, che sto ancora avendo difficoltà a capire:

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 

Qualcuno può fornire qualche spiegazione sul motivo per cui la prima chiamata restituisce 555 e perché la seconda chiamata restituisce 123?

+1

Willson, che risponde sotto pensi che sia degno della bontà? Grazie – rainkinz

+0

Suggerimento: aggiungi "puts Module.nesting" dopo che le due inseriscono il tuo codice. Vedi anche questo: http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/ –

risposta

33

si può pensare di ogni aspetto della module Something, class Something o def something come “gateway” in un nuovo ambito. Quando Ruby cerca la definizione di un nome che è stato referenziato, prima cerca nell'attuale scope (il metodo, la classe o il modulo), e se non viene trovato lì ritornerà attraverso ogni "gateway" contenente e ricerca lo scopo lì.

Nel tuo esempio il metodo baz è definito come

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

Così, quando si cerca di determinare il valore di FOO, prima classe Bar viene controllato, e dal momento che Bar non contiene un FOO la ricerca si muove su tramite il "class Bar gateway" nel modulo Foo che è l'ambito di contenimento. Foo contiene una costante FOO (555) quindi questo è il risultato che si vede.

Procedimento glorf è definito come:

class Foo::Bar 
    def glorf 
    puts FOO 
    end 
end 

Qui il “gateway” è class Foo::Bar, così quando FOO non si trova all'interno Bar la “porta” passa attraverso il modulo Foo e direttamente nel livello superiore , dove c'è un altro FOO (123) che è ciò che viene visualizzato.

Nota come l'uso di class Foo::Bar crea un unico “porta”, saltando la portata della Foo, ma module Foo; class Bar ... apre due “porte” separati

+3

Btw. il termine del gateway. Nelle fonti di Ruby sembra esserci quello che si potrebbe definire una "pila di obiettivi". Quindi ogni volta che si digita 'class' o' module' un nuovo scope viene inserito in questo stack. Quando Ruby cerca le variabili o le costanti consulta questa pila dal basso verso l'alto, finendo nel 'principale' di primo livello se non trova la variabile durante la salita. Nel caso di 'classe Foo :: Bar' dovrebbe davvero spingere DUE scope nello stack (sia' Foo' che 'Bar'), ma ne spinge solo uno, quindi otteniamo il" problema ". – Casper

+0

In che cosa differisce dalla risposta originale? – rainkinz

+1

@Casper che ha senso. Ho letto sull'idea del "gateway" da qualche parte (non ricordo dove sfortunatamente) come un modo di pensare a quello che sta succedendo, ma non ho visto l'implementazione. Immagino che una spiegazione per questo comportamento sia che ti permette di aprire una classe nidificata (per eseguire il patch della scimmia) senza doversi preoccupare del fatto che l'oscilloscopio che racchiude interferisce. – matt

5

wow, ottima domanda. La migliore risposta che posso dare è che in questo caso stai usando il modulo per definire uno spazio dei nomi.

Check this 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 

Quindi il mio pensiero è che quando si definisce:

module Foo 
    FOO = 555 
end 

si sta creando FOO nello spazio dei nomi di Foo. Così, quando lo si utilizza qui:

module Foo 
    class Bar 
    def baz 
     puts FOO 
    end 
    end 
end 

siete nel Foo namespace. Tuttavia, quando si fa riferimento ad esso in:

class Foo::Bar 
    def glorf 
    puts FOO 
    end 
end 

FOO è venuta dallo spazio dei nomi di default (come illustrato da ::FOO).

+0

grazie per gli esempi! questo ha senso eccetto per un punto: quando definisci la classe Foo :: Bar, non stai assegnando il nome a Foo? La parte "Foo ::" di "Foo :: Bar" non implica che si stia chiamando in una classe? – wmock

+0

Foo :: Bar.new.glorf restituire 123 è difficile per me capire quando Foo :: Bar.new.baz restituisce 555. – wmock

+1

Lo avrei pensato anche io, ma sembra, quello che sta succedendo è la barra dei nomi (in Foo) esplicitamente da Foo :: Bar e tutto il resto in quel contesto proviene ancora dallo spazio dei nomi predefinito. – rainkinz

0

la prima chiamata:

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

stampa il risultato di invocare il metodo Baz di un'istanza della classe Foo :: Bar

avviso che Foo :: Bar N ° baz definizione è in realtà una chiusura su FOO.regole di ambito A seguito di Ruby:

  1. FOO viene ricercato in Foo :: Bar (la classe, non è l'istanza) campo di applicazione, non si trova,
  2. FOO viene cercato nel ambito di inclusione Foo (perché siamo nella definizione modulo) e ci si trova (555)

la seconda chiamata:

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

stampa il risultato di invocare il metodo glorf di un'istanza della classe Foo :: Bar

avviso che Foo :: Bar N ° glorf definizione questa volta è anche una chiusura su FOO, ma se seguiamo regole di ambito di ruby ​​si noterà che il valore chiuso su questa volta è :: FOO (alto FOO ambito a livello) nel seguente modo:

  1. FOO viene cercato in Foo :: Bar (la classe, non è l'istanza) namespace, non si trova
  2. FOO viene ricercato nel perimetro che racchiude ('top level') ed è trovato lì (123)
0

glorf è un metodo di classe Foo, in => [Foo, Module, Object, Kernel, BasicObject]

all'interno di tale portata (cioè in default/modulo principale), FOO è assegnato 123

modulo Foo è definito come

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

dove metodo baz appartiene alla classe Bar nel modulo Foo => [Bar, Foo, Object, Kernel, BasicObject]

e in questo ambito è stato assegnato FOO 555

+0

il 'main' menzionato sopra è un artefatto di irb, in realtà 'FOO = 123' è un metodo di livello superiore che entra nella classe Object. – aug2uag