Skip to content

Instantly share code, notes, and snippets.

@dannvix
Created March 2, 2013 12:20
Show Gist options
  • Save dannvix/5070761 to your computer and use it in GitHub Desktop.
Save dannvix/5070761 to your computer and use it in GitHub Desktop.
Python style decorators for Ruby. Copied from github://michaelfairley/method_decorators
module MethodDecorators
class Decorator
@@current_decorators = []
def self.current_decorators
decs = @@current_decorators
@@current_decorators = []
decs
end
def self.+@
+new
end
def +@
@@current_decorators.unshift(self)
end
end
end
module MethodDecorators
def method_added(name)
super
orig_method = instance_method(name)
decorators = Decorator.current_decorators
return if decorators.empty?
if private_method_defined?(name); visibility = :private
elsif protected_method_defined?(name); visibility = :protected
else visibility = :public
end
define_method(name) do |*args, &blk|
decorated = MethodDecorators.decorate_callable(orig_method.bind(self), decorators)
decorated.call(*args, &blk)
end
case visibility
when :protected; protected name
when :private; private name
end
end
def singleton_method_added(name)
super
orig_method = method(name)
decorators = Decorator.current_decorators
return if decorators.empty?
MethodDecorators.define_others_singleton_method(self, name) do |*args, &blk|
decorated = MethodDecorators.decorate_callable(orig_method, decorators)
decorated.call(*args, &blk)
end
end
def self.decorate_callable(orig, decorators)
decorators.reduce(orig) do |callable, decorator|
lambda{ |*a, &b| decorator.call(callable, orig.receiver, *a, &b) }
end
end
def self.define_others_singleton_method(klass, name, &blk)
if klass.respond_to?(:define_singleton_method)
klass.define_singleton_method(name, &blk)
else
class << klass
self
end.send(:define_method, name, &blk)
end
end
end
module MethodDecorators
class MyDecorator < Decorator
def call (wrapped, this, *args, &blk)
puts "before call"
wrapped.call(*args, &blk)
puts "after call"
end
end
end
class Foo
extend MethodDecorators
+MethodDecorators::MyDecorator.new
def bar
puts "somebody wraps me"
end
def foobar
puts "i survived, yay!"
end
end
foo = Foo.new
foo.bar
foo.foobar
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment