manveru-innate 2009.04.18 → 2009.05
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +230 -0
- data/MANIFEST +2 -4
- data/Rakefile +6 -2
- data/example/app/whywiki_erb/start.rb +1 -1
- data/innate.gemspec +7 -3
- data/lib/innate.rb +5 -4
- data/lib/innate/action.rb +17 -25
- data/lib/innate/cache.rb +1 -1
- data/lib/innate/cache/drb.rb +5 -5
- data/lib/innate/cache/file_based.rb +3 -0
- data/lib/innate/cache/marshal.rb +4 -1
- data/lib/innate/cache/memory.rb +1 -2
- data/lib/innate/cache/yaml.rb +4 -1
- data/lib/innate/current.rb +11 -13
- data/lib/innate/dynamap.rb +5 -0
- data/lib/innate/helper.rb +9 -7
- data/lib/innate/helper/aspect.rb +9 -9
- data/lib/innate/helper/cgi.rb +3 -0
- data/lib/innate/helper/redirect.rb +1 -1
- data/lib/innate/helper/render.rb +68 -7
- data/lib/innate/log/color_formatter.rb +19 -13
- data/lib/innate/node.rb +38 -35
- data/lib/innate/options/dsl.rb +5 -2
- data/lib/innate/request.rb +1 -1
- data/lib/innate/response.rb +1 -0
- data/lib/innate/route.rb +4 -0
- data/lib/innate/session.rb +16 -14
- data/lib/innate/state.rb +10 -11
- data/lib/innate/state/accessor.rb +8 -8
- data/lib/innate/traited.rb +15 -10
- data/lib/innate/version.rb +1 -1
- data/lib/innate/view.rb +41 -4
- data/lib/innate/view/erb.rb +1 -2
- data/lib/innate/view/etanni.rb +9 -12
- data/spec/innate/action/layout.rb +0 -3
- data/spec/innate/helper/flash.rb +0 -3
- data/spec/innate/helper/redirect.rb +11 -0
- data/spec/innate/helper/render.rb +32 -0
- data/spec/innate/node/node.rb +1 -0
- data/spec/innate/options.rb +5 -1
- data/tasks/authors.rake +30 -0
- data/tasks/release.rake +3 -3
- data/tasks/ycov.rake +84 -0
- metadata +16 -9
- data/lib/innate/state/fiber.rb +0 -74
- data/lib/innate/state/thread.rb +0 -47
- data/spec/innate/state/fiber.rb +0 -58
- data/spec/innate/state/thread.rb +0 -40
@@ -2,6 +2,9 @@ module Innate
|
|
2
2
|
class Cache
|
3
3
|
|
4
4
|
# Used by caches that serialize their contents to the filesystem.
|
5
|
+
# Right now we do not lock around write access to the file outside of the
|
6
|
+
# process, that means that all FileBased caches are not safe for use if you
|
7
|
+
# need more than one instance of your application.
|
5
8
|
module FileBased
|
6
9
|
attr_reader :filename
|
7
10
|
|
data/lib/innate/cache/marshal.rb
CHANGED
@@ -3,8 +3,11 @@ require 'pstore'
|
|
3
3
|
module Innate
|
4
4
|
class Cache
|
5
5
|
# Keeps every cache in a separate file like this:
|
6
|
-
#
|
7
6
|
# /tmp/innate-cache-marshal/delta-manveru-session.marshal
|
7
|
+
#
|
8
|
+
# The Marshal cache is not safe for use between multiple processes, it is
|
9
|
+
# also slow compared to other caches, so generally the use of it is
|
10
|
+
# discouraged.
|
8
11
|
class Marshal
|
9
12
|
include Cache::API
|
10
13
|
include Cache::FileBased
|
data/lib/innate/cache/memory.rb
CHANGED
data/lib/innate/cache/yaml.rb
CHANGED
@@ -3,8 +3,11 @@ require 'yaml/store'
|
|
3
3
|
module Innate
|
4
4
|
class Cache
|
5
5
|
# Keeps every cache in a separate file like this:
|
6
|
-
#
|
7
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.
|
8
11
|
class YAML
|
9
12
|
include Cache::API
|
10
13
|
include Cache::FileBased
|
data/lib/innate/current.rb
CHANGED
@@ -2,9 +2,9 @@ require 'innate/request'
|
|
2
2
|
require 'innate/response'
|
3
3
|
|
4
4
|
module Innate
|
5
|
-
#
|
6
|
-
# reach them from anywhere in the code without passing around the
|
7
|
-
# directly.
|
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
8
|
class Current
|
9
9
|
extend Trinity
|
10
10
|
|
@@ -16,22 +16,20 @@ module Innate
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
#
|
20
|
-
|
19
|
+
# Run setup and call the app
|
21
20
|
def call(env)
|
22
|
-
|
23
|
-
|
24
|
-
@app.call(env)
|
25
|
-
end
|
21
|
+
setup(env)
|
22
|
+
@app.call(env)
|
26
23
|
end
|
27
24
|
|
28
25
|
# Setup new Request/Response/Session for this request/response cycle.
|
29
26
|
# The parameters are here to allow Ramaze to inject its own classes.
|
30
27
|
def setup(env, request = Request, response = Response, session = Session)
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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)
|
35
33
|
end
|
36
34
|
end
|
37
35
|
end
|
data/lib/innate/dynamap.rb
CHANGED
data/lib/innate/helper.rb
CHANGED
@@ -165,19 +165,21 @@ module Innate
|
|
165
165
|
# Figure out files that might have the helper we ask for and then require
|
166
166
|
# the first we find, if any.
|
167
167
|
def try_require(name)
|
168
|
-
if found =
|
168
|
+
if found = find_helper(name.to_s)
|
169
169
|
require(found) || true
|
170
170
|
else
|
171
171
|
raise(LoadError, "Helper #{name} not found")
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
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
|
181
183
|
end
|
182
184
|
end
|
183
185
|
end
|
data/lib/innate/helper/aspect.rb
CHANGED
@@ -94,28 +94,28 @@ module Innate
|
|
94
94
|
AOP[self][:before_all] = block
|
95
95
|
end
|
96
96
|
|
97
|
-
def before(
|
98
|
-
AOP[self][:before][name] = block
|
97
|
+
def before(*names, &block)
|
98
|
+
names.each{|name| AOP[self][:before][name] = block }
|
99
99
|
end
|
100
100
|
|
101
101
|
def after_all(&block)
|
102
102
|
AOP[self][:after_all] = block
|
103
103
|
end
|
104
104
|
|
105
|
-
def after(
|
106
|
-
AOP[self][:after][name] = block
|
105
|
+
def after(*names, &block)
|
106
|
+
names.each{|name| AOP[self][:after][name] = block }
|
107
107
|
end
|
108
108
|
|
109
|
-
def wrap(
|
110
|
-
before(
|
111
|
-
after(
|
109
|
+
def wrap(*names, &block)
|
110
|
+
before(*names, &block)
|
111
|
+
after(*names, &block)
|
112
112
|
end
|
113
113
|
|
114
114
|
def add_action_wrapper(order, method_name)
|
115
115
|
if wrap = trait[:wrap]
|
116
|
-
wrap.merge(SortedSet[[order, method_name]])
|
116
|
+
wrap.merge(SortedSet[[order, method_name.to_s]])
|
117
117
|
else
|
118
|
-
trait :wrap => SortedSet[[order, method_name]]
|
118
|
+
trait :wrap => SortedSet[[order, method_name.to_s]]
|
119
119
|
end
|
120
120
|
end
|
121
121
|
end
|
data/lib/innate/helper/cgi.rb
CHANGED
@@ -57,7 +57,7 @@ module Innate
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def raw_redirect(target, options = {}, &block)
|
60
|
-
header =
|
60
|
+
header = response.header.merge('Location' => target.to_s)
|
61
61
|
status = options[:status] || 302
|
62
62
|
body = options[:body] || redirect_body(target)
|
63
63
|
|
data/lib/innate/helper/render.rb
CHANGED
@@ -5,7 +5,6 @@ module Innate
|
|
5
5
|
#
|
6
6
|
# @example of added functionality
|
7
7
|
# YourController.render_partial(:foo, :x => 42)
|
8
|
-
#
|
9
8
|
def self.included(into)
|
10
9
|
into.extend(self)
|
11
10
|
end
|
@@ -20,6 +19,14 @@ module Innate
|
|
20
19
|
#
|
21
20
|
# As usual, patches welcome.
|
22
21
|
#
|
22
|
+
# @example usage
|
23
|
+
#
|
24
|
+
# render_full('/blog/article/1')
|
25
|
+
# render_full('/blog/article/1', :lang => :de)
|
26
|
+
#
|
27
|
+
# Please note that you have to give the full path in the same way you'd
|
28
|
+
# do in a direct request with curl or a browser.
|
29
|
+
#
|
23
30
|
# @api external
|
24
31
|
# @see Mock.session
|
25
32
|
# @author manveru
|
@@ -38,17 +45,44 @@ module Innate
|
|
38
45
|
end
|
39
46
|
|
40
47
|
# Renders an action without any layout.
|
48
|
+
# You can further tweak the action to be rendered by passing a block.
|
49
|
+
#
|
50
|
+
# @example usage
|
51
|
+
#
|
52
|
+
# render_partial(:index)
|
53
|
+
# render_partial(:index, :title => :foo)
|
54
|
+
#
|
55
|
+
# Please note that you only have to supply the action name, if your
|
56
|
+
# action requires arguments then you have to pass a name suitable for
|
57
|
+
# that.
|
58
|
+
#
|
59
|
+
# @example usage with action that requires arguments
|
60
|
+
#
|
61
|
+
# # requires two arguments
|
62
|
+
# def foo(a, b)
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# # pass two suitable arguments
|
66
|
+
# render_partial('foo/1/2')
|
67
|
+
#
|
41
68
|
# @api external
|
42
69
|
# @see render_custom
|
43
70
|
# @author manveru
|
44
71
|
def render_partial(action_name, variables = {})
|
45
72
|
render_custom(action_name, variables) do |action|
|
46
73
|
action.layout = nil
|
74
|
+
yield(action) if block_given?
|
47
75
|
end
|
48
76
|
end
|
49
77
|
|
50
78
|
# Renders an action view, doesn't execute any methods and won't wrap it
|
51
79
|
# into a layout.
|
80
|
+
# You can further tweak the action to be rendered by passing a block.
|
81
|
+
#
|
82
|
+
# @example usage
|
83
|
+
#
|
84
|
+
# render_view(:index)
|
85
|
+
# render_view(:index, :title => :foo)
|
52
86
|
#
|
53
87
|
# @api external
|
54
88
|
# @see render_custom
|
@@ -57,12 +91,41 @@ module Innate
|
|
57
91
|
render_custom(action_name, variables) do |action|
|
58
92
|
action.layout = nil
|
59
93
|
action.method = nil
|
94
|
+
yield(action) if block_given?
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Use the given file as a template and render it in the same scope as
|
99
|
+
# the current action.
|
100
|
+
# The +filename+ may be an absolute path or relative to the process
|
101
|
+
# working directory.
|
102
|
+
#
|
103
|
+
# @example usage
|
104
|
+
#
|
105
|
+
# path = '/home/manveru/example/app/todo/view/index.xhtml'
|
106
|
+
# render_file(path)
|
107
|
+
# render_file(path, :title => :foo)
|
108
|
+
#
|
109
|
+
# Ramaze will emit a warning if you try to render an Action without a
|
110
|
+
# method or view template, but will still try to render it.
|
111
|
+
# The usual {Action#valid?} doesn't apply here, as sometimes you just
|
112
|
+
# cannot have a method associated with a template.
|
113
|
+
#
|
114
|
+
# @api external
|
115
|
+
# @see render_custom
|
116
|
+
# @author manveru
|
117
|
+
def render_file(filename, variables = {})
|
118
|
+
render_custom(action.path, variables) do |action|
|
119
|
+
action.layout = nil
|
120
|
+
action.method = nil
|
121
|
+
action.view = filename
|
122
|
+
yield(action) if block_given?
|
60
123
|
end
|
61
124
|
end
|
62
125
|
|
63
126
|
def render_custom(action_name, variables = {})
|
64
127
|
unless action = resolve(action_name.to_s)
|
65
|
-
raise(ArgumentError, "No Action %p on #{self}" % action_name)
|
128
|
+
raise(ArgumentError, "No Action %p on #{self}" % [action_name])
|
66
129
|
end
|
67
130
|
|
68
131
|
action.sync_variables(self.action)
|
@@ -71,11 +134,9 @@ module Innate
|
|
71
134
|
|
72
135
|
yield(action) if block_given?
|
73
136
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
Log.warn("Invalid action: %p" % action)
|
78
|
-
end
|
137
|
+
valid_action = action.view || action.method
|
138
|
+
Log.warn("Empty action: %p" % [action]) unless valid_action
|
139
|
+
action.render
|
79
140
|
end
|
80
141
|
end
|
81
142
|
end
|
@@ -1,19 +1,25 @@
|
|
1
1
|
class Logger
|
2
2
|
# Extended Formatter that supports ANSI colors.
|
3
|
+
#
|
4
|
+
# The basic mapping of ANSI colors is as follows:
|
5
|
+
#
|
6
|
+
# | reset | bold | dark | underline | blink | negative
|
7
|
+
# MOD | 0 | 1 | 2 | 4 | 5 | 7
|
8
|
+
#
|
9
|
+
# | black | red | green | yellow | blue | magenta | cyan | white
|
10
|
+
# FG | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37
|
11
|
+
# BG | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47
|
12
|
+
#
|
13
|
+
# The output is done by: "\e[#{mod};#{fg};#{bg}m#{string}\e[0m"
|
14
|
+
# The suffix is to reset the terminal to the original state again.
|
3
15
|
class ColorFormatter < Formatter
|
4
16
|
LEVEL_COLOR = {
|
5
|
-
'DEBUG' =>
|
6
|
-
'INFO' =>
|
7
|
-
'WARN' =>
|
8
|
-
'ERROR' =>
|
9
|
-
'FATAL' =>
|
10
|
-
'UNKNOWN' =>
|
11
|
-
}
|
12
|
-
|
13
|
-
COLOR_CODE = {
|
14
|
-
:reset => 0, :bold => 1, :dark => 2, :underline => 4, :blink => 5,
|
15
|
-
:negative => 7, :black => 30, :red => 31, :green => 32, :yellow => 33,
|
16
|
-
:blue => 34, :magenta => 35, :cyan => 36, :white => 37,
|
17
|
+
'DEBUG' => "\e[0;34;40m%s\e[0m", # blue on black
|
18
|
+
'INFO' => "\e[0;37;40m%s\e[0m", # white on black
|
19
|
+
'WARN' => "\e[0;33;40m%s\e[0m", # yellow on black
|
20
|
+
'ERROR' => "\e[0;31;40m%s\e[0m", # red on black
|
21
|
+
'FATAL' => "\e[0;35;40m%s\e[0m", # red on black
|
22
|
+
'UNKNOWN' => "\e[0;32;40m%s\e[0m", # green on black
|
17
23
|
}
|
18
24
|
|
19
25
|
FORMAT_TIME = "%Y-%m-%d %H:%M:%S"
|
@@ -33,7 +39,7 @@ class Logger
|
|
33
39
|
end
|
34
40
|
|
35
41
|
def colorize(string, severity)
|
36
|
-
|
42
|
+
LEVEL_COLOR[severity] % string
|
37
43
|
end
|
38
44
|
|
39
45
|
def self.color?(logdev)
|
data/lib/innate/node.rb
CHANGED
@@ -244,7 +244,7 @@ module Innate
|
|
244
244
|
# with feedback in your logs.
|
245
245
|
#
|
246
246
|
# A lot of functionality in here relies on the fact that call is executed
|
247
|
-
# within
|
247
|
+
# within Current#call which populates the variables used by Trinity.
|
248
248
|
# So if you use the Node directly as a middleware make sure that you #use
|
249
249
|
# Innate::Current as a middleware before it.
|
250
250
|
#
|
@@ -261,11 +261,7 @@ module Innate
|
|
261
261
|
path << '/' if path.empty?
|
262
262
|
|
263
263
|
response.reset
|
264
|
-
|
265
|
-
|
266
|
-
Current.session.flush(response)
|
267
|
-
|
268
|
-
response.finish
|
264
|
+
try_resolve(path).finish
|
269
265
|
end
|
270
266
|
|
271
267
|
# Let's try to find some valid action for given +path+.
|
@@ -364,7 +360,7 @@ module Innate
|
|
364
360
|
def resolve(path)
|
365
361
|
name, wish, engine = find_provide(path)
|
366
362
|
node = (respond_to?(:ancestors) && respond_to?(:new)) ? self : self.class
|
367
|
-
action = Action.create(:node => node, :wish => wish, :engine => engine)
|
363
|
+
action = Action.create(:node => node, :wish => wish, :engine => engine, :path => path)
|
368
364
|
|
369
365
|
if content_type = node.ancestral_trait["#{wish}_content_type"]
|
370
366
|
action.options = {:content_type => content_type}
|
@@ -742,8 +738,6 @@ module Innate
|
|
742
738
|
#
|
743
739
|
# Since Innate supports multiple paths to templates the +path+ has to be an
|
744
740
|
# Array that may be nested one level.
|
745
|
-
# The +path+ is then translated by {Node#path_glob} and the +wish+ by
|
746
|
-
# {Node#ext_glob}.
|
747
741
|
#
|
748
742
|
# @example Usage to find available templates
|
749
743
|
#
|
@@ -779,7 +773,6 @@ module Innate
|
|
779
773
|
#
|
780
774
|
# @api external
|
781
775
|
# @see Node#find_view Node#to_layout Node#find_aliased_view
|
782
|
-
# Node#path_glob Node#ext_glob
|
783
776
|
# @author manveru
|
784
777
|
def to_template(path, wish)
|
785
778
|
to_view(path, wish) || to_layout(path, wish)
|
@@ -802,22 +795,27 @@ module Innate
|
|
802
795
|
|
803
796
|
def update_mapping_shared(paths)
|
804
797
|
mapping = {}
|
798
|
+
paths.reject!{|path| !File.directory?(path) }
|
805
799
|
|
806
800
|
provides.each do |wish_key, engine|
|
807
801
|
wish = wish_key[/(.*)_handler/, 1]
|
808
|
-
|
802
|
+
exts = possible_exts_for(wish)
|
809
803
|
|
810
804
|
paths.reverse_each do |path|
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
805
|
+
Find.find(path) do |file|
|
806
|
+
exts.each do |ext|
|
807
|
+
next unless file =~ ext
|
808
|
+
|
809
|
+
case file.sub(path, '').gsub('/', '__')
|
810
|
+
when /^(.*)\.(.*)\.(.*)$/
|
811
|
+
action_name, wish_ext, engine_ext = $1, $2, $3
|
812
|
+
when /^(.*)\.(.*)$/
|
813
|
+
action_name, wish_ext, engine_ext = $1, wish, $2
|
814
|
+
end
|
815
|
+
|
816
|
+
mapping[wish_ext] ||= {}
|
817
|
+
mapping[wish_ext][action_name] = file
|
817
818
|
end
|
818
|
-
|
819
|
-
mapping[wish_ext] ||= {}
|
820
|
-
mapping[wish_ext][action_name] = file
|
821
819
|
end
|
822
820
|
end
|
823
821
|
end
|
@@ -825,32 +823,37 @@ module Innate
|
|
825
823
|
return mapping
|
826
824
|
end
|
827
825
|
|
826
|
+
# Answer with an array of possible paths in order of significance for
|
827
|
+
# template lookup of the given +mappings+.
|
828
|
+
#
|
829
|
+
# @param [#map] An array two Arrays of inner and outer directories.
|
830
|
+
#
|
831
|
+
# @return [Array]
|
832
|
+
# @see update_view_mappings update_layout_mappings update_template_mappings
|
833
|
+
# @author manveru
|
828
834
|
def possible_paths_for(mappings)
|
829
|
-
root_mappings.map{|
|
830
|
-
mappings.first.map{|
|
831
|
-
mappings.last.map{|
|
832
|
-
File.join(
|
833
|
-
}
|
834
|
-
}
|
835
|
-
}.flatten
|
835
|
+
root_mappings.map{|root|
|
836
|
+
mappings.first.map{|inner|
|
837
|
+
mappings.last.map{|outer|
|
838
|
+
::File.join(root, inner, outer, '/') }}}.flatten
|
836
839
|
end
|
837
840
|
|
838
|
-
#
|
839
|
-
#
|
841
|
+
# Answer with an array of possible extensions in order of significance for
|
842
|
+
# the given +wish+.
|
840
843
|
#
|
841
844
|
# @param [#to_s] wish the extension (no leading '.')
|
842
845
|
#
|
843
|
-
# @return [
|
846
|
+
# @return [Array] list of exts valid for this +wish+
|
844
847
|
#
|
845
848
|
# @api internal
|
846
849
|
# @see Node#to_template View::exts_of Node#provides
|
847
850
|
# @author manveru
|
848
|
-
def
|
851
|
+
def possible_exts_for(wish)
|
849
852
|
pr = provides
|
850
853
|
return unless engine = pr["#{wish}_handler"]
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
+
View.exts_of(engine).map{|e_ext|
|
855
|
+
[[*wish].map{|w_ext| /#{w_ext}\.#{e_ext}$/ }, /#{e_ext}$/]
|
856
|
+
}.flatten
|
854
857
|
end
|
855
858
|
|
856
859
|
# For compatibility with new Kernel#binding behaviour in 1.9
|
@@ -929,7 +932,7 @@ module Innate
|
|
929
932
|
# @author manveru
|
930
933
|
def layout_mappings
|
931
934
|
paths = [*ancestral_trait[:layouts]]
|
932
|
-
paths = [
|
935
|
+
paths = ['/'] if paths.empty?
|
933
936
|
|
934
937
|
[[*options.layouts].flatten, [*paths].flatten]
|
935
938
|
end
|