Skip to content

Instantly share code, notes, and snippets.

@cqfd
Created July 21, 2011 21:19
Show Gist options
  • Save cqfd/1098237 to your computer and use it in GitHub Desktop.
Save cqfd/1098237 to your computer and use it in GitHub Desktop.
Python-ish decorators for Ruby
#
# Adding Python-ish decorations to Ruby!
#
# Usage:
#
# class Foo
# extend WithDecorations
#
# decorate :bar do |b|
# puts "Do something here before bar gets invoked!"
# b.call
# puts "Do something here after bar gets invoked!"
# end
#
# def bar
# puts "My name's bar!"
# end
# end
module WithDecorations
# hash with method name keys pointing to arrays of decorators waiting to be
# applied
decorations = {}
# method_added is a Ruby runtime hook. If method_added is defined as a class
# method on class Foo, then it will be invoked immediately after a new
# instance method is added to Foo.
#
# The plan is to check whenever a new function is added if there are any
# decorations to apply. If so, dynamically create a new function with the
# same name that "does the right thing".
define_method :method_added do |m|
# grab a procified version of the old, undecorated method
old_m = instance_method m
unless decorations[m].nil? || decorations[m].empty?
decorated_m = decorations[m].pop
define_method m do |*args|
# old_m is actually an UnboundMethod. In order to call an unbound
# method you need to bind it to something, so we bind it to the object
# that called the decorated method, namely self.
decorated_m.call old_m.bind(self)
end
end
end
# calling decorate :foo with a block adds the block to the list of foo's
# decorations
define_method :decorate do |m, &block|
(decorations[m] ||= []) << block
end
end
class A
extend WithDecorations
def initialize
@foo = "Hi, I'm foo!"
end
decorate :foo do |f|
puts "Even futher outside foo!"
f.call
puts "Even futher outside foo!"
end
decorate :foo do |f|
puts "Outside foo!"
f.call
puts "Outside foo!"
end
def foo
puts @foo
end
end
a = A.new
a.foo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment