manveru-innate 2009.04.08 → 2009.04.18
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +126 -0
- data/MANIFEST +5 -4
- data/README.md +1 -9
- data/Rakefile +6 -6
- data/example/app/retro_games.rb +3 -3
- data/example/app/todo/layout/{default.erb → default.xhtml} +0 -0
- data/example/app/todo/view/{index.erb → index.xhtml} +0 -0
- data/example/app/whywiki_erb/start.rb +2 -2
- data/example/provides.rb +9 -6
- data/innate.gemspec +5 -5
- data/lib/innate.rb +12 -18
- data/lib/innate/action.rb +14 -10
- data/lib/innate/cache/file_based.rb +2 -0
- data/lib/innate/helper.rb +2 -2
- data/lib/innate/helper/link.rb +2 -2
- data/lib/innate/helper/render.rb +3 -1
- data/lib/innate/helper/send_file.rb +9 -1
- data/lib/innate/node.rb +1 -3
- data/lib/innate/response.rb +0 -7
- data/lib/innate/session.rb +1 -2
- data/lib/innate/spec.rb +6 -47
- data/lib/innate/version.rb +1 -1
- data/spec/example/app/retro_games.rb +30 -0
- data/spec/example/provides.rb +16 -0
- data/spec/example/session.rb +8 -14
- data/spec/innate/helper/flash.rb +28 -47
- data/spec/innate/helper/link.rb +8 -0
- data/spec/innate/helper/redirect.rb +58 -43
- data/spec/innate/helper/render.rb +3 -27
- data/spec/innate/session.rb +14 -15
- data/tasks/install_dependencies.rake +2 -4
- data/tasks/release.rake +48 -9
- data/tasks/setup.rake +28 -0
- metadata +8 -7
- data/lib/innate/core_compatibility/basic_object.rb +0 -10
- data/lib/innate/core_compatibility/string.rb +0 -3
data/lib/innate/helper.rb
CHANGED
@@ -152,10 +152,10 @@ module Innate
|
|
152
152
|
# helper :foo_bar # => FooBar
|
153
153
|
# helper :foo # => Foo
|
154
154
|
def get(name)
|
155
|
-
|
155
|
+
module_name = /^#{name.to_s.dup.delete('_')}$/i
|
156
156
|
|
157
157
|
options.namespaces.each do |namespace|
|
158
|
-
found = namespace.constants.grep(
|
158
|
+
found = namespace.constants.grep(module_name).first
|
159
159
|
return namespace.const_get(found) if found
|
160
160
|
end
|
161
161
|
|
data/lib/innate/helper/link.rb
CHANGED
@@ -28,12 +28,12 @@ module Innate
|
|
28
28
|
hashes, names = args.partition{|arg| arg.respond_to?(:merge!) }
|
29
29
|
hashes.each{|to_merge| hash.merge!(to_merge) }
|
30
30
|
|
31
|
+
escape = Rack::Utils.method(:escape)
|
31
32
|
location = route_location(self)
|
32
|
-
front = Array[location, name, *names].join('/').squeeze('/')
|
33
|
+
front = Array[location, name, *names.map{|n| escape[n]}].join('/').squeeze('/')
|
33
34
|
|
34
35
|
return URI(front) if hash.empty?
|
35
36
|
|
36
|
-
escape = Rack::Utils.method(:escape)
|
37
37
|
query = hash.map{|k, v| "#{escape[k]}=#{escape[v]}" }.join(';')
|
38
38
|
URI("#{front}?#{query}")
|
39
39
|
end
|
data/lib/innate/helper/render.rb
CHANGED
@@ -61,7 +61,9 @@ module Innate
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def render_custom(action_name, variables = {})
|
64
|
-
action = resolve(action_name.to_s)
|
64
|
+
unless action = resolve(action_name.to_s)
|
65
|
+
raise(ArgumentError, "No Action %p on #{self}" % action_name)
|
66
|
+
end
|
65
67
|
|
66
68
|
action.sync_variables(self.action)
|
67
69
|
action.instance = action.node.new
|
@@ -3,12 +3,20 @@ module Innate
|
|
3
3
|
module SendFile
|
4
4
|
# Not optimally performing but convenient way to send files by their
|
5
5
|
# filename.
|
6
|
-
|
6
|
+
#
|
7
|
+
# I think we should remove this from the default helpers and move it into
|
8
|
+
# Ramaze, the functionality is almost never used, the naming is ambigous,
|
9
|
+
# and it doesn't use the send_file capabilities of frontend servers.
|
10
|
+
#
|
11
|
+
# So for now, I'll mark it for deprecation
|
12
|
+
def send_file(filename, content_type = nil, content_disposition = nil)
|
7
13
|
content_type ||= Rack::Mime.mime_type(::File.extname(filename))
|
14
|
+
content_disposition ||= File.basename(filename)
|
8
15
|
|
9
16
|
response.body = ::File.readlines(filename, 'rb')
|
10
17
|
response['Content-Length'] = ::File.size(filename).to_s
|
11
18
|
response['Content-Type'] = content_type
|
19
|
+
response['Content-Disposition'] = content_disposition
|
12
20
|
response.status = 200
|
13
21
|
|
14
22
|
throw(:respond, response)
|
data/lib/innate/node.rb
CHANGED
@@ -813,9 +813,7 @@ module Innate
|
|
813
813
|
when /^(.*)\.(.*)\.(.*)$/
|
814
814
|
action_name, wish_ext, engine_ext = $1, $2, $3
|
815
815
|
when /^(.*)\.(.*)$/
|
816
|
-
action_name, wish_ext, engine_ext = $1,
|
817
|
-
when /.*/
|
818
|
-
p $1
|
816
|
+
action_name, wish_ext, engine_ext = $1, wish, $2
|
819
817
|
end
|
820
818
|
|
821
819
|
mapping[wish_ext] ||= {}
|
data/lib/innate/response.rb
CHANGED
@@ -1,9 +1,4 @@
|
|
1
1
|
module Innate
|
2
|
-
|
3
|
-
# In order to reset the body contents we also need to reset the length set by
|
4
|
-
# Response#write - until I can submit a patch to Rack and the next release we
|
5
|
-
# just do this.
|
6
|
-
|
7
2
|
class Response < Rack::Response
|
8
3
|
include Optioned
|
9
4
|
|
@@ -12,8 +7,6 @@ module Innate
|
|
12
7
|
:headers, {'Content-Type' => 'text/html'}
|
13
8
|
end
|
14
9
|
|
15
|
-
attr_accessor :length
|
16
|
-
|
17
10
|
def reset
|
18
11
|
self.status = 200
|
19
12
|
self.header.delete('Content-Type')
|
data/lib/innate/session.rb
CHANGED
data/lib/innate/spec.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
begin; require 'rubygems'; rescue LoadError; end
|
2
|
+
|
1
3
|
require 'bacon'
|
4
|
+
require 'rack/test'
|
5
|
+
require(File.expand_path("#{__FILE__}/../")) unless defined?(Innate)
|
2
6
|
|
3
7
|
Bacon.summary_on_exit
|
4
|
-
# Bacon.extend(Bacon::TestUnitOutput)
|
5
|
-
|
6
|
-
innate = File.expand_path(File.join(File.dirname(__FILE__), '../innate'))
|
7
|
-
require(innate) unless defined?(Innate)
|
8
8
|
|
9
9
|
module Innate
|
10
10
|
# minimal middleware, no exception handling
|
@@ -15,50 +15,9 @@ module Innate
|
|
15
15
|
options.mode = :spec
|
16
16
|
end
|
17
17
|
|
18
|
-
# Shortcut to use persistent cookies via Innate::Mock::Session
|
19
|
-
#
|
20
|
-
# Usage:
|
21
|
-
#
|
22
|
-
# describe 'something' do
|
23
|
-
# behaves_like :session
|
24
|
-
#
|
25
|
-
# should 'get some stuff' do
|
26
|
-
# session do |mock|
|
27
|
-
# mock.get('/')
|
28
|
-
# end
|
29
|
-
# end
|
30
|
-
# end
|
31
|
-
shared :session do
|
32
|
-
Innate.setup_dependencies
|
33
|
-
|
34
|
-
def session(&block)
|
35
|
-
Innate::Mock.session(&block)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
18
|
shared :mock do
|
40
19
|
Innate.setup_dependencies
|
20
|
+
extend Rack::Test::Methods
|
41
21
|
|
42
|
-
def
|
43
|
-
def post(*args) Innate::Mock.post(*args) end
|
44
|
-
def put(*args) Innate::Mock.put(*args) end
|
45
|
-
def delete(*args) Innate::Mock.delete(*args) end
|
46
|
-
end
|
47
|
-
|
48
|
-
shared :multipart do
|
49
|
-
def multipart(hash)
|
50
|
-
boundary = 'MuLtIpArT56789'
|
51
|
-
data = []
|
52
|
-
hash.each do |key, value|
|
53
|
-
data << "--#{boundary}"
|
54
|
-
data << %(Content-Disposition: form-data; name="#{key}")
|
55
|
-
data << '' << value
|
56
|
-
end
|
57
|
-
data << "--#{boundary}--"
|
58
|
-
body = data.join("\r\n")
|
59
|
-
|
60
|
-
{ 'CONTENT_TYPE' => "multipart/form-data; boundary=#{boundary}",
|
61
|
-
'CONTENT_LENGTH' => Rack::Utils.bytesize(body).to_s,
|
62
|
-
:input => StringIO.new(body) }
|
63
|
-
end
|
22
|
+
def app; Innate.middleware; end
|
64
23
|
end
|
data/lib/innate/version.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
require 'example/app/retro_games'
|
3
|
+
|
4
|
+
describe 'Retro-games app' do
|
5
|
+
behaves_like :mock
|
6
|
+
|
7
|
+
it 'lists the first game' do
|
8
|
+
get '/'
|
9
|
+
last_response.should =~ /1 => Pacman/
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'has a form to add another game' do
|
13
|
+
get '/'
|
14
|
+
last_response.should =~ /<form/
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'allows you to add another game' do
|
18
|
+
post '/create', :name => 'Street Fighter II'
|
19
|
+
follow_redirect!
|
20
|
+
last_response.should =~ /0 => Street Fighter II/
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'allows you to vote for a game' do
|
24
|
+
get '/vote/Street+Fighter+II'
|
25
|
+
follow_redirect!
|
26
|
+
last_response.should =~ /1 => Street Fighter II/
|
27
|
+
end
|
28
|
+
|
29
|
+
FileUtils.rm_f('games.yaml')
|
30
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec/helper'
|
2
|
+
require 'example/provides'
|
3
|
+
|
4
|
+
describe 'examples/provide' do
|
5
|
+
behaves_like :mock
|
6
|
+
|
7
|
+
it 'provides YAML representation' do
|
8
|
+
get '/list.yaml'
|
9
|
+
last_response.body.should == ARTICLES.to_yaml
|
10
|
+
last_response['Content-Type'].should == 'text/yaml'
|
11
|
+
|
12
|
+
get '/list'
|
13
|
+
last_response.body.should == ''
|
14
|
+
last_response['Content-Type'].should == 'text/html'
|
15
|
+
end
|
16
|
+
end
|
data/spec/example/session.rb
CHANGED
@@ -2,27 +2,21 @@ require 'spec/helper'
|
|
2
2
|
require 'example/session'
|
3
3
|
|
4
4
|
describe 'example/session' do
|
5
|
-
behaves_like :
|
5
|
+
behaves_like :mock
|
6
6
|
|
7
7
|
it 'starts at 0' do
|
8
|
-
|
9
|
-
mock.get('/').should =~ /Value is: 0/
|
10
|
-
end
|
8
|
+
get('/').body.should =~ /Value is: 0/
|
11
9
|
end
|
12
10
|
|
13
11
|
it 'increments the counter' do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
mock.get('/increment').should =~ /Value is: 3/
|
18
|
-
end
|
12
|
+
get('/increment').body.should =~ /Value is: 1/
|
13
|
+
get('/increment').body.should =~ /Value is: 2/
|
14
|
+
get('/increment').body.should =~ /Value is: 3/
|
19
15
|
end
|
20
16
|
|
21
17
|
it 'decrements the counter' do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
mock.get('/decrement').should =~ /Value is: -3/
|
26
|
-
end
|
18
|
+
get('/decrement').body.should =~ /Value is: 2/
|
19
|
+
get('/decrement').body.should =~ /Value is: 1/
|
20
|
+
get('/decrement').body.should =~ /Value is: 0/
|
27
21
|
end
|
28
22
|
end
|
data/spec/innate/helper/flash.rb
CHANGED
@@ -57,81 +57,62 @@ class SpecFlashSub < SpecFlash
|
|
57
57
|
end
|
58
58
|
|
59
59
|
describe Innate::Helper::Flash do
|
60
|
-
behaves_like :
|
60
|
+
behaves_like :mock
|
61
61
|
|
62
62
|
should 'set and forget flash twice' do
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
mock.get('/bye').body.should == 'Bye'
|
63
|
+
get('/welcome').body.should == 'Welcome manveru'
|
64
|
+
get('/bye').body.should == 'Bye manveru'
|
65
|
+
get('/bye').body.should == 'Bye'
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
67
|
+
get('/welcome').body.should == 'Welcome manveru'
|
68
|
+
get('/bye').body.should == 'Bye manveru'
|
69
|
+
get('/bye').body.should == 'Bye'
|
72
70
|
end
|
73
71
|
|
74
72
|
should 'work over multiple nodes' do
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
mock.get('/sub/bye').body.should == 'Bye'
|
73
|
+
get('/welcome').body.should == 'Welcome manveru'
|
74
|
+
get('/sub/bye').body.should == 'Bye manveru'
|
75
|
+
get('/sub/bye').body.should == 'Bye'
|
79
76
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
77
|
+
get('/sub/welcome').body.should == 'Welcome manveru'
|
78
|
+
get('/bye').body.should == 'Bye manveru'
|
79
|
+
get('/bye').body.should == 'Bye'
|
84
80
|
end
|
85
81
|
|
86
82
|
should 'check if flash is empty' do
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
mock.get('/check_empty').body.should == 'true'
|
91
|
-
end
|
83
|
+
get('/welcome').body.should == 'Welcome manveru'
|
84
|
+
get('/check_empty').body.should == 'false'
|
85
|
+
get('/check_empty').body.should == 'true'
|
92
86
|
end
|
93
87
|
|
94
88
|
should 'set and delete key within one request' do
|
95
|
-
|
96
|
-
mock.get('/set_delete_key').body.should == ''
|
97
|
-
end
|
89
|
+
get('/set_delete_key').body.should == ''
|
98
90
|
end
|
99
91
|
|
100
92
|
should 'set and delete key over two request' do
|
101
|
-
|
102
|
-
|
103
|
-
mock.get('/delete_key').body.should == 'Bye'
|
104
|
-
end
|
93
|
+
get('/welcome').body.should == 'Welcome manveru'
|
94
|
+
get('/delete_key').body.should == 'Bye'
|
105
95
|
end
|
106
96
|
|
107
97
|
should 'merge with hash' do
|
108
|
-
|
109
|
-
|
110
|
-
mock.get('/bye').body.should == 'Bye'
|
111
|
-
end
|
98
|
+
get('/merge').body.should == {:name => 'feagliir'}.inspect
|
99
|
+
get('/bye').body.should == 'Bye'
|
112
100
|
end
|
113
101
|
|
114
102
|
should 'merge! with hash' do
|
115
|
-
|
116
|
-
|
117
|
-
mock.get('/bye').body.should == 'Bye feagliir'
|
118
|
-
end
|
103
|
+
get('/merge!').body.should == {:name => 'feagliir'}.inspect
|
104
|
+
get('/bye').body.should == 'Bye feagliir'
|
119
105
|
end
|
120
106
|
|
121
107
|
should 'inspect combined' do
|
122
|
-
|
123
|
-
|
124
|
-
mock.get('/inspect').body.
|
125
|
-
should == {:name => 'manveru', :yes => :yeah}.inspect
|
126
|
-
end
|
108
|
+
get('/welcome')
|
109
|
+
get('/inspect').body.should == {:name => 'manveru', :yes => :yeah}.inspect
|
127
110
|
end
|
128
111
|
|
129
112
|
should 'iterate over combined' do
|
130
|
-
|
131
|
-
mock.get('/welcome')
|
113
|
+
get('/welcome')
|
132
114
|
|
133
|
-
|
134
|
-
|
135
|
-
end
|
115
|
+
hash = {:yes => :yeah, :name => 'manveru'}
|
116
|
+
Hash[*eval(get('/iterate').body).flatten].should == hash
|
136
117
|
end
|
137
118
|
end
|
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
|
|
@@ -20,7 +20,7 @@ class SpecRedirectHelper
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def redirect_referer_action
|
23
|
-
redirect_referer
|
23
|
+
redirect_referer(r(:noop))
|
24
24
|
end
|
25
25
|
|
26
26
|
def no_actual_redirect
|
@@ -69,77 +69,92 @@ describe Innate::Helper::Redirect do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
should 'redirect' do
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
72
|
+
get("#@uri/redirection")
|
73
|
+
|
74
|
+
last_response.status.should == 302
|
75
|
+
last_response.headers['Location'].should == "#@uri/index"
|
76
|
+
last_response.headers['Content-Type'].should == "text/html"
|
76
77
|
end
|
77
78
|
|
78
79
|
should 'redirect twice' do
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
80
|
+
get("#@uri/double_redirection")
|
81
|
+
|
82
|
+
last_response.status.should == 302
|
83
|
+
last_response.headers['Location'].should == "#@uri/redirection"
|
84
|
+
last_response.headers['Content-Type'].should == "text/html"
|
83
85
|
end
|
84
86
|
|
85
87
|
should 'redirect to referer' do
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
88
|
+
header 'HTTP_REFERER', '/index'
|
89
|
+
get("#@uri/redirect_referer_action")
|
90
|
+
|
91
|
+
last_response.status.should == 302
|
92
|
+
last_response.headers['Location'].should == "#@uri/index"
|
93
|
+
last_response.headers['Content-Type'].should == "text/html"
|
94
|
+
end
|
95
|
+
|
96
|
+
should 'redirect to fallback if referrer is identical' do
|
97
|
+
header 'HTTP_REFERER', "#@uri/redirect_referer_action"
|
98
|
+
get("#@uri/redirect_referer_action")
|
99
|
+
|
100
|
+
last_response.status.should == 302
|
101
|
+
last_response.headers['Location'].should == "#@uri/noop"
|
102
|
+
last_response.headers['Content-Type'].should == "text/html"
|
94
103
|
end
|
95
104
|
|
96
105
|
should 'use #r' do
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
106
|
+
get("#@uri/redirect_method")
|
107
|
+
|
108
|
+
last_response.status.should == 302
|
109
|
+
last_response.headers['Location'].should == "#@uri/noop"
|
110
|
+
last_response.headers['Content-Type'].should == "text/html"
|
101
111
|
end
|
102
112
|
|
103
113
|
should 'work with absolute uris' do
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
114
|
+
get("#@uri/absolute_redirect")
|
115
|
+
|
116
|
+
last_response.status.should == 302
|
117
|
+
last_response.headers['Location'].should == "#@uri/noop"
|
118
|
+
last_response.headers['Content-Type'].should == "text/html"
|
108
119
|
end
|
109
120
|
|
110
121
|
should 'support #respond' do
|
111
|
-
|
112
|
-
|
113
|
-
|
122
|
+
get("#@uri/loop")
|
123
|
+
|
124
|
+
last_response.status.should == 200
|
125
|
+
last_response.body.should == 'no loop'
|
114
126
|
end
|
115
127
|
|
116
128
|
should 'support #respond with status' do
|
117
|
-
|
118
|
-
|
119
|
-
|
129
|
+
get("#@uri/respond_with_status")
|
130
|
+
|
131
|
+
last_response.status.should == 404
|
132
|
+
last_response.body.should == 'not found'
|
120
133
|
end
|
121
134
|
|
122
135
|
should 'support #respond!' do
|
123
|
-
|
124
|
-
|
125
|
-
|
136
|
+
get("#@uri/destructive_respond")
|
137
|
+
|
138
|
+
last_response.status.should == 200
|
139
|
+
last_response.body.should == 'destructive'
|
126
140
|
end
|
127
141
|
|
128
142
|
should 'redirect without modifying the target' do
|
129
|
-
|
130
|
-
|
131
|
-
|
143
|
+
get("#@uri/redirect_unmodified")
|
144
|
+
|
145
|
+
last_response.status.should == 302
|
146
|
+
last_response.headers['Location'].should == '/noop'
|
132
147
|
end
|
133
148
|
|
134
149
|
should 'catch redirection' do
|
135
|
-
|
136
|
-
|
137
|
-
|
150
|
+
get("#@uri/no_actual_redirect")
|
151
|
+
last_response.status.should == 200
|
152
|
+
last_response.body.should == 'no actual redirect'
|
138
153
|
end
|
139
154
|
|
140
155
|
should 'catch double redirect' do
|
141
|
-
|
142
|
-
|
143
|
-
|
156
|
+
get("#@uri/no_actual_double_redirect")
|
157
|
+
last_response.status.should == 200
|
158
|
+
last_response.body.should == 'no actual double redirect'
|
144
159
|
end
|
145
160
|
end
|