简体   繁体   中英

How to access to ghost parent classes in ruby?

I was watching the first ruby metaprogramming screencast by prag dave. At some point he said that ruby introduce 'ghost classes' when you add a method to an instance variable. 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

Where is really the speak method store? If it is an invisible proxy class, How can we access to that proxy class?

The method speak is stored in a metaclass (also known as an eigenclass), what you call an "invisible proxy class". In Ruby, instance variables have no place to store methods. They can only store instance variables and their class. So when you add a method to an instance, a metaclass is created and inserted into its class chain. For a better understanding of the internals, I recommend this article from Klank Boom Klang.

In order to get at the meta class, you can do the following:

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

Some ppl call it "Singleton Class"

singleton_class = class << animal; self; end

And actually this singleton class is the host for class methods at any class, check this example, first by defining class Foo with class methods 'hi' and 'bye':

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

Now let's define a method that returns back the singleton class for us:

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

Now try this :

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM