webmachine 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +13 -11
- data/README.md +85 -89
- data/Rakefile +0 -1
- data/documentation/adapters.md +39 -0
- data/documentation/authentication-and-authorization.md +37 -0
- data/documentation/configurator.md +19 -0
- data/documentation/error-handling.md +86 -0
- data/documentation/examples.md +215 -0
- data/documentation/how-it-works.md +76 -0
- data/documentation/routes.md +97 -0
- data/documentation/validation.md +159 -0
- data/documentation/versioning-apis.md +74 -0
- data/documentation/visual-debugger.md +38 -0
- data/examples/application.rb +2 -2
- data/examples/debugger.rb +1 -1
- data/lib/webmachine.rb +3 -1
- data/lib/webmachine/adapter.rb +7 -13
- data/lib/webmachine/adapters.rb +1 -2
- data/lib/webmachine/adapters/httpkit.rb +74 -0
- data/lib/webmachine/adapters/lazy_request_body.rb +1 -2
- data/lib/webmachine/adapters/rack.rb +37 -21
- data/lib/webmachine/adapters/reel.rb +21 -23
- data/lib/webmachine/adapters/webrick.rb +16 -16
- data/lib/webmachine/application.rb +2 -2
- data/lib/webmachine/chunked_body.rb +3 -4
- data/lib/webmachine/constants.rb +75 -0
- data/lib/webmachine/decision/conneg.rb +12 -10
- data/lib/webmachine/decision/flow.rb +31 -21
- data/lib/webmachine/decision/fsm.rb +10 -18
- data/lib/webmachine/decision/helpers.rb +9 -37
- data/lib/webmachine/dispatcher.rb +13 -10
- data/lib/webmachine/dispatcher/route.rb +18 -8
- data/lib/webmachine/errors.rb +7 -1
- data/lib/webmachine/header_negotiation.rb +25 -0
- data/lib/webmachine/headers.rb +7 -2
- data/lib/webmachine/locale/en.yml +7 -5
- data/lib/webmachine/media_type.rb +10 -8
- data/lib/webmachine/request.rb +44 -15
- data/lib/webmachine/resource.rb +1 -1
- data/lib/webmachine/resource/callbacks.rb +6 -4
- data/lib/webmachine/spec/IO_response.body +1 -0
- data/lib/webmachine/spec/adapter_lint.rb +70 -36
- data/lib/webmachine/spec/test_resource.rb +10 -4
- data/lib/webmachine/streaming/fiber_encoder.rb +1 -5
- data/lib/webmachine/streaming/io_encoder.rb +6 -0
- data/lib/webmachine/trace.rb +1 -0
- data/lib/webmachine/trace/fsm.rb +20 -10
- data/lib/webmachine/trace/resource_proxy.rb +2 -0
- data/lib/webmachine/translation.rb +2 -1
- data/lib/webmachine/version.rb +3 -3
- data/memory_test.rb +37 -0
- data/spec/spec_helper.rb +9 -9
- data/spec/webmachine/adapter_spec.rb +14 -15
- data/spec/webmachine/adapters/httpkit_spec.rb +10 -0
- data/spec/webmachine/adapters/rack_spec.rb +6 -6
- data/spec/webmachine/adapters/reel_spec.rb +15 -11
- data/spec/webmachine/adapters/webrick_spec.rb +2 -2
- data/spec/webmachine/application_spec.rb +18 -17
- data/spec/webmachine/chunked_body_spec.rb +3 -3
- data/spec/webmachine/configuration_spec.rb +5 -5
- data/spec/webmachine/cookie_spec.rb +13 -13
- data/spec/webmachine/decision/conneg_spec.rb +48 -42
- data/spec/webmachine/decision/falsey_spec.rb +4 -4
- data/spec/webmachine/decision/flow_spec.rb +194 -144
- data/spec/webmachine/decision/fsm_spec.rb +17 -17
- data/spec/webmachine/decision/helpers_spec.rb +20 -20
- data/spec/webmachine/dispatcher/route_spec.rb +73 -27
- data/spec/webmachine/dispatcher_spec.rb +34 -24
- data/spec/webmachine/errors_spec.rb +1 -1
- data/spec/webmachine/etags_spec.rb +19 -19
- data/spec/webmachine/events_spec.rb +6 -6
- data/spec/webmachine/headers_spec.rb +14 -14
- data/spec/webmachine/media_type_spec.rb +36 -36
- data/spec/webmachine/request_spec.rb +33 -33
- data/spec/webmachine/resource/authentication_spec.rb +6 -6
- data/spec/webmachine/response_spec.rb +12 -12
- data/spec/webmachine/trace/fsm_spec.rb +8 -8
- data/spec/webmachine/trace/resource_proxy_spec.rb +9 -9
- data/spec/webmachine/trace/trace_store_spec.rb +5 -5
- data/spec/webmachine/trace_spec.rb +3 -3
- data/webmachine.gemspec +2 -6
- metadata +48 -206
- data/lib/webmachine/adapters/hatetepe.rb +0 -108
- data/lib/webmachine/adapters/mongrel.rb +0 -127
- data/lib/webmachine/dispatcher/not_found_resource.rb +0 -5
- data/lib/webmachine/fiber18.rb +0 -88
- data/spec/webmachine/adapters/hatetepe_spec.rb +0 -60
- data/spec/webmachine/adapters/mongrel_spec.rb +0 -16
@@ -6,63 +6,63 @@ describe Webmachine::Decision::FSM do
|
|
6
6
|
subject { described_class.new(resource, request, response) }
|
7
7
|
|
8
8
|
describe 'handling of exceptions from decision methods' do
|
9
|
-
let(:exception) {
|
9
|
+
let(:exception) { RuntimeError.new }
|
10
10
|
|
11
11
|
before do
|
12
|
-
subject.
|
12
|
+
allow(subject).to receive(Webmachine::Decision::Flow::START) { raise exception }
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'calls resource.handle_exception' do
|
16
|
-
resource.
|
16
|
+
expect(resource).to receive(:handle_exception).with(exception)
|
17
17
|
subject.run
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'calls resource.finish_request' do
|
21
|
-
resource.
|
21
|
+
expect(resource).to receive(:finish_request)
|
22
22
|
subject.run
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
describe 'handling of exceptions from resource.handle_exception' do
|
27
|
-
let(:exception) {
|
27
|
+
let(:exception) { RuntimeError.new('an error message') }
|
28
28
|
|
29
29
|
before do
|
30
|
-
subject.
|
31
|
-
resource.
|
30
|
+
allow(subject).to receive(Webmachine::Decision::Flow::START) { raise }
|
31
|
+
allow(resource).to receive(:handle_exception) { raise exception }
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'does not call resource.handle_exception again' do
|
35
|
-
resource.
|
35
|
+
expect(resource).to receive(:handle_exception).once { raise }
|
36
36
|
subject.run
|
37
37
|
end
|
38
38
|
|
39
39
|
it 'does not call resource.finish_request' do
|
40
|
-
resource.
|
40
|
+
expect(resource).not_to receive(:finish_request)
|
41
41
|
subject.run
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'renders an error' do
|
45
|
-
Webmachine.
|
46
|
-
|
45
|
+
expect(Webmachine).
|
46
|
+
to receive(:render_error).
|
47
47
|
with(500, request, response, { :message => exception.message })
|
48
48
|
subject.run
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
52
|
describe 'handling of exceptions from resource.finish_request' do
|
53
|
-
let(:exception) {
|
53
|
+
let(:exception) { RuntimeError.new }
|
54
54
|
|
55
55
|
before do
|
56
|
-
resource.
|
56
|
+
allow(resource).to receive(:finish_request) { raise exception }
|
57
57
|
end
|
58
58
|
|
59
59
|
it 'calls resource.handle_exception' do
|
60
|
-
resource.
|
60
|
+
expect(resource).to receive(:handle_exception).with(exception)
|
61
61
|
subject.run
|
62
62
|
end
|
63
63
|
|
64
64
|
it 'does not call resource.finish_request again' do
|
65
|
-
resource.
|
65
|
+
expect(resource).to receive(:finish_request).once { raise }
|
66
66
|
subject.run
|
67
67
|
end
|
68
68
|
end
|
@@ -84,7 +84,7 @@ describe Webmachine::Decision::FSM do
|
|
84
84
|
|
85
85
|
subject.run
|
86
86
|
|
87
|
-
resource_class.current_response_code.
|
87
|
+
expect(resource_class.current_response_code).to be(201)
|
88
88
|
end
|
89
89
|
|
90
90
|
it 'respects a response code set by resource.finish_request' do
|
@@ -96,6 +96,6 @@ describe Webmachine::Decision::FSM do
|
|
96
96
|
|
97
97
|
subject.run
|
98
98
|
|
99
|
-
response.code.
|
99
|
+
expect(response.code).to be(451)
|
100
100
|
end
|
101
101
|
end
|
@@ -29,20 +29,20 @@ describe Webmachine::Decision::Helpers do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should return 415 when no types are accepted" do
|
32
|
-
subject.accept_helper.
|
32
|
+
expect(subject.accept_helper).to eq 415
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should return 415 when the posted type is not acceptable" do
|
36
36
|
resource.accepted = %W{application/json}
|
37
37
|
headers['Content-Type'] = "text/xml"
|
38
|
-
subject.accept_helper.
|
38
|
+
expect(subject.accept_helper).to eq 415
|
39
39
|
end
|
40
40
|
|
41
41
|
it "should call the method for the first acceptable type, taking into account params" do
|
42
42
|
resource.accepted = ["application/json;v=3", ["application/json", :other]]
|
43
|
-
resource.
|
43
|
+
expect(resource).to receive(:other).and_return(true)
|
44
44
|
headers['Content-Type'] = 'application/json;v=2'
|
45
|
-
subject.accept_helper.
|
45
|
+
expect(subject.accept_helper).to be(true)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -52,7 +52,7 @@ describe Webmachine::Decision::Helpers do
|
|
52
52
|
response.headers['Content-Length'] = '0'
|
53
53
|
response.body = nil
|
54
54
|
subject.send :respond, code
|
55
|
-
response.headers.
|
55
|
+
expect(response.headers).to_not include 'Content-Length'
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -65,7 +65,7 @@ describe Webmachine::Decision::Helpers do
|
|
65
65
|
response.code = code
|
66
66
|
response.body = nil
|
67
67
|
subject.send :respond, code
|
68
|
-
response.headers['Content-Length'].
|
68
|
+
expect(response.headers['Content-Length']).to eq '0'
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
@@ -76,7 +76,7 @@ describe Webmachine::Decision::Helpers do
|
|
76
76
|
response.headers['Transfer-Encoding'] = 'chunked'
|
77
77
|
response.body = []
|
78
78
|
subject.send :respond, code
|
79
|
-
response.headers.
|
79
|
+
expect(response.headers).to_not include 'Content-Length'
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|
@@ -89,24 +89,24 @@ describe Webmachine::Decision::Helpers do
|
|
89
89
|
|
90
90
|
it "does not modify the response body" do
|
91
91
|
subject.encode_body
|
92
|
-
|
92
|
+
expect(response.body).to be_instance_of(String)
|
93
93
|
end
|
94
94
|
|
95
95
|
it "sets the Content-Length header in the response" do
|
96
96
|
subject.encode_body
|
97
|
-
response.headers['Content-Length'].
|
97
|
+
expect(response.headers['Content-Length']).to eq response.body.bytesize.to_s
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
101
|
shared_examples_for "a non-String body" do
|
102
102
|
it "does not set the Content-Length header in the response" do
|
103
103
|
subject.encode_body
|
104
|
-
response.headers.
|
104
|
+
expect(response.headers).to_not have_key('Content-Length')
|
105
105
|
end
|
106
106
|
|
107
107
|
it "sets the Transfer-Encoding response header to chunked" do
|
108
108
|
subject.encode_body
|
109
|
-
response.headers['Transfer-Encoding'].
|
109
|
+
expect(response.headers['Transfer-Encoding']).to eq 'chunked'
|
110
110
|
end
|
111
111
|
end
|
112
112
|
|
@@ -115,7 +115,7 @@ describe Webmachine::Decision::Helpers do
|
|
115
115
|
|
116
116
|
it "wraps the response body in an EnumerableEncoder" do
|
117
117
|
subject.encode_body
|
118
|
-
Webmachine::Streaming::EnumerableEncoder
|
118
|
+
expect(response.body).to be_instance_of(Webmachine::Streaming::EnumerableEncoder)
|
119
119
|
end
|
120
120
|
|
121
121
|
it_should_behave_like "a non-String body"
|
@@ -126,7 +126,7 @@ describe Webmachine::Decision::Helpers do
|
|
126
126
|
|
127
127
|
it "wraps the response body in a CallableEncoder" do
|
128
128
|
subject.encode_body
|
129
|
-
Webmachine::Streaming::CallableEncoder
|
129
|
+
expect(response.body).to be_instance_of(Webmachine::Streaming::CallableEncoder)
|
130
130
|
end
|
131
131
|
|
132
132
|
it_should_behave_like "a non-String body"
|
@@ -137,7 +137,7 @@ describe Webmachine::Decision::Helpers do
|
|
137
137
|
|
138
138
|
it "wraps the response body in a FiberEncoder" do
|
139
139
|
subject.encode_body
|
140
|
-
Webmachine::Streaming::FiberEncoder
|
140
|
+
expect(response.body).to be_instance_of(Webmachine::Streaming::FiberEncoder)
|
141
141
|
end
|
142
142
|
|
143
143
|
it_should_behave_like "a non-String body"
|
@@ -148,22 +148,22 @@ describe Webmachine::Decision::Helpers do
|
|
148
148
|
|
149
149
|
it "wraps the response body in an IOEncoder" do
|
150
150
|
subject.encode_body
|
151
|
-
Webmachine::Streaming::IOEncoder
|
151
|
+
expect(response.body).to be_instance_of(Webmachine::Streaming::IOEncoder)
|
152
152
|
end
|
153
153
|
|
154
154
|
it "sets the Content-Length header to the size of the file" do
|
155
155
|
subject.encode_body
|
156
|
-
response.headers['Content-Length'].
|
156
|
+
expect(response.headers['Content-Length']).to eq File.stat('spec/spec_helper.rb').size.to_s
|
157
157
|
end
|
158
158
|
|
159
159
|
it "progressively yields file contents for each enumeration" do
|
160
160
|
subject.encode_body
|
161
161
|
body_size = 0
|
162
162
|
response.body.each do |chunk|
|
163
|
-
chunk.
|
163
|
+
expect(chunk).to be_instance_of(String)
|
164
164
|
body_size += chunk.length
|
165
165
|
end
|
166
|
-
body_size.
|
166
|
+
expect(body_size).to eq File.stat('spec/spec_helper.rb').size
|
167
167
|
end
|
168
168
|
|
169
169
|
context "when the resource provides a non-identity encoding that the client accepts" do
|
@@ -188,12 +188,12 @@ describe Webmachine::Decision::Helpers do
|
|
188
188
|
|
189
189
|
it "wraps the response body in an IOEncoder" do
|
190
190
|
subject.encode_body
|
191
|
-
Webmachine::Streaming::IOEncoder
|
191
|
+
expect(response.body).to be_instance_of(Webmachine::Streaming::IOEncoder)
|
192
192
|
end
|
193
193
|
|
194
194
|
it "sets the Content-Length header to the size of the string" do
|
195
195
|
subject.encode_body
|
196
|
-
response.headers['Content-Length'].
|
196
|
+
expect(response.headers['Content-Length']).to eq response.body.size.to_s
|
197
197
|
end
|
198
198
|
|
199
199
|
context "when the resource provides a non-identity encoding that the client accepts" do
|
@@ -1,11 +1,32 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
Webmachine::Dispatcher::Route.class_eval do
|
4
|
+
def warn(*msgs); end # silence warnings for tests
|
5
|
+
end
|
6
|
+
|
3
7
|
describe Webmachine::Dispatcher::Route do
|
4
8
|
let(:method) { "GET" }
|
5
9
|
let(:uri) { URI.parse("http://localhost:8080/") }
|
6
10
|
let(:request){ Webmachine::Request.new(method, uri, Webmachine::Headers.new, "") }
|
7
11
|
let(:resource){ Class.new(Webmachine::Resource) }
|
8
12
|
|
13
|
+
describe '#apply' do
|
14
|
+
let(:route) {
|
15
|
+
Webmachine::Dispatcher::Route.new ['hello', :string], resource, {}
|
16
|
+
}
|
17
|
+
|
18
|
+
describe 'a path_info fragment' do
|
19
|
+
before do
|
20
|
+
uri.path = '/hello/planet%20earth%20++'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should decode the value' do
|
24
|
+
route.apply(request)
|
25
|
+
expect(request.path_info).to eq({:string => 'planet earth ++'})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
9
30
|
matcher :match_route do |*expected|
|
10
31
|
route = Webmachine::Dispatcher::Route.new(expected[0], Class.new(Webmachine::Resource), expected[1] || {})
|
11
32
|
match do |actual|
|
@@ -13,31 +34,40 @@ describe Webmachine::Dispatcher::Route do
|
|
13
34
|
route.match?(request)
|
14
35
|
end
|
15
36
|
|
16
|
-
|
37
|
+
failure_message do |_|
|
17
38
|
"expected route #{expected[0].inspect} to match path #{request.uri.path}"
|
18
39
|
end
|
19
|
-
|
40
|
+
failure_message_when_negated do |_|
|
20
41
|
"expected route #{expected[0].inspect} not to match path #{request.uri.path}"
|
21
42
|
end
|
22
43
|
end
|
23
44
|
|
45
|
+
it "warns about the deprecated string splat when initializing" do
|
46
|
+
[["*"],["foo", "*"],["foo", :bar, "*"]].each do |path|
|
47
|
+
route = described_class.allocate
|
48
|
+
expect(route).to receive(:warn)
|
49
|
+
route.send :initialize, path, resource, {}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
24
53
|
context "matching a request" do
|
25
54
|
context "on the root path" do
|
26
55
|
subject { "/" }
|
27
|
-
it {
|
28
|
-
it {
|
29
|
-
it {
|
30
|
-
it {
|
56
|
+
it { is_expected.to match_route([]) }
|
57
|
+
it { is_expected.to match_route ['*'] }
|
58
|
+
it { is_expected.to match_route [:*] }
|
59
|
+
it { is_expected.not_to match_route %w{foo} }
|
60
|
+
it { is_expected.not_to match_route [:id] }
|
31
61
|
end
|
32
62
|
|
33
63
|
context "on a deep path" do
|
34
64
|
subject { "/foo/bar/baz" }
|
35
|
-
it {
|
36
|
-
it {
|
37
|
-
it {
|
38
|
-
it {
|
39
|
-
it {
|
40
|
-
it {
|
65
|
+
it { is_expected.to match_route %w{foo bar baz} }
|
66
|
+
it { is_expected.to match_route ['foo', :id, "baz"] }
|
67
|
+
it { is_expected.to match_route ['foo', :*] }
|
68
|
+
it { is_expected.to match_route [:id, :*] }
|
69
|
+
it { is_expected.not_to match_route [] }
|
70
|
+
it { is_expected.not_to match_route ['bar', :*] }
|
41
71
|
end
|
42
72
|
|
43
73
|
context "with a guard on the request method" do
|
@@ -53,17 +83,17 @@ describe Webmachine::Dispatcher::Route do
|
|
53
83
|
|
54
84
|
context "when guard passes" do
|
55
85
|
let(:method){ "POST" }
|
56
|
-
it {
|
86
|
+
it { is_expected.to be_match(request) }
|
57
87
|
|
58
88
|
context "but the path match fails" do
|
59
89
|
let(:uri){ URI.parse("http://localhost:8080/other") }
|
60
|
-
it {
|
90
|
+
it { is_expected.not_to be_match(request) }
|
61
91
|
end
|
62
92
|
end
|
63
93
|
|
64
94
|
context "when guard fails" do
|
65
95
|
let(:method) { "GET" }
|
66
|
-
it {
|
96
|
+
it { is_expected.not_to be_match(request) }
|
67
97
|
end
|
68
98
|
|
69
99
|
context "when the guard responds to #call" do
|
@@ -85,12 +115,12 @@ describe Webmachine::Dispatcher::Route do
|
|
85
115
|
|
86
116
|
context "when the guard passes" do
|
87
117
|
let(:method){ "POST" }
|
88
|
-
it {
|
118
|
+
it { is_expected.to be_match(request) }
|
89
119
|
end
|
90
120
|
|
91
121
|
context "when the guard fails" do
|
92
122
|
# let(:method){ "GET" }
|
93
|
-
it {
|
123
|
+
it { is_expected.not_to be_match(request) }
|
94
124
|
end
|
95
125
|
end
|
96
126
|
end
|
@@ -102,30 +132,38 @@ describe Webmachine::Dispatcher::Route do
|
|
102
132
|
before { subject.apply(request) }
|
103
133
|
|
104
134
|
it "should assign the dispatched path to the empty string" do
|
105
|
-
request.disp_path.
|
135
|
+
expect(request.disp_path).to eq("")
|
106
136
|
end
|
107
137
|
|
108
138
|
it "should assign empty bindings" do
|
109
|
-
request.path_info.
|
139
|
+
expect(request.path_info).to eq({})
|
110
140
|
end
|
111
141
|
|
112
142
|
it "should assign empty path tokens" do
|
113
|
-
request.path_tokens.
|
143
|
+
expect(request.path_tokens).to eq([])
|
114
144
|
end
|
115
145
|
|
116
146
|
context "with extra user-defined bindings" do
|
117
147
|
subject { described_class.new([], resource, "bar" => "baz") }
|
118
148
|
|
119
149
|
it "should assign the user-defined bindings" do
|
120
|
-
request.path_info.
|
150
|
+
expect(request.path_info).to eq({"bar" => "baz"})
|
121
151
|
end
|
122
152
|
end
|
123
153
|
|
124
154
|
context "with a splat" do
|
155
|
+
subject { described_class.new([:*], resource) }
|
156
|
+
|
157
|
+
it "should assign empty path tokens" do
|
158
|
+
expect(request.path_tokens).to eq([])
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context "with a deprecated splat string" do
|
125
163
|
subject { described_class.new(['*'], resource) }
|
126
164
|
|
127
165
|
it "should assign empty path tokens" do
|
128
|
-
request.path_tokens.
|
166
|
+
expect(request.path_tokens).to eq([])
|
129
167
|
end
|
130
168
|
end
|
131
169
|
end
|
@@ -135,30 +173,38 @@ describe Webmachine::Dispatcher::Route do
|
|
135
173
|
before { request.uri.path = "/foo/bar/baz"; subject.apply(request) }
|
136
174
|
|
137
175
|
it "should assign the dispatched path as the path past the initial slash" do
|
138
|
-
request.disp_path.
|
176
|
+
expect(request.disp_path).to eq("foo/bar/baz")
|
139
177
|
end
|
140
178
|
|
141
179
|
it "should assign empty bindings" do
|
142
|
-
request.path_info.
|
180
|
+
expect(request.path_info).to eq({})
|
143
181
|
end
|
144
182
|
|
145
183
|
it "should assign empty path tokens" do
|
146
|
-
request.path_tokens.
|
184
|
+
expect(request.path_tokens).to eq([])
|
147
185
|
end
|
148
186
|
|
149
187
|
context "with path variables" do
|
150
188
|
subject { described_class.new(['foo', :id, 'baz'], resource) }
|
151
189
|
|
152
190
|
it "should assign the path variables in the bindings" do
|
153
|
-
request.path_info.
|
191
|
+
expect(request.path_info).to eq({:id => "bar"})
|
154
192
|
end
|
155
193
|
end
|
156
194
|
|
157
195
|
context "with a splat" do
|
196
|
+
subject { described_class.new(['foo', :*], resource) }
|
197
|
+
|
198
|
+
it "should capture the path tokens matched by the splat" do
|
199
|
+
expect(request.path_tokens).to eq(%w{ bar baz })
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
context "with a deprecated splat string" do
|
158
204
|
subject { described_class.new(%w{foo *}, resource) }
|
159
205
|
|
160
206
|
it "should capture the path tokens matched by the splat" do
|
161
|
-
request.path_tokens.
|
207
|
+
expect(request.path_tokens).to eq(%w{ bar baz })
|
162
208
|
end
|
163
209
|
end
|
164
210
|
end
|
@@ -14,66 +14,76 @@ describe Webmachine::Dispatcher do
|
|
14
14
|
def to_html; "goodbye, cruel world"; end
|
15
15
|
end
|
16
16
|
end
|
17
|
-
let(:fsm){
|
17
|
+
let(:fsm){ double }
|
18
18
|
|
19
19
|
before { dispatcher.reset }
|
20
20
|
|
21
21
|
it "should add routes from a block" do
|
22
22
|
_resource = resource
|
23
|
-
Webmachine.routes do
|
24
|
-
add [
|
25
|
-
end.
|
26
|
-
dispatcher.routes.
|
23
|
+
expect(Webmachine.routes do
|
24
|
+
add [:*], _resource
|
25
|
+
end).to eq(Webmachine)
|
26
|
+
expect(dispatcher.routes.size).to eq(1)
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should add routes" do
|
30
30
|
expect {
|
31
|
-
dispatcher.add_route [
|
31
|
+
dispatcher.add_route [:*], resource
|
32
32
|
}.to_not raise_error
|
33
33
|
end
|
34
34
|
|
35
35
|
it "should have add_route return the newly created route" do
|
36
|
-
route = dispatcher.add_route [
|
37
|
-
route.
|
36
|
+
route = dispatcher.add_route [:*], resource
|
37
|
+
expect(route).to be_instance_of Webmachine::Dispatcher::Route
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should route to the proper resource" do
|
41
41
|
dispatcher.add_route ["goodbye"], resource2
|
42
|
-
dispatcher.add_route [
|
43
|
-
Webmachine::Decision::FSM.
|
44
|
-
fsm.
|
42
|
+
dispatcher.add_route [:*], resource
|
43
|
+
expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource), request, response).and_return(fsm)
|
44
|
+
expect(fsm).to receive(:run)
|
45
45
|
dispatcher.dispatch(request, response)
|
46
46
|
end
|
47
47
|
|
48
48
|
it "should apply route to request before creating the resource" do
|
49
|
-
route = dispatcher.add_route [
|
49
|
+
route = dispatcher.add_route [:*], resource
|
50
50
|
applied = false
|
51
51
|
|
52
|
-
route.
|
53
|
-
resource.
|
54
|
-
applied.
|
52
|
+
expect(route).to receive(:apply) { applied = true }
|
53
|
+
expect(resource).to(receive(:new) do
|
54
|
+
expect(applied).to be(true)
|
55
55
|
resource2.new(request, response)
|
56
|
-
end
|
56
|
+
end)
|
57
57
|
|
58
58
|
dispatcher.dispatch(request, response)
|
59
59
|
end
|
60
60
|
|
61
61
|
it "should add routes with guards" do
|
62
62
|
dispatcher.add [], lambda {|req| req.method == "POST" }, resource
|
63
|
-
dispatcher.add [
|
63
|
+
dispatcher.add [:*], resource2 do |req|
|
64
64
|
!req.query.empty?
|
65
65
|
end
|
66
66
|
request.uri.query = "?foo=bar"
|
67
|
-
dispatcher.routes.
|
68
|
-
Webmachine::Decision::FSM.
|
69
|
-
fsm.
|
67
|
+
expect(dispatcher.routes.size).to eq(2)
|
68
|
+
expect(Webmachine::Decision::FSM).to receive(:new).with(instance_of(resource2), request, response).and_return(fsm)
|
69
|
+
expect(fsm).to receive(:run)
|
70
|
+
dispatcher.dispatch(request, response)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should respond with a valid resource for a 404" do
|
70
74
|
dispatcher.dispatch(request, response)
|
75
|
+
expect(response.code).to eq(404)
|
76
|
+
expect(response.body).to_not be_empty
|
77
|
+
expect(response.headers).to have_key('Content-Length')
|
78
|
+
expect(response.headers).to have_key('Date')
|
71
79
|
end
|
72
80
|
|
73
|
-
it "should respond with valid resource
|
81
|
+
it "should respond with a valid resource for a 404 with a custom Accept header" do
|
82
|
+
request.headers['Accept'] = "application/json"
|
74
83
|
dispatcher.dispatch(request, response)
|
75
|
-
response.code.
|
76
|
-
response.body.
|
77
|
-
response.headers.
|
84
|
+
expect(response.code).to eq(404)
|
85
|
+
expect(response.body).to_not be_empty
|
86
|
+
expect(response.headers).to have_key('Content-Length')
|
87
|
+
expect(response.headers).to have_key('Date')
|
78
88
|
end
|
79
89
|
end
|