19 Dec, 2008 in Ruby by khelll

Ruby reflection

If you are here, then most probably you want to know more about ruby reflection interface. Well that’s true, but I always find myself in need to explain few things before I get started with my posts, and this time I find myself in need of explaining few things related to ruby’s OOP.

I’m pretty sure that you always heard that “in ruby: everything is an object.” , but have you ever thought of that carefully?
The first thing that comes to a one’s mind is something like :

5.class #=> Fixnum
"hello".class #=> String

But have you thought of your class as an object? Well that seems odd, but that’s how ruby works:

class Foo;end  #=> nil
Foo.class #=> Class

What does the above snippet of code mean exactly?
It means 2 things : Foo is a constant and that constant holds(refers to) an object of Class type.

Let me prove that 2 you:

Foo = Class.new
(irb):8 warning: already initialized constant Foo
=> Foo

As you can see, I got a warning because I tried to initialize the constant Foo again.

So ,when you define some class ‘Foo’ in ruby, all you are doing is:
1-instantiating an object of type Class.
2-initializing a constant Foo that refers to that created object .

So bear in mind that when I say “object” ,then I do mean any object; an object of Class type, or any object of any type.

Now, let’s move to another point. What about the ‘Singleton Class’, did you have the chance to work with it before?
Simply it’s the class that holds all singleton methods of an object, whether it’s a class object , or any other object.

Let’s start by defining 2 class methods (a class method is nothing but: a singleton method of an object of Class type) :

class Foo
  def self.hi ; p "hi" ;end
  def self.bye ; p "bye" ; end
end
Foo.singleton_methods #=> ["hi","bye"]

You could also have written that in this way:

class Foo
  class << self
    def hi ; p "hi" ; end
    def bye ; p "bye" ; end
  end
end
Foo.singleton_methods #=> ["hi","bye"]

The above inner class mentioned with “class << self" is what we call : a singleton class.
Let's define a method that returns back the singleton class for us :

class Object
  def singleton_class 
     class << self
       self
     end
  end
end

Now try this :

Foo.singleton_methods #=> ["bye", "hi"]
Foo.singleton_class.instance_methods(false) #=> ["bye", "hi"]

As you can see, the singleton class is the class that holds all singleton methods.
We will use the singleton class later in this series, so keep the concept in mind.

Let’s now get back to our topic on ruby’s reflection api , i will introduce 3 methods in this post: eval , instance_eval and class_eval.

eval

‘eval’ is a method that evaluates a ruby string :

eval "3+4" #=> 7
eval "def multiply(x,y) ; x*y; end"
multiply(4,7) #=> 28

eval can also work in the scope of bindings ; a binding is an object that encapsulates the execution context at some particular place in the code and retain this context for future use. Look at this example of using bindings with eval :

class Demo
  def initialize(n)
    @secret = n
  end
  def getBinding
    return binding()# a method defined in Kernel module
  end
end
k1 = Demo.new(99)
#get the value of the instance variable @secrete stored in the binding of object k1
eval("@secret", k1.getBinding)   #=> 99

Also can work with proc objects :

def greeting(name)
  lambda{|greetings| greetings.collect {|g| "#{g} #{name}"} }
end
greeter = greeting("dude") #=> #<Proc:0xb752b810@(irb):2>
greeter.call ["hi","hello","hola"] #=> ["hi dude", "hello dude", "hola dude"]
eval("name='khelll'",greeter) #=> "khelll"
greeter.call ["hi","hello","hola"] #=> ["hi khelll", "hello khelll", "hola khelll"]

instance_eval

This method works in the context of the object :

class Klass
  def initialize
    @secret = 99
   end
end
k = Klass.new
k.instance_eval { @secret }   #=> 99 , notice the @

And could be used to define singleton methods :

Fixnum.instance_eval "def zero; 0 ;end"                                                 
Fixnum.zero #=> 0

you can pass it a block instead of the string :

Fixnum.instance_eval{ def ten ;10;end }
Fixnum.ten #=> 10

class_eval

Evaluates a string or a block in the context of the receiver

Foo.class_eval{@@x=1} #=> 1
Foo.class_eval{@@x} #=> 1

And it defines instance methods when called on some object

Fixnum.class_eval "def number ; self ;end"
5.number #=> 5

And as instance_eval, a block instead of the string could be passed

Fixnum.class_eval{ def number;self;end}
7.number #=> 7

You can use class_eval to dynamically use private methods, for example to use the private method ‘include’:

module M; end
String.include M #=> NoMethodError: private method `include' called for String:Class
String.class_eval{include M} #=> you could do it with String.send(:include,M)

Now let’s make use of our knowledge,let’s try to redefine the attr_accessor method in our way, I will make a similar method called attr_access :

class Class
  def attr_access(*attrs)
    attrs.each do |attr|
      class_eval %Q{
	    def #{attr} 
	      @#{attr}
	    end
	    def #{attr}=(value)
	      @#{attr} = value
	    end
      }
    end
  end
end
 
class Foo 
 attr_access :a,:b 
end
 
Foo.instance_methods(false) #=> ["b=", "a=", "b", "a"]

in a similar way we can define class attribute accessors :

class Class
    def cattr_access(*attrs)
      attrs.each do |attr|
        class_eval %Q{
  	    def self.#{attr}
  	      @@#{attr}
  	    end
  	    def self.#{attr}=(value)
  	      @@#{attr} = value
  	    end
        }
      end
    end
end

Or with we can use the singleton class :

class Class
  def singleton_class 
    class << self
      self 
    end 
  end
 
  def cattr_access(*attrs)
    attrs.each do |attr|
      singleton_class.class_eval %Q{
        def #{attr}
  	   @@#{attr}
  	 end
  	 def #{attr}=(value)
  	    @@#{attr} = value
  	 end
       }
    end
  end
end

And in both cases we can do :

class Foo ; cattr_access :cx,:cy end
Foo.singleton_methods(false) #=> ["cy", "cy=", "cx", "cx="]

Give it a try and try to define attr_reader and attr_writer for both object and class variables.

I think it’s enough for this post, the next post will contain more methods to look at. See you then.

Update 1: fixing some typos.
Update 2: second part is here.

11 Responses so far | Have Your Say!

  1. Anton - Gravatar

    Anton  |  December 21st, 2008 at 11:42 pm #

    Thanks! Nice Post.

  2. 7 Ruby Articles to Read Over The Holiday Season - Gravatar

    7 Ruby Articles to Read Over The Holiday Season  |  December 26th, 2008 at 8:08 pm #

    [...] Ruby reflection by Khaled al Habache. Khaled takes a look at Ruby’s reflection features and the operation of the various eval functions (eval, instance_eval, class_eval, etc). [...]

  3. Len Lattanzi - Gravatar

    Len Lattanzi  |  December 26th, 2008 at 9:03 pm #

    Small typo defining multiply:

    eval "def mulitply(x,y) ; x*y; end"

  4. Ruby reflection 2 – Khaled alHabache’s official blog - Gravatar

    Ruby reflection 2 - Khaled alHabache’s official blog  |  December 26th, 2008 at 11:00 pm #

    [...] is the second post related to ruby’s reflection API, the previous post was an extensive intro to this topic. While the current one will be lighter somehow, it would [...]

  5. admin - Gravatar

    admin  |  December 26th, 2008 at 11:03 pm #

    @Len Lattanzi
    Fixed, thanks for notifying me….

  6. suman gurung - Gravatar

    suman gurung  |  January 1st, 2009 at 8:14 pm #

    Excellent tutorial, something solid to start ruby’s reflection.

  7. روابـــ(2)ــط « Mutati0N - Gravatar

    روابـــ(2)ــط « Mutati0N  |  January 3rd, 2009 at 5:10 pm #

    [...] قضائيه ضد جوجل ومايكرسوفت ضد الصور المصغرة حصيلة2008 الأنعكاس في روبي هل سيكون عام 2009 عام للمصادر المفتوحه ام لا [...]

  8. Fun with Ruby’s instance_eval and class_eval « I like stuff - Gravatar

    Fun with Ruby’s instance_eval and class_eval « I like stuff  |  January 9th, 2009 at 10:04 am #

    [...] By Brian Morearty In an attempt to better understand instance_eval and class_eval, I just read Khaled’s post on Ruby reflection. It helped, and I came up with a memory crutch I can use to remember when to use each of them: Use [...]

  9. Undefining class at runtime « My explorations in rails - Gravatar

    Undefining class at runtime « My explorations in rails  |  June 15th, 2009 at 10:58 pm #

    [...] can learn much about class_eval from this very good article by Khaled. [...]

  10. satya - Gravatar

    satya  |  June 15th, 2009 at 11:01 pm #

    Wonderful article. Made the world of eval very friendly to me.

Leave a Feedback

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">