procedure globali in Ruby non sono davvero procedure globali. Sono metodi, come tutto il resto. In particolare, quando si definisce cosa è come una procedura globale, si è in realtà che definisce un metodo di istanza privato di Object
. Poiché ogni parte del codice in Ruby viene valutata nel contesto di un oggetto, questo consente di utilizzare tali metodi come se fossero procedure globali, poiché self
è il destinatario predefinito e self
è un oggetto la cui classe eredita da Object
.
Quindi, questo:
# file1.rb
def foo
puts 123
end
è in realtà equivale a
# file1.rb
class Object
private
def foo
puts 123
end
end
Ora avete una "procedura globale" chiamato foo
, che si può chiamare proprio come questo:
foo
motivo perché è possibile chiamarlo così, è che questa chiamata è in realtà equivalente a
self.foo
e self
è un oggetto che include Object
nella sua catena discendenza, quindi eredita il metodo privato foo
.
[Nota: per essere precisi, i metodi privati non possono essere chiamati con un ricevitore esplicito, anche se il destinatario esplicito è self
. Così, per essere davvero pedante, è realtà equivalente a self.send(:foo)
e non self.foo
]
Il A.new.foo
nel vostro file2.rb
è una falsa pista:. Si potrebbe altrettanto bene provare Object.new.foo
o [].foo
o 42.foo
e ottenere lo stesso risultato .
proposito: puts
e require
sono essi stessi esempi di tali "procedure globali", che sono in realtà metodi privati Object
(o più precisamente, si tratta di metodi privati Kernel
che viene miscelata in Object
).
Su un sidenote: è davvero cattivo stile di mettere le chiamate a require
all'interno di una definizione di classe, perché lo fa apparire come il codice require
D è in qualche modo con ambito o namespace all'interno della classe, che è ovviamente falso. require
semplicemente esegue il codice nel file, niente di più.
Così, mentre
# file2.rb
class A
require 'file1.rb'
end
è il codice perfettamente valido, ma è anche molto confusa. È molto meglio usare il seguente, semanticamente equivalente, codice:
# file2.rb
require 'file1.rb'
class A
end
questo modo è perfettamente chiaro al lettore del codice che file1.rb
è in alcun modo ambito o namespace all'interno A
.
Inoltre, in genere è preferibile lasciare l'estensione del file, ovvero utilizzare require 'file1'
anziché require 'file1.rb'
. Ciò consente di sostituire il file Ruby con, ad esempio, codice nativo (per MRI, YARV, Rubinius, MacRuby o JRuby), codice byte JVM in un file .jar
o .class
(per JRuby), codice byte CIL nel file .dll
(per IronRuby) e così via, senza dover cambiare nessuna delle tue chiamate require
.
Un ultimo commento: il modo idiomatico per aggirare la protezione di accesso è quella di utilizzare send
, non instance_eval
, vale a dire utilizzare A.new.send(:foo)
invece di A.new.instance_eval {foo}
.
Hai provato 'A.new.instance_eval {foo}'? Non funziona per me (rubino 1.9.2). – knut
Stai confondendo 'require con' include'? –
@knut l'ho fatto. Funziona. – alexloh