Created
March 24, 2011 21:31
-
-
Save snuggs/885938 to your computer and use it in GitHub Desktop.
Meta Programming Made Easy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Yehuda Katz - (It's all about the self) | |
# http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/ | |
####################################################################################### | |
# All classes are objects themselves | |
####################################################################################### | |
# Defining a class using the "class" keyword is merely syntactic sugar. | |
# All class definitions are actually instances of the Class object. | |
class MyClass; end # MyClass = Class.new | |
class ParentClass; end # ParentClass = Class.new | |
class ChildClass < ParentClass; end # MyClass = Class.new(ParentClass) | |
######################################################################################## | |
# NOTICE: All classes in Ruby are open! Ruby code is interpreted. There is no compiler. | |
# Meaning they can be "reopened" and redefined at runtime. | |
# Hence why this code is valid if you run this file with the ruby interpreter | |
# (or paste this code into irb) | |
####################################################################################### | |
# open MyClass and define a Class (singleton) method in class definition | |
class MyClass | |
def self.my_class_method;end | |
end | |
# open String base class and define an instance method in class definition | |
class String | |
def i_can_haz_cheezburgr? | |
true | |
end | |
end | |
######################################################################################## | |
# NOTICE: All objects are open as well. Methods can be defined on a particular instance (and its class). | |
# In this case a method is added to the instance's class; an Eigenclass (ghost, shadow class) | |
# is created which duplicates the class of the instance. This makes the method | |
# available to the instance and that instance ONLY! | |
# | |
# This "Eigenclass" cannot be accessed directly. (e.g. cannot be inherited) | |
####################################################################################### | |
# e.g. | |
my_class_instance = MyClass.new | |
def my_class_instance.method_for_this_instance_only | |
# MyClass is duplicated into an Eigenclass (ghost class) | |
# and this method definition is stored there. | |
return "I can only be accessed from this instance of MyClass" | |
end | |
my_class_instance.method_for_this_instance_only # => "I can only be accessed from this instance of MyClass" | |
# Notice: The class of my_class_instance is still MyClass. The Eigenclass(MyClass) is a ghost. | |
my_class_instance.class # => MyClass | |
another_my_class_instance = MyClass.new | |
another_my_class_instance.respond_to?(:method_for_this_instance_only) # => false | |
# Class (singleton) method defined outside of class definition | |
def MyClass.my_class_method; end | |
MyClass.my_class_method | |
# Multiple class (singleton) methods | |
class MyClass | |
# Use this style of metaprogramming to group 2 or more class methods | |
# instead of repeating def self.<method_name>; end | |
class << self # Define all methods on self's class (here self = MyClass) | |
def my_class_method; end | |
def my_second_class_method; end | |
end | |
def my_instance_method; end | |
end | |
MyClass.my_class_method | |
MyClass.my_second_class_method | |
MyClass.new.my_instance_method | |
################################################################################################ | |
# ALL methods have a receiver | |
# To fully grok Ruby one must understand the "dot notation" within an object's method call | |
# <object>(dot)<method> # is equivelant to: | |
old_self = self | |
# self = <object> | |
# self.send(<method>.to_sym) | |
# self = old_self | |
################################################################################################ | |
# e.g. | |
my_class_instance = MyClass.new | |
my_class_instance.my_instance_method # is equivelant to: | |
old_self = self | |
# self = my_class_instance | |
# self.send(:my_instance_method) | |
# self = old_self | |
# Same works for classes (since they are only object instances of Class.new) | |
MyClass.my_class_method # is equivelant to: | |
old_self = self | |
# self = MyClass | |
# self.send(:my_class_method) | |
# self = old_self | |
################################################################################################ | |
# "This above all; to thine own SELF be true, | |
# and it must follow, as the night the day, | |
# thou canst not then be false to any [class]" - William Shakespeare | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment