rjspotter-innate 2009.06.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +10 -0
- data/CHANGELOG +3261 -0
- data/COPYING +18 -0
- data/MANIFEST +127 -0
- data/README.md +563 -0
- data/Rakefile +39 -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 +41 -0
- data/lib/innate.rb +269 -0
- data/lib/innate/action.rb +137 -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 +44 -0
- data/lib/innate/cache/marshal.rb +20 -0
- data/lib/innate/cache/memory.rb +21 -0
- data/lib/innate/cache/yaml.rb +20 -0
- data/lib/innate/current.rb +35 -0
- data/lib/innate/dynamap.rb +96 -0
- data/lib/innate/helper.rb +185 -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 +152 -0
- data/lib/innate/helper/send_file.rb +26 -0
- data/lib/innate/log.rb +20 -0
- data/lib/innate/log/color_formatter.rb +49 -0
- data/lib/innate/log/hub.rb +77 -0
- data/lib/innate/middleware_compiler.rb +65 -0
- data/lib/innate/mock.rb +49 -0
- data/lib/innate/node.rb +1029 -0
- data/lib/innate/options.rb +37 -0
- data/lib/innate/options/dsl.rb +205 -0
- data/lib/innate/options/stub.rb +7 -0
- data/lib/innate/request.rb +141 -0
- data/lib/innate/response.rb +24 -0
- data/lib/innate/route.rb +114 -0
- data/lib/innate/session.rb +133 -0
- data/lib/innate/session/flash.rb +94 -0
- data/lib/innate/spec.rb +1 -0
- data/lib/innate/spec/bacon.rb +28 -0
- data/lib/innate/state.rb +26 -0
- data/lib/innate/state/accessor.rb +130 -0
- data/lib/innate/traited.rb +90 -0
- data/lib/innate/trinity.rb +18 -0
- data/lib/innate/version.rb +3 -0
- data/lib/innate/view.rb +97 -0
- data/lib/innate/view/erb.rb +14 -0
- data/lib/innate/view/etanni.rb +33 -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 +121 -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 +115 -0
- data/spec/innate/helper/link.rb +139 -0
- data/spec/innate/helper/redirect.rb +171 -0
- data/spec/innate/helper/render.rb +165 -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/modes.rb +61 -0
- data/spec/innate/node/mapping.rb +37 -0
- data/spec/innate/node/node.rb +135 -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 +123 -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 +79 -0
- data/spec/innate/route.rb +135 -0
- data/spec/innate/session.rb +58 -0
- data/spec/innate/traited.rb +55 -0
- data/tasks/authors.rake +30 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_setup.rake +99 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +19 -0
- data/tasks/release.rake +53 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +6 -0
- data/tasks/ycov.rake +84 -0
- metadata +218 -0
@@ -0,0 +1,21 @@
|
|
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 and the default cache.
|
5
|
+
class Memory < Hash
|
6
|
+
include Cache::API
|
7
|
+
|
8
|
+
def cache_store(*args)
|
9
|
+
super{|key, value| self[key] = value }
|
10
|
+
end
|
11
|
+
|
12
|
+
def cache_fetch(*args)
|
13
|
+
super{|key| self[key] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def cache_delete(*args)
|
17
|
+
super{|key| delete(key) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'yaml/store'
|
2
|
+
|
3
|
+
module Innate
|
4
|
+
class Cache
|
5
|
+
# Keeps every cache in a separate file like this:
|
6
|
+
# /tmp/innate-cache-yaml/delta-manveru-session.yaml
|
7
|
+
#
|
8
|
+
# The YAML cache is not safe for use between multiple processes, it is also
|
9
|
+
# very slow compared to other caches, so generally the use of it is
|
10
|
+
# discouraged.
|
11
|
+
class YAML
|
12
|
+
include Cache::API
|
13
|
+
include Cache::FileBased
|
14
|
+
|
15
|
+
STORE = ::YAML::Store
|
16
|
+
DIR = 'innate-cache-yaml'
|
17
|
+
EXT = '.yaml'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'innate/request'
|
2
|
+
require 'innate/response'
|
3
|
+
|
4
|
+
module Innate
|
5
|
+
# We track the current request/response/session (Trinity) in Thread.current
|
6
|
+
# so we can reach them from anywhere in the code without passing around the
|
7
|
+
# objects 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
|
+
# Run setup and call the app
|
20
|
+
def call(env)
|
21
|
+
setup(env)
|
22
|
+
@app.call(env)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Setup new Request/Response/Session for this request/response cycle.
|
26
|
+
# The parameters are here to allow Ramaze to inject its own classes.
|
27
|
+
def setup(env, request = Request, response = Response, session = Session)
|
28
|
+
current = Thread.current
|
29
|
+
req = current[:request] = request.new(env)
|
30
|
+
res = current[:response] = response.new
|
31
|
+
current[:actions] = []
|
32
|
+
current[:session] = Session.new(req, res)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
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,185 @@
|
|
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 = find_helper(name.to_s)
|
169
|
+
require(found) || true
|
170
|
+
else
|
171
|
+
raise(LoadError, "Helper #{name} not found")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def find_helper(name)
|
176
|
+
options.paths.uniq.find do |path|
|
177
|
+
base = ::File.join(path, 'helper', name)
|
178
|
+
options.exts.find do |ext|
|
179
|
+
full = "#{base}.#{ext}"
|
180
|
+
return full if ::File.file?(full)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
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(*names, &block)
|
98
|
+
names.each{|name| 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(*names, &block)
|
106
|
+
names.each{|name| AOP[self][:after][name] = block }
|
107
|
+
end
|
108
|
+
|
109
|
+
def wrap(*names, &block)
|
110
|
+
before(*names, &block)
|
111
|
+
after(*names, &block)
|
112
|
+
end
|
113
|
+
|
114
|
+
def add_action_wrapper(order, method_name)
|
115
|
+
if wrap = trait[:wrap]
|
116
|
+
wrap.merge(SortedSet[[order, method_name.to_s]])
|
117
|
+
else
|
118
|
+
trait :wrap => SortedSet[[order, method_name.to_s]]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|