scorched 0.14 → 0.15

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: 2583f96bd04c7a31f7edf598acd84eaa11689feb
4
- data.tar.gz: 8148c65523e21d3aaa68b6dd2dd7ce0ac62eddac
3
+ metadata.gz: 252309e125591f6ffd81a1ac36bb79c851aabce8
4
+ data.tar.gz: 4100f0dc1f942fb4067f32e27f966b8fb327c8d8
5
5
  SHA512:
6
- metadata.gz: 73ed932ce8783845f70c041da390eca59f9bb487b834191a31863a2e8f23290457317db4a8fccf574aaaba3d17530d5e8cd36a739491af61bda024daaab75086
7
- data.tar.gz: 8ac3bd00774d449e68e40d90639a937c5b7963c9630b5aa86a478b283b8eb6f5586188bc7cc5bc85d48c6b7c8630b1c22a43aad551ad6488e47ebf6b529abafc
6
+ metadata.gz: 5cda7022f16ff4d70a47552dbb6563f86e8ece672036b221373a639990c48bd12fbedce6e7989eabe0cf9282a08621eec342a129ea9c74dadd66b0b289642b25
7
+ data.tar.gz: 6dc0e3f1aef90a462a610f33fc7ffc34f087f5426f7919c2ae555f3599aeb048668fb7c72e3e7e39b6ea4664eeb68048b060b255af6ae2687f9c7d578e5678ff
data/CHANGES.md CHANGED
@@ -1,6 +1,10 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ ### v0.15
5
+ * Route DSL methods (`route`, `get`, `post`, ...) now accept an array of patterns as the pattern argument. Each pattern is defined as a separate mapping, sharing the same target proc. This provides a cleaner and more efficient solution to simply wrapping a route definition within a loop.
6
+ * URI unescaping has been implemented for `Scorched::Request#unmatched_path`. This modification directly affects route matching. Previously, routes were matched against the escaped path, e.g. `/this%20has%20spaces`. Routes are now matched against the unescaped form `/this has spaces`. The only exception is the escaped forward-slash `%2F` and percent sign `%25` which remain unaltered for the fact their unescaped form as special meaning which you wouldn't be able to disambiguate. It's however safe to unescape the path a second time to resolve these characters.
7
+
4
8
  ### v0.14
5
9
  * If a matched mapping _passes_ the request and there are no other matching mappings, a 404 status is now set by default, rather than a 200 status.
6
10
  * Renamed `matched` condition to `handled` to be less ambiguous.
data/README.md CHANGED
@@ -35,13 +35,13 @@ $ rackup hello_world.ru
35
35
 
36
36
  #### A Note on Requirements
37
37
 
38
- Scorched requires Ruby 2.0 or above. It's important to ensure your version of Ruby 2.0 includes [changeset 39919](http://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39919) in order to avoid suffering from [random segmentation faults](http://bugs.ruby-lang.org/issues/8100). Ruby 2.0.0-p195 and newer include the fix, otherwise you can manually patch it during installation.
38
+ Scorched requires Ruby 2.0 or above. If you've got Ruby 2.0.0-p195 and newer, you're good. Otherwise, you need to ensure that your version of Ruby 2.0 includes [changeset 39919](http://bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/39919) in order to avoid suffering from [random segmentation faults](http://bugs.ruby-lang.org/issues/8100).
39
39
 
40
- The Errors of Our Past
40
+ The Errors of Our Past (and Present!)
41
41
  ----------------------
42
- One of the mistakes made by a lot of other Ruby frameworks, was to not leverage the power of the class. The consequences of this made for some awkwardness. Helpers for example, are a classical reinvention of what classes and modules were already made to solve. Scorched implements Controllers as classes, which in addition to having their own DSL, allow defining and calling traditional instance methods. The decision to allow developers to implement helpers and other common functionality as proper methods not only makes Controllers somewhat more predictable and familiar, but of course allow such helpers to be inheritable via plain-old class inheritance.
42
+ One of the mistakes made by a lot of other Ruby frameworks is to not leverage the power of the class. The consequences of this have made for some awkwardness. Helpers, for example, are a classical reinvention of what classes and modules are already made to solve. Scorched implements Controllers as classes, which, in addition to having their own DSL, allow you to define and call whatever you need as traditional instance methods. The decision to allow developers to implement helpers and other common functionality as proper methods not only makes Controllers somewhat more predictable and familiar, but also allows for such helpers to be inheritable via plain-old class inheritance.
43
43
 
44
- Perhaps another design oversight of other frameworks, has been the lack of consideration for the hierarchical nature of websites, and the fact that sub-directories are often expected to inherit attributes of their parents. Scorched supports sub-controllers to any arbitrary depth, with each controllers configuration, filters, route conditions, etc, applied along the way. This can assist many areas of web development, including security, restful interfaces, and interchangeable content types.
44
+ Perhaps another design oversight of other frameworks has been the lack of consideration for the hierarchical nature of websites, and the fact that sub-directories are often expected to inherit attributes of their parents. Scorched supports sub-controllers to any arbitrary depth, with each controller's configuration, filters, route conditions, etc. applied along the way. This can help in many areas of web development, including security, restful interfaces, and interchangeable content types.
45
45
 
46
46
 
47
47
  Design Philosophy
data/Rakefile CHANGED
@@ -11,8 +11,10 @@ task :test => :spec
11
11
 
12
12
  RSpec::Core::RakeTask.new(:spec)
13
13
 
14
- task :release => [:spec, :'gem:install', :commit_version, :'gem:release', :clean]
14
+ desc 'Releases a new version of Scorched.'
15
+ task :release => [:prerelease, :spec, :'gem:install', :commit_version, :'gem:release', :clean]
15
16
 
17
+ desc 'Commits and tags git repository as new version, pushing up to github'
16
18
  task :commit_version do
17
19
  sh "git commit --allow-empty -a -m 'v#{Scorched::VERSION} release.' &&
18
20
  git tag -a #{Scorched::VERSION} -m 'v#{Scorched::VERSION} release.' &&
@@ -20,6 +22,15 @@ task :commit_version do
20
22
  git push --tags"
21
23
  end
22
24
 
25
+ desc 'Displays a pre-release message, requiring user input'
26
+ task :prerelease do
27
+ puts <<-MSG
28
+
29
+ About to release Scorched v#{Scorched::VERSION}. Please ensure CHANGES log is up-to-date, all relevant documentation is updated, and that any new files not under version control have been added/staged. Press any key to continue...
30
+ MSG
31
+ STDIN.gets
32
+ end
33
+
23
34
  namespace :gem do
24
35
  require "bundler/gem_tasks"
25
36
  end
@@ -33,9 +33,9 @@ end
33
33
 
34
34
  You can see pretty clearly how these examples correspond to the pattern, priority, conditions and target options of a manual mapping. The pattern, priority and conditions behave exactly as they do for a manual mapping, with a couple of exceptions.
35
35
 
36
- The first exception is that the pattern must match to the end of the request path. This is mentioned in the _pattern matching_ section below.
36
+ The first exception is that the pattern must match to the end of the request path. This is mentioned in the _pattern matching_ section below. You can also define a route with multiple patterns by using an array. This creates a different mapping for each URL, but using the same proc object and other arguments.
37
37
 
38
- The other more notable exception is in how the given block is treated. The block given to the route helper is wrapped in another proc. The wrapping proc does a couple of things. It first sends all the captures in the url pattern as argument to the given block, this is shown in the example above. The other thing it does is takes care of assigning the return value to the body of the response.
38
+ The other more notable exception is in how the given block is treated. The block given to the route helper is wrapped in another proc. The wrapping proc does a couple of things. It first sends all the captures in the url pattern as arguments to the given block; this is shown in the example above. The other thing it does is takes care of assigning the return value to the body of the response.
39
39
 
40
40
  In the latter of the two examples above, a `:method` condition defines what methods the route is intended to process. The first example has no such condition, so it accepts all HTTP methods. Typically however, a route will handle a single HTTP method, which is why Scorched also provides the convenience helpers: `get`, `post`, `put`, `delete`, `head`, `options`, and `patch`. These methods automatically define the corresponding `:method` condition, with the `get` helper also including `head` as an accepted HTTP method.
41
41
 
@@ -44,6 +44,10 @@ Pattern Matching
44
44
  All patterns attempt to match the remaining unmatched portion of the _request path_; the _request path_ being Rack's
45
45
  `path_info` request variable. The unmatched path will always begin with a forward slash if the previously matched portion of the path ended immediately before, or included as the last character, a forward slash. As an example, if the request was to "/article/21", then both "/article/" => "/21" and "/article" => "/21" would match.
46
46
 
47
+ The `path_info` used to match against is unescaped, meaning percent-codes are resolved, e.g. `%20` resolves to a space. The two exceptions are the escaped forward-slash and percent sign, which remain escaped as `%2F` and `%25` respectively.
48
+
49
+ > The forward-slash cannot be automatically escaped as it would make it impossible to disambiguate from an actual forward-slash in the URL (which has special meaning). The encoded percent-sign thus also needs to remain unescaped, otherwise it'd be impossible to safely unescape the escaped forward-slash in your application, if you needed to. If this all sounds very confusing, rest assured you probably won't ever encounter a scenario in which you'd have to think about this.
50
+
47
51
  All patterns must match from the beginning of the path. So even though the pattern "article" would match "/article/21", it wouldn't count as a match because the match didn't start at a non-zero offset.
48
52
 
49
53
  If a pattern contains named captures, unnamed captures will be lost - this is how named regex captures work in Ruby. So if you name one capture, make sure you name any other captures you may want to access.
@@ -1,12 +1,9 @@
1
1
  require File.expand_path('../../lib/scorched.rb', __FILE__)
2
2
 
3
3
  class MyApp < Scorched::Controller
4
- controller '/' do
5
-
6
- end
7
-
8
- after do
9
- p @_matched
4
+ get '/*' do |part|
5
+ p part
6
+ part
10
7
  end
11
8
  end
12
9
 
@@ -170,7 +170,9 @@ module Scorched
170
170
  env['scorched.response'].body = instance_exec(*env['scorched.request'].captures, &block)
171
171
  env['scorched.response']
172
172
  end
173
- self << {pattern: compile(pattern, true), priority: priority, conditions: conds, target: target} if pattern
173
+ [*pattern].compact.each do |pattern|
174
+ self << {pattern: compile(pattern, true), priority: priority, conditions: conds, target: target}
175
+ end
174
176
  target
175
177
  end
176
178
 
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module Scorched
2
4
  class Request < Rack::Request
3
5
  # Keeps track of the matched URL portions and what object handled them. Useful for debugging and building
@@ -23,11 +25,16 @@ module Scorched
23
25
 
24
26
  # The remaining portion of the path that has yet to be matched by any mappings.
25
27
  def unmatched_path
26
- path = path_info.partition(matched_path).last
28
+ path = unescaped_path.partition(matched_path).last
27
29
  path[0,0] = '/' if path.empty? || matched_path[-1] == '/'
28
30
  path
29
31
  end
30
-
32
+
33
+ # The unescaped URL, excluding the escaped forward-slash and percent. The resulting string will always be safe
34
+ # to unescape again in situations where the forward-slash or percent are expected and valid characters.
35
+ def unescaped_path
36
+ path_info.split(/(%25|%2F)/i).each_slice(2).map { |v, m| URI.unescape(v) << (m || '') }.join('')
37
+ end
31
38
  private
32
39
 
33
40
  # Joins an array of path segments ensuring a single forward slash seperates them.
@@ -1,3 +1,3 @@
1
1
  module Scorched
2
- VERSION = '0.14'
2
+ VERSION = '0.15'
3
3
  end
@@ -72,6 +72,16 @@ module Scorched
72
72
  response.status.should == 200
73
73
  end
74
74
 
75
+ it "unescapes all characters except for the forward-slash and percent sign" do
76
+ app << {pattern: '/a (quite) big fish', target: generic_handler}
77
+ rt.get('/a%20%28quite%29%20big%20fish').status.should == 200
78
+ app << {pattern: '/article/100%25 big%2Fsmall', target: generic_handler}
79
+ rt.get('/article/100%25%20big%2Fsmall').status.should == 200
80
+ app << {pattern: '/*$', target: generic_handler}
81
+ rt.get('/page%2Fabout').status.should == 200
82
+ rt.get('/page/about').status.should == 404
83
+ end
84
+
75
85
  it "unmatched path doesn't always begin with a forward slash" do
76
86
  gh = generic_handler
77
87
  app << {pattern: '/ab', target: Class.new(Scorched::Controller) do
@@ -238,6 +248,13 @@ module Scorched
238
248
  end
239
249
  rt.get('/')
240
250
  end
251
+
252
+ it "can take an array of patterns" do
253
+ app.get(['/', '/dog']) { 'rad' }
254
+ rt.get('/dog').status.should == 200
255
+ rt.get('/').status.should == 200
256
+ rt.get('/cat').status.should == 404
257
+ end
241
258
  end
242
259
 
243
260
  describe "sub-controllers" do
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.14'
4
+ version: '0.15'
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-06-24 00:00:00.000000000 Z
11
+ date: 2013-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack