innate 2009.04.12 → 2009.05
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +10 -0
- data/CHANGELOG +360 -0
- data/MANIFEST +8 -8
- data/README.md +1 -9
- data/Rakefile +7 -5
- data/example/app/whywiki_erb/start.rb +1 -1
- data/innate.gemspec +9 -5
- data/lib/innate.rb +6 -13
- data/lib/innate/action.rb +29 -33
- 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 +11 -9
- data/lib/innate/helper/aspect.rb +9 -9
- data/lib/innate/helper/cgi.rb +3 -0
- data/lib/innate/helper/link.rb +2 -2
- data/lib/innate/helper/redirect.rb +1 -1
- data/lib/innate/helper/render.rb +70 -7
- data/lib/innate/helper/send_file.rb +9 -1
- 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 -7
- 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/link.rb +8 -0
- 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 +48 -9
- data/tasks/ycov.rake +84 -0
- metadata +21 -13
- data/lib/innate/core_compatibility/basic_object.rb +0 -10
- data/lib/innate/core_compatibility/string.rb +0 -3
- 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/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
data/spec/innate/helper/link.rb
CHANGED
@@ -56,6 +56,14 @@ describe Innate::Helper::Link do
|
|
56
56
|
Two.route(:foo, :bar).should == URI('/two/foo/bar')
|
57
57
|
end
|
58
58
|
|
59
|
+
should 'respond with URI for node with path /foo/bar+baz' do
|
60
|
+
One.route('/foo/bar+baz').should == URI('/foo/bar+baz')
|
61
|
+
One.route(:foo, 'bar baz').should == URI('/foo/bar+baz')
|
62
|
+
|
63
|
+
Two.route('/foo/bar+baz').should == URI('/two/foo/bar+baz')
|
64
|
+
Two.route(:foo, 'bar baz').should == URI('/two/foo/bar+baz')
|
65
|
+
end
|
66
|
+
|
59
67
|
should 'respond with URI for node with GET params' do
|
60
68
|
One.route('/', :a => :b).should == URI('/?a=b')
|
61
69
|
|
@@ -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
|
data/spec/innate/node/node.rb
CHANGED
data/spec/innate/options.rb
CHANGED
@@ -46,7 +46,7 @@ describe Options do
|
|
46
46
|
|
47
47
|
should 'get sub-sub option' do
|
48
48
|
@options.get(:deep, :down, :me).
|
49
|
-
should == {:value => :too, :doc => 'deep down'
|
49
|
+
should == {:value => :too, :doc => 'deep down'}
|
50
50
|
end
|
51
51
|
|
52
52
|
should 'respond with nil on getting missing option' do
|
@@ -98,6 +98,10 @@ describe Options do
|
|
98
98
|
lambda{ @options[:foo] = :bar }.should.raise(ArgumentError)
|
99
99
|
end
|
100
100
|
|
101
|
+
should "raise when trying to assign to an option that doesn't exist" do
|
102
|
+
lambda{ @options.merge!(:foo => :bar) }.should.raise(IndexError)
|
103
|
+
end
|
104
|
+
|
101
105
|
should 'pretty_print' do
|
102
106
|
require 'pp'
|
103
107
|
p = PP.new
|
data/tasks/authors.rake
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Once git has a fix for the glibc in handling .mailmap and another fix for
|
2
|
+
# allowing empty mail address to be mapped in .mailmap we won't have to handle
|
3
|
+
# them manually.
|
4
|
+
|
5
|
+
desc 'Update AUTHORS'
|
6
|
+
task :authors do
|
7
|
+
authors = Hash.new(0)
|
8
|
+
|
9
|
+
`git shortlog -nse`.scan(/(\d+)\s(.+)\s<(.*)>$/) do |count, name, email|
|
10
|
+
case name
|
11
|
+
when "ahoward"
|
12
|
+
name, email = "Ara T. Howard", "ara.t.howard@gmail.com"
|
13
|
+
when "Martin Hilbig blueonyx@dev-area.net"
|
14
|
+
name, email = "Martin Hilbig", "blueonyx@dev-area.net"
|
15
|
+
when "Michael Fellinger m.fellinger@gmail.com"
|
16
|
+
name, email = "Michael Fellinger", "m.fellinger@gmail.com"
|
17
|
+
end
|
18
|
+
|
19
|
+
authors[[name, email]] += count.to_i
|
20
|
+
end
|
21
|
+
|
22
|
+
File.open('AUTHORS', 'w+') do |io|
|
23
|
+
io.puts "Following persons have contributed to #{GEMSPEC.name}."
|
24
|
+
io.puts '(Sorted by number of submitted patches, then alphabetically)'
|
25
|
+
io.puts ''
|
26
|
+
authors.sort_by{|(n,e),c| [-c, n.downcase] }.each do |(name, email), count|
|
27
|
+
io.puts("%6d %s <%s>" % [count, name, email])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/tasks/release.rake
CHANGED
@@ -1,12 +1,51 @@
|
|
1
|
-
|
2
|
-
task :
|
3
|
-
name, version = GEMSPEC.name, GEMSPEC.version
|
1
|
+
namespace :release do
|
2
|
+
task :all => [:release_github, :release_rubyforge]
|
4
3
|
|
5
|
-
|
4
|
+
desc 'Display instructions to release on github'
|
5
|
+
task :github => [:reversion, :authors, :gemspec] do
|
6
|
+
name, version = GEMSPEC.name, GEMSPEC.version
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
puts <<INSTRUCTIONS
|
9
|
+
First add the relevant files:
|
10
|
+
|
11
|
+
git add AUTHORS MANIFEST CHANGELOG #{name}.gemspec lib/#{name}/version.rb
|
12
|
+
|
13
|
+
Then commit them, tag the commit, and push:
|
14
|
+
|
15
|
+
git commit -m 'Version #{version}'
|
16
|
+
git tag -a -m '#{version}' '#{version}'
|
17
|
+
git push
|
18
|
+
|
19
|
+
INSTRUCTIONS
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: Not tested
|
24
|
+
desc 'Display instructions to release on rubyforge'
|
25
|
+
task :rubyforge => [:reversion, :authors, :gemspec, :package] do
|
26
|
+
name, version = GEMSPEC.name, GEMSPEC.version
|
27
|
+
|
28
|
+
puts <<INSTRUCTIONS
|
29
|
+
To publish to rubyforge do following:
|
30
|
+
|
31
|
+
rubyforge login
|
32
|
+
rubyforge add_release #{name} '#{version}' pkg/#{name}-#{version}.gem
|
33
|
+
|
34
|
+
After you have done these steps, see:
|
35
|
+
|
36
|
+
rake release:rubyforge_archives
|
37
|
+
|
38
|
+
INSTRUCTIONS
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Display instructions to add archives after release:rubyforge'
|
42
|
+
task :rubyforge_archives do
|
43
|
+
puts "Adding archives for distro packagers is:", ""
|
44
|
+
|
45
|
+
Dir["pkg/#{name}-#{version}.{gz,zip}"].each do |file|
|
46
|
+
puts "rubyforge add_file #{name} #{name} '#{version}' '#{file}'"
|
47
|
+
end
|
48
|
+
|
49
|
+
puts
|
50
|
+
end
|
12
51
|
end
|