Blog

Showing posts with label meta-programming. Show all posts
Showing posts with label meta-programming. Show all posts

Wednesday, September 8, 2010

Ruby Hook Methods

Here is a list of all the hook methods in Ruby. This list is taken from the screencast Some Hook Methods in the The Ruby Object Model and Metaprogramming series.

Method-related Hooks

  • method_missing
  • method_added
  • singleton_method_added
  • method_removed
  • singleton_method_removed
  • method_undefined
  • singleton_method_undefined

Class & Module Hooks

  • inherited
  • append_features
  • included
  • extend_object
  • extended
  • initialize_copy
  • const_missing

Marshalling Hooks

  • marshal_dump
  • marshal_load

Coercion Hooks

  • coerce
  • induced_from
  • to_xxx

Saturday, August 21, 2010

Defining Methods in Ruby using #instance_eval

Last week I discussed the differences between class_eval and instance_eval.

I stated there were two basic rules to follow when choosing which method to use:

  1. When the object is a class use class_eval, you will typically be using the def keyword
  2. When the object is an instance use instance_eval

When we use instance_eval to define methods where are the located? The are stored in the instance’s singleton class. I will write more about Ruby’s singleton class in the future, but for now you may want to read Ola Bini’s excellent post on the subject.

Let’s look at an example:

class MyClass; end

my_instance = MyClass.new

my_instance.instance_eval do
  # add the method to the instance's singleton class
  def foo
    "bar" 
  end
end

puts my_instance.foo # => "bar" 

another_instance = MyClass.new

begin
  # since the method exists only on the my_instance singleton class, calling
  # it on another_instance will raise a NoMethodError exception

  puts another_instance.greeting
rescue NoMethodError
  puts "The foo method does not exist" 
end

What happens when we call instance_eval on Class?
MyClass.instance_eval do
  def baz
    "qux" 
  end
end

puts MyClass.baz # => "qux" 

As you can see it defines a class method. I would argue that you should never use instance_eval on a class (although my last post regarding the subject suggested you could). I feel for a beginner in Ruby it may confuse. Stick to class_eval for class objects, and instance_eval for instances. If you need to dynamically define a class method then use this technique:

MyClass.class_eval do

  class << self

    # define .quux as a class method
    #    
    def quux
      "corge" 
    end
  end

  def grault
    "garply" 
  end
end

puts MyClass.quux # => "corge" 
puts my_instance.grault # => "garply" 

Saturday, August 14, 2010

When to use Ruby's class_eval vs. instance_eval

When to use class_eval vs instance_eval? Here are some basic rules to follow:

  1. When the object is a class use class_eval, you will typically be using the def keyword
  2. When the object is an instance use instance_eval

There is an important subtle difference between the two.

  • class_eval changes self and the current class
  • instance_eval only changes self

If you don't need to use def then what should use use? Well you could use MyClass.instance_eval. But as Paolo Perrotta states from Metaprogramming Ruby:

"…pick the method that best communicates our intentions."
class Book
  
  # define a class instance variable
  #
  @books_published = 0

  # define the attr_accessor as a class method
  #
  class << self
    attr_accessor :books_published
  end
    
  def initialize(title)
    @title = title
    Book.books_published =+ 1
  end
end

b = Book.new("Metaprogramming Ruby")

Book.class_eval do
  def introduction
    "Thank you for reading #{@title}"
  end
  
  private
  
  def units_sold
    100_000
  end
end

b.instance_eval do
  puts @title # access an instance variable => Metaprogramming Ruby
  puts units_sold # send a message to a private method => 100000
end

puts b.introduction # => Thank you for reading Metaprogramming Ruby

# I don't care if this is a class or an instance
Book.instance_eval do
  puts @books_published # => 1
end

Please note this blog is no longer maintained. Please visit CivilCode Inc - Custom Software Development.