2009-09-10 8 views
1

Je regardais le premier screencast de métaprogrammation ruby ​​par prag dave. À un moment donné, il a dit que ruby ​​introduisait des «classes fantômes» lorsque vous ajoutez une méthode à une variable d'instance. je.Comment accéder aux classes de parents fantômes à ruby?

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 

Où est vraiment le magasin de méthode speak? S'il s'agit d'une classe proxy invisible, Comment pouvons-nous accéder à cette classe proxy?

Répondre

3

La méthode speak est stockée dans une métaclasse (également appelée classe propre), ce que vous appelez une "classe proxy invisible". Dans Ruby, les variables d'instance n'ont pas de place pour stocker les méthodes. Ils peuvent uniquement stocker les variables d'instance et leur classe. Ainsi, lorsque vous ajoutez une méthode à une instance, une métaclasse est créée et insérée dans sa chaîne de classe. Pour une meilleure compréhension des internes, je recommande this article de Klank Boom Klang.

Afin d'obtenir à la classe meta, vous pouvez effectuer les opérations suivantes:

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 
+0

Thx, thats une très bonne réponse. – Pedro

1

Certains ppl appellent « Singleton classe »

singleton_class = class << animal; self; end 

Et en fait cette classe singleton est l'hôte méthodes de classe à n'importe quelle classe, vérifiez cet exemple, d'abord en définissant la classe Foo avec les méthodes de classe «salut» et «au revoir»:

class Foo 
    def self.hi ; p "hi" ; end 
    def self.bye ; p "bye" ; end 
end 
Foo.singleton_methods #=> ["hi","bye"] 

Maintenant, nous allons définir une méthode qui retourne la classe singleton pour nous:

class Object 
    def singleton_class 
    class << self 
     self 
    end 
    end 
end 

Maintenant, essayez ceci:

Foo.singleton_methods #=> ["bye", "hi"] 
Foo.singleton_class.instance_methods(false) #=> ["bye", "hi"] 
Questions connexes