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

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 12: Line 12:


One of the first artilces that I read concerning metaprogramming in Ruby was posted on a blog by Ola Bini[4] wrote somewhat of a guide on metaprogramming in Ruby and broke it down into 11 different techniques used by metaprogramming. Although, I haven’t decided to use his categories verbatum, he did leave a good outline when trying to understand the power generated through metaprogramming. I have decided to breakdown this discussion of metaprogramming in Ruby into 4 categories:
One of the first artilces that I read concerning metaprogramming in Ruby was posted on a blog by Ola Bini[4] wrote somewhat of a guide on metaprogramming in Ruby and broke it down into 11 different techniques used by metaprogramming. Although, I haven’t decided to use his categories verbatum, he did leave a good outline when trying to understand the power generated through metaprogramming. I have decided to breakdown this discussion of metaprogramming in Ruby into 4 categories:
<pre>
1. Using the different versions of eval;  
1. Using the different versions of eval;  
2. Create Procs from blocks and send them around;
2. Create Procs from blocks and send them around;
3. Create classes and modules dynamically;
3. Create classes and modules dynamically;
4. Using the Singleton Class
4. Using the Singleton Class
 
</pre>
====Using the Different Versions of eval====
====Using the Different Versions of eval====
Line 24: Line 25:


=====Example 1=====  
=====Example 1=====  
 
<pre>
test = TestBean.new
test = TestBean.new
test.name = “parker”
test.name = “parker”
Line 31: Line 32:
TestBean.name_count # => 2
TestBean.name_count # => 2
TestBean.firstname_count # => 0
TestBean.firstname_count # => 0
 
</pre>
The solution for Ruby was to us class_eval, although he does state that there are more elegant ways of doing it. This is just one exmple on how implement the eval statement in metaprogramming.
The solution for Ruby was to us class_eval, although he does state that there are more elegant ways of doing it. This is just one exmple on how implement the eval statement in metaprogramming.


=====Example 2=====
=====Example 2=====
 
<pre>
1. def RubyBean.property(*properties)
1. def RubyBean.property(*properties)
2.   properties.each { |property|
2.   properties.each { |property|
Line 63: Line 64:
26.   }
26.   }
27. end
27. end
 
</pre>
I also found an article on Devsource that gave an extensive example of the powers of metaprogramming in Ruby. The article “An Exercixe in Metaprogramming with Ruby” [6] starts with a simple example and continues to expand it. For the purposes of this paper I will only use the first part of his exmple.  
I also found an article on Devsource that gave an extensive example of the powers of metaprogramming in Ruby. The article “An Exercixe in Metaprogramming with Ruby” [6] starts with a simple example and continues to expand it. For the purposes of this paper I will only use the first part of his exmple.  
He first states his assumptions that we want to create a class with a name derived from a file name and the first line of the file is comma separate list of attribute name. [6]
He first states his assumptions that we want to create a class with a name derived from a file name and the first line of the file is comma separate list of attribute name. [6]


=====Example 3=====
=====Example 3=====
 
<pre>
We are given a file and we want to create a class with its contents. First he creates a new class.
We are given a file and we want to create a class with its contents. First he creates a new class.
class_name = File.basename(file_name,".txt").capitalize   
class_name = File.basename(file_name,".txt").capitalize   
Line 83: Line 84:
klass.class_eval do
klass.class_eval do
     attr_accessor *names
     attr_accessor *names
 
</pre>
This is again using class_eval in this example to metaprogramming, creating all the necessary accessor methods.
This is again using class_eval in this example to metaprogramming, creating all the necessary accessor methods.


Line 90: Line 91:


In the article mentioned earlier, Bini statest that creating Procs is what makes many API’s easy to use and one way Markaby uses to manage the CSS class definitions. [4] He illustrates how to turn a block into a Proc:
In the article mentioned earlier, Bini statest that creating Procs is what makes many API’s easy to use and one way Markaby uses to manage the CSS class definitions. [4] He illustrates how to turn a block into a Proc:
=====Example 1=====
<pre>
def create_proc(&p); p; end
def create_proc(&p); p; end
create_proc do
create_proc do
Line 97: Line 100:
And to call it is also very simple. When using proc for defining methods we should use lambda to create it.
And to call it is also very simple. When using proc for defining methods we should use lambda to create it.


p.call(*args)
p.call(*args)
p = lambda { puts "hoho"; return 1 }
p = lambda { puts "hoho"; return 1 }
define_method(:a, &p)
define_method(:a, &p)
 
</pre>
Again this is a very important aspect of metaprogramming in Ruby.
Again this is a very important aspect of metaprogramming in Ruby.
In an article by Daniel Bernier,  “Ruby, Meta-Programming, and Waitr” another example of using proc is given. [6] A simple method is present as follows:
In an article by Daniel Bernier,  “Ruby, Meta-Programming, and Waitr” another example of using proc is given. [6] A simple method is present as follows:


=====Example 2=====
<pre>
def divs (*args, &proc)
def divs (*args, &proc)
     proc ||= make_filter(args)
     proc ||= make_filter(args)
Line 111: Line 116:
     }
     }
end
end
 
</pre>
This is a simple example where &proc is used as a parameter in the method definition and it can now be treated as a variable. It is no longer called with the yield but instead the call is made with proc.call. This again illustrates the power of metaprogramming allowing the programmer to pass this block as a variable.
This is a simple example where &proc is used as a parameter in the method definition and it can now be treated as a variable. It is no longer called with the yield but instead the call is made with proc.call. This again illustrates the power of metaprogramming allowing the programmer to pass this block as a variable.


Line 119: Line 124:
Being able create things dynamically, is essential to the Ruby programming language. You can do pretty much any thing to a non-frozen class or module. [4] Bini uses the example of a Struct class to show this.  
Being able create things dynamically, is essential to the Ruby programming language. You can do pretty much any thing to a non-frozen class or module. [4] Bini uses the example of a Struct class to show this.  


=====Example 1=====
<pre>
PersonVO = Struct.new(:name, :phone, :email)
PersonVO = Struct.new(:name, :phone, :email)
p1 = PersonVO.new(:name => "Ola Bini")
p1 = PersonVO.new(:name => "Ola Bini")
Line 130: Line 137:
end
end
c.new.foo    # => "Hello World"
c.new.foo    # => "Hello World"
 
</pre>
Again we are using class_eval to create this new class. This is a very simple example of how to create a module or method dynamically.
Again we are using class_eval to create this new class. This is a very simple example of how to create a module or method dynamically.
There is an article on bias2build.com that also discussing the ability to create classes and modules dynamically.[8] Although no coded example is given the information is very useful. He talks specifically about define_method and alias_method that can be used to create a wrapper around a class. This can in turn can be used to change the functionality of a method. The ability to do this gives Ruby metaprogramming its strength.
There is an article on bias2build.com that also discussing the ability to create classes and modules dynamically.[8] Although no coded example is given the information is very useful. He talks specifically about define_method and alias_method that can be used to create a wrapper around a class. This can in turn can be used to change the functionality of a method. The ability to do this gives Ruby metaprogramming its strength.
An Ariel Ortiz article on linuxjournal.com outlined another aspect to dynamic programming in relation to metaprogramming. [9] What Ortiz points out is that we are able to “modify different parts of your program easily during runtime without having to generate source code explicitly as we did previously.” [9] The example he cites is the use of the attr_accessor to produce the read/write methods automatically. The code is as follows:
An Ariel Ortiz article on linuxjournal.com outlined another aspect to dynamic programming in relation to metaprogramming. [9] What Ortiz points out is that we are able to “modify different parts of your program easily during runtime without having to generate source code explicitly as we did previously.” [9] The example he cites is the use of the attr_accessor to produce the read/write methods automatically. The code is as follows:
=====Example 2=====
<pre>
class Person
class Person
   attr_accessor :name
   attr_accessor :name
Line 149: Line 158:
   end
   end
end
end
 
</pre>
This truly shows the power of dynamic operations.
This truly shows the power of dynamic operations.
Line 156: Line 165:
Bini asserts that the use of the Singleton class is very helpful in implementing different aspects of metaprogramming. Being able to manipulate single objects through the singleton class is essential. [4]  An easy way to get to the singleton class is as follows:
Bini asserts that the use of the Singleton class is very helpful in implementing different aspects of metaprogramming. Being able to manipulate single objects through the singleton class is essential. [4]  An easy way to get to the singleton class is as follows:


=====Example 1=====
<pre>
sclass = (class << self; self; end)
sclass = (class << self; self; end)


Line 165: Line 176:
end
end
end
end
 
</pre>
Another example of using a singleton class is presented in an article on bias2build.com. [8]  The author states that “Singleton classes are used to add methods or attributes to instances of a class rather than to classes. Ruby's syntax allows the programmer to either define individual methods of the singleton class, or to pry open the singleton class and add methods or variables that way.” [8] Having examples of the singleton implementation can be useful, like as follows.
Another example of using a singleton class is presented in an article on bias2build.com. [8]  The author states that “Singleton classes are used to add methods or attributes to instances of a class rather than to classes. Ruby's syntax allows the programmer to either define individual methods of the singleton class, or to pry open the singleton class and add methods or variables that way.” [8] Having examples of the singleton implementation can be useful, like as follows.


=====Example 2=====
<pre>
greeting = "Hello"
greeting = "Hello"
   bob = "Bob"
   bob = "Bob"
Line 178: Line 191:
greeting.say_twice # This will print "Hello" twice
greeting.say_twice # This will print "Hello" twice
bob.say_twice # This will throw a NoMethodError
bob.say_twice # This will throw a NoMethodError
 
</pre>
===True Power of Meta-programming===
===True Power of Meta-programming===


Line 186: Line 199:




 
REFERENCES:
 
 
 
 
 
 
 
 
 
{{reflist}}
 
 
 
REFERENCES:<references />
 


[1] http://ftp.cs.olemiss.edu/~hcc/papers/RubyMetaprogramming.pdf
[1] http://ftp.cs.olemiss.edu/~hcc/papers/RubyMetaprogramming.pdf

Latest revision as of 03:36, 11 October 2007

Metaprogramming in Ruby

Ruby is a dynamically-typed, interpreted, object oriented language. One of the unique aspects of Ruby is its extensive reflexive metaprogramming facilities. According to H. Conrad Cunningham, Professor in the Department of Computer and Information Science, “Reflexive programming is the capability of a program to both inspect and change its own program structures.”[1] He goes hello on to so that “it has long been a staple of languages such as Smalltalk and Lisp but the recent interest in Ruby has renewed interest in metaprogramming and in techniques like internal DSL.”[2]

What is Metaprogramming?

According to lecture 8 of our class lectures “the related technique of metaprogramming allows one to create new program entities, such as method or classes, at run time. Why is this called metaprogramming? Essentially the program is writing a program.” In a more detailed description of metaprogramming we can turn to wikipedia.org. “Metaprogramming is the writing of computer programs that write or manipulate other programs (or themselves) as their data or that do part of the work during compile time that is otherwise done at run time. In many cases, this allows programmers to get more done in the same amount of time as they would take to write all the code manually.”[3] This is the essential message learned throughout our discovery of metaprogramming. It is a program writing a program. Following are a dozen examples of metaprogramming in Ruby. The examples have been broken down into several catagories to better examine the different aspects of metaprogramming in Ruby.

Examples of Metaprogramming

One of the first artilces that I read concerning metaprogramming in Ruby was posted on a blog by Ola Bini[4] wrote somewhat of a guide on metaprogramming in Ruby and broke it down into 11 different techniques used by metaprogramming. Although, I haven’t decided to use his categories verbatum, he did leave a good outline when trying to understand the power generated through metaprogramming. I have decided to breakdown this discussion of metaprogramming in Ruby into 4 categories:

	1. Using the different versions of eval; 
	2. Create Procs from blocks and send them around;
	3. Create classes and modules dynamically;
	4. Using the Singleton Class

Using the Different Versions of eval

Bini in his article, goes on to explain the different eval’s that are availble and the importance of knowing what each of them do and when to use them. The major difference is that eval will evalute a string while the others can evaluate a block. Eval, instance_eval, module_eval and class_eval are some that he mentioned. “Instance eval will evaluate the string or block in the context of the receiver, meaning self will be set to the receiver while evaluating.”[4] Module_eval will use the context of the module to do the evaluation. For example, String.instance_eval with a def foo inside will be available as String.foo, while String.module_eval will be String.new.foo instead. Although Bini didn’t give an extensive example when illustrating the different eval’s, another example was found on Ozone.com in an article entitled “RubyBeans, a short example of Ruby metaprogramming.” [5] In the article, the author is trying to explaining why implementing a JavaBean would benefit greatly by metaprogramming in Ruby. At the end of the article, however, is the question of how to create static methods through metaprogramming. The example of a class that counts the number of properties that have been assigned was given.

Example 1
	test = TestBean.new
	test.name = “parker”
	test2 = TestBean.new
	test2.name = “lewis”
	TestBean.name_count # => 2
	TestBean.firstname_count # => 0

The solution for Ruby was to us class_eval, although he does state that there are more elegant ways of doing it. This is just one exmple on how implement the eval statement in metaprogramming.

Example 2
1.	def RubyBean.property(*properties)
2.	  properties.each { |property|
3.	    class_eval(%Q[
4.	      @@#{property}_count = 0
5.	
6.	      def #{property}
7.	        @#{property}
8.	      end
9.	
10.	      def #{property}=(value)
11.	        oldValue = @#{property}
12.	        return if (value == oldValue)
13.	        @listeners.each { |listener|
14.	          listener.propertyChanged(:#{property},
15.	                                   oldValue,
16.	                                   value)
17.	        }
18.	        @#{property} = value
19.	        @@#{property}_count += 1
20.	      end
21.	
22.	      def self.#{property}_count
23.	        @@#{property}_count
24.	      end
25.	    ])
26.	  }
27.	end

I also found an article on Devsource that gave an extensive example of the powers of metaprogramming in Ruby. The article “An Exercixe in Metaprogramming with Ruby” [6] starts with a simple example and continues to expand it. For the purposes of this paper I will only use the first part of his exmple. He first states his assumptions that we want to create a class with a name derived from a file name and the first line of the file is comma separate list of attribute name. [6]

Example 3
We are given a file and we want to create a class with its contents. First he creates a new class.
	class_name = File.basename(file_name,".txt").capitalize  
  	 # e.g. "foo.txt" => "Foo"
    	klass = Object.const_set(class_name,Class.new)

He then goes on to add the attributes in the form of an array.

	data = File.new(file_name)        
  	 names = data.gets.chomp.split(",")  # an array of strings

Then he is able to use the class_eval in the context of the new class klass.

	klass.class_eval do
     	 attr_accessor *names

This is again using class_eval in this example to metaprogramming, creating all the necessary accessor methods.


Create Procs from Blocks and Send Them Around

In the article mentioned earlier, Bini statest that creating Procs is what makes many API’s easy to use and one way Markaby uses to manage the CSS class definitions. [4] He illustrates how to turn a block into a Proc:

Example 1
	def create_proc(&p); p; end
	create_proc do
	puts "hello"
	end       # => #<Proc ...>

And to call it is also very simple. When using proc for defining methods we should use lambda to create it.

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

Again this is a very important aspect of metaprogramming in Ruby. In an article by Daniel Bernier, “Ruby, Meta-Programming, and Waitr” another example of using proc is given. [6] A simple method is present as follows:

Example 2
def divs (*args, &proc)
    proc ||= make_filter(args)
    # Find all sub-nodes for which this block evaluates to 'true'
    self.find_all { |n|
        n.tagName.upcase == "div".upcase and proc.call(n)
    }
end

This is a simple example where &proc is used as a parameter in the method definition and it can now be treated as a variable. It is no longer called with the yield but instead the call is made with proc.call. This again illustrates the power of metaprogramming allowing the programmer to pass this block as a variable.


Creating Classes and Modules Dynamically

Being able create things dynamically, is essential to the Ruby programming language. You can do pretty much any thing to a non-frozen class or module. [4] Bini uses the example of a Struct class to show this.

Example 1
	PersonVO = Struct.new(:name, :phone, :email)
	p1 = PersonVO.new(:name => "Ola Bini")

Once you’ve done this,  creating a new class and method is as follows:
	c = Class.new
	c.class_eval do
	define_method :foo do
	puts "Hello World"
	end
	end
	c.new.foo    # => "Hello World"

Again we are using class_eval to create this new class. This is a very simple example of how to create a module or method dynamically. There is an article on bias2build.com that also discussing the ability to create classes and modules dynamically.[8] Although no coded example is given the information is very useful. He talks specifically about define_method and alias_method that can be used to create a wrapper around a class. This can in turn can be used to change the functionality of a method. The ability to do this gives Ruby metaprogramming its strength. An Ariel Ortiz article on linuxjournal.com outlined another aspect to dynamic programming in relation to metaprogramming. [9] What Ortiz points out is that we are able to “modify different parts of your program easily during runtime without having to generate source code explicitly as we did previously.” [9] The example he cites is the use of the attr_accessor to produce the read/write methods automatically. The code is as follows:

Example 2
class Person
  	attr_accessor :name
end
 
Expanded out it would look like this:

class Person
  def name
    @name
  end
  def name=(new_name)
    @name = new_name
  end
end

This truly shows the power of dynamic operations.

Using the Singleton Class

Bini asserts that the use of the Singleton class is very helpful in implementing different aspects of metaprogramming. Being able to manipulate single objects through the singleton class is essential. [4] An easy way to get to the singleton class is as follows:

Example 1
	sclass = (class << self; self; end)

Another definition is as follows:

	module Kernel
	def singleton_class
	class << self; self; end
	end
	end

Another example of using a singleton class is presented in an article on bias2build.com. [8] The author states that “Singleton classes are used to add methods or attributes to instances of a class rather than to classes. Ruby's syntax allows the programmer to either define individual methods of the singleton class, or to pry open the singleton class and add methods or variables that way.” [8] Having examples of the singleton implementation can be useful, like as follows.

Example 2
greeting = "Hello"
  bob = "Bob"

  def greeting.say_twice
    puts self
    puts self
  end

greeting.say_twice # This will print "Hello" twice
bob.say_twice # This will throw a NoMethodError

True Power of Meta-programming

Rubyonrails.com gives a great example of the power of metaprogramming. [7] The author gives the example of having to test some algorithms he was working on trees. He then explored how the code would work for this for a simple binary tree in Java, XML and Ruby. The Java code took 15 lines of code, while the XML took 11 lines of code. He was then able to drive the number of lines of code down to 4 with the help of metaprogramming through Ruby. Althought the Ruby cod might need some work, he admits, he states “Metaprogramming is a way to drive Ruby with Ruby.” [7] Metaprogramming truly is powerful while implemented with the techniques discussed above. Although this is not a comprehensive representation of metaprogramming many of the links provided can assurdly push any new programmer in Ruby in the right direction.


REFERENCES:

[1] http://ftp.cs.olemiss.edu/~hcc/papers/RubyMetaprogramming.pdf

[2] http://ftp.cs.olemiss.edu/~hcc/papers/RubyMetaprogramming.pdf

[3] http://en.wikipedia.org/wiki/Metaprogramming

[4] http://ola-bini.blogspot.com/2006/09/ruby-metaprogramming-techniques.html

[5] http://ozone.wordpress.com/2006/02/22/rubybeans-a-short-example-of-ruby-metaprogramming/

[6] http://invisibleblocks.wordpress.com/2006/06/14/ruby-meta-programming-and-watir/

[7] http://www.rubyrailways.com/sometimes-less-is-more/

[8] http://www.bias2build.com/thesis/ruby_v_js_MP.html

[9] http://www.linuxjournal.com/article/9604