The Proxy Pattern in Ruby

Manfred Stienstra

My new favorite idiom to use in Ruby is the proxy pattern. But I’m not using it to reduce the memory footprint or to manage some complex resource. I’m using it to keep the original class clean of my torrent of methods and to make my API easy to use.

One of the biggest problems with adding methods to a core class is the chance of collision with other libraries or code, in order to keep this chance low you don’t want to flood classes with new methods. Imagine we want to perform some textual operations on a String, for example ‘Textilize’ it.

require 'redcloth'
RedCloth.new('h1. Proxies!').to_html

But that doesn’t look very nice, especially if we have to duplicate it. Duplication will get us in trouble when we want to change the parameters we send to RedCloth or when we want to switch to another textile processor.

class Formatters
  def self.textilize(str)
    RedCloth.new(str).to_html
  end
end

Formatters.textilize 'h1. Proxies!'

Even though we packaged the code nicely in a method, I’m still not satisfied. This will require us to type that long classname before every call to textilize. And what if we want to perform a number of operations on the same string? Brackets will have to come into play and Lisp our code.

module Formatters
  def textilized
    RedCloth.new(self).to_html
  end
  
  def unnewlined
    self.gsub!(/\r\n/, "\n")
  end
end

String.send :include, Formatters

"h1. Proxies!\r\n".unnewlined.textilized #=> "<h1>Proxies!</h1>"

Very nice! But there are still some problems with this solution. The formatting methods might accidentally override other methods on String, especially if we define even more of these formatting methods. Even though the methods work on the string, they don’t really have much to do with the String class.

This is where the proxy class comes into the picture, it will only take one method on the String class and work as a portal to all our formatting code. In the process the proxy class is even going to make our solution pluggable.

require 'rubygems'
require 'redcloth'

module Formatting
  class Formatter
    
    def initialize(str)
      @str = str
    end
    
    def to_str
      @str
    end
    alias_method :to_s, :to_str
  end
  
  module StringExtension
    def format
      Formatting::Formatter.new self
    end
  end
  
  def register(mod)
    Formatting::Formatter.send :include, mod
  end
  module_function :register
end

module Formatting::Textilize
  def textilized
    @str = RedCloth.new(@str).to_html
    self
  end
end
Formatting.register Formatting::Textilize

module Formatting::UnNewline
  def unnewlined
    @str.gsub!(/\r\n/, "\n")
    self
  end
end
Formatting.register Formatting::UnNewline

String.send :include, Formatting::StringExtension

See how the well placed self enables us to to chain methods?

"h1. Proxies!\r\n".format.unnewlined #=> #<Formatting::Formatter:0x1087c4c @str="h1. Proxies!\n">
"h1. Proxies!\r\n".format.unnewlined.textilized.to_s #=> "<h1>Proxies!</h1>"

There we go, a nice proxy implementation with all the benefits of the original solution. Unfortunately there are some drawbacks, instead of a String instance the methods return a Formatter instance. The to_str keeps us safe in most cases, like concatenation, but not in all cases. Further cloaking measures are left as an exercise for the reader (hint: method_missing, the boat and Comparable).


You’re reading an archived weblog post that was originally published on our website.