Thursday, June 18, 2009

Proxy design pattern in Ruby

I have recently started exploring Ruby and it's meta programing features. Just look how straightforward it is to implement proxy pattern :)


class SimpleProxy

def initialize(klass, *args)
@proxee_class, @proxee_class_args = klass, *args
@proxee = nil
end

def method_missing(symbol, *args)
if @proxee.nil?
raise NoMethodError unless @proxee_class.instance_methods(true).include?(symbol.to_s)
@proxee = @proxee_class.new(*@proxee_class_args)
end

begin
puts @proxee.class
@proxee.send(symbol, *args)
rescue NoMethodError
raise NoMethodError
end
end
end

You have to remember that calls to methods already defined on on object will not be sent to the "proxee" so you may need to redefine those to make use cases like the one in the test blow work.

require 'test/unit'
require 'simple_proxy'

class SimpleProxyTest < Test::Unit::TestCase
def test_proxy
name = 'Michal'
friends = ['Eliza', 'Radek', 'Sasha']

proxy = SimpleProxy.new(SocialAnimal, [name])

assert_equal name, proxy.name
assert_nothing_raised(Exception) {
proxy.friends = friends
}

assert_equal proxy.friends, friends

assert_match(Regexp.new("#{friends[0]}"), proxy.to_s)
end
end

class SocialAnimal

attr_reader :name
attr_accessor :friends

def initialize(name)
@name = name
end

def to_s
"#{@name}'s friends are #{@friends.join(" ,")}"
end
end

No comments:

Post a Comment