Skip to content

Instantly share code, notes, and snippets.

@jbgo
Created February 8, 2012 23:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jbgo/1775300 to your computer and use it in GitHub Desktop.
Save jbgo/1775300 to your computer and use it in GitHub Desktop.
A cleaner way to decorate all methods in a module
module Decorator
def self.decorate(target_klass, include_module, decorator_method)
proxy = Class.new { include include_module }.new
target_klass.class_eval do
include_module.instance_methods.each do |name|
undecorated_method = proxy.method(name)
define_method(name) do |*args, &block|
send(decorator_method, undecorated_method, *args, &block)
end
end
end
end
end
module PlainOldRubyMethods
def exclaim!(value)
value.to_s + '!'
end
def map_words(sentence, separator, &block)
sentence.split(' ').collect { |word| yield word }.join(separator)
end
alias :scramble :map_words
end
class MethodChain
# Decorate all methods in the PlainOldRubyMethods module with the :chainable method
# and define them on this class.
Decorator.decorate self, PlainOldRubyMethods, :chainable
def chainable(undecorated_method, *args, &block)
@chain << undecorated_method.call(@chain.last, *args, &block)
self
end
def initialize(value)
@chain = [value]
end
def finish
@chain.last
end
end
# A simple example:
chain = MethodChain.new('ouch')
puts 'exclaim: ' + chain.exclaim!.finish
# Blocks, arguments, and aliased methods all work as expected:
chain = MethodChain.new('what am I saying?')
puts 'scramble: ' + chain.scramble('-') { |word| word.reverse }.finish
$ ruby decorate_module.rb
exclaim: ouch!
scramble: tahw-ma-I-?gniyas
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment