scorched 0.16 → 0.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4f2b6b091aaaea15a4bd11fbcc7d70fc27e783d1
4
- data.tar.gz: db2e3b73d7b0f2aa82472f90299915cdfa3e2c4a
3
+ metadata.gz: 5ad267343b4c7040dda32f6c394418bf9494dbcf
4
+ data.tar.gz: e8161cbafa5becf64f73ee970ac247a2ed43ef5f
5
5
  SHA512:
6
- metadata.gz: e937339dd3d1470e201050a395d68f4cf3635c355683c5fee6a4570cc12044e7f584dd57bed84fb01c89ac3cc89ac73f026a1b88cd9dc06dd08fdd79bdf748d7
7
- data.tar.gz: 3fb1e340771264fe6738d6ea030e0387cea91fc716fa6b651883194973b12b498dd7b0bee27a6994d64ea126a936c47da057fc45f8f6698793fad553685c58b5
6
+ metadata.gz: d8184c8ba998ffc82d2292b089fccbb0ce60e9e6c89e35679b0e8a14121ff3da46ad338cb33296b0139a98ba4fe226228d83387f34f1f424567f8620c26a1278
7
+ data.tar.gz: 723fd6f62103871197a99b39912677ebff7c4bc77d1e3cf707efc842e948da8c79aa4c8806cefe0cdc88d843c6aa9df89ea4e804bb54cf5e54f0c786606db194
data/CHANGES.md CHANGED
@@ -1,6 +1,11 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ### v0.17
5
+ * Fixes an issue introduced in v0.16 where joining `SCRIPT_NAME` and `PATH_INFO` would sometimes produce a path with two forward slashes, and a related issue where `PATH_INFO` would sometimes be missing a leading forward slash when it should have had one.
6
+ * Mappings are now sorted by the best matching `media type` in addition to the existing logic that included definition order and priority. This required that mappings be sorted at request-time rather than at the time they're mapped. Note, because of limitations of `rack-accept`, this doesn't completely respect the HTTP spec when it comes to prioritising which media type to serve for a given request. Full support for the HTTP spec is intended for a future release.
7
+ * File path references to views are now joined to the view directory using #expand_path. This allows views to be specified with an absolute path (effectively ignoring the view directory), and better support for relative paths.
8
+
4
9
  ### v0.16
5
10
  * A copy of the Rack env hash is now handed off to sub-controllers and other Rack-callable objects, with `PATH_INFO` and `SCRIPT_NAME` now set to appropriate values, bring Scorched inline with the Rack specification. This differs from the original behaviour which was to just forward on the original env hash unmodified.
6
11
  * URL helper method `absolute` and `url` now use the new env property `scorched.root_path` as their base path, rather than `SCRIPT_NAME`.
@@ -72,7 +72,7 @@ module Scorched
72
72
  handled: proc { |bool|
73
73
  @_handled == bool
74
74
  },
75
- proc: proc { |*blocks|
75
+ proc: proc { |blocks|
76
76
  [*blocks].all? { |b| instance_exec(&b) }
77
77
  },
78
78
  user_agent: proc { |user_agent|
@@ -127,14 +127,12 @@ module Scorched
127
127
  # Raises ArgumentError if required key values are not provided.
128
128
  def map(pattern: nil, priority: nil, conditions: {}, target: nil)
129
129
  raise ArgumentError, "Mapping must specify url pattern and target" unless pattern && target
130
- priority = priority.to_i
131
- insert_pos = mappings.take_while { |v| priority <= v[:priority] }.length
132
- mappings.insert(insert_pos, {
130
+ mappings << {
133
131
  pattern: compile(pattern),
134
- priority: priority,
132
+ priority: priority.to_i,
135
133
  conditions: conditions,
136
134
  target: target
137
- })
135
+ }
138
136
  end
139
137
  alias :<< :map
140
138
 
@@ -242,8 +240,6 @@ module Scorched
242
240
  env
243
241
  end
244
242
  env['scorched.root_path'] ||= env['SCRIPT_NAME']
245
- env['scorched.path_info'] ||= env['PATH_INFO']
246
- env['scorched.script_name'] ||= env['SCRIPT_NAME']
247
243
  @request = Request.new(env)
248
244
  @response = Response.new
249
245
  end
@@ -267,7 +263,16 @@ module Scorched
267
263
  pass if config[:auto_pass] && eligable_matches.empty?
268
264
  run_filters(:before)
269
265
  begin
270
- eligable_matches.each { |match|
266
+ # Re-order matches based on media_type, ensuring priority and definition order are respected appropriately.
267
+ eligable_matches.each_with_index.sort_by { |m,idx|
268
+ [
269
+ m.mapping[:priority] || 0,
270
+ [*m.mapping[:conditions][:media_type]].map { |type|
271
+ env['rack-accept.request'].media_type.qvalue(type)
272
+ }.max || 0,
273
+ -idx
274
+ ]
275
+ }.reverse.each { |match,|
271
276
  request.breadcrumb << match
272
277
  break if catch(:pass) {
273
278
  target = match.mapping[:target]
@@ -276,8 +281,8 @@ module Scorched
276
281
  instance_exec(&target)
277
282
  else
278
283
  target.call(env.merge(
279
- 'SCRIPT_NAME' => request.matched_path,
280
- 'PATH_INFO' => request.unmatched_path[match.path.length..-1]
284
+ 'SCRIPT_NAME' => request.matched_path.chomp('/'),
285
+ 'PATH_INFO' => request.unmatched_path[match.path.chomp('/').length..-1]
281
286
  ))
282
287
  end
283
288
  end
@@ -431,7 +436,7 @@ module Scorched
431
436
  template = if Symbol === string_or_file
432
437
  file = string_or_file.to_s
433
438
  file = file << ".#{engine}" unless derived_engine
434
- file = File.join(dir, file) if dir
439
+ file = File.expand_path(file, dir) if dir
435
440
  # Tilt still has unresolved file encoding issues. Until that's fixed, we read the file manually.
436
441
  template_cache.fetch(:file, tilt_engine, file, tilt_options) do
437
442
  tilt_engine.new(file, nil, tilt_options)
@@ -5,7 +5,7 @@ module Scorched
5
5
  # Keeps track of the matched URL portions and what object handled them. Useful for debugging and building
6
6
  # breadcrumb navigation.
7
7
  def breadcrumb
8
- env['breadcrumb'] ||= []
8
+ env['scorched.breadcrumb'] ||= []
9
9
  end
10
10
 
11
11
  # Returns a hash of captured strings from the last matched URL in the breadcrumb.
@@ -25,7 +25,7 @@ module Scorched
25
25
 
26
26
  # The remaining portion of the path that has yet to be matched by any mappings.
27
27
  def unmatched_path
28
- path = unescaped_path.dup
28
+ path = unescaped_path
29
29
  path[0,0] = '/' if (path[0] != '/' && matched_path[-1] == '/') || path.empty?
30
30
  path
31
31
  end
@@ -35,6 +35,7 @@ module Scorched
35
35
  def unescaped_path
36
36
  path_info.split(/(%25|%2F)/i).each_slice(2).map { |v, m| URI.unescape(v) << (m || '') }.join('')
37
37
  end
38
+
38
39
  private
39
40
 
40
41
  # Joins an array of path segments ensuring a single forward slash seperates them.
@@ -1,3 +1,3 @@
1
1
  module Scorched
2
- VERSION = '0.16'
2
+ VERSION = '0.17'
3
3
  end
@@ -159,14 +159,29 @@ module Scorched
159
159
  end
160
160
 
161
161
  it "matches routes based on priority, otherwise giving precedence to those defined first" do
162
- app << {pattern: '/', priority: -1, target: proc { |env| self.class.mappings.shift; [200, {}, ['four']] }}
163
- app << {pattern: '/', target: proc { |env| self.class.mappings.shift; [200, {}, ['two']] }}
164
- app << {pattern: '/', target: proc { |env| self.class.mappings.shift; [200, {}, ['three']] }}
165
- app << {pattern: '/', priority: 2, target: proc { |env| self.class.mappings.shift; [200, {}, ['one']] }}
166
- rt.get('/').body.should == 'one'
167
- rt.get('/').body.should == 'two'
168
- rt.get('/').body.should == 'three'
169
- rt.get('/').body.should == 'four'
162
+ order = []
163
+ app << {pattern: '/', priority: -1, target: proc { |env| order << 'four'; [200, {}, ['ok']] }}
164
+ app << {pattern: '/', target: proc { |env| order << 'two'; throw :pass }}
165
+ app << {pattern: '/', target: proc { |env| order << 'three'; throw :pass }}
166
+ app << {pattern: '/', priority: 2, target: proc { |env| order << 'one'; throw :pass }}
167
+ rt.get('/').body.should == 'ok'
168
+ order.should == %w{one two three four}
169
+ end
170
+
171
+ it "finds the best match for media type whilst respecting priority and definition order" do
172
+ app << {pattern: '/', conditions: {media_type: 'text/html'}, target: proc { |env|
173
+ [200, {}, ['text/html']]
174
+ }}
175
+ app << {pattern: '/', conditions: {media_type: 'application/json'}, target: proc { |env|
176
+ [200, {}, ['application/json']]
177
+ }}
178
+ app << {pattern: '/', priority: 1, target: proc { |env|
179
+ [200, {}, ['anything']]
180
+ }}
181
+ rt.get('/', media_type: 'application/json, */*;q=0.5').body.should == 'anything'
182
+ app.mappings.pop
183
+ rt.get('/', {}, 'HTTP_ACCEPT' => 'text/html;q=0.5, application/json').body.should == 'application/json'
184
+ rt.get('/', {}, 'HTTP_ACCEPT' => 'text/html, */*;q=0.5').body.should == 'text/html'
170
185
  end
171
186
  end
172
187
 
@@ -267,24 +282,37 @@ module Scorched
267
282
  rt.get('/article/hello-world').body.should == 'hello-world'
268
283
  end
269
284
 
270
- they "have access to original unmangled PATH_INFO via 'scorched.path_info'" do
271
- app << {pattern: '/article', target: Class.new(Scorched::Controller) do
272
- get('/name') {
273
- env['scorched.path_info']
274
- }
275
- end}
276
- rt.get('/article/name').body.should == '/article/name'
277
- end
278
-
279
- it "propagates correclty mangles escaped PATH_INFO before passing to sub-controller" do
280
- app << {pattern: '/:category', target: Class.new(Scorched::Controller) do
281
- get('/:name') {
285
+ it "copies env, modifying PATH_INFO and SCRIPT_NAME, before passing onto Rack-callable object" do
286
+ inner_env, outer_env = nil, nil
287
+ app.before { outer_env = env }
288
+ app.controller '/article' do
289
+ get '/name' do
290
+ inner_env = env
282
291
  'hello'
283
- }
284
- end}
285
- resp = rt.get('/big%20articles/article%20name')
292
+ end
293
+ end
294
+
295
+ resp = rt.get('/article/name')
286
296
  resp.status.should == 200
287
- resp.body.should == 'hello'
297
+ outer_env['SCRIPT_NAME'].should == ''
298
+ outer_env['PATH_INFO'].should == '/article/name'
299
+ inner_env['SCRIPT_NAME'].should == '/article'
300
+ inner_env['PATH_INFO'].should == '/name'
301
+ end
302
+
303
+ example "PATH_INFO and SCRIPT_NAME joined, should produce a full path" do
304
+ app.controller '/article/' do
305
+ get '/name' do
306
+ env['SCRIPT_NAME'] + env['PATH_INFO']
307
+ end
308
+ end
309
+ app.controller '/blah' do
310
+ get '/baz' do
311
+ env['SCRIPT_NAME'] + env['PATH_INFO']
312
+ end
313
+ end
314
+ rt.get('/article/name').body.should == '/article/name'
315
+ rt.get('/blah/baz').body.should == '/blah/baz'
288
316
  end
289
317
 
290
318
  describe "controller helper" do
@@ -895,7 +923,7 @@ module Scorched
895
923
  app.render_defaults.each { |k,v| app.render_defaults[k] = nil }
896
924
  end
897
925
 
898
- it "can render a file, relative to the application root" do
926
+ it "can render a file, relative to the working directory" do
899
927
  app.get('/') do
900
928
  render(:'views/main.erb').should == "3 for me"
901
929
  end
@@ -909,12 +937,24 @@ module Scorched
909
937
  rt.get('/')
910
938
  end
911
939
 
912
- it "takes an optional view directory, relative to the application root" do
940
+ it "takes an optional view directory, relative to the working directory" do
913
941
  app.get('/') do
914
942
  render(:'main.erb', dir: 'views').should == "3 for me"
915
943
  end
916
944
  rt.get('/')
917
945
  end
946
+
947
+ it "properly respects absolute and relative file paths in respect to the view directory" do
948
+ app.get('/relative') do
949
+ render(:'../views/main.erb', dir: 'views')
950
+ end
951
+ app.get('/absolute') do
952
+ File.dirname(__FILE__)
953
+ render(:"#{File.dirname(__FILE__)}/views/main.erb", dir: 'views')
954
+ end
955
+ rt.get('/relative').body.should == "3 for me"
956
+ rt.get('/absolute').body.should == "3 for me"
957
+ end
918
958
 
919
959
  it "takes an optional block to be yielded by the view" do
920
960
  app.get('/') do
@@ -1014,6 +1054,15 @@ module Scorched
1014
1054
  builder.to_app
1015
1055
  end
1016
1056
 
1057
+ it "can determine the root path of the current Scorched application" do
1058
+ my_app.controller '/article' do
1059
+ get '/name' do
1060
+ env['scorched.root_path']
1061
+ end
1062
+ end
1063
+ rt.get('/myapp/article/name').body.should == '/myapp'
1064
+ end
1065
+
1017
1066
  describe "url" do
1018
1067
  it "returns the fully qualified URL" do
1019
1068
  my_app.get('/') { url }
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: '0.16'
4
+ version: '0.17'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Wardrop
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-06 00:00:00.000000000 Z
11
+ date: 2013-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack