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
data/lib/innate/options/dsl.rb
CHANGED
@@ -78,7 +78,8 @@ module Innate
|
|
78
78
|
# :doc, :value keys will be ignored
|
79
79
|
def option(doc, key, value, other = {}, &block)
|
80
80
|
trigger = block || other[:trigger]
|
81
|
-
convert = {:doc => doc.to_s, :value => value
|
81
|
+
convert = {:doc => doc.to_s, :value => value}
|
82
|
+
convert[:trigger] = trigger if trigger
|
82
83
|
@hash[key.to_sym] = other.merge(convert)
|
83
84
|
end
|
84
85
|
alias o option
|
@@ -115,7 +116,9 @@ module Innate
|
|
115
116
|
# @param [Array] keys
|
116
117
|
# @param [Object] value
|
117
118
|
def set_value(keys, value)
|
118
|
-
get(*keys)
|
119
|
+
got = get(*keys)
|
120
|
+
return got[:value] = value if got
|
121
|
+
raise(IndexError, "There is no option available for %p" % [keys])
|
119
122
|
end
|
120
123
|
|
121
124
|
# Retrieve only the :value from the value hash if found via +keys+.
|
data/lib/innate/request.rb
CHANGED
@@ -56,7 +56,7 @@ module Innate
|
|
56
56
|
# * values_at
|
57
57
|
|
58
58
|
class Request < Rack::Request
|
59
|
-
# Currently handled request from
|
59
|
+
# Currently handled request from Thread.current[:request]
|
60
60
|
# Call it from anywhere via Innate::Request.current
|
61
61
|
def self.current
|
62
62
|
Current.request
|
data/lib/innate/response.rb
CHANGED
data/lib/innate/route.rb
CHANGED
@@ -5,6 +5,10 @@ module Innate
|
|
5
5
|
#
|
6
6
|
# This middleware should wrap Innate::DynaMap.
|
7
7
|
#
|
8
|
+
# Please note that Rack::File is put before Route and Rewrite, that means
|
9
|
+
# that you cannot apply routes to static files unless you add your own route
|
10
|
+
# middleware before.
|
11
|
+
#
|
8
12
|
# String routers are the simplest way to route in Innate. One path is
|
9
13
|
# translated into another:
|
10
14
|
#
|
data/lib/innate/session.rb
CHANGED
@@ -9,12 +9,12 @@ module Innate
|
|
9
9
|
# You may store anything in here that you may also store in the corresponding
|
10
10
|
# store, usually it's best to keep it to things that are safe to Marshal.
|
11
11
|
#
|
12
|
-
# The default time of expiration is
|
13
|
-
#
|
12
|
+
# The default time of expiration is:
|
14
13
|
# Time.at(2147483647) # => Tue Jan 19 12:14:07 +0900 2038
|
15
14
|
#
|
16
15
|
# Hopefully we all have 64bit systems by then.
|
17
|
-
|
16
|
+
#
|
17
|
+
# The Session instance is compatible with the specification of rack.session.
|
18
18
|
class Session
|
19
19
|
include Optioned
|
20
20
|
|
@@ -40,13 +40,17 @@ module Innate
|
|
40
40
|
@flash = Flash.new(self)
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
# Rack interface
|
44
|
+
|
45
|
+
def store(key, value)
|
44
46
|
cache_sid[key] = value
|
45
47
|
end
|
48
|
+
alias []= store
|
46
49
|
|
47
|
-
def
|
50
|
+
def fetch(key, value = nil)
|
48
51
|
cache_sid[key]
|
49
52
|
end
|
53
|
+
alias [] fetch
|
50
54
|
|
51
55
|
def delete(key)
|
52
56
|
cache_sid.delete(key)
|
@@ -57,9 +61,7 @@ module Innate
|
|
57
61
|
@cache_sid = nil
|
58
62
|
end
|
59
63
|
|
60
|
-
|
61
|
-
@cache_sid ||= cache[sid] || {}
|
62
|
-
end
|
64
|
+
# Additional interface
|
63
65
|
|
64
66
|
def flush(response = @response)
|
65
67
|
return if !@cache_sid or @cache_sid.empty?
|
@@ -70,6 +72,12 @@ module Innate
|
|
70
72
|
set_cookie(response)
|
71
73
|
end
|
72
74
|
|
75
|
+
private
|
76
|
+
|
77
|
+
def cache_sid
|
78
|
+
@cache_sid ||= cache[sid] || {}
|
79
|
+
end
|
80
|
+
|
73
81
|
def sid
|
74
82
|
@sid ||= cookie || generate_sid
|
75
83
|
end
|
@@ -78,12 +86,6 @@ module Innate
|
|
78
86
|
@request.cookies[options.key]
|
79
87
|
end
|
80
88
|
|
81
|
-
def inspect
|
82
|
-
cache.inspect
|
83
|
-
end
|
84
|
-
|
85
|
-
private
|
86
|
-
|
87
89
|
def cache
|
88
90
|
Innate::Cache.session
|
89
91
|
end
|
data/lib/innate/state.rb
CHANGED
@@ -1,12 +1,6 @@
|
|
1
|
-
|
2
|
-
begin
|
3
|
-
require 'innate/state/fiber'
|
4
|
-
STATE = State::Fiber.new
|
5
|
-
rescue LoadError
|
6
|
-
require 'innate/state/thread'
|
7
|
-
STATE = State::Thread.new
|
8
|
-
end
|
1
|
+
require 'thread'
|
9
2
|
|
3
|
+
module Innate
|
10
4
|
module SingletonMethods
|
11
5
|
# Use this method to achieve thread-safety for sensitive operations.
|
12
6
|
#
|
@@ -17,11 +11,16 @@ module Innate
|
|
17
11
|
# @param [Proc] block the things you want to execute
|
18
12
|
# @see State::Thread#sync State::Fiber#sync
|
19
13
|
def sync(&block)
|
20
|
-
|
14
|
+
Thread.exclusive(&block)
|
21
15
|
end
|
22
16
|
|
23
|
-
def defer
|
24
|
-
|
17
|
+
def defer
|
18
|
+
outer = ::Thread.current
|
19
|
+
::Thread.new{
|
20
|
+
inner = ::Thread.current
|
21
|
+
outer.keys.each{|k| inner[k] = outer[k] }
|
22
|
+
yield
|
23
|
+
}
|
25
24
|
end
|
26
25
|
end
|
27
26
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Innate
|
2
|
-
# Simplify accessing
|
2
|
+
# Simplify accessing Thread.current variables.
|
3
3
|
#
|
4
4
|
# Example:
|
5
5
|
#
|
@@ -54,7 +54,7 @@ module Innate
|
|
54
54
|
state_reader(*names, &initializer)
|
55
55
|
end
|
56
56
|
|
57
|
-
# Writer accessor to
|
57
|
+
# Writer accessor to Thread.current[key]=
|
58
58
|
#
|
59
59
|
# Example:
|
60
60
|
#
|
@@ -81,11 +81,11 @@ module Innate
|
|
81
81
|
|
82
82
|
def state_writer(*names)
|
83
83
|
StateAccessor.each(*names) do |key, meth|
|
84
|
-
class_eval("def %s=(obj)
|
84
|
+
class_eval("def %s=(obj) Thread.current[%p] = obj; end" % [meth, key])
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
# Reader accessor for
|
88
|
+
# Reader accessor for Thread.current[key]
|
89
89
|
#
|
90
90
|
# Example:
|
91
91
|
#
|
@@ -115,14 +115,14 @@ module Innate
|
|
115
115
|
StateAccessor.each(*names) do |key, meth|
|
116
116
|
if initializer
|
117
117
|
define_method(meth) do
|
118
|
-
unless
|
119
|
-
|
118
|
+
unless Thread.current.key?(key)
|
119
|
+
Thread.current[key] = instance_eval(&initializer)
|
120
120
|
else
|
121
|
-
|
121
|
+
Thread.current[key]
|
122
122
|
end
|
123
123
|
end
|
124
124
|
else
|
125
|
-
class_eval("def %s;
|
125
|
+
class_eval("def %s; Thread.current[%p]; end" % [meth, key])
|
126
126
|
end
|
127
127
|
end
|
128
128
|
end
|
data/lib/innate/traited.rb
CHANGED
@@ -26,7 +26,7 @@ module Innate
|
|
26
26
|
# foo.trait[:hello] # => "World!"
|
27
27
|
# foo.show # => ["Hello", "World!", "World!"]
|
28
28
|
module Traited
|
29
|
-
TRAITS = {}
|
29
|
+
TRAITS, ANCESTRAL_TRAITS, ANCESTRAL_VALUES = {}, {}, {}
|
30
30
|
|
31
31
|
def self.included(into)
|
32
32
|
into.extend(self)
|
@@ -35,7 +35,10 @@ module Innate
|
|
35
35
|
def trait(hash = nil)
|
36
36
|
if hash
|
37
37
|
TRAITS[self] ||= {}
|
38
|
-
TRAITS[self].merge!(hash)
|
38
|
+
result = TRAITS[self].merge!(hash)
|
39
|
+
ANCESTRAL_VALUES.clear
|
40
|
+
ANCESTRAL_TRAITS.clear
|
41
|
+
result
|
39
42
|
else
|
40
43
|
TRAITS[self] || {}
|
41
44
|
end
|
@@ -60,21 +63,23 @@ module Innate
|
|
60
63
|
# Foobar.ancestral_trait
|
61
64
|
# # => {:three => :drei, :two => :zwei, :one => :eins, :first => :overwritten}
|
62
65
|
def ancestral_trait
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
+
klass = self.kind_of?(Module) ? self : self.class
|
67
|
+
ANCESTRAL_TRAITS[klass] ||=
|
68
|
+
each_ancestral_trait({}){|hash, trait| hash.update(trait) }
|
66
69
|
end
|
67
70
|
|
68
71
|
def ancestral_trait_values(key)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
+
klass = self.kind_of?(Module) ? self : self.class
|
73
|
+
cache = ANCESTRAL_VALUES[klass] ||= {}
|
74
|
+
cache[key] ||= each_ancestral_trait([]){|array, trait|
|
75
|
+
array << trait[key] if trait.key?(key) }
|
72
76
|
end
|
73
77
|
|
74
|
-
def each_ancestral_trait
|
78
|
+
def each_ancestral_trait(obj)
|
75
79
|
ancs = respond_to?(:ancestors) ? ancestors : self.class.ancestors
|
76
80
|
ancs.unshift(self)
|
77
|
-
ancs.reverse_each{|anc| yield(TRAITS[anc]) if TRAITS.key?(anc) }
|
81
|
+
ancs.reverse_each{|anc| yield(obj, TRAITS[anc]) if TRAITS.key?(anc) }
|
82
|
+
obj
|
78
83
|
end
|
79
84
|
|
80
85
|
# trait for self.class if we are an instance
|
data/lib/innate/version.rb
CHANGED
data/lib/innate/view.rb
CHANGED
@@ -2,12 +2,32 @@ module Innate
|
|
2
2
|
|
3
3
|
# This is a container module for wrappers of templating engines and handles
|
4
4
|
# lazy requiring of needed engines.
|
5
|
-
|
6
5
|
module View
|
6
|
+
include Optioned
|
7
|
+
|
7
8
|
ENGINE, TEMP = {}, {}
|
8
9
|
|
10
|
+
options.dsl do
|
11
|
+
o "Cache compiled templates",
|
12
|
+
:cache, true
|
13
|
+
|
14
|
+
o "Cache template files after they're read to prevent additional filesystem calls",
|
15
|
+
:read_cache, false
|
16
|
+
end
|
17
|
+
|
18
|
+
# In order to be able to render actions without running
|
19
|
+
# Innate::setup_dependencies we have to add the cache here already.
|
20
|
+
Cache.add(:view)
|
21
|
+
|
9
22
|
module_function
|
10
23
|
|
24
|
+
def compile(string)
|
25
|
+
return yield(string.to_s) unless View.options.cache
|
26
|
+
string = string.to_s
|
27
|
+
checksum = Digest::MD5.hexdigest(string)
|
28
|
+
Cache.view[checksum] ||= yield(string)
|
29
|
+
end
|
30
|
+
|
11
31
|
def exts_of(engine)
|
12
32
|
name = engine.to_s
|
13
33
|
ENGINE.reject{|k,v| v != name }.keys
|
@@ -29,10 +49,27 @@ module Innate
|
|
29
49
|
# on the first request (before TEMP is set).
|
30
50
|
# No mutex is used in Fiber environment, see Innate::State and subclasses.
|
31
51
|
def obtain(klass, root = Object)
|
32
|
-
|
52
|
+
Thread.exclusive{
|
33
53
|
klass.to_s.scan(/\w+/){|part| root = root.const_get(part) }
|
34
|
-
root
|
35
|
-
|
54
|
+
return root
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
# Reads the specified view template from the filesystem. When the read_cache
|
59
|
+
# option is enabled, templates will be cached to prevent unnecessary
|
60
|
+
# filesystem reads in the future.
|
61
|
+
#
|
62
|
+
# @example usage
|
63
|
+
#
|
64
|
+
# View.read('some/file.xhtml')
|
65
|
+
#
|
66
|
+
# @param [#to_str] view
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
# @see Action#render
|
70
|
+
def read(view)
|
71
|
+
return Cache.view[view] ||= ::File.read(view) if View.options.read_cache
|
72
|
+
::File.read(view)
|
36
73
|
end
|
37
74
|
|
38
75
|
# Register given templating engine wrapper and extensions for later usage.
|
data/lib/innate/view/erb.rb
CHANGED
@@ -4,10 +4,9 @@ module Innate
|
|
4
4
|
module View
|
5
5
|
module ERB
|
6
6
|
def self.call(action, string)
|
7
|
-
erb = ::ERB.new(
|
7
|
+
erb = View.compile(string){|s| ::ERB.new(s, nil, '%<>') }
|
8
8
|
erb.filename = (action.view || action.method).to_s
|
9
9
|
html = erb.result(action.binding)
|
10
|
-
|
11
10
|
return html, 'text/html'
|
12
11
|
end
|
13
12
|
end
|
data/lib/innate/view/etanni.rb
CHANGED
@@ -2,14 +2,19 @@ module Innate
|
|
2
2
|
module View
|
3
3
|
module Etanni
|
4
4
|
def self.call(action, string)
|
5
|
-
|
6
|
-
html =
|
5
|
+
etanni = View.compile(string){|s| Innate::Etanni.new(s) }
|
6
|
+
html = etanni.result(action.binding, (action.view || action.method))
|
7
7
|
return html, 'text/html'
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
class Etanni
|
13
|
+
SEPARATOR = "E69t116A65n110N78i105S83e101P80a97R82a97T84o111R82"
|
14
|
+
START = "\n<<#{SEPARATOR}.chomp\n"
|
15
|
+
STOP = "\n#{SEPARATOR}\n"
|
16
|
+
ADD = "_out_ << "
|
17
|
+
|
13
18
|
def initialize(template)
|
14
19
|
@template = template
|
15
20
|
compile
|
@@ -17,16 +22,8 @@ module Innate
|
|
17
22
|
|
18
23
|
def compile
|
19
24
|
temp = @template.dup
|
20
|
-
|
21
|
-
|
22
|
-
bufadd = "_out_ << "
|
23
|
-
|
24
|
-
temp.gsub!(/<\?r\s+(.*?)\s+\?>/m,
|
25
|
-
"#{end_heredoc} \\1; #{bufadd} #{start_heredoc}")
|
26
|
-
|
27
|
-
@compiled = "_out_ = ''
|
28
|
-
#{bufadd} #{start_heredoc} #{temp} #{end_heredoc}
|
29
|
-
_out_"
|
25
|
+
temp.gsub!(/<\?r\s+(.*?)\s+\?>/m, "#{STOP} \\1; #{ADD} #{START}")
|
26
|
+
@compiled = "_out_ = #{START} #{temp} #{STOP} _out_"
|
30
27
|
end
|
31
28
|
|
32
29
|
def result(binding, filename = '<Etanni>')
|
data/spec/innate/helper/flash.rb
CHANGED
@@ -57,6 +57,11 @@ class SpecRedirectHelper
|
|
57
57
|
def redirect_unmodified
|
58
58
|
raw_redirect '/noop'
|
59
59
|
end
|
60
|
+
|
61
|
+
def redirect_with_cookie
|
62
|
+
response.set_cookie('user', :value => 'manveru')
|
63
|
+
redirect r(:noop)
|
64
|
+
end
|
60
65
|
end
|
61
66
|
|
62
67
|
describe Innate::Helper::Redirect do
|
@@ -157,4 +162,10 @@ describe Innate::Helper::Redirect do
|
|
157
162
|
last_response.status.should == 200
|
158
163
|
last_response.body.should == 'no actual double redirect'
|
159
164
|
end
|
165
|
+
|
166
|
+
should 'set cookie before redirect' do
|
167
|
+
get("#@uri/redirect_with_cookie")
|
168
|
+
follow_redirect!
|
169
|
+
last_request.cookies.should == {'user' => 'manveru'}
|
170
|
+
end
|
160
171
|
end
|
@@ -74,6 +74,26 @@ class SpecHelperRenderMisc
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
class SpecHelperRenderFile
|
78
|
+
Innate.node '/render_file'
|
79
|
+
|
80
|
+
layout :layout
|
81
|
+
|
82
|
+
def layout
|
83
|
+
'{ #{@content} }'
|
84
|
+
end
|
85
|
+
|
86
|
+
FILE = File.expand_path('../view/aspect_hello.xhtml', __FILE__)
|
87
|
+
|
88
|
+
def absolute
|
89
|
+
render_file(FILE)
|
90
|
+
end
|
91
|
+
|
92
|
+
def absolute_with(foo, bar)
|
93
|
+
render_file(FILE, :foo => foo, :bar => bar)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
77
97
|
describe Innate::Helper::Render do
|
78
98
|
describe '#render_full' do
|
79
99
|
behaves_like :mock
|
@@ -130,4 +150,16 @@ describe Innate::Helper::Render do
|
|
130
150
|
get('/misc/recursive').body.scan(/\S/).join.should == '{1{2{3{44}3}2}1}'
|
131
151
|
end
|
132
152
|
end
|
153
|
+
|
154
|
+
describe '#render_file' do
|
155
|
+
behaves_like :mock
|
156
|
+
|
157
|
+
it 'renders file from absolute path' do
|
158
|
+
get('/render_file/absolute').body.should == '{ ! }'
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'renders file from absolute path with variables' do
|
162
|
+
get('/render_file/absolute_with/one/two').body.should == '{ one two! }'
|
163
|
+
end
|
164
|
+
end
|
133
165
|
end
|