innate 2009.04
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2981 -0
- data/COPYING +18 -0
- data/MANIFEST +127 -0
- data/README.md +563 -0
- data/Rakefile +35 -0
- data/example/app/retro_games.rb +60 -0
- data/example/app/todo/layout/default.xhtml +11 -0
- data/example/app/todo/spec/todo.rb +63 -0
- data/example/app/todo/start.rb +51 -0
- data/example/app/todo/view/index.xhtml +39 -0
- data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
- data/example/app/whywiki_erb/spec/wiki.rb +19 -0
- data/example/app/whywiki_erb/start.rb +42 -0
- data/example/app/whywiki_erb/view/edit.erb +6 -0
- data/example/app/whywiki_erb/view/index.erb +12 -0
- data/example/custom_middleware.rb +35 -0
- data/example/hello.rb +11 -0
- data/example/howto_spec.rb +35 -0
- data/example/link.rb +27 -0
- data/example/provides.rb +31 -0
- data/example/session.rb +38 -0
- data/innate.gemspec +29 -0
- data/lib/innate.rb +269 -0
- data/lib/innate/action.rb +150 -0
- data/lib/innate/adapter.rb +76 -0
- data/lib/innate/cache.rb +134 -0
- data/lib/innate/cache/api.rb +128 -0
- data/lib/innate/cache/drb.rb +58 -0
- data/lib/innate/cache/file_based.rb +41 -0
- data/lib/innate/cache/marshal.rb +17 -0
- data/lib/innate/cache/memory.rb +22 -0
- data/lib/innate/cache/yaml.rb +17 -0
- data/lib/innate/current.rb +37 -0
- data/lib/innate/dynamap.rb +96 -0
- data/lib/innate/helper.rb +183 -0
- data/lib/innate/helper/aspect.rb +124 -0
- data/lib/innate/helper/cgi.rb +54 -0
- data/lib/innate/helper/flash.rb +36 -0
- data/lib/innate/helper/link.rb +94 -0
- data/lib/innate/helper/redirect.rb +85 -0
- data/lib/innate/helper/render.rb +87 -0
- data/lib/innate/helper/send_file.rb +26 -0
- data/lib/innate/log.rb +20 -0
- data/lib/innate/log/color_formatter.rb +43 -0
- data/lib/innate/log/hub.rb +73 -0
- data/lib/innate/middleware_compiler.rb +65 -0
- data/lib/innate/mock.rb +49 -0
- data/lib/innate/node.rb +1025 -0
- data/lib/innate/options.rb +37 -0
- data/lib/innate/options/dsl.rb +202 -0
- data/lib/innate/options/stub.rb +7 -0
- data/lib/innate/request.rb +141 -0
- data/lib/innate/response.rb +23 -0
- data/lib/innate/route.rb +110 -0
- data/lib/innate/session.rb +121 -0
- data/lib/innate/session/flash.rb +94 -0
- data/lib/innate/spec.rb +23 -0
- data/lib/innate/state.rb +27 -0
- data/lib/innate/state/accessor.rb +130 -0
- data/lib/innate/state/fiber.rb +74 -0
- data/lib/innate/state/thread.rb +47 -0
- data/lib/innate/traited.rb +85 -0
- data/lib/innate/trinity.rb +18 -0
- data/lib/innate/version.rb +3 -0
- data/lib/innate/view.rb +60 -0
- data/lib/innate/view/erb.rb +15 -0
- data/lib/innate/view/etanni.rb +36 -0
- data/lib/innate/view/none.rb +9 -0
- data/spec/example/app/retro_games.rb +30 -0
- data/spec/example/hello.rb +13 -0
- data/spec/example/link.rb +25 -0
- data/spec/example/provides.rb +16 -0
- data/spec/example/session.rb +22 -0
- data/spec/helper.rb +10 -0
- data/spec/innate/action/layout.rb +107 -0
- data/spec/innate/action/layout/file_layout.xhtml +1 -0
- data/spec/innate/cache/common.rb +47 -0
- data/spec/innate/cache/marshal.rb +5 -0
- data/spec/innate/cache/memory.rb +5 -0
- data/spec/innate/cache/yaml.rb +5 -0
- data/spec/innate/dynamap.rb +22 -0
- data/spec/innate/helper.rb +86 -0
- data/spec/innate/helper/aspect.rb +75 -0
- data/spec/innate/helper/cgi.rb +37 -0
- data/spec/innate/helper/flash.rb +118 -0
- data/spec/innate/helper/link.rb +139 -0
- data/spec/innate/helper/redirect.rb +160 -0
- data/spec/innate/helper/render.rb +133 -0
- data/spec/innate/helper/send_file.rb +21 -0
- data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
- data/spec/innate/helper/view/locals.xhtml +1 -0
- data/spec/innate/helper/view/loop.xhtml +4 -0
- data/spec/innate/helper/view/num.xhtml +1 -0
- data/spec/innate/helper/view/partial.xhtml +1 -0
- data/spec/innate/helper/view/recursive.xhtml +7 -0
- data/spec/innate/mock.rb +84 -0
- data/spec/innate/node/mapping.rb +37 -0
- data/spec/innate/node/node.rb +134 -0
- data/spec/innate/node/resolve.rb +82 -0
- data/spec/innate/node/view/another_layout/another_layout.xhtml +3 -0
- data/spec/innate/node/view/bar.xhtml +1 -0
- data/spec/innate/node/view/foo.html.xhtml +1 -0
- data/spec/innate/node/view/only_view.xhtml +1 -0
- data/spec/innate/node/view/with_layout.xhtml +1 -0
- data/spec/innate/node/wrap_action_call.rb +83 -0
- data/spec/innate/options.rb +115 -0
- data/spec/innate/parameter.rb +154 -0
- data/spec/innate/provides.rb +99 -0
- data/spec/innate/provides/list.html.xhtml +1 -0
- data/spec/innate/provides/list.txt.xhtml +1 -0
- data/spec/innate/request.rb +77 -0
- data/spec/innate/route.rb +135 -0
- data/spec/innate/session.rb +54 -0
- data/spec/innate/state/fiber.rb +58 -0
- data/spec/innate/state/thread.rb +40 -0
- data/spec/innate/traited.rb +55 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/install_dependencies.rake +4 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +19 -0
- data/tasks/release.rake +51 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +28 -0
- metadata +181 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Innate
|
2
|
+
class Cache
|
3
|
+
# Memory cache is simply a Hash with the Cache::API, it's the reference
|
4
|
+
# implementation for every other cache.
|
5
|
+
|
6
|
+
class Memory < Hash
|
7
|
+
include Cache::API
|
8
|
+
|
9
|
+
def cache_store(*args)
|
10
|
+
super{|key, value| self[key] = value }
|
11
|
+
end
|
12
|
+
|
13
|
+
def cache_fetch(*args)
|
14
|
+
super{|key| self[key] }
|
15
|
+
end
|
16
|
+
|
17
|
+
def cache_delete(*args)
|
18
|
+
super{|key| delete(key) }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'yaml/store'
|
2
|
+
|
3
|
+
module Innate
|
4
|
+
class Cache
|
5
|
+
# Keeps every cache in a separate file like this:
|
6
|
+
#
|
7
|
+
# /tmp/innate-cache-yaml/delta-manveru-session.yaml
|
8
|
+
class YAML
|
9
|
+
include Cache::API
|
10
|
+
include Cache::FileBased
|
11
|
+
|
12
|
+
STORE = ::YAML::Store
|
13
|
+
DIR = 'innate-cache-yaml'
|
14
|
+
EXT = '.yaml'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'innate/request'
|
2
|
+
require 'innate/response'
|
3
|
+
|
4
|
+
module Innate
|
5
|
+
# Uses STATE to scope request/response/session per Fiber/Thread so we can
|
6
|
+
# reach them from anywhere in the code without passing around the objects
|
7
|
+
# directly.
|
8
|
+
class Current
|
9
|
+
extend Trinity
|
10
|
+
|
11
|
+
def initialize(app, *rest)
|
12
|
+
if rest.empty?
|
13
|
+
@app = app
|
14
|
+
else
|
15
|
+
@app = Rack::Cascade.new([app, *rest])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Wrap into STATE, run setup and call the app inside STATE.
|
20
|
+
|
21
|
+
def call(env)
|
22
|
+
STATE.wrap do
|
23
|
+
setup(env)
|
24
|
+
@app.call(env)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Setup new Request/Response/Session for this request/response cycle.
|
29
|
+
# The parameters are here to allow Ramaze to inject its own classes.
|
30
|
+
def setup(env, request = Request, response = Response, session = Session)
|
31
|
+
req = STATE[:request] = request.new(env)
|
32
|
+
res = STATE[:response] = response.new
|
33
|
+
STATE[:actions] = []
|
34
|
+
STATE[:session] = Session.new(req, res)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Innate
|
2
|
+
class URLMap < Rack::URLMap
|
3
|
+
def initialize(map = {})
|
4
|
+
@originals = map
|
5
|
+
super
|
6
|
+
end
|
7
|
+
|
8
|
+
# super may raise when given invalid locations, so we only replace the
|
9
|
+
# `@originals` if we are sure the new map is valid
|
10
|
+
def remap(map)
|
11
|
+
value = super
|
12
|
+
@originals = map
|
13
|
+
value
|
14
|
+
end
|
15
|
+
|
16
|
+
def map(location, object)
|
17
|
+
return unless location and object
|
18
|
+
remap(@originals.merge(location.to_s => object))
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete(location)
|
22
|
+
@originals.delete(location)
|
23
|
+
remap(@originals)
|
24
|
+
end
|
25
|
+
|
26
|
+
def at(location)
|
27
|
+
@originals[location]
|
28
|
+
end
|
29
|
+
|
30
|
+
def to(object)
|
31
|
+
@originals.invert[object]
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_hash
|
35
|
+
@originals.dup
|
36
|
+
end
|
37
|
+
|
38
|
+
def call(env)
|
39
|
+
raise "Nothing mapped yet" if @originals.empty?
|
40
|
+
super
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
DynaMap = URLMap.new
|
45
|
+
|
46
|
+
# script_name, path_info = env['SCRIPT_NAME'], env['PATH_INFO']
|
47
|
+
# answer = app.call(env)
|
48
|
+
# env.merge!('SCRIPT_NAME' => script_name, 'PATH_INFO' => path_info)
|
49
|
+
# answer
|
50
|
+
|
51
|
+
module SingletonMethods
|
52
|
+
# Maps the given +object+ or +block+ to +location+, +object+ must respond to
|
53
|
+
# #call in order to be of any use.
|
54
|
+
#
|
55
|
+
# @example with passed +object+
|
56
|
+
#
|
57
|
+
# Innate.map('/', lambda{|env| [200, {}, "Hello, World"] })
|
58
|
+
# Innate.at('/').call({}) # => [200, {}, "Hello, World"]
|
59
|
+
#
|
60
|
+
# @example with passed +block+
|
61
|
+
#
|
62
|
+
# Innate.map('/'){|env| [200, {}, ['Hello, World!']] }
|
63
|
+
# Innate.at('/').call({})
|
64
|
+
def map(location, object = nil, &block)
|
65
|
+
DynaMap.map(location, object || block)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Answer with object at +location+.
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
#
|
72
|
+
# class Hello
|
73
|
+
# include Innate::Node
|
74
|
+
# map '/'
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# Innate.at('/') # => Hello
|
78
|
+
def at(location)
|
79
|
+
DynaMap.at(location)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns one of the paths the given +object+ is mapped to.
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
#
|
86
|
+
# class Hello
|
87
|
+
# include Innate::Node
|
88
|
+
# map '/'
|
89
|
+
# end
|
90
|
+
#
|
91
|
+
# Innate.to(Hello) # => '/'
|
92
|
+
def to(object)
|
93
|
+
DynaMap.to(object)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
module Innate
|
2
|
+
|
3
|
+
# Acts as name-space for helpers
|
4
|
+
module Helper
|
5
|
+
# Public instance methods of helpers in here will be recognized as actions
|
6
|
+
LOOKUP = EXPOSE = Set.new
|
7
|
+
|
8
|
+
# Usually called from Innate::Node::included
|
9
|
+
# We also include Innate::Trinity here, as it may be needed in models when
|
10
|
+
# you use helper methods there.
|
11
|
+
def self.included(into)
|
12
|
+
into.extend(HelperAccess)
|
13
|
+
into.__send__(:include, Trinity)
|
14
|
+
into.helper(*HelpersHelper.options[:default])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Provides access to #helper method without polluting the name-space any
|
19
|
+
# further.
|
20
|
+
module HelperAccess
|
21
|
+
|
22
|
+
# Convenience method used by Innate::Node.
|
23
|
+
#
|
24
|
+
# Usage:
|
25
|
+
#
|
26
|
+
# class Hi
|
27
|
+
# extend Innate::HelperAccess
|
28
|
+
# helper :cgi, :link, :aspect
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# This will require the helpers and call:
|
32
|
+
#
|
33
|
+
# Hi.include(Innate::Helper::CGI)
|
34
|
+
# Hi.include(Innate::Helper::Link)
|
35
|
+
# Hi.include(Innate::Helper::Aspect)
|
36
|
+
def helper(*helpers)
|
37
|
+
HelpersHelper.each_include(self, *helpers)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Here come the utility methods used from the HelperAccess#helper method, we
|
42
|
+
# do this to keep method count at a minimum and because HelpersHelper is such
|
43
|
+
# an awesome name that just can't be wasted.
|
44
|
+
#
|
45
|
+
# Usage if you want to only extend with helpers:
|
46
|
+
#
|
47
|
+
# class Hi
|
48
|
+
# Innate::HelpersHelper.each_extend(self, :cgi, :link, :aspect)
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# Usage if you only want to include helpers:
|
52
|
+
#
|
53
|
+
# class Hi
|
54
|
+
# Innate::HelpersHelper.each_include(self, :cgi, :link, :aspect)
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# Usage for iteration:
|
58
|
+
#
|
59
|
+
# Innate::HelpersHelper.each(:cgi, :link, :aspect) do |mod|
|
60
|
+
# p mod
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# Usage for translating helpers to modules:
|
64
|
+
#
|
65
|
+
# p Innate::HelpersHelper.each(:cgi, :link, :aspect)
|
66
|
+
module HelpersHelper
|
67
|
+
include Optioned
|
68
|
+
|
69
|
+
options.dsl do
|
70
|
+
o "Paths that will be searched for helper files",
|
71
|
+
:paths, [Dir.pwd, File.dirname(__FILE__)]
|
72
|
+
|
73
|
+
o "Namespaces that will be searched for helper modules",
|
74
|
+
:namespaces, [Helper]
|
75
|
+
|
76
|
+
o "Filename extensions considered for helper files",
|
77
|
+
:exts, %w[rb so bundle]
|
78
|
+
|
79
|
+
o "Default helpers, added on inclusion of the Helper module",
|
80
|
+
:default, [:aspect, :cgi, :flash, :link, :render, :redirect, :send_file]
|
81
|
+
end
|
82
|
+
|
83
|
+
EXTS = %w[rb so bundle]
|
84
|
+
|
85
|
+
# all of the following are singleton methods
|
86
|
+
|
87
|
+
module_function
|
88
|
+
|
89
|
+
# Yield all the modules we can find for the given names of helpers, try to
|
90
|
+
# require them if not available.
|
91
|
+
#
|
92
|
+
# NOTE: Unlike usual #each, this will actually return an Array of the found
|
93
|
+
# modules instead of the given +*names+
|
94
|
+
#
|
95
|
+
#
|
96
|
+
# Usage:
|
97
|
+
#
|
98
|
+
# Innate::HelpersHelper.each(:cgi, :link, :aspect) do |mod|
|
99
|
+
# p mod
|
100
|
+
# end
|
101
|
+
|
102
|
+
def each(*names)
|
103
|
+
names.map do |name|
|
104
|
+
if name.class == Module
|
105
|
+
yield(name) if block_given?
|
106
|
+
name
|
107
|
+
elsif mod = get(name)
|
108
|
+
yield(mod) if block_given?
|
109
|
+
mod
|
110
|
+
elsif try_require(name)
|
111
|
+
redo
|
112
|
+
else
|
113
|
+
raise LoadError, "Helper #{name} not found"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Shortcut to extend +into+ with Helper modules corresponding to +*names+.
|
119
|
+
# +into+ has to respond to #extend.
|
120
|
+
#
|
121
|
+
# Usage:
|
122
|
+
#
|
123
|
+
# class Hi
|
124
|
+
# Innate::HelpersHelper.each_extend(self, :cgi, :link, :aspect)
|
125
|
+
# end
|
126
|
+
def each_extend(into, *names, &block)
|
127
|
+
return if names.empty?
|
128
|
+
into.extend(*each(*names, &block))
|
129
|
+
end
|
130
|
+
|
131
|
+
# Shortcut to include Helper modules corresponding to +*names+ on +into+.
|
132
|
+
# +into+ has to respond to #include.
|
133
|
+
# #__send__(:include) is used in case #include raises due to being
|
134
|
+
# private/protected
|
135
|
+
#
|
136
|
+
# in case #include is a private/protected method.
|
137
|
+
#
|
138
|
+
# Usage:
|
139
|
+
#
|
140
|
+
# class Hi
|
141
|
+
# Innate::HelpersHelper.each_include(self, :cgi, :link, :aspect)
|
142
|
+
# end
|
143
|
+
def each_include(into, *names, &block)
|
144
|
+
return if names.compact.empty?
|
145
|
+
into.__send__(:include, *each(*names, &block))
|
146
|
+
end
|
147
|
+
|
148
|
+
# Based on a simple set of rules we will first construct the most likely
|
149
|
+
# name for the helper and then grep the constants in the Innate::Helper
|
150
|
+
# module for any matches.
|
151
|
+
#
|
152
|
+
# helper :foo_bar # => FooBar
|
153
|
+
# helper :foo # => Foo
|
154
|
+
def get(name)
|
155
|
+
module_name = /^#{name.to_s.dup.delete('_')}$/i
|
156
|
+
|
157
|
+
options.namespaces.each do |namespace|
|
158
|
+
found = namespace.constants.grep(module_name).first
|
159
|
+
return namespace.const_get(found) if found
|
160
|
+
end
|
161
|
+
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
|
165
|
+
# Figure out files that might have the helper we ask for and then require
|
166
|
+
# the first we find, if any.
|
167
|
+
def try_require(name)
|
168
|
+
if found = Dir[glob(name)].first
|
169
|
+
require(found) || true
|
170
|
+
else
|
171
|
+
raise(LoadError, "Helper #{name} not found")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Return a nice list of filenames in correct locations with correct
|
176
|
+
# filename-extensions.
|
177
|
+
def glob(name = '*')
|
178
|
+
exts, paths = options.exts, options.paths
|
179
|
+
paths.uniq!
|
180
|
+
"{#{paths.join(',')}}/helper/#{name}.{#{exts.join(',')}}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Innate
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
# Provides before/after wrappers for actions
|
5
|
+
#
|
6
|
+
# This helper is essential for proper working of {Action#render}.
|
7
|
+
module Aspect
|
8
|
+
AOP = Hash.new{|h,k| h[k] = Hash.new{|hh,kk| hh[kk] = {} }}
|
9
|
+
|
10
|
+
def self.included(into)
|
11
|
+
into.extend(SingletonMethods)
|
12
|
+
into.add_action_wrapper(5.0, :aspect_wrap)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Consider objects that have Aspect included
|
16
|
+
def self.ancestral_aop(from)
|
17
|
+
aop = {}
|
18
|
+
from.ancestors.reverse.map{|anc| aop.merge!(AOP[anc]) if anc < Aspect }
|
19
|
+
aop
|
20
|
+
end
|
21
|
+
|
22
|
+
def aspect_call(position, name)
|
23
|
+
return unless aop = Aspect.ancestral_aop(self.class)
|
24
|
+
return unless block = at_position = aop[position]
|
25
|
+
|
26
|
+
block = at_position[name.to_sym] unless at_position.is_a?(Proc)
|
27
|
+
|
28
|
+
instance_eval(&block) if block
|
29
|
+
end
|
30
|
+
|
31
|
+
def aspect_wrap(action)
|
32
|
+
return yield unless method = action.name
|
33
|
+
|
34
|
+
aspect_call(:before_all, method)
|
35
|
+
aspect_call(:before, method)
|
36
|
+
result = yield
|
37
|
+
aspect_call(:after, method)
|
38
|
+
aspect_call(:after_all, method)
|
39
|
+
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
43
|
+
# This awesome piece of hackery implements action AOP.
|
44
|
+
#
|
45
|
+
# The so-called aspects are simply methods that may yield the next aspect
|
46
|
+
# in the chain, this is similar to racks concept of middleware, but instead
|
47
|
+
# of initializing with an app we simply pass a block that may be yielded
|
48
|
+
# with the action being processed.
|
49
|
+
#
|
50
|
+
# This gives us things like logging, caching, aspects, authentication, etc.
|
51
|
+
#
|
52
|
+
# Add the name of your method to the trait[:wrap] to add your own method to
|
53
|
+
# the wrap_action_call chain.
|
54
|
+
#
|
55
|
+
# @example adding your method
|
56
|
+
#
|
57
|
+
# class MyNode
|
58
|
+
# Innate.node '/'
|
59
|
+
#
|
60
|
+
# private
|
61
|
+
#
|
62
|
+
# def wrap_logging(action)
|
63
|
+
# Innate::Log.info("Executing #{action.name}")
|
64
|
+
# yield
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# trait[:wrap]
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
#
|
71
|
+
# methods may register
|
72
|
+
# themself in the trait[:wrap] and will be called in left-to-right order,
|
73
|
+
# each being passed the action instance and a block that they have to yield
|
74
|
+
# to continue the chain.
|
75
|
+
#
|
76
|
+
# @param [Action] action instance that is being passed to every registered method
|
77
|
+
# @param [Proc] block contains the instructions to call the action method if any
|
78
|
+
#
|
79
|
+
# @see Action#render
|
80
|
+
# @author manveru
|
81
|
+
def wrap_action_call(action, &block)
|
82
|
+
wrap = SortedSet.new
|
83
|
+
action.node.ancestral_trait_values(:wrap).each{|sset| wrap.merge(sset) }
|
84
|
+
head, *tail = wrap.map{|k,v| v }
|
85
|
+
tail.reverse!
|
86
|
+
combined = tail.inject(block){|s,v| lambda{ __send__(v, action, &s) } }
|
87
|
+
__send__(head, action, &combined)
|
88
|
+
end
|
89
|
+
|
90
|
+
module SingletonMethods
|
91
|
+
include Traited
|
92
|
+
|
93
|
+
def before_all(&block)
|
94
|
+
AOP[self][:before_all] = block
|
95
|
+
end
|
96
|
+
|
97
|
+
def before(name, &block)
|
98
|
+
AOP[self][:before][name] = block
|
99
|
+
end
|
100
|
+
|
101
|
+
def after_all(&block)
|
102
|
+
AOP[self][:after_all] = block
|
103
|
+
end
|
104
|
+
|
105
|
+
def after(name, &block)
|
106
|
+
AOP[self][:after][name] = block
|
107
|
+
end
|
108
|
+
|
109
|
+
def wrap(name, &block)
|
110
|
+
before(name, &block)
|
111
|
+
after(name, &block)
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_action_wrapper(order, method_name)
|
115
|
+
if wrap = trait[:wrap]
|
116
|
+
wrap.merge(SortedSet[[order, method_name]])
|
117
|
+
else
|
118
|
+
trait :wrap => SortedSet[[order, method_name]]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|