scorched 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|