usher 0.7.5 → 0.8.0
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.
- data/lib/usher/exceptions.rb +2 -0
- data/lib/usher/interface/rack.rb +8 -4
- data/lib/usher/interface/sinatra.rb +33 -5
- data/lib/usher/node/failed_response.rb +34 -0
- data/lib/usher/node/response.rb +6 -0
- data/lib/usher/node/root_ignoring_trailing_delimiters.rb +1 -1
- data/lib/usher/node.rb +10 -3
- data/lib/usher/route/variable.rb +1 -1
- data/lib/usher/splitter.rb +2 -2
- data/lib/usher/util/generate.rb +1 -1
- data/lib/usher/util/parser.rb +6 -14
- data/lib/usher.rb +11 -3
- data/spec/private/rack/dispatch_spec.rb +9 -0
- data/spec/private/recognize_spec.rb +11 -2
- data/spec/private/sinatra/recognize_spec.rb +12 -0
- data/spec/private/splitter_spec.rb +6 -6
- data/usher.gemspec +1 -1
- metadata +5 -4
data/lib/usher/exceptions.rb
CHANGED
@@ -7,4 +7,6 @@ class Usher
|
|
7
7
|
class MissingParameterException < RuntimeError; end
|
8
8
|
# Raised when a route is added with identical variable names and allow_identical_variable_names? is false
|
9
9
|
class MultipleParameterException < RuntimeError; end
|
10
|
+
# Raised when a route is added with two regex validators
|
11
|
+
class DoubleRegexpException < RuntimeError; end
|
10
12
|
end
|
data/lib/usher/interface/rack.rb
CHANGED
@@ -33,7 +33,7 @@ class Usher
|
|
33
33
|
if redirect_on_trailing_delimiters
|
34
34
|
options[:ignore_trailing_delimiters] = true
|
35
35
|
end
|
36
|
-
usher_options = {:request_methods => request_methods, :generator => generator, :allow_identical_variable_names => allow_identical_variable_names}
|
36
|
+
usher_options = {:request_methods => request_methods, :generator => generator, :allow_identical_variable_names => allow_identical_variable_names, :detailed_failure => true}
|
37
37
|
usher_options.merge!(options)
|
38
38
|
@router = Usher.new(usher_options)
|
39
39
|
@router.route_class = Rack::Route
|
@@ -120,12 +120,12 @@ class Usher
|
|
120
120
|
env[router_key] = self
|
121
121
|
request = ::Rack::Request.new(env)
|
122
122
|
response = @router.recognize(request, request.path_info)
|
123
|
-
if redirect_on_trailing_delimiters and response.only_trailing_delimiters and (request.get? || request.head?)
|
123
|
+
if response.succeeded? && redirect_on_trailing_delimiters and response.only_trailing_delimiters and (request.get? || request.head?)
|
124
124
|
response = ::Rack::Response.new
|
125
125
|
response.redirect(request.path_info[0, request.path_info.size - 1], 302)
|
126
126
|
response.finish
|
127
127
|
else
|
128
|
-
after_match(request, response) if response
|
128
|
+
after_match(request, response) if response.succeeded?
|
129
129
|
determine_respondant(response).call(env)
|
130
130
|
end
|
131
131
|
end
|
@@ -161,11 +161,15 @@ class Usher
|
|
161
161
|
#
|
162
162
|
# @api private
|
163
163
|
def determine_respondant(response)
|
164
|
-
usable_response = use_destinations? && response && response.destination
|
164
|
+
usable_response = response.succeeded? && use_destinations? && response && response.destination
|
165
165
|
if usable_response && response.destination.respond_to?(:call)
|
166
166
|
response.destination
|
167
167
|
elsif usable_response && response.destination.respond_to?(:args) && response.destination.args.first.respond_to?(:call)
|
168
168
|
response.args.first
|
169
|
+
elsif !response.succeeded? && response.request_method?
|
170
|
+
rack_response = ::Rack::Response.new("Method not allowed", 405)
|
171
|
+
rack_response['Allow'] = response.acceptable_responses_only_strings.join(", ")
|
172
|
+
proc { |env| rack_response.finish }
|
169
173
|
else
|
170
174
|
_app
|
171
175
|
end
|
@@ -23,10 +23,18 @@ class Usher
|
|
23
23
|
private
|
24
24
|
def route!(base=self.class, pass_block=nil)
|
25
25
|
if base.router and match = base.router.recognize(@request, @request.path_info)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
if match.succeeded?
|
27
|
+
@block_params = match.params.map { |p| p.last }
|
28
|
+
(@params ||= {}).merge!(match.params_as_hash)
|
29
|
+
pass_block = catch(:pass) do
|
30
|
+
route_eval(&match.destination)
|
31
|
+
end
|
32
|
+
elsif match.request_method?
|
33
|
+
route_eval {
|
34
|
+
response['Allow'] = match.acceptable_responses_only_strings.join(", ")
|
35
|
+
status 405
|
36
|
+
}
|
37
|
+
return
|
30
38
|
end
|
31
39
|
end
|
32
40
|
|
@@ -76,7 +84,8 @@ class Usher
|
|
76
84
|
:ignore_trailing_delimiters => true,
|
77
85
|
:generator => Usher::Util::Generators::URL.new,
|
78
86
|
:delimiters => ['/', '.', '-'],
|
79
|
-
:valid_regex => '[0-9A-Za-z\$_\+!\*\',]+'
|
87
|
+
:valid_regex => '[0-9A-Za-z\$_\+!\*\',]+',
|
88
|
+
:detailed_failure => true)
|
80
89
|
block_given? ? yield(@router) : @router
|
81
90
|
end
|
82
91
|
|
@@ -114,6 +123,25 @@ class Usher
|
|
114
123
|
</html>
|
115
124
|
HTML
|
116
125
|
end
|
126
|
+
error 405 do
|
127
|
+
content_type 'text/html'
|
128
|
+
|
129
|
+
(<<-HTML).gsub(/^ {17}/, '')
|
130
|
+
<!DOCTYPE html>
|
131
|
+
<html>
|
132
|
+
<head>
|
133
|
+
<style type="text/css">
|
134
|
+
body { text-align:center;font-family:helvetica,arial;font-size:22px;
|
135
|
+
color:#888;margin:20px}
|
136
|
+
#c {margin:0 auto;width:500px;text-align:left}
|
137
|
+
</style>
|
138
|
+
</head>
|
139
|
+
<body>
|
140
|
+
<h2>Sinatra sorta knows this ditty, but the request method is not allowed.</h2>
|
141
|
+
</body>
|
142
|
+
</html>
|
143
|
+
HTML
|
144
|
+
end
|
117
145
|
end
|
118
146
|
|
119
147
|
@_configured = true
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Usher
|
2
|
+
class Node
|
3
|
+
# The response from {Usher::Node::Root#lookup}. Adds some convenience methods for common parameter manipulation.
|
4
|
+
class FailedResponse < Struct.new(:last_matching_node, :fail_type, :fail_sub_type)
|
5
|
+
# The success of the response
|
6
|
+
# @return [Boolean] Always returns false
|
7
|
+
def succeeded?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def request_method?
|
12
|
+
fail_type == :request_method
|
13
|
+
end
|
14
|
+
|
15
|
+
def normal_or_greedy?
|
16
|
+
fail_type == :normal_or_greedy
|
17
|
+
end
|
18
|
+
|
19
|
+
def acceptable_responses
|
20
|
+
case fail_type
|
21
|
+
when :request_method
|
22
|
+
last_matching_node.request.keys
|
23
|
+
when :normal_or_greedy
|
24
|
+
(last_matching_node.greedy || []) + (last_matching_node.normal || [])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def acceptable_responses_only_strings
|
29
|
+
acceptable_responses.select{|r| r.is_a?(String)}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/usher/node/response.rb
CHANGED
@@ -3,6 +3,12 @@ class Usher
|
|
3
3
|
# The response from {Usher::Node::Root#lookup}. Adds some convenience methods for common parameter manipulation.
|
4
4
|
class Response < Struct.new(:path, :params_as_array, :remaining_path, :matched_path, :only_trailing_delimiters)
|
5
5
|
|
6
|
+
# The success of the response
|
7
|
+
# @return [Boolean] Always returns true
|
8
|
+
def succeeded?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
6
12
|
# The params from recognition
|
7
13
|
# @return [Array<Symbol, String>] The parameters detected from recognition returned as an array of arrays.
|
8
14
|
def params
|
@@ -13,7 +13,7 @@ class Usher
|
|
13
13
|
if path.size > 1
|
14
14
|
new_path = path.gsub(@stripper, '')
|
15
15
|
response = lookup_without_stripping(request_object, new_path)
|
16
|
-
response.only_trailing_delimiters = (new_path.size != path.size) if response
|
16
|
+
response.only_trailing_delimiters = (new_path.size != path.size) if response && response.succeeded?
|
17
17
|
response
|
18
18
|
else
|
19
19
|
lookup_without_stripping(request_object, path)
|
data/lib/usher/node.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require File.join('usher', 'node', 'root')
|
2
2
|
require File.join('usher', 'node', 'root_ignoring_trailing_delimiters')
|
3
3
|
require File.join('usher', 'node', 'response')
|
4
|
+
require File.join('usher', 'node', 'failed_response')
|
4
5
|
|
5
6
|
class Usher
|
6
7
|
|
@@ -120,19 +121,25 @@ class Usher
|
|
120
121
|
route_candidates << ret
|
121
122
|
end
|
122
123
|
route_candidates.sort!{|r1, r2| r1.path.route.priority <=> r2.path.route.priority}
|
123
|
-
route_candidates.last
|
124
|
+
request_method_respond(route_candidates.last, request_method_type)
|
124
125
|
else
|
125
126
|
if specific_node = request[request_object.send(request_method_type)] and ret = specific_node.find(request_object, original_path, path.dup, params && params.dup)
|
126
127
|
ret
|
127
128
|
elsif general_node = request[nil] and ret = general_node.find(request_object, original_path, path.dup, params && params.dup)
|
128
|
-
ret
|
129
|
+
request_method_respond(ret, request_method_type)
|
130
|
+
else
|
131
|
+
request_method_respond(nil, request_method_type)
|
129
132
|
end
|
130
133
|
end
|
131
134
|
else
|
132
|
-
nil
|
135
|
+
route_set.detailed_failure? ? FailedResponse.new(self, :normal_or_greedy, nil) : nil
|
133
136
|
end
|
134
137
|
end
|
135
138
|
|
139
|
+
def request_method_respond(ret, request_method_respond)
|
140
|
+
ret || (route_set.detailed_failure? ? FailedResponse.new(self, :request_method, request_method_respond) : nil)
|
141
|
+
end
|
142
|
+
|
136
143
|
def activate_normal!
|
137
144
|
@normal ||= {}
|
138
145
|
end
|
data/lib/usher/route/variable.rb
CHANGED
@@ -12,7 +12,7 @@ class Usher
|
|
12
12
|
include Validator
|
13
13
|
def valid!(val)
|
14
14
|
begin
|
15
|
-
@validator.call(val)
|
15
|
+
@validator.call(val) or raise(ValidationException.new("#{val} does not conform to #{@validator}"))
|
16
16
|
rescue Exception => e
|
17
17
|
raise ValidationException.new("#{val} does not conform to #{@validator}, root cause #{e.inspect}")
|
18
18
|
end
|
data/lib/usher/splitter.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Usher
|
2
2
|
class Splitter
|
3
3
|
|
4
|
-
def self.
|
4
|
+
def self.new(delimiters_array)
|
5
5
|
delimiters = Delimiters.new(delimiters_array)
|
6
6
|
delimiters.any?{|d| d.size > 1} ?
|
7
7
|
MultiCharacterSplitterInstance.new(delimiters) :
|
@@ -13,7 +13,7 @@ class Usher
|
|
13
13
|
def initialize(delimiters)
|
14
14
|
@url_split_regex = Regexp.new("[^#{delimiters.regexp_char_class}]+|[#{delimiters.regexp_char_class}]")
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def split(path)
|
18
18
|
path.scan(@url_split_regex)
|
19
19
|
end
|
data/lib/usher/util/generate.rb
CHANGED
@@ -178,7 +178,7 @@ class Usher
|
|
178
178
|
when Array
|
179
179
|
v.each do |v_part|
|
180
180
|
extra_params_result << '&' unless extra_params_result.empty?
|
181
|
-
extra_params_result << Rack::Utils.escape(
|
181
|
+
extra_params_result << Rack::Utils.escape(k.to_s) << '%5B%5D=' << Rack::Utils.escape(v_part.to_s)
|
182
182
|
end
|
183
183
|
else
|
184
184
|
extra_params_result << '&' unless extra_params_result.empty?
|
data/lib/usher/util/parser.rb
CHANGED
@@ -6,16 +6,9 @@ class Usher
|
|
6
6
|
|
7
7
|
attr_reader :router
|
8
8
|
|
9
|
-
def
|
10
|
-
new(
|
11
|
-
router,
|
12
|
-
Regexp.new('((:|\*)?' + valid_regex + '|' + router.delimiters_regex + '|\(|\)|\||\{)')
|
13
|
-
)
|
14
|
-
end
|
15
|
-
|
16
|
-
def initialize(router, split_regex)
|
9
|
+
def initialize(router, valid_regex)
|
17
10
|
@router = router
|
18
|
-
@split_regex =
|
11
|
+
@split_regex = Regexp.new('((:|\*)?' + valid_regex + '|' + router.delimiters_regex + '|\(|\)|\||\{)')
|
19
12
|
@delimiters_regex = Regexp.new(router.delimiters_regex)
|
20
13
|
end
|
21
14
|
|
@@ -102,12 +95,10 @@ class Usher
|
|
102
95
|
end
|
103
96
|
|
104
97
|
case part[0]
|
105
|
-
when
|
106
|
-
|
107
|
-
current_group << Usher::Route::Variable::Glob.new(part[1, part.size - 1], nil, requirements && requirements[var_name])
|
108
|
-
when ?:
|
98
|
+
when ?*, ?:
|
99
|
+
variable_class = part[0] == ?* ? Usher::Route::Variable::Glob : Usher::Route::Variable::Single
|
109
100
|
var_name = part[1, part.size - 1].to_sym
|
110
|
-
current_group <<
|
101
|
+
current_group << variable_class.new(part[1, part.size - 1], requirements && requirements[var_name].is_a?(Regexp) ? requirements[var_name] : nil, requirements && requirements[var_name])
|
111
102
|
when ?{
|
112
103
|
pattern = ''
|
113
104
|
count = 1
|
@@ -131,6 +122,7 @@ class Usher
|
|
131
122
|
when ?: then Usher::Route::Variable::Single
|
132
123
|
end
|
133
124
|
variable_name = variable[0, variable.size - 1].to_sym
|
125
|
+
raise DoubleRegexpException.new("#{variable_name} has two regex validators, #{pattern} and #{requirements[variable_name]}") if requirements && requirements[variable_name] && requirements[variable_name].is_a?(Regexp)
|
134
126
|
current_group << variable_class.new(variable_name, Regexp.new(pattern), requirements && requirements[variable_name])
|
135
127
|
elsif simple
|
136
128
|
static = Usher::Route::Static::Greedy.new(pattern)
|
data/lib/usher.rb
CHANGED
@@ -56,7 +56,7 @@ class Usher
|
|
56
56
|
@routes = []
|
57
57
|
@grapher = Grapher.new(self)
|
58
58
|
@priority_lookups = false
|
59
|
-
@parser = Util::Parser.
|
59
|
+
@parser = Util::Parser.new(self, valid_regex)
|
60
60
|
end
|
61
61
|
|
62
62
|
# Creates a route set, with options
|
@@ -67,6 +67,7 @@ class Usher
|
|
67
67
|
# @option options [nil or Generator] :generator (nil) Take a look at `Usher::Util::Generators for examples.`.
|
68
68
|
# @option options [Boolean] :ignore_trailing_delimiters (false) Ignore trailing delimiters in recognizing paths.
|
69
69
|
# @option options [Boolean] :consider_destination_keys (false) When generating, and using hash destinations, you can have Usher use the destination hash to match incoming params.
|
70
|
+
# @option options [Boolean] :detailed_failure (false) When a route fails to match, return a {Node::FailedResponse} instead of a `nil`
|
70
71
|
# Example, you create a route with a destination of :controller => 'test', :action => 'action'. If you made a call to generator with :controller => 'test',
|
71
72
|
# :action => 'action', it would pick that route to use for generation.
|
72
73
|
# @option options [Boolean] :allow_identical_variable_names (true) When adding routes, allow identical variable names to be used.
|
@@ -79,6 +80,8 @@ class Usher
|
|
79
80
|
self.ignore_trailing_delimiters = options && options.key?(:ignore_trailing_delimiters) ? options.delete(:ignore_trailing_delimiters) : false
|
80
81
|
self.consider_destination_keys = options && options.key?(:consider_destination_keys) ? options.delete(:consider_destination_keys) : false
|
81
82
|
self.allow_identical_variable_names = options && options.key?(:allow_identical_variable_names) ? options.delete(:allow_identical_variable_names) : true
|
83
|
+
self.detailed_failure = options && options.key?(:detailed_failure) ? options.delete(:detailed_failure) : false
|
84
|
+
|
82
85
|
unless options.nil? || options.empty?
|
83
86
|
raise "unrecognized options -- #{options.keys.join(', ')}"
|
84
87
|
end
|
@@ -90,6 +93,11 @@ class Usher
|
|
90
93
|
@allow_identical_variable_names
|
91
94
|
end
|
92
95
|
|
96
|
+
# @return [Boolean] State of detailed_failure feature.
|
97
|
+
def detailed_failure?
|
98
|
+
@detailed_failure
|
99
|
+
end
|
100
|
+
|
93
101
|
# @return [Boolean] State of ignore_trailing_delimiters feature.
|
94
102
|
def ignore_trailing_delimiters?
|
95
103
|
@ignore_trailing_delimiters
|
@@ -320,7 +328,7 @@ class Usher
|
|
320
328
|
|
321
329
|
private
|
322
330
|
|
323
|
-
attr_accessor :request_methods, :ignore_trailing_delimiters, :consider_destination_keys, :allow_identical_variable_names
|
331
|
+
attr_accessor :request_methods, :ignore_trailing_delimiters, :consider_destination_keys, :allow_identical_variable_names, :detailed_failure
|
324
332
|
attr_reader :valid_regex
|
325
333
|
attr_writer :parser
|
326
334
|
|
@@ -340,7 +348,7 @@ class Usher
|
|
340
348
|
|
341
349
|
def valid_regex=(valid_regex)
|
342
350
|
@valid_regex = valid_regex
|
343
|
-
@splitter = Splitter.
|
351
|
+
@splitter = Splitter.new(self.delimiters)
|
344
352
|
@valid_regex
|
345
353
|
end
|
346
354
|
|
@@ -66,6 +66,15 @@ describe "Usher (for rack) route dispatching" do
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
it "should returns HTTP 405 if the method mis-matches" do
|
70
|
+
route_set.reset!
|
71
|
+
route_set.add('/sample', :conditions => {:request_method => 'POST'}).to(@app)
|
72
|
+
route_set.add('/sample', :conditions => {:request_method => 'PUT'}).to(@app)
|
73
|
+
response = route_set.call_with_mock_request('/sample', 'GET')
|
74
|
+
response.status.should eql(405)
|
75
|
+
response['Allow'].should == 'POST, PUT'
|
76
|
+
end
|
77
|
+
|
69
78
|
it "should returns HTTP 404 if route doesn't exist" do
|
70
79
|
response = route_set.call_with_mock_request("/not-existing-url")
|
71
80
|
response.status.should eql(404)
|
@@ -288,9 +288,18 @@ describe "Usher route recognition" do
|
|
288
288
|
result.params.should == [[:name, "homer"],[:surname, "simpson"]]
|
289
289
|
end
|
290
290
|
|
291
|
-
it "should
|
291
|
+
it "should use a regexp requirement as part of recognition" do
|
292
292
|
@route_set.add_route('/products/show/:id', :id => /\d+/, :conditions => {:method => 'get'})
|
293
|
-
|
293
|
+
@route_set.recognize(build_request({:method => 'get', :path => '/products/show/qweasd', :domain => 'admin.host.com'})).should be_nil
|
294
|
+
end
|
295
|
+
|
296
|
+
it "should use a inline regexp and proc requirement as part of recognition" do
|
297
|
+
@route_set.add_route('/products/show/{:id,^\d+$}', :id => proc{|v| v == '123'}, :conditions => {:method => 'get'})
|
298
|
+
proc { @route_set.recognize(build_request({:method => 'get', :path => '/products/show/234', :domain => 'admin.host.com'}))}.should raise_error(Usher::ValidationException)
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should not allow the use of an inline regexp and regexp requirement as part of recognition" do
|
302
|
+
proc { @route_set.add_route('/products/show/{:id,^\d+$}', :id => /\d+/, :conditions => {:method => 'get'}) }.should raise_error(Usher::DoubleRegexpException)
|
294
303
|
end
|
295
304
|
|
296
305
|
it "should recognize multiple optional parts" do
|
@@ -117,4 +117,16 @@ describe "Usher (for Sinatra) route recognition" do
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
+
describe "method not allowed" do
|
121
|
+
|
122
|
+
it "should correctly generate a not found page without images and return a 405" do
|
123
|
+
@app.post('/bar') { 'found' }
|
124
|
+
@app.put('/bar') { 'found' }
|
125
|
+
response = @app.call_with_mock_request('/bar')
|
126
|
+
response.status.should == 405
|
127
|
+
response.headers['Allow'].should == 'POST, PUT'
|
128
|
+
response.body.should_not match(/__sinatra__/)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
120
132
|
end
|
@@ -4,37 +4,37 @@ require "usher"
|
|
4
4
|
describe Usher::Splitter, "#split" do
|
5
5
|
describe "when there are single-character delimiters" do
|
6
6
|
it "should split correctly" do
|
7
|
-
Usher::Splitter.
|
7
|
+
Usher::Splitter.new(['.', '/']).split('/one/two.three/').should == ['/', 'one', '/', 'two', '.', 'three', '/']
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
11
|
describe "when there are multi-character delimiters" do
|
12
12
|
it "should split correctly" do
|
13
|
-
Usher::Splitter.
|
13
|
+
Usher::Splitter.new(['/', '%28', '%29']).split('/one%28two%29three/').should == ['/', 'one', '%28', 'two', '%29', 'three', '/']
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
17
|
describe "when there is no delimiter in the end" do
|
18
18
|
it "should split correctly" do
|
19
|
-
Usher::Splitter.
|
19
|
+
Usher::Splitter.new(['.', '/']).split('/one/two.three').should == ['/', 'one', '/', 'two', '.', 'three']
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
describe "when there is no delimiter in the beginning" do
|
24
24
|
it "should split correctly" do
|
25
|
-
Usher::Splitter.
|
25
|
+
Usher::Splitter.new(['.', '/']).split('one/two.three/').should == ['one', '/', 'two', '.', 'three', '/']
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
29
|
describe "when delimiters are consecutive" do
|
30
30
|
it "should split correctly" do
|
31
|
-
Usher::Splitter.
|
31
|
+
Usher::Splitter.new(['/', '!']).split('/cheese/!parmesan').should == ['/', 'cheese', '/', '!', 'parmesan']
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
35
|
describe "when delimiters contain escaped characters" do
|
36
36
|
it "should split correctly" do
|
37
|
-
Usher::Splitter.
|
37
|
+
Usher::Splitter.new(['/', '\(', '\)']).split('/cheese(parmesan)').should == ['/', 'cheese', '(', 'parmesan', ')']
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
data/usher.gemspec
CHANGED
@@ -5,7 +5,7 @@ require "base64"
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "usher"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.8.0"
|
9
9
|
s.authors = ["Daniel Neighman", "Daniel Vartanov", "Jakub Šťastný", "Joshua Hull", "Davide D'Agostino"].sort
|
10
10
|
s.homepage = "http://github.com/joshbuddy/usher"
|
11
11
|
s.summary = "Pure ruby general purpose router with interfaces for rails, rack, email or choose your own adventure"
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 8
|
8
|
+
- 0
|
9
|
+
version: 0.8.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Daniel Neighman
|
@@ -19,7 +19,7 @@ authors:
|
|
19
19
|
autorequire:
|
20
20
|
bindir: bin
|
21
21
|
cert_chain:
|
22
|
-
date: 2010-05-
|
22
|
+
date: 2010-05-05 00:00:00 -04:00
|
23
23
|
default_executable:
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
@@ -121,6 +121,7 @@ files:
|
|
121
121
|
- lib/usher/interface/sinatra.rb
|
122
122
|
- lib/usher/interface/text.rb
|
123
123
|
- lib/usher/node.rb
|
124
|
+
- lib/usher/node/failed_response.rb
|
124
125
|
- lib/usher/node/response.rb
|
125
126
|
- lib/usher/node/root.rb
|
126
127
|
- lib/usher/node/root_ignoring_trailing_delimiters.rb
|