These are my notes from Dave Thomas's Ruby Object Model.
# Ruby Object Model # http://www.engineyard.com/blog/community/scotland-on-rails/page-2/ # everything is an object # object is a class # class is an object # self: # - current object # - where instance vars are found # - default receiver for methods calls # changes in self changes ruby's view of the universe # by: methods calls & class/module definitions animal = "cat" puts animal.upcase # find animal object -> find table of methods -> call method # class => object that has a table of methods # every single method call works exactly the same way puts animal.object_id # if can't methods in 1st table => goes to parent # (superclass of the object) # Object toplevel in Ruby 1.8, BasicObject in Ruby 1.9 # If no matching methods found in ruby, you are back # to original object and look for method_missing method. def animal.speak puts "meaow" end animal.speak # --- SELF changes on method call # Method lookup -> one right and one up # So the above object instance method sits # one to the right of that particular object. # So a newly created class just for the animal # object is anonymous. But when asked what class # the above object belongs to, it says string, # and not the newly created anonymous class. # AKA, singleton class or metaclasss or eigenclass # How is the animal.speak method defined? # (1) Ruby sets "self" to the cat string object -- self # set to the receiver # (2) Looks for the method in the method table associated # with that object (look in self's class for the object) # (3) If not found, scan for method_missing # (4) Eventually find some method & invoke it & when done, # restores original value of self. # # If a method call in Ruby doesn't have an explicit # receiver -- then Ruby doesn't reset self -- self # stays the same & no need to pop back at the end. # So the method "puts" is a private method in Object (actually # in Kernel), so you can only call it with an implicit receiver, # not an explicit one. class String puts "in string" end begin "hi".puts rescue NoMethodError puts "puts is private" end # In Ruby class definitions are executable code. puts "===class defn" puts "toplevel #{self}" class << self puts "class << self's #{self}" end class A puts "class A's #{self}" end module B puts "module B's #{self}" end # When you define a class like "class A; end", # Ruby creates a brand new class and assigns that # to the constant A. # When excuting a class or module definition, self # is set to the class or module object. Why? You can # do "def self.a" for class methods (or old school # ruby programmers using "def A.a"); But ruby doesn't # have class methods (or static methods), all methods # are the same. These methods are just defined on the class. # It inserts a singleton class on that particular class object. # To do metaprogramming in Ruby: # - Instance variables are looked up in self # - Methods are looked up in self's class # these 2 are the same: def animal.do puts "doing" end # "class << animal" means open up the singleton class of this object # self is set to that singleton class class << animal puts "class << animal: #{self}" def do puts "doing" end end class N # opening up the meta/singleton class and dumping all the # methods defined there class << self # class methods end end # This doesn't work class F @a = 10 # self is class object def f @a # self is the instance end def F.f # this work @a end class << self # this also works attr_accessor :f end end class Y; end class Z < Y; end # the Y in "Z < Y" is an expression wxyz = Y class Z < wxyz; end # same as above a = Struct.new(:a, :b, :c) # creates a class object on the fly puts a.new(1,2,3) # Struct is just a data holder class T < Struct.new(:a, :b) end # include Module in a class, then invoke the instance methods # of the module with class as the receiver # It doesn't add the methods; any instance methods define # in class overrides the module methods, even if it is included # after the method definition. module M def speak; puts :no; end end class AM def speak; puts :ok; end include M end am = AM.new.speak # include => singleton as immediate parent of my class # and its methods are methods of my module # hierarchy => singleton, class, module