Come accedere alle classi fantasma dei genitori in ruby?
Domanda
Stavo guardando il primo programma di metaprogrammazione ruby ??di prag dave. Ad un certo punto ha detto che ruby ??introduce "classi fantasma" quando aggiungi un metodo a una variabile di istanza. i.
animal = "cat"
def animal.speak
puts "hola"
end
animal.speak # => hola
animal.class # => String
dog = "dog"
dog.speak # Undefined method `speak' for "dog":String
String.send :speak # NoMethodError: undefined method `speak' for String:Class
animal.send :speak # hola
Dov'è davvero l'archivio del metodo speak? Se si tratta di una classe proxy invisibile, come possiamo accedere a quella classe proxy?
Soluzione
Il metodo speak
è memorizzato in una metaclasse (nota anche come eigenclass), quella che tu chiami una "classe proxy invisibile". In Ruby, le variabili di istanza non hanno spazio per memorizzare i metodi. Possono solo memorizzare variabili di istanza e la loro classe. Pertanto, quando si aggiunge un metodo a un'istanza, viene creata una metaclasse e inserita nella sua catena di classi. Per una migliore comprensione degli interni, consiglio questo articolo di Klank Boom Klang.
Per accedere alla meta classe, puoi fare quanto segue:
animal = "cat"
def animal.speak
puts "hola"
end
animal.speak # => hola
animal.class # => String
metaclass = class << animal; self; end
metaclass.inspect # => #<Class:#<String:0x2c9c460>>
metaclass.instance_methods.index 'speak' # => 102
metaclass.class # => Class
Altri suggerimenti
Alcuni ppl lo chiamano " Singleton Class "
singleton_class = class << animal; self; end
E in realtà questa classe singleton è l'host per i metodi di classe in qualsiasi classe, controlla questo esempio, prima definendo la classe Foo con i metodi di classe 'hi' e 'bye':
class Foo
def self.hi ; p "hi" ; end
def self.bye ; p "bye" ; end
end
Foo.singleton_methods #=> ["hi","bye"]
Ora definiamo un metodo che restituisce la classe singleton per noi:
class Object
def singleton_class
class << self
self
end
end
end
Ora prova questo:
Foo.singleton_methods #=> ["bye", "hi"]
Foo.singleton_class.instance_methods(false) #=> ["bye", "hi"]