scorched 0.16 → 0.17

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 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