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

Instance Method Summary collapse

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.

Examples:

adding your method


class MyNode
  Innate.node '/'

  private

  def wrap_logging(action)
    Innate::Log.info("Executing #{action.name}")
    yield
  end

  trait[:wrap]
end

Parameters:

  • action (Action)

    instance that is being passed to every registered method

  • block (Proc)

    contains the instructions to call the action method if any

See Also:

Author:

  • manveru



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.options[: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