CSC/ECE 517 Fall 2007/wiki1b 4 pm: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
mNo edit summary
mNo edit summary
 
(46 intermediate revisions by the same user not shown)
Line 1: Line 1:
'''Metaprogramming''' refers to the writing of programs that generates code at run time. It allows us to dynamically add behavior to existing classes and objects.
=Introduction=


'''Ruby''' is useful for metaprogramming as it is dynamic and reflective. It allows flexibility in writing new control structures.
'''[http://en.wikipedia.org/wiki/Metaprogramming Metaprogramming]''' refers to the writing of programs that generates code at run time.  Naturally, this is lucrative, as a programmer can direct his efforts towards developing other code in the time that it would to take to generate this code. Metaprogramming allows us to ''dynamically add behavior'' to existing classes and objects.
We’ve explored different ways of implementing metaprogramming in Ruby. We’ve listed some of them below, categorized according to the dynamically generated entities:


Ruby has several evals: eval, class_eval, module_eval, instance_eval.
'''[http://www.ruby-lang.org/ Ruby]''' is useful for Metaprogramming as it is ''[http://en.wikipedia.org/wiki/Dynamic_language dynamic]'' and ''[http://en.wikipedia.org/wiki/Reflection_%28computer_science%29 reflective]''. It allows flexibility in writing new control structures.


'''Example using eval:'''
==Uses of Metaprogramming==


class MagicLamp   
*Programs written in a language such as Ruby require less code to be written. Therefore, it takes to develop such programs and consequently, less time to market them.
  def self.remember_incantation(incantation)   
 
    eval "def #{incantation}; puts '#{incantation}!'; end"   
*If programs are written with less code, they will eventually have fewer bugs.
 
*The programs are also easier to maintain, taking less time to develop new features, leading ultimately to greater user satisfaction.
 
==Problem Definition==
 
Our problem states: ''“There are many good examples of metaprogramming in Ruby on the Web. Take a look at, say, a dozen of them, and write a guide to them. Classify them into whatever categories are appropriate, and give recommendations on how to proceed through them to acquire a good knowledge of the uses and usefulness of metaprogramming.”''
 
=Implementing Metaprogramming=
 
We’ve explored different ways of implementing metaprogramming in Ruby. This article is a guide to learning Metaprogramming ''by example''.
 
There are several methods to implement Metaprogramming. These can be classified into the following categories:
 
* ''eval, class_eval, module_eval, instance_eval''
 
* ''define_method''
 
* ''proc''
 
* ''instance_variable_set and instance_variable_get''
 
== Metaprogramming with eval, class_eval, module_eval, instance_eval ==
 
Here are a few examples using evals. Ruby has several evals: eval, class_eval, module_eval, instance_eval.
 
===Using eval===
 
In this example, MagicLamp creates an instance method only when the class method remember_incantation is called. The instance method corresponds to the incantation that the MagicLamp was told to remember.
 
  class MagicLamp   
    def self.remember_incantation(incantation)   
      eval "def #{incantation}; puts '#{incantation}!'; end"
    end  
   end   
   end   
end 
    
    
lamp = MagicLamp.new   
  lamp = MagicLamp.new   
lamp.respond_to? :kazaam                 #false
  lamp.respond_to? :kazaam                 #false
 
  #This tests if the object will respond to a method call “kazaam”
  #This code produces “FALSE” since kazaam doesn’t exist
 
  MagicLamp.remember_incantation "kazaam" 
    lamp.respond_to? :kazaam # true 
    lamp.kazaam # "kazaam!"


# This tests if the object will respond to a method call “kazaam”
===Using class_eval===
# This code produces “FALSE” since kazaam doesn’t exist


MagicLamp.remember_incantation "kazaam" 
Let’s say we need to define an attribute for a class:  
lamp.respond_to? :kazaam # true 
lamp.kazaam # "kazaam!"
In this example, MagicLamp creates an instance method only when the class method remember_incantation is called. The instance method corresponds to the incantation that the MagicLamp was told to remember.
Example using class_eval:


Let’s say we need to define an attribute for a class:  
  class MyClass
    attr_accessor    :id, :diagram, :telegram
  end


class MyClass
  attr_accessor    :id, :diagram, :telegram
end
This code can be refactored to accept attribute names as arguments rather than specifying them (using metaprogramming) as follows:
This code can be refactored to accept attribute names as arguments rather than specifying them (using metaprogramming) as follows:
class Class
 
  def my_attr_accessor( *args )
  class Class
    args.each do |name|
    def my_attr_accessor( *args )
      self.class_eval do
      args.each do |name|
          attr_accessor :"#{name}"
        self.class_eval do
            attr_accessor :"#{name}"
        end
       end
       end
    end
    end
  end
 
  class MyNewClass
    my_attr_accessor :id, :diagram, :telegram
   end
   end
end


class MyNewClass
The use of metaprogramming is illustrated above in they way the attributes are created; ‘my_attr_accessor’ creates an attribute by iterating over the arguments passed to it.
  my_attr_accessor :id, :diagram, :telegram
end


Here, the use of metaprogramming is illustrated in they way the attributes are created; ‘my_attr_accessor’ creates an attribute by iterating over the arguments passed to it.
===Using module_eval===


Examples using module_eval:
Sometimes, we need to define instance and class methods of a class at runtime, when you are outside the class. module_eval helps do just that.
module_eval defines instance and class methods of a class at runtime, when you are outside the class.


Example: Defining an instance method
Example: Defining an instance method


class C   
  class C   
end   
  end   
    
    
C.module_eval do   
  C.module_eval do   
  define_method :wish do   
    define_method :wish do   
    p "hello instance method"   
      p "hello instance method"
    end  
   end   
   end   
end 
    
    
c = C.new   
  c = C.new   
c.wish #hello instance method   
  c.wish #hello instance method   
 
Example: Defining a class method
Example: Defining a class method
class C
 
end   
  class C  
  end   
    
    
C.module_eval do   
  C.module_eval do   
  class << self   
  class << self   
    define_method :wish do   
      define_method :wish do   
      p "hello class method"   
        p "hello class method"   
      end   
        end 
    end   
   end   
   end   
end 
    
    
C.wish #hello class method   
  C.wish #hello class method   


Example: Another form of using module_eval when method body is available as a String object
Example: Another form of using module_eval when method body is available as a String object
class D   
 
  class << self   
  class D   
    def method_body   
    class << self   
      ret =<<-EOS   
      def method_body   
        def wish   
        ret =<<-EOS   
          p "hello, supplied as String object"   
          def wish   
         end  
            p "hello, supplied as String object"
       EOS  
          end  
         EOS  
       end  
     end   
     end   
  end 
     class C   
      
      end
  class C   
      c = C.new   
  end
      c.class.module_eval(D.method_body)   
 
      c.wish # hello, supplied as String object
  c = C.new   
  end
   
  c.class.module_eval(D.method_body)   
 
  c.wish # hello, supplied as String object
end


Example using instance_eval
===Using instance_eval===


The instance_eval method of Object allows you to evaluate a string or block in the context of an instance of a class. One can create a block of code in any context and evaluate it later in the context of an individual instance. In order to set the context, the variable self is set to the instance while the code is executing, giving the code access to the instance's variables.  
The instance_eval method of Object allows you to evaluate a string or block in the context of an instance of a class. One can create a block of code in any context and evaluate it later in the context of an individual instance. In order to set the context, the variable self is set to the instance while the code is executing, giving the code access to the instance's variables.  
class Navigator
  class Navigator
  def initialize
    def initialize
     @page_index = 0
      @page_index = 0
     end
    def next
      @page_index += 1
    end
   end
   end
  def next
    @page_index += 1
  end
end


navigator = Navigator.new
  navigator = Navigator.new
navigator.next
  navigator.next
navigator.next
  navigator.next
navigator.instance_eval "@page_index" #=> 2
  navigator.instance_eval "@page_index" #=> 2
navigator.instance_eval { @page_index } #=> 2
  navigator.instance_eval { @page_index } #=> 2
 
== Metaprogramming with define_method ==
 
===Using define_method===


Example using define_method
We can dynamically create methods at run-time, using define_method as follows:


class A
  class A
     def fred
     def fred
       puts "In Fred"
       puts "In Fred"
     end
     end
   
  def create_method(name, &block)
def create_method(name, &block)
       self.class.send(:define_method, name, &block)
       self.class.send(:define_method, name, &block)
   end
   end
  define_method(:wilma)
    define_method(:wilma)
    puts "Charge it!"
{ puts "Charge it!" }
   end
   end
   class B < A
   class B < A
    define_method(:barney, instance_method(:fred))
    define_method(:barney, instance_method(:fred))
   end
   end


Line 141: Line 175:
   a.wilma #Charge it
   a.wilma #Charge it
   a.create_method(:betty) { p self }
   a.create_method(:betty) { p self }
   a.betty #<B:0x401b39e8>
   a.betty #B:0x401b39e8
 
The above code illustrates how to use metaprogramming by dynamically creating methods using define method.
The above code illustrates how to use metaprogramming by dynamically creating methods using define method.
There are two ways of using define method:
There are two ways of using define method:
   
   
define_method(symbol, method)     
  define_method(symbol, method)     
define_method(symbol) { block }  
  define_method(symbol) { block }  
 
The following example shows another implementation of metaprogramming in which the define method gives us a way to bind the attributes of a method to the created methods, thereby changing its parameters.
 
  MyCounter = Class.new
      shared_count = 0 # A new local variable.
      MyCounter.send :define_method, :double_count do
        shared_count += 1
        @count ||= 0
        @count += 1
        [shared_count, @count]
      end
      first_counter = MyCounter.new
  second_counter = MyCounter.new
  assert_equal [1, 1], first_counter.double_count
  assert_equal [2, 2], first_counter.double_count
  assert_equal [3, 1], second_counter.double_count
  assert_equal [4, 2], second_counter.double_count


Example: The following example shows another implementation of metaprogramming in which the define method gives us a way to bind the attributes of a method to the created methods, thereby changing its parameters.
As can be seen, even if the method that defined the local variable  shared_count completed execution, the method in MyCounter will still be bound to the context of the method.
GuineaCounter = Class.new
 
    shared_count = 0 # A new local variable.
  class C   
    GuineaCounter.send :define_method, :double_count do
  def wish  
      shared_count += 1
      p "hello" 
      @count ||= 0
    end 
      @count += 1
  end 
      [shared_count, @count]
  c = C.new 
    end
    c.wish # hello 
    first_counter = GuineaCounter.new
  class D
second_counter = GuineaCounter.new
  class << self  
assert_equal [1, 1], first_counter.double_count
     def keep_some_record 
assert_equal [2, 2], first_counter.double_count
        p "I am keeping some records"
assert_equal [3, 1], second_counter.double_count
        end 
assert_equal [4, 2], second_counter.double_count
      end  
As, can be seen, even if the method that defined the local variable  shared_count completed execution, the method in GuineaCounter will still be bound to the context of the method.
class C   
  def wish   
     p "hello"   
   end   
   end   
end 
c = C.new 
c.wish # hello 


class D
  # aliasing the wish method 
  class << self 
    c.class.module_eval do 
  def keep_some_record   
    alias_method :wish_orig, :wish  
      p "I am keeping some records"  
      define_method :wish do   
        D.keep_some_record   
        wish_orig  
       end   
       end   
     end   
     end   
end 
  c.wish # I am keeping some records; hello
# aliasing the wish method 
 
== Metaprogramming with proc ==


c.class.module_eval do 
===Using proc===
alias_method :wish_orig, :wish 
  define_method :wish do   
    D.keep_some_record 
    wish_orig 
  end 
end 
c.wish # I am keeping some records; hello 


Example: Using proc
  def create_proc(&p); p; end
  create_proc do
    puts "hello"
  end     
  p.call(*args)


def create_proc(&p); p; end
create_proc do
puts "hello"
end      #  #<Proc ...>
p.call(*args)
If you want to use the proc for defining methods, you should use lambda to create it, so return and break will behave the way you expect:
If you want to use the proc for defining methods, you should use lambda to create it, so return and break will behave the way you expect:
p = lambda { puts "hoho"; return 1 }
define_method(:a, &p)


Example: Adding fields based on need for them
  p = lambda { puts "hoho"; return 1 }
  define_method(:a, &p)


class BinaryTree
== Metaprogramming with instance_variable_set/ instance_variable_get ==
  def add(value)
 
    if @root.nil?
===Adding fields based on need for them===
      @root = BinaryTreeNode.new(value)
    else
      @root.add(value)
    end
  end
end


class BinaryTreeNode
Sometimes, one might not know what fields a class requires while defining the class. Ruby's Metaprogramming circumvents that problem, as illustrated below.
  def initialize(value)
    @value = value
  end


   def add(value)
   class BinaryTree
    if value < @value
    def add(value)
       if @left.nil?
       if @root.nil?
         @left = BinaryTreeNode.new(value)
         @root = BinaryTreeNode.new(value)
       else
       else
         @left.add(value)
         @root.add(value)
       end
       end
     else
     end
       if @right.nil?
  end
        @right = BinaryTreeNode.new(value)
 
  class BinaryTreeNode
    def initialize(value)
      @value = value
    end
 
    def add(value)
       if value < @value
        if @left.nil?
          @left = BinaryTreeNode.new(value)
        else
          @left.add(value)
        end
       else
       else
         @right.add(value)
         if @right.nil?
          @right = BinaryTreeNode.new(value)
        else
          @right.add(value)
        end
       end
       end
     end
     end
   end
   end
end


We see that there are many calls to create new objects of BinaryTree and BinaryTreeNode. Metaprogramming can help replace this code snippet:
We see that there are many calls to create new objects of BinaryTree and BinaryTreeNode. Metaprogramming can help replace this code snippet:


if field.nil?
  if field.nil?
  field = BinaryTreeNode.new(value)
    field = BinaryTreeNode.new(value)
else
  else
  field.add(value)
    field.add(value)
end
  end


With:
With:


module BinaryTreeHelper
  module BinaryTreeHelper
  private
    private
  def add_or_create_node(field, value)
    def add_or_create_node(field, value)
    if instance_variable_get(field).nil?
      if instance_variable_get(field).nil?
      instance_variable_set(field,
        instance_variable_set(field,
                            BinaryTreeNode.new(value))
                              BinaryTreeNode.new(value))
    else
      else
      instance_variable_get(field).add(value)
        instance_variable_get(field).add(value)
      end
     end
     end
   end
   end
end


And the classes can be changed accordingly as:
And the classes can be changed accordingly as:


class BinaryTree
  class BinaryTree
   include BinaryTreeHelper
    include BinaryTreeHelper
    def add(value)
      add_or_create_node(:@root, value)
    end
   end
  class BinaryTreeNode
    include BinaryTreeHelper


  def add(value)
    def initialize(value)
    add_or_create_node(:@root, value)
      @value = value
    end
    def add(value)
      add_or_create_node(value < @value ? :@left : :@right,
                        value)
    end
   end
   end
end


class BinaryTreeNode
This example is very illustrative in demonstrating how we can generate entities at runtime.
  include BinaryTreeHelper
 
= See Also =
 
[http://en.wikipedia.org/wiki/Metaprogramming Metaprogramming]
 
[http://www.ruby-lang.org/ Ruby]
 
=References=
 
[http://rails.aizatto.com/category/language-features/metaprogramming/ Archive for Metaprogramming]
 
[http://theplana.wordpress.com/2007/03/12/how-to-define-a-attribute-using-metaprogramming/ Defining attributes with Metaprogramming]


  def initialize(value)
[http://ozone.wordpress.com/2006/03/02/binary-search-tree-sauce-ruby-part-1/ Blog page with an example on Metaprogramming]
    @value = value
  end


  def add(value)
[http://www.ruby-doc.org/core/classes/Object.src/M000366.html Example on Metaprogramming]
    add_or_create_node(value < @value ? :@left : :@right,
                      value)
  end
end


This example is very illustrative in demonstrating how we can generate entities at runtime.
[http://expressica.com/category/metaprogramming/ More examples]


      '''REFERENCES'''                     
[http://ozone.wordpress.com/2006/02/22/rubybeans-a-short-example-of-ruby-metaprogramming/#comment-1286 Rubybeans and Metaprogramming]


http://en.wikipedia.org/wiki/Metaprogramming
[http://theplana.wordpress.com/2007/09/16/blocks-parameters-list-and-metaprogramming/ Blocks parameters list]
http://rails.aizatto.com/category/language-features/metaprogramming/
http://theplana.wordpress.com/2007/03/12/how-to-define-a-attribute-using-metaprogramming/
http://ozone.wordpress.com/2006/03/02/binary-search-tree-sauce-ruby-part-1/
http://www.ruby-doc.org/core/classes/Object.src/M000366.html
http://expressica.com/category/metaprogramming/
http://www.whytheluckystiff.net/articles/seeingMetaclassesClearly.html
http://ozone.wordpress.com/2006/02/22/rubybeans-a-short-example-of-ruby-metaprogramming/#comment-1286
http://theplana.wordpress.com/2007/09/16/blocks-parameters-list-and-metaprogramming/http://poignantguide.net/ruby/chapter-6.html


[http://www.whytheluckystiff.net/articles/seeingMetaclassesClearly.html Seeing Metaclasses clearly]


<nowiki><nowiki>Insert non-formatted text here</nowiki></nowiki>
[http://poignantguide.net/ruby/chapter-6.html A poignant guide to Ruby]

Latest revision as of 19:37, 10 October 2007

Introduction

Metaprogramming refers to the writing of programs that generates code at run time. Naturally, this is lucrative, as a programmer can direct his efforts towards developing other code in the time that it would to take to generate this code. Metaprogramming allows us to dynamically add behavior to existing classes and objects.

Ruby is useful for Metaprogramming as it is dynamic and reflective. It allows flexibility in writing new control structures.

Uses of Metaprogramming

  • Programs written in a language such as Ruby require less code to be written. Therefore, it takes to develop such programs and consequently, less time to market them.
  • If programs are written with less code, they will eventually have fewer bugs.
  • The programs are also easier to maintain, taking less time to develop new features, leading ultimately to greater user satisfaction.

Problem Definition

Our problem states: “There are many good examples of metaprogramming in Ruby on the Web. Take a look at, say, a dozen of them, and write a guide to them. Classify them into whatever categories are appropriate, and give recommendations on how to proceed through them to acquire a good knowledge of the uses and usefulness of metaprogramming.”

Implementing Metaprogramming

We’ve explored different ways of implementing metaprogramming in Ruby. This article is a guide to learning Metaprogramming by example.

There are several methods to implement Metaprogramming. These can be classified into the following categories:

  • eval, class_eval, module_eval, instance_eval
  • define_method
  • proc
  • instance_variable_set and instance_variable_get

Metaprogramming with eval, class_eval, module_eval, instance_eval

Here are a few examples using evals. Ruby has several evals: eval, class_eval, module_eval, instance_eval.

Using eval

In this example, MagicLamp creates an instance method only when the class method remember_incantation is called. The instance method corresponds to the incantation that the MagicLamp was told to remember.

 class MagicLamp  
   def self.remember_incantation(incantation)  
     eval "def #{incantation}; puts '#{incantation}!'; end"  
   end  
 end  
 
 lamp = MagicLamp.new  
 lamp.respond_to? :kazaam	                 #false
 
 #This tests if the object will respond to a method call “kazaam”
 #This code produces “FALSE” since kazaam doesn’t exist
 
 MagicLamp.remember_incantation "kazaam"  
   lamp.respond_to? :kazaam			 # true  
   lamp.kazaam					 # "kazaam!"

Using class_eval

Let’s say we need to define an attribute for a class:

 class MyClass
   attr_accessor    :id, :diagram, :telegram
 end

This code can be refactored to accept attribute names as arguments rather than specifying them (using metaprogramming) as follows:

 class Class
   def my_attr_accessor( *args )
      args.each do |name|
        self.class_eval do
           attr_accessor :"#{name}"
        end
      end
   end
 end
 class MyNewClass
   my_attr_accessor :id, :diagram, :telegram
 end

The use of metaprogramming is illustrated above in they way the attributes are created; ‘my_attr_accessor’ creates an attribute by iterating over the arguments passed to it.

Using module_eval

Sometimes, we need to define instance and class methods of a class at runtime, when you are outside the class. module_eval helps do just that.

Example: Defining an instance method

 class C  
 end  
 
 C.module_eval do  
   define_method :wish do  
     p "hello instance method"  
   end  
 end  
 
 c = C.new  
 c.wish 	#hello instance method  

Example: Defining a class method

 class C   
 end  
 
 C.module_eval do  
  class << self  
     define_method :wish do  
       p "hello class method"  
       end  
   end  
 end  
 
 C.wish 	#hello class method  

Example: Another form of using module_eval when method body is available as a String object

 class D  
   class << self  
     def method_body  
       ret =<<-EOS  
         def wish  
           p "hello, supplied as String object"  
         end  
       EOS  
     end  
   end  
   class C  
     end
     c = C.new  
     c.class.module_eval(D.method_body)  
     c.wish # hello, supplied as String object
 end

Using instance_eval

The instance_eval method of Object allows you to evaluate a string or block in the context of an instance of a class. One can create a block of code in any context and evaluate it later in the context of an individual instance. In order to set the context, the variable self is set to the instance while the code is executing, giving the code access to the instance's variables.

 class Navigator
    def initialize
      @page_index = 0
    end
    def next
      @page_index += 1
    end
  end
 navigator = Navigator.new
 navigator.next
 navigator.next
 navigator.instance_eval "@page_index" #=> 2
 navigator.instance_eval { @page_index } #=> 2

Metaprogramming with define_method

Using define_method

We can dynamically create methods at run-time, using define_method as follows:

 class A
    def fred
      puts "In Fred"
    end
 def create_method(name, &block)
      self.class.send(:define_method, name, &block)
 end
 define_method(:wilma)
   puts "Charge it!"
  end
  class B < A
   define_method(:barney, instance_method(:fred))
  end
  a = B.new
  a.barney				#In Fred
  a.wilma				#Charge it
  a.create_method(:betty) { p self }
  a.betty				#B:0x401b39e8

The above code illustrates how to use metaprogramming by dynamically creating methods using define method. There are two ways of using define method:

 define_method(symbol, method)     
 define_method(symbol) { block } 

The following example shows another implementation of metaprogramming in which the define method gives us a way to bind the attributes of a method to the created methods, thereby changing its parameters.

 MyCounter = Class.new
     shared_count = 0 # A new local variable.
     MyCounter.send :define_method, :double_count do
       shared_count += 1
       @count ||= 0
       @count += 1
       [shared_count, @count]
     end
     first_counter = MyCounter.new 
 second_counter = MyCounter.new
 assert_equal [1, 1], first_counter.double_count
 assert_equal [2, 2], first_counter.double_count
 assert_equal [3, 1], second_counter.double_count
 assert_equal [4, 2], second_counter.double_count

As can be seen, even if the method that defined the local variable shared_count completed execution, the method in MyCounter will still be bound to the context of the method.

 class C  
  def wish  
     p "hello"  
   end  
 end  
  c = C.new  
   c.wish # hello  
 class D 
  class << self  
   def keep_some_record  
        p "I am keeping some records"  
       end  
     end  
 end  
 # aliasing the wish method  
   c.class.module_eval do  
    alias_method :wish_orig, :wish  
     define_method :wish do    
       D.keep_some_record  
       wish_orig  
     end  
   end  
 c.wish # I am keeping some records; hello

Metaprogramming with proc

Using proc

 def create_proc(&p); p; end
 create_proc do
   puts "hello"
 end      
 p.call(*args)

If you want to use the proc for defining methods, you should use lambda to create it, so return and break will behave the way you expect:

 p = lambda { puts "hoho"; return 1 }
 define_method(:a, &p)

Metaprogramming with instance_variable_set/ instance_variable_get

Adding fields based on need for them

Sometimes, one might not know what fields a class requires while defining the class. Ruby's Metaprogramming circumvents that problem, as illustrated below.

 class BinaryTree
   def add(value)
     if @root.nil?
       @root = BinaryTreeNode.new(value)
     else
       @root.add(value)
     end
   end
 end
 class BinaryTreeNode
   def initialize(value)
     @value = value
   end
 
   def add(value)
     if value < @value
       if @left.nil?
         @left = BinaryTreeNode.new(value)
       else
         @left.add(value)
       end
     else
       if @right.nil?
         @right = BinaryTreeNode.new(value)
       else
         @right.add(value)
       end
     end
   end
 end

We see that there are many calls to create new objects of BinaryTree and BinaryTreeNode. Metaprogramming can help replace this code snippet:

 if field.nil?
   field = BinaryTreeNode.new(value)
 else
   field.add(value)
 end

With:

 module BinaryTreeHelper
   private
   def add_or_create_node(field, value)
     if instance_variable_get(field).nil?
       instance_variable_set(field,
                             BinaryTreeNode.new(value))
     else
       instance_variable_get(field).add(value)
     end
   end
 end

And the classes can be changed accordingly as:

 class BinaryTree
   include BinaryTreeHelper
   def add(value)
     add_or_create_node(:@root, value)
   end
 end
 class BinaryTreeNode
   include BinaryTreeHelper
   def initialize(value)
     @value = value
   end
   def add(value)
     add_or_create_node(value < @value ? :@left : :@right,
                        value)
   end
 end

This example is very illustrative in demonstrating how we can generate entities at runtime.

See Also

Metaprogramming

Ruby

References

Archive for Metaprogramming

Defining attributes with Metaprogramming

Blog page with an example on Metaprogramming

Example on Metaprogramming

More examples

Rubybeans and Metaprogramming

Blocks parameters list

Seeing Metaclasses clearly

A poignant guide to Ruby