Module: Innate::Helper::Aspect

Defined in:
/home/manveru/github/ramaze/ramaze.net/tmp/git/innate/lib/innate/helper/aspect.rb

Overview

The Aspect helper allows you to execute hooks before or after a number of actions.

See SingletonMethods for more details on the various hooks available.

This helper is essential for proper working of Action#render.

Examples:

Querying a database before a number of actions.

class Posts
  include Innate::Node

  map    '/'
  helper :aspect

  before(:index, :other) do
    @posts = Post.all
  end

  def index
    return @posts
  end

  def other
    return @posts[0]
  end
end

Defined Under Namespace

Modules: SingletonMethods

Constant Summary

AOP =

Hash containing the various hooks to call for certain actions.

Hash.new { |h,k| h[k] = Hash.new { |hh,kk| hh[kk] = {} } }

Class Method Summary (collapse)

Instance Method Summary (collapse)

Class Method Details

+ (Object) ancestral_aop(from)

Consider objects that have Aspect included



49
50
51
52
53
54
55
56
57
# File '/home/manveru/github/ramaze/ramaze.net/tmp/git/innate/lib/innate/helper/aspect.rb', line 49

def self.ancestral_aop(from)
  aop = {}

  from.ancestors.reverse.each do |anc|
    aop.merge!(AOP[anc]) if anc < Aspect
  end

  aop
end

+ (Object) included(into)

Called whenever this helper is included into a class.

Parameters:

  • into (Class)

    The class the module was included into.



43
44
45
46
# File '/home/manveru/github/ramaze/ramaze.net/tmp/git/innate/lib/innate/helper/aspect.rb', line 43

def self.included(into)
  into.extend(SingletonMethods)
  into.add_action_wrapper(5.0, :aspect_wrap)
end

Instance Method Details

- (Object) aspect_call(position, name)

Calls the aspect for a given position and name.

Parameters:

  • position (#to_sym)

    The position of the hook, e.g. :before_all.

  • name (#to_sym)

    The name of the method for which to call the hook.



65
66
67
68
69
70
71
72
# File '/home/manveru/github/ramaze/ramaze.net/tmp/git/innate/lib/innate/helper/aspect.rb', line 65

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

- (Object) aspect_wrap(action)

Wraps the specified action between various hooks.

Parameters:



79
80
81
82
83
84
85
86
87
88
89
# File '/home/manveru/github/ramaze/ramaze.net/tmp/git/innate/lib/innate/helper/aspect.rb', line 79

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

- (Object) wrap_action_call(action, &block)

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[:wrap] to add your own method to the wrap_action_call chain.

methods may register themself in the trait[:wrap] 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



131
132
133
134
135
136
137
138
139
# File '/home/manveru/github/ramaze/ramaze.net/tmp/git/innate/lib/innate/helper/aspect.rb', line 131

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