usher 0.4.8 → 0.5.1
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 +12 -1
- data/Rakefile +5 -29
- data/VERSION.yml +2 -2
- data/lib/usher.rb +126 -37
- data/lib/usher/grapher.rb +5 -4
- data/lib/usher/interface.rb +12 -5
- data/lib/usher/interface/email_interface.rb +1 -1
- data/lib/usher/interface/rack_interface.rb +31 -13
- data/lib/usher/interface/rails2_2_interface.rb +3 -4
- data/lib/usher/interface/rails2_3_interface.rb +3 -4
- data/lib/usher/interface/rails3_interface.rb +57 -0
- data/lib/usher/node.rb +121 -73
- data/lib/usher/route.rb +45 -11
- data/lib/usher/route/path.rb +50 -11
- data/lib/usher/route/util.rb +65 -0
- data/lib/usher/route/variable.rb +22 -11
- data/lib/usher/splitter.rb +4 -141
- data/lib/usher/util.rb +6 -0
- data/lib/usher/util/generate.rb +129 -0
- data/lib/usher/util/parser.rb +145 -0
- data/spec/private/email/recognize_spec.rb +2 -4
- data/spec/private/generate_spec.rb +86 -32
- data/spec/private/grapher_spec.rb +5 -6
- data/spec/private/parser_spec.rb +75 -0
- data/spec/private/path_spec.rb +35 -4
- data/spec/private/rack/dispatch_spec.rb +100 -15
- data/spec/private/recognize_spec.rb +88 -50
- data/spec/spec_helper.rb +22 -0
- metadata +13 -7
- data/lib/usher/generate.rb +0 -131
- data/spec/private/split_spec.rb +0 -76
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
class Usher
|
4
|
+
module Util
|
5
|
+
class Parser
|
6
|
+
|
7
|
+
def self.for_delimiters(router, valid_regex)
|
8
|
+
ParserInstance.new(
|
9
|
+
router,
|
10
|
+
Regexp.new('((:|\*)?' + valid_regex + '|' + router.delimiters_regex + '|\(|\)|\||\{)')
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
class ParserInstance
|
15
|
+
|
16
|
+
def initialize(router, split_regex)
|
17
|
+
@router = router
|
18
|
+
@split_regex = split_regex
|
19
|
+
end
|
20
|
+
|
21
|
+
def generate_route(unprocessed_path, conditions, requirements, default_values, generate_with)
|
22
|
+
match_partially = if unprocessed_path.is_a?(String)
|
23
|
+
unprocessed_path = parse(unprocessed_path, requirements, default_values)
|
24
|
+
if unprocessed_path[-1] == ?*
|
25
|
+
unprocessed_path.slice!(-1)
|
26
|
+
true
|
27
|
+
else
|
28
|
+
false
|
29
|
+
end
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
|
34
|
+
unless unprocessed_path.first.is_a?(Route::Util::Group)
|
35
|
+
group = Usher::Route::Util::Group.new(:all, nil)
|
36
|
+
unprocessed_path.each{|p| group << p}
|
37
|
+
unprocessed_path = group
|
38
|
+
end
|
39
|
+
|
40
|
+
paths = Route::Util.expand_path(unprocessed_path)
|
41
|
+
|
42
|
+
paths.each do |path|
|
43
|
+
path.each_with_index do |part, index|
|
44
|
+
part.default_value = default_values[part.name] if part.is_a?(Usher::Route::Variable) && default_values && default_values[part.name]
|
45
|
+
case part
|
46
|
+
when Usher::Route::Variable::Glob
|
47
|
+
part.look_ahead = path[index + 1, path.size].find{|p| !p.is_a?(Usher::Route::Variable) && !router.delimiter_chars.include?(p[0])} || nil
|
48
|
+
when Usher::Route::Variable
|
49
|
+
part.look_ahead = path[index + 1, path.size].find{|p| router.delimiter_chars.include?(p[0])} || router.delimiters.first
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
Route.new(
|
55
|
+
paths,
|
56
|
+
router,
|
57
|
+
conditions,
|
58
|
+
requirements,
|
59
|
+
default_values,
|
60
|
+
generate_with,
|
61
|
+
match_partially
|
62
|
+
)
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def parse_and_expand(path, requirements = nil, default_values = nil)
|
68
|
+
Usher::Route::Util.expand_path(parse(path, requirements, default_values))
|
69
|
+
end
|
70
|
+
|
71
|
+
def parse(path, requirements = nil, default_values = nil)
|
72
|
+
parts = Usher::Route::Util::Group.new(:all, nil)
|
73
|
+
ss = StringScanner.new(path)
|
74
|
+
current_group = parts
|
75
|
+
while !ss.eos?
|
76
|
+
part = ss.scan(@split_regex)
|
77
|
+
case part[0]
|
78
|
+
when ?*
|
79
|
+
var_name = part[1, part.size - 1].to_sym
|
80
|
+
current_group << Usher::Route::Variable::Glob.new(part[1, part.size - 1], nil, requirements && requirements[var_name])
|
81
|
+
when ?:
|
82
|
+
var_name = part[1, part.size - 1].to_sym
|
83
|
+
current_group << Usher::Route::Variable::Single.new(part[1, part.size - 1], nil, requirements && requirements[var_name])
|
84
|
+
when ?{
|
85
|
+
pattern = ''
|
86
|
+
count = 1
|
87
|
+
variable = ss.scan(/[!:\*]([^,]+),/)
|
88
|
+
until count.zero?
|
89
|
+
regex_part = ss.scan(/\{|\}|[^\{\}]+/)
|
90
|
+
case regex_part[0]
|
91
|
+
when ?{
|
92
|
+
count += 1
|
93
|
+
when ?}
|
94
|
+
count -= 1
|
95
|
+
end
|
96
|
+
pattern << regex_part
|
97
|
+
end
|
98
|
+
pattern.slice!(pattern.length - 1)
|
99
|
+
regex = Regexp.new(pattern)
|
100
|
+
if variable
|
101
|
+
variable_type = variable.slice!(0).chr.to_sym
|
102
|
+
variable_class = case variable_type
|
103
|
+
when :'!' then Usher::Route::Variable::Greedy
|
104
|
+
when :* then Usher::Route::Variable::Glob
|
105
|
+
when :':' then Usher::Route::Variable::Single
|
106
|
+
end
|
107
|
+
|
108
|
+
variable_name = variable[0, variable.size - 1].to_sym
|
109
|
+
current_group << variable_class.new(variable_name, regex, requirements && requirements[variable_name])
|
110
|
+
else
|
111
|
+
current_group << regex
|
112
|
+
end
|
113
|
+
when ?(
|
114
|
+
new_group = Usher::Route::Util::Group.new(:any, current_group)
|
115
|
+
current_group << new_group
|
116
|
+
current_group = new_group
|
117
|
+
when ?)
|
118
|
+
current_group = current_group.parent.group_type == :one ? current_group.parent.parent : current_group.parent
|
119
|
+
when ?|
|
120
|
+
unless current_group.parent.group_type == :one
|
121
|
+
detached_group = current_group.parent.pop
|
122
|
+
new_group = Usher::Route::Util::Group.new(:one, detached_group.parent)
|
123
|
+
detached_group.parent = new_group
|
124
|
+
detached_group.group_type = :all
|
125
|
+
new_group << detached_group
|
126
|
+
new_group.parent << new_group
|
127
|
+
end
|
128
|
+
current_group.parent << Usher::Route::Util::Group.new(:all, current_group.parent)
|
129
|
+
current_group = current_group.parent.last
|
130
|
+
else
|
131
|
+
current_group << part
|
132
|
+
end
|
133
|
+
end unless !path || path.empty?
|
134
|
+
parts
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
attr_reader :router
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
require 'lib/usher'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
3
|
def build_email_mock(email)
|
6
4
|
request = mock "Request"
|
7
5
|
request.should_receive(:email).any_number_of_times.and_return(email)
|
@@ -24,14 +22,14 @@ describe "Usher (for email) route recognition" do
|
|
24
22
|
it "should recognize a wildcard domain" do
|
25
23
|
receiver = mock('receiver')
|
26
24
|
receiver.should_receive(:action).with({:domain => 'gmail.com'}).exactly(1)
|
27
|
-
@route_set.for('joshbuddy
|
25
|
+
@route_set.for('joshbuddy@{!domain,.*}') { |params| receiver.action(params) }
|
28
26
|
@route_set.act('joshbuddy@gmail.com')
|
29
27
|
end
|
30
28
|
|
31
29
|
it "should recognize a complex email" do
|
32
30
|
receiver = mock('receiver')
|
33
31
|
receiver.should_receive(:action).with({:subject => 'sub+ect', :id => '123', :sid => '456', :tok => 'sdqwe123ae', :domain => 'mydomain.org'}).exactly(1)
|
34
|
-
@route_set.for(':subject.{
|
32
|
+
@route_set.for(':subject.{!id,\d+}-{!sid,\d+}-{!tok,\w+}@{!domain,.*}') { |params| receiver.action(params) }
|
35
33
|
@route_set.act('sub+ect.123-456-sdqwe123ae@mydomain.org')
|
36
34
|
end
|
37
35
|
|
@@ -4,138 +4,192 @@ require 'rack'
|
|
4
4
|
describe "Usher URL generation" do
|
5
5
|
|
6
6
|
before(:each) do
|
7
|
-
@route_set = Usher.new
|
7
|
+
@route_set = Usher.new(:generator => Usher::Util::Generators::URL.new)
|
8
8
|
@route_set.reset!
|
9
|
-
@url_generator = Usher::Generators::URL.new(@route_set)
|
10
9
|
end
|
11
10
|
|
12
11
|
it "should generate a simple URL" do
|
13
12
|
@route_set.add_named_route(:sample, '/sample', :controller => 'sample', :action => 'action')
|
14
|
-
@
|
13
|
+
@route_set.generator.generate(:sample, {}).should == '/sample'
|
15
14
|
end
|
16
15
|
|
17
16
|
it "should generate a simple URL with a single variable" do
|
18
17
|
@route_set.add_named_route(:sample, '/sample/:action', :controller => 'sample')
|
19
|
-
@
|
18
|
+
@route_set.generator.generate(:sample, {:action => 'action'}).should == '/sample/action'
|
20
19
|
end
|
21
20
|
|
22
21
|
it "should generate a simple URL with a single variable (and escape)" do
|
23
22
|
@route_set.add_named_route(:sample, '/sample/:action', :controller => 'sample')
|
24
|
-
@
|
23
|
+
@route_set.generator.generate(:sample, {:action => 'action time'}).should == '/sample/action%20time'
|
25
24
|
end
|
26
25
|
|
27
26
|
it "should generate a simple URL with a single variable (thats not a string)" do
|
28
27
|
@route_set.add_named_route(:sample, '/sample/:action/:id', :controller => 'sample')
|
29
|
-
@
|
28
|
+
@route_set.generator.generate(:sample, {:action => 'action', :id => 123}).should == '/sample/action/123'
|
30
29
|
end
|
31
30
|
|
32
31
|
it "should generate a simple URL with a glob variable" do
|
33
32
|
@route_set.add_named_route(:sample, '/sample/*action', :controller => 'sample')
|
34
|
-
@
|
33
|
+
@route_set.generator.generate(:sample, {:action => ['foo', 'baz']}).should == '/sample/foo/baz'
|
35
34
|
end
|
36
35
|
|
37
36
|
it "should generate a mutliple vairable URL from a hash" do
|
38
37
|
@route_set.add_named_route(:sample, '/sample/:first/:second', :controller => 'sample')
|
39
|
-
@
|
38
|
+
@route_set.generator.generate(:sample, {:first => 'zoo', :second => 'maz'}).should == '/sample/zoo/maz'
|
40
39
|
end
|
41
40
|
|
42
41
|
it "should generate a mutliple vairable URL from an array" do
|
43
42
|
@route_set.add_named_route(:sample, '/sample/:first/:second', :controller => 'sample')
|
44
|
-
@
|
43
|
+
@route_set.generator.generate(:sample, ['maz', 'zoo']).should == '/sample/maz/zoo'
|
45
44
|
end
|
46
45
|
|
47
46
|
it "should generate append extra hash variables to the end" do
|
48
47
|
@route_set.add_named_route(:sample, '/sample/:first/:second', :controller => 'sample')
|
49
|
-
@
|
48
|
+
@route_set.generator.generate(:sample, {:first => 'maz', :second => 'zoo', :third => 'zanz'}).should == '/sample/maz/zoo?third=zanz'
|
50
49
|
end
|
51
50
|
|
52
51
|
it "should generate append extra hash variables to the end (when the first parts are an array)" do
|
53
52
|
@route_set.add_named_route(:sample, '/sample/:first/:second', :controller => 'sample')
|
54
|
-
['/sample/maz/zoo?four=jane&third=zanz', '/sample/maz/zoo?third=zanz&four=jane'].include?(@
|
53
|
+
['/sample/maz/zoo?four=jane&third=zanz', '/sample/maz/zoo?third=zanz&four=jane'].include?(@route_set.generator.generate(:sample, ['maz', 'zoo', {:third => 'zanz', :four => 'jane'}])).should == true
|
55
54
|
end
|
56
55
|
|
57
56
|
it "should generate append extra hash variables to the end using [] syntax if its an array" do
|
58
57
|
@route_set.add_named_route(:sample, '/sample/:first/:second', :controller => 'sample')
|
59
|
-
@
|
58
|
+
@route_set.generator.generate(:sample, {:first => 'maz', :second => 'zoo', :third => ['zanz', 'susie']}).should == '/sample/maz/zoo?third%5B%5D=zanz&third%5B%5D=susie'
|
60
59
|
end
|
61
60
|
|
62
61
|
it "should generate a mutliple vairable URL from an array" do
|
63
62
|
@route_set.add_named_route(:sample, '/sample/:first/:second', :controller => 'sample')
|
64
|
-
@
|
63
|
+
@route_set.generator.generate(:sample, ['maz', 'zoo']).should == '/sample/maz/zoo'
|
65
64
|
end
|
66
65
|
|
67
66
|
it "should generate a simple URL with a format" do
|
68
67
|
@route_set.add_named_route(:sample, '/sample/:action.:format', :controller => 'sample')
|
69
|
-
@
|
68
|
+
@route_set.generator.generate(:sample, {:action => 'action', :format => 'html'}).should == '/sample/action.html'
|
70
69
|
end
|
71
70
|
|
72
71
|
it "should generate from parameters" do
|
73
72
|
caf = @route_set.add_route('/:controller/:action.:format')
|
74
73
|
ca = @route_set.add_route('/:controller/:action')
|
75
|
-
@
|
76
|
-
@
|
74
|
+
@route_set.generator.generate(nil, {:controller => 'controller', :action => 'action'}).should == '/controller/action'
|
75
|
+
@route_set.generator.generate(nil, {:controller => 'controller', :action => 'action', :format => 'html'}).should == '/controller/action.html'
|
77
76
|
end
|
78
77
|
|
79
78
|
it "should use the first route when generating a URL from two ambiguous routes" do
|
80
79
|
@route_set.add_route('/:controller/:action')
|
81
80
|
@route_set.add_route('/:action/:controller')
|
82
|
-
@
|
81
|
+
@route_set.generator.generate(nil, {:controller => 'controller', :action => 'action'}).should == '/controller/action'
|
83
82
|
end
|
84
83
|
|
85
84
|
it "should accept an array of parameters" do
|
86
85
|
caf = @route_set.add_named_route(:name, '/:controller/:action.:format')
|
87
|
-
@
|
86
|
+
@route_set.generator.generate(:name, ['controller', 'action', 'html']).should == '/controller/action.html'
|
88
87
|
end
|
89
88
|
|
90
89
|
it "should generate a route with a specific host" do
|
91
90
|
caf = @route_set.add_named_route(:name, '/:controller/:action.:format', :generate_with => {:host => 'www.slashdot.org', :port => 80})
|
92
|
-
@
|
91
|
+
@route_set.generator.generate_full(:name, Rack::Request.new(Rack::MockRequest.env_for("http://localhost:8080")), ['controller', 'action', 'html']).should == 'http://www.slashdot.org/controller/action.html'
|
93
92
|
end
|
94
93
|
|
95
94
|
it "should require all the parameters (hash) to generate a route" do
|
96
|
-
proc
|
95
|
+
proc{@route_set.generator.generate(@route_set.add_route('/:controller/:action'), {:controller => 'controller'})}.should raise_error(Usher::MissingParameterException)
|
97
96
|
end
|
98
97
|
|
99
98
|
it "should generate from a route" do
|
100
|
-
@
|
99
|
+
@route_set.generator.generate(@route_set.add_route('/:controller/:action'), {:controller => 'controller', :action => 'action'}).should == '/controller/action'
|
101
100
|
end
|
102
101
|
|
103
102
|
it "should require all the parameters (array) to generate a route" do
|
104
103
|
@route_set.add_named_route(:name, '/:controller/:action.:format')
|
105
|
-
proc {@
|
104
|
+
proc {@route_set.generator.generate(:name, ['controller', 'action'])}.should raise_error(Usher::MissingParameterException)
|
106
105
|
end
|
107
106
|
|
108
107
|
it "should generate a route when only one parameter is given" do
|
109
108
|
@route_set.add_named_route(:name, '/:controller')
|
110
|
-
@
|
109
|
+
@route_set.generator.generate(:name, 'controller').should == '/controller'
|
111
110
|
end
|
112
111
|
|
113
112
|
it "should generate the correct route from a route containing optional parts" do
|
114
113
|
@route_set.add_named_route(:name, '/:controller(/:action(/:id))')
|
115
|
-
@
|
116
|
-
@
|
117
|
-
@
|
114
|
+
@route_set.generator.generate(:name, {:controller => 'controller'}).should == '/controller'
|
115
|
+
@route_set.generator.generate(:name, {:controller => 'controller', :action => 'action'}).should == '/controller/action'
|
116
|
+
@route_set.generator.generate(:name, {:controller => 'controller', :action => 'action', :id => 'id'}).should == '/controller/action/id'
|
118
117
|
end
|
119
118
|
|
120
119
|
it "should generate a route using defaults for everything but the first parameter" do
|
121
120
|
@route_set.add_named_route(:name, '/:one/:two/:three', {:default_values => {:one => 'one', :two => 'two', :three => 'three'}})
|
122
|
-
@
|
121
|
+
@route_set.generator.generate(:name, {:one => "1"}).should == '/1/two/three'
|
123
122
|
end
|
124
123
|
|
125
124
|
it "should generate a route using defaults for everything" do
|
126
125
|
@route_set.add_named_route(:name, '/:one/:two/:three', {:default_values => {:one => 'one', :two => 'two', :three => 'three'}})
|
127
|
-
@
|
126
|
+
@route_set.generator.generate(:name).should == '/one/two/three'
|
128
127
|
end
|
129
128
|
|
130
129
|
it "should generate a route using defaults and optionals using the last parameter" do
|
131
130
|
@route_set.add_named_route(:opts_with_defaults, '/:one(/:two(/:three))', {:default_values => {:one => '1', :two => '2', :three => '3'}})
|
132
|
-
@
|
131
|
+
@route_set.generator.generate(:opts_with_defaults, {:three => 'three'}).should == '/1/2/three'
|
133
132
|
end
|
134
133
|
|
135
134
|
it "should generate a route with optional segments given two nested optional parameters" do
|
136
135
|
@route_set.add_named_route(:optionals, '/:controller(/:action(/:id))(.:format)')
|
137
|
-
@
|
136
|
+
@route_set.generator.generate(:optionals, {:controller => "foo", :action => "bar"}).should == '/foo/bar'
|
137
|
+
end
|
138
|
+
|
139
|
+
describe "nested generation" do
|
140
|
+
before do
|
141
|
+
@route_set2 = Usher.new(:generator => Usher::Util::Generators::URL.new)
|
142
|
+
@route_set3 = Usher.new(:generator => Usher::Util::Generators::URL.new)
|
143
|
+
@route_set4 = Usher.new(:generator => Usher::Util::Generators::URL.new)
|
144
|
+
|
145
|
+
@route_set.add_named_route(:simple, "/mount_point").match_partially!.to(@route_set2)
|
146
|
+
@route_set.add_route("/third/:foo", :default_values => {:foo => "foo"}).match_partially!.to(@route_set3)
|
147
|
+
@route_set.add_route("/fourth/:bar").match_partially!.to(@route_set4)
|
148
|
+
|
149
|
+
@route_set2.add_named_route(:nested_simple, "/nested/simple", :controller => "nested", :action => "simple")
|
150
|
+
@route_set2.add_named_route(:nested_complex, "/another_nested(/:complex)", :controller => "nested", :action => "complex")
|
151
|
+
|
152
|
+
@route_set3.add_named_route(:nested_simple, "/nested/simple", :controller => "nested", :action => "simple")
|
153
|
+
@route_set3.add_named_route(:nested_complex, "/another_nested(/:complex)", :controller => "nested", :action => "complex")
|
154
|
+
|
155
|
+
@route_set4.add_named_route(:nested_simple, "/nested/simple", :controller => "nested", :action => "simple")
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should generate a route for the simple nested route" do
|
159
|
+
@route_set2.generator.generate(:nested_simple).should == "/mount_point/nested/simple"
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should generate a simple route without optional segments" do
|
163
|
+
@route_set2.generator.generate(:nested_complex).should == "/mount_point/another_nested"
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should generate a route with optional segements" do
|
167
|
+
@route_set2.generator.generate(:nested_complex, :complex => "foo").should == "/mount_point/another_nested/foo"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should genearte a route with the specified value for the parent route" do
|
171
|
+
@route_set3.generator.generate(:nested_simple, :foo => "bar").should == "/third/bar/nested/simple"
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should generate a route with the default value from the parent route" do
|
175
|
+
@route_set3.generator.generate(:nested_simple).should == "/third/foo/nested/simple"
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should generate a route with an optional segement in the parent and child" do
|
179
|
+
@route_set3.generator.generate(:nested_complex, :complex => "complex").should == "/third/foo/another_nested/complex"
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should generate a route without the optional value from the child" do
|
183
|
+
@route_set3.generator.generate(:nested_complex).should == "/third/foo/another_nested"
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should raise an exception when trying to generate a route where the parent variable is not defined and does not have a default value" do
|
187
|
+
lambda do
|
188
|
+
@route_set4.generator.generate(:nested_simple)
|
189
|
+
end.should raise_error(Usher::MissingParameterException)
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
|
138
194
|
end
|
139
|
-
|
140
|
-
|
141
195
|
end
|
@@ -4,31 +4,30 @@ require 'lib/usher'
|
|
4
4
|
describe "Usher grapher" do
|
5
5
|
|
6
6
|
before(:each) do
|
7
|
-
@route_set = Usher.new
|
7
|
+
@route_set = Usher.new(:generator => Usher::Util::Generators::URL.new)
|
8
8
|
@route_set.reset!
|
9
|
-
@url_generator = Usher::Generators::URL.new(@route_set)
|
10
9
|
end
|
11
10
|
|
12
11
|
it "should find a simple path" do
|
13
12
|
@route_set.add_route('/:a/:b/:c')
|
14
|
-
@
|
13
|
+
@route_set.generator.generate(nil, {:a => 'A', :b => 'B', :c => 'C'}).should == '/A/B/C'
|
15
14
|
end
|
16
15
|
|
17
16
|
it "should pick a more specific route" do
|
18
17
|
@route_set.add_route('/:a/:b')
|
19
18
|
@route_set.add_route('/:a/:b/:c')
|
20
|
-
@
|
19
|
+
@route_set.generator.generate(nil, {:a => 'A', :b => 'B', :c => 'C'}).should == '/A/B/C'
|
21
20
|
end
|
22
21
|
|
23
22
|
it "should fail to generate a route when none matches" do
|
24
23
|
@route_set.add_route('/:a/:b')
|
25
|
-
proc {@
|
24
|
+
proc {@route_set.generator.generate(nil, {:c => 'C', :d => 'D'}) }.should raise_error Usher::UnrecognizedException
|
26
25
|
end
|
27
26
|
|
28
27
|
it "should find the most specific route and append extra parts on as a query string" do
|
29
28
|
@route_set.add_route('/:a/:b/:c')
|
30
29
|
@route_set.add_route('/:a/:b')
|
31
|
-
@
|
30
|
+
@route_set.generator.generate(nil, {:a => 'A', :b => 'B', :d => 'C'}).should == '/A/B?d=C'
|
32
31
|
end
|
33
32
|
|
34
33
|
# FIXME
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'lib/usher'
|
2
|
+
|
3
|
+
describe "Usher route tokenizing" do
|
4
|
+
|
5
|
+
|
6
|
+
it "should split / delimited routes" do
|
7
|
+
Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/test/this/split').should == [['/', 'test', '/','this', '/', 'split']]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should split / delimited routes with a regex in it" do
|
11
|
+
Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/test/{this}/split').should == [['/', 'test', '/', /this/, '/', 'split']]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should split on ' ' delimited routes as well" do
|
15
|
+
Usher.new(:delimiters => [' '], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('test this split').should == [['test', ' ', 'this', ' ', 'split']]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should split on email delimiters as well" do
|
19
|
+
Usher.new(:delimiters => ['@', '+', '-', '.'], :valid_regex => '[a-zA-Z0-9]+').parser.parse_and_expand('one+more.12345-09876-alphanum3ric5@domain.com').should == [["one", '+', "more", ".", "12345", '-', "09876", '-', "alphanum3ric5", "@", "domain", ".", "com"]]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should split on ' ' delimited routes for more complex routes as well" do
|
23
|
+
Usher.new(:delimiters => [' '], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('(test|this) split').should == [['test', ' ', 'split'], ['this', ' ', 'split']]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should group optional parts with brackets" do
|
27
|
+
Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/test/this(/split)').should == [
|
28
|
+
['/', 'test', '/', 'this'],
|
29
|
+
['/', 'test', '/', 'this', '/', 'split']
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should group exclusive optional parts with brackets and pipes" do
|
34
|
+
Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/test/this(/split|/split2)').should == [
|
35
|
+
['/', 'test', '/', 'this','/', 'split'],
|
36
|
+
['/', 'test', '/', 'this','/', 'split2']
|
37
|
+
]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should group exclusive optional-optional parts with brackets and pipes" do
|
41
|
+
Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/test/this((/split|/split2))').should == [
|
42
|
+
['/', 'test','/', 'this'],
|
43
|
+
['/', 'test','/', 'this', '/', 'split'],
|
44
|
+
['/', 'test','/', 'this', '/', 'split2']
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should group optional parts with brackets (for non overlapping groups)" do
|
49
|
+
Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/test/this(/split)(/split2)') == [
|
50
|
+
['/', "test", '/', "this"],
|
51
|
+
['/', "test", '/', "this", '/', "split"],
|
52
|
+
['/', "test", '/', "this", '/', "split2"],
|
53
|
+
['/', "test", '/', "this", '/', "split", '/', "split2"]
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should group nested-optional parts with brackets" do
|
58
|
+
Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/test/this(/split(.:format))') == [
|
59
|
+
['/', "test", '/', "this"],
|
60
|
+
['/', "test", '/', "this", '/', "split"],
|
61
|
+
['/', "test", '/', "this", '/', "split", '.', Usher::Route::Variable::Single.new(:format)]
|
62
|
+
]
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should to_s all different variable types" do
|
66
|
+
Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/:split/*splitter').first.collect{|v| v.to_s} ==
|
67
|
+
[ ':split', '*splitter' ]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should == variable types" do
|
71
|
+
parts = Usher.new(:delimiters => ['/', '.'], :valid_regex => '[0-9A-Za-z\$\-_\+!\*\',]+').parser.parse_and_expand('/:split/:split').first
|
72
|
+
parts[1].should == parts[3]
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|