Module: MethodDecorators
- Defined in:
- lib/decorators.rb
Class Method Summary collapse
Instance Method Summary collapse
- #common_method_added(name, is_class_method) ⇒ Object
- #decorate(klass, *args) ⇒ Object
-
#method_added(name) ⇒ Object
first, when you write a contract, the decorate method gets called which sets the @decorators variable.
- #singleton_method_added(name) ⇒ Object
Class Method Details
.extended(klass) ⇒ Object
2 3 4 5 6 |
# File 'lib/decorators.rb', line 2 def self.extended(klass) class << klass attr_accessor :decorated_methods end end |
Instance Method Details
#common_method_added(name, is_class_method) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/decorators.rb', line 23 def common_method_added name, is_class_method return unless @decorators decorators = @decorators.dup @decorators = nil @decorated_methods ||= {:class_methods => {}, :instance_methods => {}} # attr_accessor on the class variable decorated_methods class << self; attr_accessor :decorated_methods; end is_private = nil decorators.each do |klass, args| # a reference to the method gets passed into the contract here. This is good because # we are going to redefine this method with a new name below...so this reference is # now the *only* reference to the old method that exists. # We assume here that the decorator (klass) responds to .new if is_class_method decorator = klass.new(self, method(name), *args) @decorated_methods[:class_methods][name] = decorator is_private = self.private_methods.include?(name) else decorator = klass.new(self, instance_method(name), *args) @decorated_methods[:instance_methods][name] = decorator is_private = self.private_instance_methods.include?(name) end end # in place of this method, we are going to define our own method. This method # just calls the decorator passing in all args that were to be passed into the method. # The decorator in turn has a reference to the actual method, so it can call it # on its own, after doing it's decorating of course. class_eval <<-ruby_eval, __FILE__, __LINE__ + 1 def #{is_class_method ? "self." : ""}#{name}(*args, &blk) this = self#{is_class_method ? "" : ".class"} unless this.respond_to?(:decorated_methods) && !this.decorated_methods.nil? raise "Couldn't find decorator for method " + self.class.name + ":#{name}.\nDoes this method look correct to you? If you are using contracts from rspec, rspec wraps classes in it's own class.\nLook at the specs for contracts.ruby as an example of how to write contracts in this case." end this.decorated_methods[#{is_class_method ? ":class_methods" : ":instance_methods"}][#{name.inspect}].call_with(self, *args, &blk) end #{is_private ? "private #{name.inspect}" : ""} ruby_eval end |
#decorate(klass, *args) ⇒ Object
66 67 68 69 |
# File 'lib/decorators.rb', line 66 def decorate(klass, *args) @decorators ||= [] @decorators << [klass, args] end |
#method_added(name) ⇒ Object
first, when you write a contract, the decorate method gets called which sets the @decorators variable. Then when the next method after the contract is defined, method_added is called and we look at the @decorators variable to find the decorator for that method. This is how we associate decorators with methods.
13 14 15 16 |
# File 'lib/decorators.rb', line 13 def method_added(name) common_method_added name, false super end |
#singleton_method_added(name) ⇒ Object
18 19 20 21 |
# File 'lib/decorators.rb', line 18 def singleton_method_added name common_method_added name, true super end |