Skip to content

Instantly share code, notes, and snippets.

@tjstankus
Created June 17, 2009 20:22
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tjstankus/131482 to your computer and use it in GitHub Desktop.
Save tjstankus/131482 to your computer and use it in GitHub Desktop.
# Slight modifications to code posted by Gregory Brown at http://pastie.org/515450
require 'delegate'
module Decoration
def decorator_for(*types, &block)
types.each do |type|
decorators[type] = Module.new(&block)
end
end
def decorators
@decorators ||= {}
end
def decorate(target)
obj = SimpleDelegator.new(target)
# walk in reverse order so most specific patches get applied LAST
target.class.ancestors.reverse.each do |a|
if decorators[a]
obj.extend(decorators[a])
end
end
return obj
end
end
class MyView
extend Decoration
attr_reader :target
decorator_for Numeric, String do
def double
self * 2
end
end
decorator_for Symbol do
def double
(self.to_s * 2).to_sym
end
end
decorator_for Array do
def double
map { |o| MyView.new(o).double }
end
end
decorator_for Hash do
def double
h = {}
self.each { |key, val| h[MyView.new(key).double] = MyView.new(val).double }
h
end
end
decorator_for Object do
def double
raise "Don't know how to double #{self.inspect}"
end
end
def initialize(target)
@target = self.class.decorate(target)
end
def double
target.double
end
end
p MyView.new('aaa').double
p MyView.new(49).double
p MyView.new(:a).double
p MyView.new(['b', 6]).double
p MyView.new({:a => 1}).double
class MyCollaborator
def double
'MyCollaborator#double'
end
end
p MyView.new(MyCollaborator.new).double
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment