scorched 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/scorched/controller.rb +3 -3
- data/lib/scorched/request.rb +1 -1
- data/lib/scorched/version.rb +1 -1
- data/spec/controller_spec.rb +56 -56
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7f92bebbf77d1dcb97866e21a55223afb5b82999aded99e512a3443c7acd890
|
4
|
+
data.tar.gz: e29a12262a8613ebd390767e00d874d46cbc8bba6543e5369fa217b172d823a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 717a7f99d8120ac394baf59223179a58e24c15336fb6a7fe446b42bd24d780b98429fc7bfa4be264201720cbf99870045ab2b8f6c034f31a925b672f46ddc403
|
7
|
+
data.tar.gz: b1313b2f83893c5ac40e52c861e4b281d0d41e0d904a3d76a88eba3db9f8631944921435e2d14af77aeb9dddd46fad4a47179070d24920cdaad7516076296dac
|
data/lib/scorched/controller.rb
CHANGED
@@ -156,7 +156,7 @@ module Scorched
|
|
156
156
|
else
|
157
157
|
controller = klass
|
158
158
|
end
|
159
|
-
self
|
159
|
+
self.map **{pattern: pattern, target: controller}.merge(mapping)
|
160
160
|
controller
|
161
161
|
end
|
162
162
|
|
@@ -180,7 +180,7 @@ module Scorched
|
|
180
180
|
response
|
181
181
|
end
|
182
182
|
[*pattern].compact.each do |pattern|
|
183
|
-
self
|
183
|
+
self.map pattern: compile(pattern, true), priority: priority, conditions: conds, target: target
|
184
184
|
end
|
185
185
|
target
|
186
186
|
end
|
@@ -466,7 +466,7 @@ module Scorched
|
|
466
466
|
if value.empty?
|
467
467
|
request.cookies[name]
|
468
468
|
else
|
469
|
-
value = Hash === value[0] ? value[0] : {value: value}
|
469
|
+
value = (Hash === value[0]) ? value[0] : {value: value[0]}
|
470
470
|
if value[:value].nil?
|
471
471
|
response.delete_cookie(name, value)
|
472
472
|
else
|
data/lib/scorched/request.rb
CHANGED
@@ -33,7 +33,7 @@ module Scorched
|
|
33
33
|
# The unescaped URL, excluding the escaped forward-slash and percent. The resulting string will always be safe
|
34
34
|
# to unescape again in situations where the forward-slash or percent are expected and valid characters.
|
35
35
|
def unescaped_path
|
36
|
-
path_info.split(/(%25|%2F)/i).each_slice(2).map { |v, m|
|
36
|
+
path_info.split(/(%25|%2F)/i).each_slice(2).map { |v, m| CGI.unescape(v) << (m || '') }.join('')
|
37
37
|
end
|
38
38
|
|
39
39
|
private
|
data/lib/scorched/version.rb
CHANGED
data/spec/controller_spec.rb
CHANGED
@@ -24,13 +24,13 @@ module Scorched
|
|
24
24
|
end
|
25
25
|
|
26
26
|
it "handles a root rack call correctly" do
|
27
|
-
app
|
27
|
+
app.map pattern: '/$', target: generic_handler
|
28
28
|
response = rt.get '/'
|
29
29
|
response.status.should == 200
|
30
30
|
end
|
31
31
|
|
32
32
|
it "does not maintain state between requests" do
|
33
|
-
app
|
33
|
+
app.map pattern: '/state', target: proc { |env| [200, {}, [@state = 1 + @state.to_i]] }
|
34
34
|
response = rt.get '/state'
|
35
35
|
response.body.should == '1'
|
36
36
|
response = rt.get '/state'
|
@@ -39,54 +39,54 @@ module Scorched
|
|
39
39
|
|
40
40
|
it "raises exception when invalid mapping hash given" do
|
41
41
|
expect {
|
42
|
-
app
|
42
|
+
app.map(pattern: '/')
|
43
43
|
}.to raise_error(ArgumentError)
|
44
44
|
expect {
|
45
|
-
app
|
45
|
+
app.map(target: generic_handler)
|
46
46
|
}.to raise_error(ArgumentError)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
describe "URL matching" do
|
51
51
|
it 'always matches from the beginning of the URL' do
|
52
|
-
app
|
52
|
+
app.map pattern: 'about', target: generic_handler
|
53
53
|
response = rt.get '/about'
|
54
54
|
response.status.should == 404
|
55
55
|
end
|
56
56
|
|
57
57
|
it "matches eagerly by default" do
|
58
58
|
req = nil
|
59
|
-
app
|
59
|
+
app.map pattern: '/*', target: proc { |env|
|
60
60
|
req = request; [200, {}, ['ok']]
|
61
|
-
|
61
|
+
}
|
62
62
|
response = rt.get '/about'
|
63
63
|
req.captures.should == ['about']
|
64
64
|
end
|
65
65
|
|
66
66
|
it "can be forced to match end of URL" do
|
67
|
-
app
|
67
|
+
app.map pattern: '/about$', target: generic_handler
|
68
68
|
response = rt.get '/about/us'
|
69
69
|
response.status.should == 404
|
70
|
-
app
|
70
|
+
app.map pattern: '/about', target: generic_handler
|
71
71
|
response = rt.get '/about/us'
|
72
72
|
response.status.should == 200
|
73
73
|
end
|
74
74
|
|
75
75
|
it "unescapes all characters except for the forward-slash and percent sign" do
|
76
|
-
app
|
76
|
+
app.map pattern: '/a (quite) big fish', target: generic_handler
|
77
77
|
rt.get('/a%20%28quite%29%20big%20fish').status.should == 200
|
78
|
-
app
|
78
|
+
app.map pattern: '/article/100%25 big%2Fsmall', target: generic_handler
|
79
79
|
rt.get('/article/100%25%20big%2Fsmall').status.should == 200
|
80
|
-
app
|
80
|
+
app.map pattern: '/*$', target: generic_handler
|
81
81
|
rt.get('/page%2Fabout').status.should == 200
|
82
82
|
rt.get('/page/about').status.should == 404
|
83
83
|
end
|
84
84
|
|
85
85
|
it "unmatched path doesn't always begin with a forward slash" do
|
86
86
|
gh = generic_handler
|
87
|
-
app
|
87
|
+
app.map pattern: '/ab', target: Class.new(Scorched::Controller) {
|
88
88
|
map(pattern: 'out', target: gh)
|
89
|
-
|
89
|
+
}
|
90
90
|
resp = rt.get('/about')
|
91
91
|
resp.status.should == 200
|
92
92
|
resp.body.should == "ok"
|
@@ -94,119 +94,119 @@ module Scorched
|
|
94
94
|
|
95
95
|
it "unmatched path begins with forward slash if last match was up to or included a forward slash" do
|
96
96
|
gh = generic_handler
|
97
|
-
app
|
97
|
+
app.map pattern: '/about/', target: Class.new(Scorched::Controller) {
|
98
98
|
map(pattern: '/us', target: gh)
|
99
|
-
|
100
|
-
app
|
99
|
+
}
|
100
|
+
app.map pattern: '/contact', target: Class.new(Scorched::Controller) {
|
101
101
|
map(pattern: '/us', target: gh)
|
102
|
-
|
102
|
+
}
|
103
103
|
rt.get('/about/us').body.should == "ok"
|
104
104
|
rt.get('/contact/us').body.should == "ok"
|
105
105
|
end
|
106
106
|
|
107
107
|
it "can match anonymous wildcards" do
|
108
108
|
req = nil
|
109
|
-
app
|
109
|
+
app.map pattern: '/anon/*/**', target: proc { |env|
|
110
110
|
req = request; [200, {}, ['ok']]
|
111
|
-
|
111
|
+
}
|
112
112
|
response = rt.get '/anon/jeff/has/crabs'
|
113
113
|
req.captures.should == ['jeff', 'has/crabs']
|
114
114
|
end
|
115
115
|
|
116
116
|
it "can match named wildcards (ignoring anonymous captures)" do
|
117
117
|
req = nil
|
118
|
-
app
|
118
|
+
app.map pattern: '/anon/:name/*/::infliction', target: proc { |env|
|
119
119
|
req = request; [200, {}, ['ok']]
|
120
|
-
|
120
|
+
}
|
121
121
|
response = rt.get '/anon/jeff/smith/has/crabs'
|
122
122
|
req.captures.should == {name: 'jeff', infliction: 'has/crabs'}
|
123
123
|
end
|
124
124
|
|
125
125
|
example "wildcards match one or more characters" do
|
126
|
-
app
|
126
|
+
app.map pattern: '/*', target: proc { |env| [200, {}, ['ok']] }
|
127
127
|
rt.get('/').status.should == 404
|
128
128
|
rt.get('/dog').status.should == 200
|
129
129
|
app.mappings.clear
|
130
|
-
app
|
130
|
+
app.map pattern: '/**', target: proc { |env| [200, {}, ['ok']] }
|
131
131
|
rt.get('/').status.should == 404
|
132
132
|
rt.get('/dog/cat').status.should == 200
|
133
133
|
app.mappings.clear
|
134
|
-
app
|
134
|
+
app.map pattern: '/:page', target: proc { |env| [200, {}, ['ok']] }
|
135
135
|
rt.get('/').status.should == 404
|
136
136
|
rt.get('/dog').status.should == 200
|
137
137
|
app.mappings.clear
|
138
|
-
app
|
138
|
+
app.map pattern: '/::page', target: proc { |env| [200, {}, ['ok']] }
|
139
139
|
rt.get('/').status.should == 404
|
140
140
|
rt.get('/dog/cat').status.should == 200
|
141
141
|
end
|
142
142
|
|
143
143
|
example "wildcards can optionally match zero or more characters" do
|
144
|
-
app
|
144
|
+
app.map pattern: '/*?', target: proc { |env| [200, {}, ['ok']] }
|
145
145
|
rt.get('/').status.should == 200
|
146
146
|
rt.get('/dog').status.should == 200
|
147
147
|
app.mappings.clear
|
148
|
-
app
|
148
|
+
app.map pattern: '/**?', target: proc { |env| [200, {}, ['ok']] }
|
149
149
|
rt.get('/').status.should == 200
|
150
150
|
rt.get('/dog/cat').status.should == 200
|
151
151
|
app.mappings.clear
|
152
|
-
app
|
152
|
+
app.map pattern: '/:page?', target: proc { |env| [200, {}, ['ok']] }
|
153
153
|
rt.get('/').status.should == 200
|
154
154
|
rt.get('/dog').status.should == 200
|
155
155
|
app.mappings.clear
|
156
|
-
app
|
156
|
+
app.map pattern: '/::page?', target: proc { |env| [200, {}, ['ok']] }
|
157
157
|
rt.get('/').status.should == 200
|
158
158
|
rt.get('/dog/cat').status.should == 200
|
159
159
|
end
|
160
160
|
|
161
161
|
it "can match regex and preserve anonymous captures" do
|
162
162
|
req = nil
|
163
|
-
app
|
163
|
+
app.map pattern: %r{/anon/([^/]+)/(.+)}, target: proc { |env|
|
164
164
|
req = request; [200, {}, ['ok']]
|
165
|
-
|
165
|
+
}
|
166
166
|
response = rt.get '/anon/jeff/has/crabs'
|
167
167
|
req.captures.should == ['jeff', 'has/crabs']
|
168
168
|
end
|
169
169
|
|
170
170
|
it "can match regex and preserve named captures (ignoring anonymous captures)" do
|
171
171
|
req = nil
|
172
|
-
app
|
172
|
+
app.map pattern: %r{/anon/(?<name>[^/]+)/([^/]+)/(?<infliction>.+)}, target: proc { |env|
|
173
173
|
req = request; [200, {}, ['ok']]
|
174
|
-
|
174
|
+
}
|
175
175
|
response = rt.get '/anon/jeff/smith/has/crabs'
|
176
176
|
req.captures.should == {name: 'jeff', infliction: 'has/crabs'}
|
177
177
|
end
|
178
178
|
|
179
179
|
it "can use symbol matchers" do
|
180
|
-
app
|
180
|
+
app.map pattern: '/:numeric', target: proc { |env| [200, {}, ['ok']] }
|
181
181
|
rt.get('/45').status.should == 200
|
182
182
|
rt.get('/dog45').status.should == 404
|
183
183
|
req = nil
|
184
|
-
app
|
184
|
+
app.map pattern: '/:alpha_numeric', target: proc { |env| req = request; [200, {}, ['ok']] }
|
185
185
|
rt.get('/dog45').status.should == 200
|
186
186
|
req.captures[:alpha_numeric].should == 'dog45'
|
187
187
|
rt.get('/_dog45').status.should == 404
|
188
188
|
end
|
189
189
|
|
190
190
|
it "can coerce symbol-matched values" do
|
191
|
-
app
|
191
|
+
app.map pattern: '/:numeric', target: proc { |env| [200, {}, [request.captures[:numeric].class.name]] }
|
192
192
|
rt.get('/45').body.should == 'Integer'
|
193
193
|
end
|
194
194
|
|
195
195
|
it "matches routes based on priority, otherwise giving precedence to those defined first" do
|
196
196
|
order = []
|
197
|
-
app
|
198
|
-
app
|
199
|
-
app
|
200
|
-
app
|
197
|
+
app.map pattern: '/', priority: -1, target: proc { |env| order << 'four'; [200, {}, ['ok']] }
|
198
|
+
app.map pattern: '/', target: proc { |env| order << 'two'; throw :pass }
|
199
|
+
app.map pattern: '/', target: proc { |env| order << 'three'; throw :pass }
|
200
|
+
app.map pattern: '/', priority: 2, target: proc { |env| order << 'one'; throw :pass }
|
201
201
|
rt.get('/').body.should == 'ok'
|
202
202
|
order.should == %w{one two three four}
|
203
203
|
end
|
204
204
|
|
205
205
|
it "finds the best match for the media type whilst respecting priority and definition order" do
|
206
|
-
app
|
207
|
-
app
|
208
|
-
app
|
209
|
-
app
|
206
|
+
app.map pattern: '/', target: proc { |env| [200, {}, ['anything']] }
|
207
|
+
app.map pattern: '/', conditions: {media_type: 'application/json'}, target: proc { |env| [200, {}, ['application/json']] }
|
208
|
+
app.map pattern: '/', conditions: {media_type: 'text/html'}, target: proc { |env| [200, {}, ['text/html']] }
|
209
|
+
app.map pattern: '/', priority: 1, target: proc { |env| [200, {}, ['anything_high_priority']] }
|
210
210
|
rt.get('/', {}, 'HTTP_ACCEPT' => 'application/json, */*;q=0.5').body.should == 'anything_high_priority'
|
211
211
|
app.mappings.pop
|
212
212
|
rt.get('/', {}, 'HTTP_ACCEPT' => 'application/json;q=0.5, text/html').body.should == 'text/html'
|
@@ -224,14 +224,14 @@ module Scorched
|
|
224
224
|
end
|
225
225
|
|
226
226
|
it "executes route only if all conditions return true" do
|
227
|
-
app
|
227
|
+
app.map pattern: '/$', conditions: {method: 'POST'}, target: generic_handler
|
228
228
|
response = rt.get "/"
|
229
229
|
response.status.should be_between(400, 499)
|
230
230
|
response = rt.post "/"
|
231
231
|
response.status.should == 200
|
232
232
|
|
233
233
|
app.conditions[:has_name] = proc { |name| request.GET['name'] }
|
234
|
-
app
|
234
|
+
app.map pattern: '/about', conditions: {method: ['GET', 'POST'], has_name: 'Ronald'}, target: generic_handler
|
235
235
|
response = rt.get "/about"
|
236
236
|
response.status.should be_between(400, 499)
|
237
237
|
response = rt.get "/about", name: 'Ronald'
|
@@ -239,21 +239,21 @@ module Scorched
|
|
239
239
|
end
|
240
240
|
|
241
241
|
it "raises exception when condition doesn't exist or is invalid" do
|
242
|
-
app
|
242
|
+
app.map pattern: '/', conditions: {surprise_christmas_turkey: true}, target: generic_handler
|
243
243
|
expect {
|
244
244
|
rt.get "/"
|
245
245
|
}.to raise_error(Scorched::Error)
|
246
246
|
end
|
247
247
|
|
248
248
|
it "falls through to next route when conditions are not met" do
|
249
|
-
app
|
250
|
-
app
|
249
|
+
app.map pattern: '/', conditions: {method: 'POST'}, target: proc { |env| [200, {}, ['post']] }
|
250
|
+
app.map pattern: '/', conditions: {method: 'GET'}, target: proc { |env| [200, {}, ['get']] }
|
251
251
|
rt.get("/").body.should == 'get'
|
252
252
|
rt.post("/").body.should == 'post'
|
253
253
|
end
|
254
254
|
|
255
255
|
it "inverts the conditions if it's referenced with a trailing exclamation mark" do
|
256
|
-
app
|
256
|
+
app.map pattern: '/', conditions: {method!: 'GET'}, target: proc { |env| [200, {}, ['ok']] }
|
257
257
|
rt.get("/").status.should == 405
|
258
258
|
rt.post("/").status.should == 200
|
259
259
|
end
|
@@ -272,7 +272,7 @@ module Scorched
|
|
272
272
|
wrapped_block = app.route(&block)
|
273
273
|
app.mappings.length.should == 0
|
274
274
|
block.should_not == wrapped_block
|
275
|
-
app
|
275
|
+
app.map pattern: '/*', target: wrapped_block
|
276
276
|
rt.get('/turkey').body.should == 'turkey'
|
277
277
|
end
|
278
278
|
|
@@ -319,9 +319,9 @@ module Scorched
|
|
319
319
|
|
320
320
|
describe "sub-controllers" do
|
321
321
|
it "should ignore the already matched portions of the path" do
|
322
|
-
app
|
322
|
+
app.map pattern: '/article', target: Class.new(Scorched::Controller) {
|
323
323
|
get('/*') { |title| title }
|
324
|
-
|
324
|
+
}
|
325
325
|
rt.get('/article/hello-world').body.should == 'hello-world'
|
326
326
|
end
|
327
327
|
|
@@ -916,7 +916,7 @@ module Scorched
|
|
916
916
|
get('/hello') { 'hello' }
|
917
917
|
after { response.status = 600 }
|
918
918
|
end
|
919
|
-
app
|
919
|
+
app.map pattern: '/', target: sub
|
920
920
|
app.get('/') { 'ok' }
|
921
921
|
rt.get('/').body.should == 'ok'
|
922
922
|
rt.get('/').status.should == 200
|
@@ -1096,7 +1096,7 @@ module Scorched
|
|
1096
1096
|
render(:'main.erb').should == "3 for me"
|
1097
1097
|
end
|
1098
1098
|
app.get('/full_path') do
|
1099
|
-
render(:'views/main.erb', {layout: :'views/layout.erb', dir: nil}).should == "(3 for me)"
|
1099
|
+
render(:'views/main.erb', **{layout: :'views/layout.erb', dir: nil}).should == "(3 for me)"
|
1100
1100
|
end
|
1101
1101
|
app.render_defaults[:dir] = 'views'
|
1102
1102
|
rt.get('/')
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scorched
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Wardrop
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -190,8 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
190
|
- !ruby/object:Gem::Version
|
191
191
|
version: '0'
|
192
192
|
requirements: []
|
193
|
-
|
194
|
-
rubygems_version: 2.7.7
|
193
|
+
rubygems_version: 3.1.2
|
195
194
|
signing_key:
|
196
195
|
specification_version: 4
|
197
196
|
summary: Light-weight, DRY as a desert, web framework for Ruby
|