2016-01-26 9 views
6

Ruby sembra aver subito modifiche diverse volte rispetto all'accessibilità costante. Per Ruby 1.9.2, c'è una descrizione riguardante l'accessibilità costante nella domanda e la risposta here, ma ciò che è scritto non è più vero.Come viene determinata l'accessibilità costante?

In Ruby 2.3, se ho una costante definita in una classe:

class A 
    Foo = :a 
end 

Non posso accedere tramite instance_eval o class_eval:

A.new.instance_eval{Foo} # => error 
A.class_eval{Foo} # => error 
A.instance_eval{Foo} # => error 

anche se posso accedervi dal corpo della classe :

class A; Foo end # => :a 

come funziona l'accessibilità costante di Ruby 2.3? Se possibile, si prega di spiegare i cambiamenti storici di accessibilità costante in Ruby e gli argomenti che li hanno portati.

+2

Inoltre, 'A.const_get: Foo # =>: a' e' A.class_eval "Foo" =>: a' (2.3). –

+0

@CarySwoveland Destra. Ma quelli sono più simili agli usi reali/principali delle varietà eval, che analizzano da una stringa/simbolo. E soprattutto, 'const_get' è progettato proprio per farlo; se non funzionasse in quel modo, sarebbe un grosso problema. – sawa

+1

Vorrei risolvere questo problema con parser parsimonioso, non con una ricerca costante. BTW, 2.1 funziona come 2.3. Ad ogni modo: 'A.instance_eval {| a | a :: Foo} # =>: a' e 'A.instance_eval {self :: Foo} # =>: a', mentre' A.instance_eval {Foo} # => error'. Gli ultimi due devono comportarsi allo stesso modo, è per questo che do la colpa al parser. – mudasobwa

risposta

2

ricerca costante in Ruby utilizza lexical scope che attraversa l'ambito corrente e moduli di contenimento. Il percorso di ricerca può essere visualizzato mediante Module.nesting

> module Out 
> module In 
>  puts Module.nesting 
> end 
> end 
Out::In # gets searched for a given constant first 
Out 

La ricerca rimane lo stesso all'interno di un blocco per consentire comportamento chiusura, anche per class_eval.

Tuttavia, in Ruby 1.9, il ricevitore per instance_eval, instance_exec, class_eval, e class_exec è stata posta prima del percorso di ricerca, il che significa che tutti i riferimenti costanti sarebbero essere consultati nella portata del ricevitore prima.

Yehuda Katz ha sollevato un issue rottura significativa citando:

Consideriamo il caso di RSpec:

describe "Date" do 
    it "equals itself" do 
    Date.today.should == Date.today 
    end 
end 

Se usiamo scope dinamico, poi se RSpec aggiunge Spec :: Data, lo farà interrompe improvvisamente questa specifica. Lo scope lessicale è più intuitivo, ed è previsto da molti usi normali oggi.

Il comportamento è stato successivamente reverted indietro a 1,8.

2

Nota: Sotto risposta è basata su Ruby 2.2, non si sono verificati su 2,3 ​​

Come da documentazione di Module#class_eval

Valuta la stringa o il blocco nel contesto di mod, eccezione del fatto che quando viene dato un blocco a , la ricerca di variabili costanti/di classe non è influenzata.

Anche se sotto il codice con errori fuori,

A.class_eval{Foo} # uninitialized constant Foo (NameError) 

in seguito a lavori in cui una stringa è essere eval ed.

A.class_eval("Foo") #=> :a 

Sembra anche che Constant richiede nome del modulo o il nome di classe per poter essere valutato correttamente. Sotto così:

A.class_eval{self::Foo} #=> :a 

Quindi, fa questi:

A.new.instance_eval {self.class::Foo} #=> :a 
A.instance_eval {self::Foo} #=> :a 
Problemi correlati