Metaprogramming Ruby: Program Like the Ruby Pros

http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Pros/dp/1934356476

Learning Ruby’s meta-programming. Though I knew the concept, I didn’t have a chance to apply them on actual coding. This book covers various meta-programming techniques with nice exercises (not boring) and actual practices (using rails codes as examples), and it was good exercise for me to organize my thoughts.

The most major one for ruby may be the “method_missing”, and the following is my trial for immitating :attr_accessor.

class Base
  def self.accessors(*attrs)
    @@getters = attrs
    @@setters = attrs.map { |x| "#{x}=".to_sym }
  end

  def method_missing(action, *args)
    if @@getters.include?(action)
      instance_variable_get("@#{action}")
    elsif @@setters.include?(action) and args.length >= 1
      instance_variable_set("@#{action.to_s.chop}", args[0])
    else
      super
    end
  end

  def respond_to?(action)
    if (@@getters + @@setters).include?(action)
      true
    else
      super
    end
  end
end

class Profile < Base
  accessors :name, :age
end

obj = Profile.new

obj.name = "John"
p obj.name
  # => "John"

p obj.age
  # => nil

obj.age = 20
p obj.age
  # => 20

begin
  obj.something
rescue => e
  p e
    # => #<NoMethodError: undefined method `something' for #<Profile:0x007f7fd204dfb8 @name="John", @age=20>>
end

p obj.respond_to?(:age)
  # => true
p obj.respond_to?(:something)
  # => false

Also, I found the following example interesting. “instance_eval” can break encapsulation of private methods.

class MyClass
  def public_method
    puts "It can be called"
  end
private
  def private_method
    puts "It should not be called, but..."
  end
end

obj = MyClass.new

obj.public_method
  # => "It can be called"
begin
  obj.private_method
rescue => e
  puts e
  # => private method `private_method' called for #<MyClass:0x007f920204fe20>
end

obj.instance_eval { private_method }
  # => It should not be called, but...
Advertisements

Posted on February 24, 2013, in Ruby. Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: