lib/glue/aspects.rb in glue-0.20.0 vs lib/glue/aspects.rb in glue-0.21.0

- old
+ new

@@ -3,232 +3,222 @@ module Glue # An Aspect is a class that defines advices. class Aspect - class << self - def wrap(target, methods = target.instance_methods, pre = :pre, post = :post) - target.send(:include, Aspects) unless target.ancestors.include?(Aspects) - target.wrap(self, :pre => pre, :post => post) - end + class << self + def wrap(target, methods = target.instance_methods, pre = :pre, post = :post) + target.send(:include, Aspects) unless target.ancestors.include?(Aspects) + target.wrap(self, :pre => pre, :post => post) + end - alias_method :observe, :wrap - end + alias_method :observe, :wrap + end - def wrap(target, methods = target.instance_methods, pre = :pre, post = :post) - target.send(:include, Aspects) unless target.ancestors.include?(Aspects) - target.wrap(self, :pre => pre, :post => post) - end - alias_method :observe, :wrap + def wrap(target, methods = target.instance_methods, pre = :pre, post = :post) + target.send(:include, Aspects) unless target.ancestors.include?(Aspects) + target.wrap(self, :pre => pre, :post => post) + end + alias_method :observe, :wrap end # Add support for Aspect Oriented Programming (AOP). # # === Examples # # class Controller -# pre :force_login, :where => :prepend -# wrap Benchmark, :on => :index -# post :taraa, :on => login +# pre :force_login, :where => :prepend +# wrap Benchmark, :on => :index +# post :taraa, :on => login # end # # module Timestamped -# pre :on => :og_insert { |this| this.create_time = Time.now } -# pre :on => :og_update { |this| this.update_time = Time.now } -# pre :on => [:og_insert, :og_update] { |this| this.create_time = Time.now } +# pre :on => :og_insert { |this| this.create_time = Time.now } +# pre :on => :og_update { |this| this.update_time = Time.now } +# pre :on => [:og_insert, :og_update] { |this| this.create_time = Time.now } # end module Aspects - # Store the code and the metadata (options) for - # an Advice. + # Store the code and the metadata (options) for + # an Advice. - Advice = Struct.new(:code, :options) + Advice = Struct.new(:code, :options) - # Apply the advices to the target class. + # Apply the advices to the target class. - def self.wrap(target, methods = target.instance_methods) - include_advice_modules(target) - - for m in [methods].flatten - args = [] - target.instance_method(m).arity.times { |i| args << "a#{i}" } - args = args.join(',') - - target.module_eval <<-end_eval, __FILE__, __LINE__ - alias_method :__unwrapped_#{m}, :#{m} - def #{m}(#{args}) - #{gen_advice_code(m, target.advices, :pre)} - __unwrapped_#{m}(#{args}) - #{gen_advice_code(m, target.advices, :post)} - end - end_eval - end - end + def self.wrap(target, methods = target.instance_methods) + include_advice_modules(target) + + for m in [methods].flatten + args = [] + target.instance_method(m).arity.times { |i| args << "a#{i}" } + args = args.join(',') + + target.module_eval <<-end_eval, __FILE__, __LINE__ + alias_method :__unwrapped_#{m}, :#{m} + def #{m}(#{args}) + #{gen_advice_code(m, target.advices, :pre)} + __unwrapped_#{m}(#{args}) + #{gen_advice_code(m, target.advices, :post)} + end + end_eval + end + end - # Include Modules that define advices. + # Include Modules that define advices. - def self.include_advice_modules(target) - for a in target.advices - if a.code.is_a?(Module) and (!a.code.class.ancestors.include?(Class)) - target.module_eval %{ include #{a.code} } - - options = a.options.reject { |k,v| k == :pre || k == :post } + def self.include_advice_modules(target) + for a in target.advices + if a.code.is_a?(Module) and (!a.code.class.ancestors.include?(Class)) + target.module_eval %{ include #{a.code} } + + options = a.options.reject { |k,v| k == :pre || k == :post } - method = (a.options[:pre] || 'pre').to_s - if a.code.instance_methods.include?(method) - options.update(:where => :prepend, :join => :pre) - target.advices << Advice.new(method, options) - end - - method = (a.options[:post] || 'post').to_s - if a.code.instance_methods.include?(method) - options.update(:where => :append, :join => :post) - target.advices << Advice.new(method, options) - end - end - end + method = (a.options[:pre] || 'pre').to_s + if a.code.instance_methods.include?(method) + options.update(:where => :prepend, :join => :pre) + target.advices << Advice.new(method, options) + end + + method = (a.options[:post] || 'post').to_s + if a.code.instance_methods.include?(method) + options.update(:where => :append, :join => :post) + target.advices << Advice.new(method, options) + end + end + end - # Remove the original advice. + # Remove the original advice. - target.advices.delete_if do |a| - a.code.is_a?(Module) and (!a.code.class.ancestors.include?(Class)) - end - end + target.advices.delete_if do |a| + a.code.is_a?(Module) and (!a.code.class.ancestors.include?(Class)) + end + end - # Generates the code to call the aspects. - - def self.gen_advice_code(method, advices, join = :pre) # :nodoc: - code = '' + # Generates the code to call the aspects. + + def self.gen_advice_code(method, advices, join = :pre) # :nodoc: + code = '' - advices.each_with_index do |advice, idx| - o = options = advice.options + advices.each_with_index do |advice, idx| + o = options = advice.options - if only = options[:only] || options[:on] - next unless [only].flatten.include?(method.to_sym) - elsif except = options[:except] - next if [except].flatten.include?(method.to_sym) - end - - advice = advice.code + if only = options[:only] || options[:on] + next unless [only].flatten.include?(method.to_sym) + elsif except = options[:except] + next if [except].flatten.include?(method.to_sym) + end + + advice = advice.code - if advice.is_a?(Symbol) or advice.is_a?(String) - next if o[:join] != join - code << "#{advice}; " - elsif advice.respond_to?('call') - next if o[:join] != join - code << "self.class.advices[#{idx}].code.call(self); " - elsif advice.is_a?(Class) - if advice.class.ancestors.include?(Class) - if m = o[join] and advice.methods.include?(m.to_s) - code << "#{advice}.#{m}(self); " - end - else - # Module, allready handled. - end - else - if m = o[join] and advice.methods.include?(m.to_s) - code << "self.class.advices[#{idx}].code.#{m}(self); " - end - end - end - - return code - end + if advice.is_a?(Symbol) or advice.is_a?(String) + next if o[:join] != join + code << "#{advice}; " + elsif advice.respond_to?('call') + next if o[:join] != join + code << "self.class.advices[#{idx}].code.call(self); " + elsif advice.is_a?(Class) + if advice.class.ancestors.include?(Class) + if m = o[join] and advice.methods.include?(m.to_s) + code << "#{advice}.#{m}(self); " + end + else + # Module, allready handled. + end + else + if m = o[join] and advice.methods.include?(m.to_s) + code << "self.class.advices[#{idx}].code.#{m}(self); " + end + end + end + + return code + end - def self.append_features(base) - super - base.extend(ClassMethods) + def self.append_features(base) + super + base.extend(ClassMethods) - base.module_eval %{ - Glue::PropertyUtils.enchant(self) + base.module_eval %{ + Glue::PropertyUtils.enchant(self) - def self.advices - __meta[:advices] || [] - end + def self.advices + __meta[:advices] || [] + end - def self.advices=(advices) - __meta[:advices] = advices - end - - #def self.inherited(child) - # super - # child.send(:include, Aspects) - #end - # - #def self.append_features(base) - # super - # base.send(:include, Aspects) - #end - } - end + def self.advices=(advices) + __meta[:advices] = advices + end + } + end - module ClassMethods - - # Add a pre (before) advice. + module ClassMethods + + # Add a pre (before) advice. - def pre(*args, &block) - o = options = { - :join => :pre, - :where => :prepend, - } - options.update(args.pop) if args.last.is_a?(Hash) + def pre(*args, &block) + o = options = { + :join => :pre, + :where => :prepend, + } + options.update(args.pop) if args.last.is_a?(Hash) - if block_given? - advices = [ Advice.new(block, options) ] - else - advices = args.collect { |a| Advice.new(a, options) } - end - - if options[:where] == :prepend - self.advices = advices + self.advices - else - self.advices = self.advices + advices - end - end - alias_method :before, :pre - - # Add a post (after) advice. + if block_given? + advices = [ Advice.new(block, options) ] + else + advices = args.collect { |a| Advice.new(a, options) } + end + + if options[:where] == :prepend + self.advices = advices + self.advices + else + self.advices = self.advices + advices + end + end + alias_method :before, :pre + + # Add a post (after) advice. - def post(*args, &block) - o = options = { - :join => :post, - :where => :append, - } - options.update(args.pop) if args.last.is_a?(Hash) + def post(*args, &block) + o = options = { + :join => :post, + :where => :append, + } + options.update(args.pop) if args.last.is_a?(Hash) - if block_given? - advices = [ Advice.new(block, options) ] - else - advices = args.collect { |a| Advice.new(a, options) } - end - - if options[:where] == :prepend - self.advices = advices + self.advices - else - self.advices = self.advices + advices - end - end - alias_method :after, :post + if block_given? + advices = [ Advice.new(block, options) ] + else + advices = args.collect { |a| Advice.new(a, options) } + end + + if options[:where] == :prepend + self.advices = advices + self.advices + else + self.advices = self.advices + advices + end + end + alias_method :after, :post - # Add a wrap (arround) aspect. An aspect is a class that - # responds to the before and after advices. - - def wrap(*args) - o = options = { - :pre => :pre, - :post => :post - } - options.update(args.pop) if args.last.is_a?(Hash) + # Add a wrap (arround) aspect. An aspect is a class that + # responds to the before and after advices. + + def wrap(*args) + o = options = { + :pre => :pre, + :post => :post + } + options.update(args.pop) if args.last.is_a?(Hash) - for aspect in args - self.advices << Advice.new(aspect, options) - end - end - alias_method :around, :wrap - alias_method :observer, :wrap + for aspect in args + self.advices << Advice.new(aspect, options) + end + end + alias_method :around, :wrap + alias_method :observer, :wrap - end + end end end