Module: Innate::Helper::Aspect
- Defined in:
- lib/innate/helper/aspect.rb
Overview
Provides before/after wrappers for actions
This helper is essential for proper working of Action#render.
Defined Under Namespace
Modules: SingletonMethods
Constant Summary collapse
- AOP =
Hash.new{|h,k| h[k] = Hash.new{|hh,kk| hh[kk] = {} }}
Class Method Summary collapse
-
.ancestral_aop(from) ⇒ Object
Consider objects that have Aspect included.
- .included(into) ⇒ Object
Instance Method Summary collapse
- #aspect_call(position, name) ⇒ Object
- #aspect_wrap(action) ⇒ Object
-
#wrap_action_call(action, &block) ⇒ Object
This awesome piece of hackery implements action AOP.
Class Method Details
.ancestral_aop(from) ⇒ Object
Consider objects that have Aspect included
16 17 18 19 20 |
# File 'lib/innate/helper/aspect.rb', line 16 def self.ancestral_aop(from) aop = {} from.ancestors.reverse.map{|anc| aop.merge!(AOP[anc]) if anc < Aspect } aop end |
.included(into) ⇒ Object
10 11 12 13 |
# File 'lib/innate/helper/aspect.rb', line 10 def self.included(into) into.extend(SingletonMethods) into.add_action_wrapper(5.0, :aspect_wrap) end |
Instance Method Details
#aspect_call(position, name) ⇒ Object
22 23 24 25 26 27 28 29 |
# File 'lib/innate/helper/aspect.rb', line 22 def aspect_call(position, name) return unless aop = Aspect.ancestral_aop(self.class) return unless block = at_position = aop[position] block = at_position[name.to_sym] unless at_position.is_a?(Proc) instance_eval(&block) if block end |
#aspect_wrap(action) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/innate/helper/aspect.rb', line 31 def aspect_wrap(action) return yield unless method = action.name aspect_call(:before_all, method) aspect_call(:before, method) result = yield aspect_call(:after, method) aspect_call(:after_all, method) result end |
#wrap_action_call(action, &block) ⇒ Object
This awesome piece of hackery implements action AOP.
The so-called aspects are simply methods that may yield the next aspect in the chain, this is similar to racks concept of middleware, but instead of initializing with an app we simply pass a block that may be yielded with the action being processed.
This gives us things like logging, caching, aspects, authentication, etc.
Add the name of your method to the trait to add your own method to the wrap_action_call chain.
methods may register themself in the trait and will be called in left-to-right order, each being passed the action instance and a block that they have to yield to continue the chain.
81 82 83 84 85 86 87 88 89 |
# File 'lib/innate/helper/aspect.rb', line 81 def wrap_action_call(action, &block) return yield if action.[:is_layout] wrap = SortedSet.new action.node.ancestral_trait_values(:wrap).each{|sset| wrap.merge(sset) } head, *tail = wrap.map{|k,v| v } tail.reverse! combined = tail.inject(block){|s,v| lambda{ __send__(v, action, &s) } } __send__(head, action, &combined) end |