joshbuddy-usher 0.4.2 → 0.4.3
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/README.rdoc +0 -1
- data/VERSION.yml +1 -1
- data/lib/usher.rb +7 -5
- data/lib/usher/interface/rack_interface.rb +2 -0
- data/lib/usher/node.rb +11 -53
- data/lib/usher/route.rb +1 -2
- data/lib/usher/route/variable.rb +2 -16
- data/lib/usher/splitter.rb +8 -17
- data/spec/private/email/recognize_spec.rb +0 -2
- data/spec/private/generate_spec.rb +5 -0
- data/spec/private/rack/dispatch_spec.rb +0 -2
- data/spec/private/recognize_spec.rb +6 -16
- data/spec/private/split_spec.rb +1 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -74,7 +74,6 @@ For instance, the path, <tt>/path/something(.xml|.html)</tt> would only match <t
|
|
74
74
|
<tt>/path/something.html</tt>. Generally its more efficent to use one and only sections over using regex.
|
75
75
|
|
76
76
|
=== +options+
|
77
|
-
* +transformers+ - Transforms a variable before it gets to the requirements. Takes either a +proc+ or a +symbol+. If its a +symbol+, calls the method on the incoming parameter. If its a +proc+, its called with the variable.
|
78
77
|
* +requirements+ - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
|
79
78
|
* +conditions+ - Accepts any of the +request_methods+ specificied in the construction of Usher. This can be either a <tt>string</tt> or a regular expression.
|
80
79
|
* Any other key is interpreted as a requirement for the variable of its name.
|
data/VERSION.yml
CHANGED
data/lib/usher.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
$:.unshift File.dirname(__FILE__)
|
2
2
|
|
3
3
|
require 'cgi'
|
4
|
+
require 'uri'
|
4
5
|
require 'usher/node'
|
5
6
|
require 'usher/route'
|
6
7
|
require 'usher/grapher'
|
@@ -135,12 +136,10 @@ class Usher
|
|
135
136
|
# <tt>/path/something.html</tt>. Generally its more efficent to use one and only sections over using regex.
|
136
137
|
#
|
137
138
|
# === +options+
|
138
|
-
# * +transformers+ - Transforms a variable before it gets to the requirements. Takes either a +proc+ or a +symbol+. If its a +symbol+, calls the method on the incoming parameter. If its a +proc+, its called with the variable.
|
139
139
|
# * +requirements+ - After transformation, tests the condition using ===. If it returns false, it raises an <tt>Usher::ValidationException</tt>
|
140
140
|
# * +conditions+ - Accepts any of the +request_methods+ specificied in the construction of Usher. This can be either a <tt>string</tt> or a regular expression.
|
141
141
|
# * Any other key is interpreted as a requirement for the variable of its name.
|
142
142
|
def add_route(path, options = nil)
|
143
|
-
transformers = options && options.delete(:transformers) || {}
|
144
143
|
conditions = options && options.delete(:conditions) || {}
|
145
144
|
requirements = options && options.delete(:requirements) || {}
|
146
145
|
if options
|
@@ -151,7 +150,7 @@ class Usher
|
|
151
150
|
end
|
152
151
|
end
|
153
152
|
end
|
154
|
-
route = Route.new(path, self, {:
|
153
|
+
route = Route.new(path, self, {:conditions => conditions, :requirements => requirements})
|
155
154
|
route.to(options) if options && !options.empty?
|
156
155
|
|
157
156
|
@tree.add(route)
|
@@ -224,15 +223,18 @@ class Usher
|
|
224
223
|
case p.type
|
225
224
|
when :*
|
226
225
|
param_list.first.each {|dp| p.valid!(dp.to_s) } if check_variables
|
227
|
-
generated_path << param_list.shift.collect{|dp| dp.to_s} * delimiter
|
226
|
+
generated_path << param_list.shift.collect{|dp| URI.escape(dp.to_s)} * delimiter
|
228
227
|
else
|
229
228
|
p.valid!(param_list.first.to_s) if check_variables
|
230
|
-
|
229
|
+
if dp = param_list.shift
|
230
|
+
generated_path << URI.escape(dp.to_s)
|
231
|
+
end
|
231
232
|
end
|
232
233
|
else
|
233
234
|
generated_path << p.to_s
|
234
235
|
end
|
235
236
|
end
|
237
|
+
|
236
238
|
unless params_hash.empty?
|
237
239
|
has_query = generated_path[??]
|
238
240
|
params_hash.each do |k,v|
|
data/lib/usher/node.rb
CHANGED
@@ -90,37 +90,27 @@ class Usher
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def find(request, path, params = [])
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
[@lookup[request.send(@exclusive_type)], @lookup[nil]].each do |n|
|
98
|
-
ret = n.find(request, path.dup, params.dup) if n
|
99
|
-
ret and return ret
|
100
|
-
end
|
101
|
-
elsif path.size.zero? && !part
|
102
|
-
if terminates?
|
103
|
-
Response.new(terminates, params)
|
104
|
-
elsif params.last.is_a?(Array) && @lookup[nil]
|
105
|
-
if @lookup[nil].exclusive_type
|
106
|
-
@lookup[nil].find(request, path, params)
|
107
|
-
else
|
108
|
-
Response.new(@lookup[nil].terminates, params)
|
93
|
+
if exclusive_type
|
94
|
+
[lookup[request.send(exclusive_type)], lookup[nil]].each do |n|
|
95
|
+
if n && (ret = n.find(request, path.dup, params.dup))
|
96
|
+
return ret
|
109
97
|
end
|
110
98
|
end
|
111
|
-
elsif
|
112
|
-
|
99
|
+
elsif path.size.zero? && terminates?
|
100
|
+
Response.new(terminates, params)
|
101
|
+
elsif next_part = lookup[part = path.shift] || lookup[nil]
|
102
|
+
case next_part.value
|
103
|
+
when Route::Variable
|
113
104
|
case next_part.value.type
|
114
105
|
when :*
|
115
106
|
params << [next_part.value.name, []] unless params.last && params.last.first == next_part.value.name
|
116
107
|
loop do
|
117
|
-
if (next_part.value.look_ahead === part || (!part.is_a?(Symbol) && !next_part.value.regex_matcher.match(part)))
|
108
|
+
if (next_part.value.look_ahead === part || (!part.is_a?(Symbol) && next_part.value.regex_matcher && !next_part.value.regex_matcher.match(part)))
|
118
109
|
path.unshift(part)
|
119
110
|
path.unshift(next_part.parent.value) if next_part.parent.value.is_a?(Symbol)
|
120
111
|
break
|
121
112
|
else
|
122
113
|
unless part.is_a?(Symbol) && !next_part.value.globs_capture_separators
|
123
|
-
part = next_part.value.transform!(part)
|
124
114
|
next_part.value.valid!(part)
|
125
115
|
params.last.last << part
|
126
116
|
end
|
@@ -131,48 +121,16 @@ class Usher
|
|
131
121
|
part = path.shift
|
132
122
|
end
|
133
123
|
end
|
134
|
-
next_part.find(request, path, params)
|
135
|
-
when :':'
|
136
|
-
part = next_part.value.transform!(part)
|
137
|
-
next_part.value.valid!(part)
|
138
|
-
var = next_part.value
|
139
|
-
params << [next_part.value.name, part]
|
140
|
-
until (path.first == var.look_ahead) || path.empty?
|
141
|
-
params.last.last << path.shift.to_s
|
142
|
-
end
|
143
|
-
next_part.find(request, path, params)
|
144
|
-
end
|
145
|
-
else
|
146
|
-
next_part.find(request, path, params)
|
147
|
-
end
|
148
|
-
elsif next_part = @lookup[nil]
|
149
|
-
if next_part.value.is_a?(Route::Variable)
|
150
|
-
case next_part.value.type
|
151
|
-
when :*
|
152
|
-
params << [next_part.value.name, []] unless params.last && params.last.first == next_part.value.name
|
153
|
-
if next_part.value.look_ahead === part
|
154
|
-
path.unshift(part)
|
155
|
-
path.unshift(next_part.parent.value) if next_part.parent.value.is_a?(Symbol)
|
156
|
-
next_part.find(request, path, params)
|
157
|
-
else
|
158
|
-
unless part.is_a?(Symbol) && !next_part.value.globs_capture_separators
|
159
|
-
part = next_part.value.transform!(part)
|
160
|
-
next_part.value.valid!(part)
|
161
|
-
params.last.last << part
|
162
|
-
end
|
163
|
-
find(request, path, params)
|
164
|
-
end
|
165
124
|
when :':'
|
166
|
-
part = next_part.value.transform!(part)
|
167
125
|
next_part.value.valid!(part)
|
168
126
|
var = next_part.value
|
169
127
|
params << [next_part.value.name, part]
|
170
128
|
until (path.first == var.look_ahead) || path.empty?
|
171
129
|
params.last.last << path.shift.to_s
|
172
130
|
end
|
173
|
-
next_part.find(request, path, params)
|
174
131
|
end
|
175
132
|
end
|
133
|
+
next_part.find(request, path, params)
|
176
134
|
else
|
177
135
|
nil
|
178
136
|
end
|
data/lib/usher/route.rb
CHANGED
@@ -13,8 +13,7 @@ class Usher
|
|
13
13
|
@router = router
|
14
14
|
@requirements = options && options.delete(:requirements)
|
15
15
|
@conditions = options && options.delete(:conditions)
|
16
|
-
@
|
17
|
-
@paths = @router.splitter.split(@original_path, @requirements, @transformers).collect {|path| Path.new(self, path)}
|
16
|
+
@paths = @router.splitter.split(@original_path, @requirements).collect {|path| Path.new(self, path)}
|
18
17
|
@primary_path = @paths.first
|
19
18
|
#FIXME params is poorly named. this shouldn't be an array
|
20
19
|
@params = []
|
data/lib/usher/route/variable.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
class Usher
|
2
2
|
class Route
|
3
3
|
class Variable
|
4
|
-
attr_reader :type, :name, :validator, :
|
4
|
+
attr_reader :type, :name, :validator, :regex_matcher
|
5
5
|
attr_accessor :look_ahead, :globs_capture_separators
|
6
6
|
|
7
|
-
def initialize(type, name, validator = nil,
|
7
|
+
def initialize(type, name, validator = nil, regex_matcher = nil, globs_capture_separators = false)
|
8
8
|
@type = type
|
9
9
|
@name = :"#{name}"
|
10
10
|
@validator = validator
|
11
|
-
@transformer = transformer
|
12
11
|
@regex_matcher = regex_matcher
|
13
12
|
@globs_capture_separators = globs_capture_separators
|
14
13
|
end
|
@@ -17,19 +16,6 @@ class Usher
|
|
17
16
|
"#{type}#{name}"
|
18
17
|
end
|
19
18
|
|
20
|
-
def transform!(val)
|
21
|
-
return val unless @transformer
|
22
|
-
|
23
|
-
case @transformer
|
24
|
-
when Proc
|
25
|
-
@transformer.call(val)
|
26
|
-
when Symbol
|
27
|
-
val.send(@transformer)
|
28
|
-
end
|
29
|
-
rescue Exception => e
|
30
|
-
raise ValidationException.new("#{val} could not be successfully transformed by #{@transformer}, root cause #{e.inspect}")
|
31
|
-
end
|
32
|
-
|
33
19
|
def valid!(val)
|
34
20
|
case @validator
|
35
21
|
when Proc
|
data/lib/usher/splitter.rb
CHANGED
@@ -19,27 +19,18 @@ class Usher
|
|
19
19
|
def initialize(delimiters, split_regex, url_split_regex)
|
20
20
|
@delimiters = delimiters
|
21
21
|
@delimiter_chars = delimiters.collect{|d| d[0]}
|
22
|
+
@delimiter_chars_map = Hash[*@delimiter_chars.map{|c| [c, c.chr.to_sym]}.flatten]
|
22
23
|
@split_regex = split_regex
|
23
24
|
@url_split_regex = url_split_regex
|
24
25
|
end
|
25
26
|
|
26
27
|
def url_split(path)
|
27
|
-
parts =
|
28
|
-
|
29
|
-
while !ss.eos?
|
30
|
-
if part = ss.scan(@url_split_regex)
|
31
|
-
parts << case part[0]
|
32
|
-
when *@delimiter_chars
|
33
|
-
part.to_sym
|
34
|
-
else
|
35
|
-
part
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end if path && !path.empty?
|
28
|
+
parts = path.scan(@url_split_regex)
|
29
|
+
parts.map!{ |part| @delimiter_chars_map[part[0]] || part}
|
39
30
|
parts
|
40
31
|
end
|
41
32
|
|
42
|
-
def split(path, requirements = nil
|
33
|
+
def split(path, requirements = nil)
|
43
34
|
parts = Group.new(:all, nil)
|
44
35
|
ss = StringScanner.new(path)
|
45
36
|
current_group = parts
|
@@ -48,9 +39,9 @@ class Usher
|
|
48
39
|
case part[0]
|
49
40
|
when ?*, ?:
|
50
41
|
type = part.slice!(0).chr.to_sym
|
51
|
-
current_group << Usher::Route::Variable.new(type, part, requirements && requirements[part.to_sym]
|
42
|
+
current_group << Usher::Route::Variable.new(type, part, requirements && requirements[part.to_sym])
|
52
43
|
when ?{
|
53
|
-
pattern = '
|
44
|
+
pattern = ''
|
54
45
|
count = 1
|
55
46
|
variable = ss.scan(/[:\*]([^,]+),/)
|
56
47
|
until count.zero?
|
@@ -63,12 +54,12 @@ class Usher
|
|
63
54
|
end
|
64
55
|
pattern << regex_part
|
65
56
|
end
|
66
|
-
pattern
|
57
|
+
pattern.slice!(pattern.length - 1)
|
67
58
|
regex = Regexp.new(pattern)
|
68
59
|
if variable
|
69
60
|
variable_type = variable.slice!(0).chr.to_sym
|
70
61
|
variable_name = variable[0, variable.size - 1].to_sym
|
71
|
-
current_group << Usher::Route::Variable.new(variable_type, variable_name, requirements && requirements[variable_name],
|
62
|
+
current_group << Usher::Route::Variable.new(variable_type, variable_name, requirements && requirements[variable_name], regex)
|
72
63
|
else
|
73
64
|
current_group << regex
|
74
65
|
end
|
@@ -18,6 +18,11 @@ describe "Usher URL generation" do
|
|
18
18
|
route_set.generate_url(:sample, {:action => 'action'}).should == '/sample/action'
|
19
19
|
end
|
20
20
|
|
21
|
+
it "should generate a simple URL with a single variable (and escape)" do
|
22
|
+
route_set.add_named_route(:sample, '/sample/:action', :controller => 'sample')
|
23
|
+
route_set.generate_url(:sample, {:action => 'action time'}).should == '/sample/action%20time'
|
24
|
+
end
|
25
|
+
|
21
26
|
it "should generate a simple URL with a single variable (thats not a string)" do
|
22
27
|
route_set.add_named_route(:sample, '/sample/:action/:id', :controller => 'sample')
|
23
28
|
route_set.generate_url(:sample, {:action => 'action', :id => 123}).should == '/sample/action/123'
|
@@ -10,8 +10,6 @@ def build_request(opts)
|
|
10
10
|
request
|
11
11
|
end
|
12
12
|
|
13
|
-
SampleController = Object.new
|
14
|
-
|
15
13
|
describe "Usher route recognition" do
|
16
14
|
|
17
15
|
before(:each) do
|
@@ -83,6 +81,12 @@ describe "Usher route recognition" do
|
|
83
81
|
route_set.recognize(build_request({:method => 'get', :path => '/test/part/hello/again/123/hello/again/onemore'})).params.should == [[:test, ['hello', 'again', '123', 'hello', 'again']]]
|
84
82
|
end
|
85
83
|
|
84
|
+
it "should recgonize a regex glob variable terminated by a single regex variable" do
|
85
|
+
target_route = route_set.add_route('/test/part/{*test,^(hello|again|\d+)$}/{:party,onemore}')
|
86
|
+
route_set.recognize(build_request({:method => 'get', :path => '/test/part/hello/again/123/hello/again/onemore'})).path.route.should == target_route
|
87
|
+
route_set.recognize(build_request({:method => 'get', :path => '/test/part/hello/again/123/hello/again/onemore'})).params.should == [[:test, ['hello', 'again', '123', 'hello', 'again']], [:party, 'onemore']]
|
88
|
+
end
|
89
|
+
|
86
90
|
it "should recgonize two glob-style variables separated by a static part" do
|
87
91
|
target_route = route_set.add_route('/*format/innovate/*onemore')
|
88
92
|
response = route_set.recognize(build_request({:method => 'get', :path => '/sample/html/innovate/apple'}))
|
@@ -143,11 +147,6 @@ describe "Usher route recognition" do
|
|
143
147
|
www_product_show_route.should == route_set.recognize(build_request({:method => 'get', :path => '/products/show/123', :subdomains => ['www'], :user_agent => false})).path.route
|
144
148
|
end
|
145
149
|
|
146
|
-
it "should use a transformer (proc) on incoming variables" do
|
147
|
-
route_set.add_route('/:controller/:action/:id', :transformers => {:id => proc{|v| v.to_i}})
|
148
|
-
route_set.recognize(build_request({:method => 'get', :path => '/products/show/123asd', :domain => 'admin.host.com'})).params.rassoc(123).first.should == :id
|
149
|
-
end
|
150
|
-
|
151
150
|
it "should use a requirement (proc) on incoming variables" do
|
152
151
|
route_set.add_route('/:controller/:action/:id', :id => proc{|v| Integer(v)})
|
153
152
|
proc {route_set.recognize(build_request({:method => 'get', :path => '/products/show/123', :domain => 'admin.host.com'}))}.should_not raise_error Usher::ValidationException
|
@@ -164,19 +163,10 @@ describe "Usher route recognition" do
|
|
164
163
|
route_set.recognize(build_request({:method => 'get', :path => '/testing/asd.qwe/testing2/poi.zxc/oiu.asd'})).params.should == [[:id, 'asd.qwe'], [:id2, 'poi.zxc'], [:id3, 'oiu.asd']]
|
165
164
|
end
|
166
165
|
|
167
|
-
it "should use a transformer (symbol) on incoming variables" do
|
168
|
-
route_set.add_route('/:controller/:action/:id', :transformers => {:id => :to_i})
|
169
|
-
route_set.recognize(build_request({:method => 'get', :path => '/products/show/123asd', :domain => 'admin.host.com'})).params.rassoc(123).first.should == :id
|
170
|
-
end
|
171
|
-
|
172
166
|
it "should should raise if malformed variables are used" do
|
173
167
|
route_set.add_route('/products/show/:id', :id => /\d+/, :conditions => {:method => 'get'})
|
174
168
|
proc {route_set.recognize(build_request({:method => 'get', :path => '/products/show/qweasd', :domain => 'admin.host.com'}))}.should raise_error
|
175
169
|
end
|
176
170
|
|
177
|
-
it "should should raise if transformer proc raises (anything)" do
|
178
|
-
route_set.add_route('/products/show/:id', :transformers => {:id => proc{|v| Integer(v)}})
|
179
|
-
proc {route_set.recognize(build_request({:method => 'get', :path => '/products/show/qweasd', :domain => 'admin.host.com'}))}.should raise_error(Usher::ValidationException)
|
180
|
-
end
|
181
171
|
|
182
172
|
end
|
data/spec/private/split_spec.rb
CHANGED
@@ -9,7 +9,7 @@ describe "Usher route tokenizing" do
|
|
9
9
|
|
10
10
|
it "should split / delimited routes with a regex in it" do
|
11
11
|
Usher::Splitter.for_delimiters(['/', '.'], '[0-9A-Za-z\$\-_\+!\*\',]+').
|
12
|
-
split('/test/{this}/split').should == [[:/, 'test', :/,
|
12
|
+
split('/test/{this}/split').should == [[:/, 'test', :/, /this/, :/, 'split']]
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should split on ' ' delimited routes as well" do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: joshbuddy-usher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Hull
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-15 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|