kernelsmith
3/10/2011 - 7:43 PM

metaclassing_notes.rb

#!/usr/bin/ruby
# This code is to demonstrate these very important things to remember about Ruby:
#
# 1. Classes are also Objects in Ruby.
# 2. Every Object in Ruby has its own Singleton Class (or "Meta Class" or "Eigen
#   Class"
# 3. In other languages you may be familiar with the idea that each Object
#   Instance is unique, but in Ruby, each Object Instance has its own unique
#   Class definition, unique to JUST THAT instance. This is called the Object's
#   singleton class.
# 
# An object's singleton class is like a human's personality. Each person not only
# has a physical body that is unique but also a personality that is unqique.
# Each Instance of a class (aka instantiated object) is like the physical body, and
# the Eigen Class is like the "personality" that is unique to just that instance.
# In other languages like Python the idea of a ClassObj exists but when an Instance
# is created from the ClassObj the Instance does not carry an "Eigen Class" object
# with it. Furthermore, because of the Python syntax, modifying the class definition
# (such as adding a method or adding other attributes) is very difficult.

# >>> class Thang:
# ...     pass
# ... 
# >>> a = Thang
# >>> type(a)
# <type 'classobj'>
# >>> a = Thang()
# >>> type(a)
# <type 'instance'>
# >>> dir(a)
# ['__doc__', '__module__']
# >>> a.__class__
# <class __main__.Thang at 0x1004b2a10>
# >>>
#
#  

class A
    B = 12

    def self.a
        puts "class method A::a : #{B}"
    end

    def A.b
        puts "class method A::b : #{B}"
    end
    # The above two methods just demonstrate two different ways of doing the
    # same thing

    class << self
        B = 24
        def c
            puts "class method A::c : #{B}"
        end
    end

end
# It is important to note that when you write:
# 
#  def my_object.mymethod
#    ...
#  end
#
# This is merely a shortcut for:
# 
# class << my_object
# #This is the inside of my_object's singleton class.
#   def my_method
#     ...
#   end
# end
A.a
A.b
A.c
puts "A::B : #{A::B}"
b = A.new
# Another neat thing about ruby is that you can also add methods to classes from
# OUTSIDE of the class definition like you can in C++
class << b
    def hi
        puts "nice huh?"
    end
end
b.hi
# The above just modifies the b's singleton class definition. YOu can also
# modify A.
class << A
    def hi2
        puts "REALLY nice huh?"
    end
end
A.hi2
# The following two lines should cause an error demonstrating that modifying of the object
# instance "b" does not effect the class definition he inherited from and that
# the instance of "b" also didnt get the update to the class "A"

A.hi # undefined method `hi' for A:Class (NoMethodError)
b.hi2 # undefined method `hi2' for #<A:0x1001546d0> (NoMethodError)

# A full run of the above gives the following output:
# stephen$ ./meta_classes.rb
# class method A::a : 12
# class method A::b : 12
# class method A::c : 24
# A::B : 12
# nice huh?
# REALLY nice huh?
# ./meta_classes.rb:74: undefined method `hi' for A:Class (NoMethodError)