journey 1.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +8 -0
- data/.gemtest +0 -0
- data/CHANGELOG.rdoc +6 -0
- data/Gemfile +11 -0
- data/Manifest.txt +50 -0
- data/README.rdoc +48 -0
- data/Rakefile +31 -0
- data/journey.gemspec +42 -0
- data/lib/journey.rb +5 -0
- data/lib/journey/backwards.rb +5 -0
- data/lib/journey/core-ext/hash.rb +11 -0
- data/lib/journey/formatter.rb +129 -0
- data/lib/journey/gtg/builder.rb +159 -0
- data/lib/journey/gtg/simulator.rb +44 -0
- data/lib/journey/gtg/transition_table.rb +152 -0
- data/lib/journey/nfa/builder.rb +74 -0
- data/lib/journey/nfa/dot.rb +34 -0
- data/lib/journey/nfa/simulator.rb +45 -0
- data/lib/journey/nfa/transition_table.rb +164 -0
- data/lib/journey/nodes/node.rb +104 -0
- data/lib/journey/parser.rb +204 -0
- data/lib/journey/parser.y +47 -0
- data/lib/journey/parser_extras.rb +21 -0
- data/lib/journey/path/pattern.rb +190 -0
- data/lib/journey/route.rb +92 -0
- data/lib/journey/router.rb +138 -0
- data/lib/journey/router/strexp.rb +22 -0
- data/lib/journey/router/utils.rb +57 -0
- data/lib/journey/routes.rb +74 -0
- data/lib/journey/scanner.rb +58 -0
- data/lib/journey/visitors.rb +186 -0
- data/lib/journey/visualizer/d3.min.js +2 -0
- data/lib/journey/visualizer/fsm.css +34 -0
- data/lib/journey/visualizer/fsm.js +134 -0
- data/lib/journey/visualizer/index.html.erb +50 -0
- data/lib/journey/visualizer/reset.css +48 -0
- data/test/gtg/test_builder.rb +77 -0
- data/test/gtg/test_transition_table.rb +113 -0
- data/test/helper.rb +4 -0
- data/test/nfa/test_simulator.rb +96 -0
- data/test/nfa/test_transition_table.rb +70 -0
- data/test/nodes/test_symbol.rb +15 -0
- data/test/path/test_pattern.rb +260 -0
- data/test/route/definition/test_parser.rb +108 -0
- data/test/route/definition/test_scanner.rb +52 -0
- data/test/router/test_strexp.rb +30 -0
- data/test/router/test_utils.rb +19 -0
- data/test/test_route.rb +95 -0
- data/test/test_router.rb +464 -0
- data/test/test_routes.rb +51 -0
- metadata +168 -0
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Journey
|
4
|
+
module GTG
|
5
|
+
class TestBuilder < MiniTest::Unit::TestCase
|
6
|
+
def test_following_states_multi
|
7
|
+
table = tt ['a|a']
|
8
|
+
assert_equal 1, table.move(0, 'a').length
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_following_states_multi_regexp
|
12
|
+
table = tt [':a|b']
|
13
|
+
assert_equal 1, table.move(0, 'fooo').length
|
14
|
+
assert_equal 2, table.move(0, 'b').length
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_multi_path
|
18
|
+
table = tt ['/:a/d', '/b/c']
|
19
|
+
|
20
|
+
[
|
21
|
+
[1, '/'],
|
22
|
+
[2, 'b'],
|
23
|
+
[2, '/'],
|
24
|
+
[1, 'c'],
|
25
|
+
].inject(0) { |state, (exp, sym)|
|
26
|
+
new = table.move(state, sym)
|
27
|
+
assert_equal exp, new.length
|
28
|
+
new
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_match_data_ambiguous
|
33
|
+
table = tt %w{
|
34
|
+
/articles(.:format)
|
35
|
+
/articles/new(.:format)
|
36
|
+
/articles/:id/edit(.:format)
|
37
|
+
/articles/:id(.:format)
|
38
|
+
}
|
39
|
+
|
40
|
+
sim = NFA::Simulator.new table
|
41
|
+
|
42
|
+
match = sim.match '/articles/new'
|
43
|
+
assert_equal 2, match.memos.length
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Identical Routes may have different restrictions.
|
48
|
+
def test_match_same_paths
|
49
|
+
table = tt %w{
|
50
|
+
/articles/new(.:format)
|
51
|
+
/articles/new(.:format)
|
52
|
+
}
|
53
|
+
|
54
|
+
sim = NFA::Simulator.new table
|
55
|
+
|
56
|
+
match = sim.match '/articles/new'
|
57
|
+
assert_equal 2, match.memos.length
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def ast strings
|
62
|
+
parser = Journey::Parser.new
|
63
|
+
asts = strings.map { |string|
|
64
|
+
memo = Object.new
|
65
|
+
ast = parser.parse string
|
66
|
+
ast.each { |n| n.memo = memo }
|
67
|
+
ast
|
68
|
+
}
|
69
|
+
Nodes::Or.new asts
|
70
|
+
end
|
71
|
+
|
72
|
+
def tt strings
|
73
|
+
Builder.new(ast(strings)).transition_table
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Journey
|
5
|
+
module GTG
|
6
|
+
class TestGeneralizedTable < MiniTest::Unit::TestCase
|
7
|
+
def test_to_json
|
8
|
+
table = tt %w{
|
9
|
+
/articles(.:format)
|
10
|
+
/articles/new(.:format)
|
11
|
+
/articles/:id/edit(.:format)
|
12
|
+
/articles/:id(.:format)
|
13
|
+
}
|
14
|
+
|
15
|
+
json = JSON.load table.to_json
|
16
|
+
assert json['regexp_states']
|
17
|
+
assert json['string_states']
|
18
|
+
assert json['accepting']
|
19
|
+
end
|
20
|
+
|
21
|
+
if system("dot -V 2>/dev/null")
|
22
|
+
def test_to_svg
|
23
|
+
table = tt %w{
|
24
|
+
/articles(.:format)
|
25
|
+
/articles/new(.:format)
|
26
|
+
/articles/:id/edit(.:format)
|
27
|
+
/articles/:id(.:format)
|
28
|
+
}
|
29
|
+
svg = table.to_svg
|
30
|
+
assert svg
|
31
|
+
refute_match(/DOCTYPE/, svg)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_simulate_gt
|
36
|
+
sim = simulator_for ['/foo', '/bar']
|
37
|
+
assert_match sim, '/foo'
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_simulate_gt_regexp
|
41
|
+
sim = simulator_for [':foo']
|
42
|
+
assert_match sim, 'foo'
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_simulate_gt_regexp_mix
|
46
|
+
sim = simulator_for ['/get', '/:method/foo']
|
47
|
+
assert_match sim, '/get'
|
48
|
+
assert_match sim, '/get/foo'
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_simulate_optional
|
52
|
+
sim = simulator_for ['/foo(/bar)']
|
53
|
+
assert_match sim, '/foo'
|
54
|
+
assert_match sim, '/foo/bar'
|
55
|
+
refute_match sim, '/foo/'
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_match_data
|
59
|
+
path_asts = asts %w{ /get /:method/foo }
|
60
|
+
paths = path_asts.dup
|
61
|
+
|
62
|
+
builder = GTG::Builder.new Nodes::Or.new path_asts
|
63
|
+
tt = builder.transition_table
|
64
|
+
|
65
|
+
sim = GTG::Simulator.new tt
|
66
|
+
|
67
|
+
match = sim.match '/get'
|
68
|
+
assert_equal [paths.first], match.memos
|
69
|
+
|
70
|
+
match = sim.match '/get/foo'
|
71
|
+
assert_equal [paths.last], match.memos
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_match_data_ambiguous
|
75
|
+
path_asts = asts %w{
|
76
|
+
/articles(.:format)
|
77
|
+
/articles/new(.:format)
|
78
|
+
/articles/:id/edit(.:format)
|
79
|
+
/articles/:id(.:format)
|
80
|
+
}
|
81
|
+
|
82
|
+
paths = path_asts.dup
|
83
|
+
ast = Nodes::Or.new path_asts
|
84
|
+
|
85
|
+
builder = GTG::Builder.new ast
|
86
|
+
sim = GTG::Simulator.new builder.transition_table
|
87
|
+
|
88
|
+
match = sim.match '/articles/new'
|
89
|
+
assert_equal [paths[1], paths[3]], match.memos
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def asts paths
|
94
|
+
parser = Journey::Parser.new
|
95
|
+
paths.map { |x|
|
96
|
+
ast = parser.parse x
|
97
|
+
ast.each { |n| n.memo = ast}
|
98
|
+
ast
|
99
|
+
}
|
100
|
+
end
|
101
|
+
|
102
|
+
def tt paths
|
103
|
+
x = asts paths
|
104
|
+
builder = GTG::Builder.new Nodes::Or.new x
|
105
|
+
builder.transition_table
|
106
|
+
end
|
107
|
+
|
108
|
+
def simulator_for paths
|
109
|
+
GTG::Simulator.new tt(paths)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Journey
|
4
|
+
module NFA
|
5
|
+
class TestSimulator < MiniTest::Unit::TestCase
|
6
|
+
def test_simulate_simple
|
7
|
+
sim = simulator_for ['/foo']
|
8
|
+
assert_match sim, '/foo'
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_simulate_simple_no_match
|
12
|
+
sim = simulator_for ['/foo']
|
13
|
+
refute_match sim, 'foo'
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_simulate_simple_no_match_too_long
|
17
|
+
sim = simulator_for ['/foo']
|
18
|
+
refute_match sim, '/foo/bar'
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_simulate_simple_no_match_wrong_string
|
22
|
+
sim = simulator_for ['/foo']
|
23
|
+
refute_match sim, '/bar'
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_simulate_regex
|
27
|
+
sim = simulator_for ['/:foo/bar']
|
28
|
+
assert_match sim, '/bar/bar'
|
29
|
+
assert_match sim, '/foo/bar'
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_simulate_or
|
33
|
+
sim = simulator_for ['/foo', '/bar']
|
34
|
+
assert_match sim, '/bar'
|
35
|
+
assert_match sim, '/foo'
|
36
|
+
refute_match sim, '/baz'
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_simulate_optional
|
40
|
+
sim = simulator_for ['/foo(/bar)']
|
41
|
+
assert_match sim, '/foo'
|
42
|
+
assert_match sim, '/foo/bar'
|
43
|
+
refute_match sim, '/foo/'
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_matchdata_has_memos
|
47
|
+
paths = %w{ /foo /bar }
|
48
|
+
parser = Journey::Parser.new
|
49
|
+
asts = paths.map { |x|
|
50
|
+
ast = parser.parse x
|
51
|
+
ast.each { |n| n.memo = ast}
|
52
|
+
ast
|
53
|
+
}
|
54
|
+
|
55
|
+
expected = asts.first
|
56
|
+
|
57
|
+
builder = Builder.new Nodes::Or.new asts
|
58
|
+
|
59
|
+
sim = Simulator.new builder.transition_table
|
60
|
+
|
61
|
+
md = sim.match '/foo'
|
62
|
+
assert_equal [expected], md.memos
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_matchdata_memos_on_merge
|
66
|
+
parser = Journey::Parser.new
|
67
|
+
routes = [
|
68
|
+
'/articles(.:format)',
|
69
|
+
'/articles/new(.:format)',
|
70
|
+
'/articles/:id/edit(.:format)',
|
71
|
+
'/articles/:id(.:format)',
|
72
|
+
].map { |path|
|
73
|
+
ast = parser.parse path
|
74
|
+
ast.each { |n| n.memo = ast }
|
75
|
+
ast
|
76
|
+
}
|
77
|
+
|
78
|
+
asts = routes.dup
|
79
|
+
|
80
|
+
ast = Nodes::Or.new routes
|
81
|
+
|
82
|
+
nfa = Journey::NFA::Builder.new ast
|
83
|
+
sim = Simulator.new nfa.transition_table
|
84
|
+
md = sim.match '/articles'
|
85
|
+
assert_equal [asts.first], md.memos
|
86
|
+
end
|
87
|
+
|
88
|
+
def simulator_for paths
|
89
|
+
parser = Journey::Parser.new
|
90
|
+
asts = paths.map { |x| parser.parse x }
|
91
|
+
builder = Builder.new Nodes::Or.new asts
|
92
|
+
Simulator.new builder.transition_table
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Journey
|
4
|
+
module NFA
|
5
|
+
class TestTransitionTable < MiniTest::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@parser = Journey::Parser.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_eclosure
|
11
|
+
table = tt '/'
|
12
|
+
assert_equal [0], table.eclosure(0)
|
13
|
+
|
14
|
+
table = tt ':a|:b'
|
15
|
+
assert_equal 3, table.eclosure(0).length
|
16
|
+
|
17
|
+
table = tt '(:a|:b)'
|
18
|
+
assert_equal 5, table.eclosure(0).length
|
19
|
+
assert_equal 5, table.eclosure([0]).length
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_following_states_one
|
23
|
+
table = tt '/'
|
24
|
+
|
25
|
+
assert_equal [1], table.following_states(0, '/')
|
26
|
+
assert_equal [1], table.following_states([0], '/')
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_following_states_group
|
30
|
+
table = tt 'a|b'
|
31
|
+
states = table.eclosure 0
|
32
|
+
|
33
|
+
assert_equal 1, table.following_states(states, 'a').length
|
34
|
+
assert_equal 1, table.following_states(states, 'b').length
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_following_states_multi
|
38
|
+
table = tt 'a|a'
|
39
|
+
states = table.eclosure 0
|
40
|
+
|
41
|
+
assert_equal 2, table.following_states(states, 'a').length
|
42
|
+
assert_equal 0, table.following_states(states, 'b').length
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_following_states_regexp
|
46
|
+
table = tt 'a|:a'
|
47
|
+
states = table.eclosure 0
|
48
|
+
|
49
|
+
assert_equal 1, table.following_states(states, 'a').length
|
50
|
+
assert_equal 1, table.following_states(states, /[^\.\/\?]+/).length
|
51
|
+
assert_equal 0, table.following_states(states, 'b').length
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_alphabet
|
55
|
+
table = tt 'a|:a'
|
56
|
+
assert_equal ['a', /[^\.\/\?]+/], table.alphabet
|
57
|
+
|
58
|
+
table = tt 'a|a'
|
59
|
+
assert_equal ['a'], table.alphabet
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
def tt string
|
64
|
+
ast = @parser.parse string
|
65
|
+
builder = Builder.new ast
|
66
|
+
builder.transition_table
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Journey
|
4
|
+
module Nodes
|
5
|
+
class TestSymbol < MiniTest::Unit::TestCase
|
6
|
+
def test_default_regexp?
|
7
|
+
sym = Symbol.new nil
|
8
|
+
assert sym.default_regexp?
|
9
|
+
|
10
|
+
sym.regexp = nil
|
11
|
+
refute sym.default_regexp?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,260 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
module Journey
|
4
|
+
module Path
|
5
|
+
class TestPattern < MiniTest::Unit::TestCase
|
6
|
+
x = /.+/
|
7
|
+
{
|
8
|
+
'/:controller(/:action)' => %r{\A/(#{x}?)(?:/([^/.?]+))?\Z},
|
9
|
+
'/:controller/foo' => %r{\A/(#{x}?)/foo\Z},
|
10
|
+
'/:controller/:action' => %r{\A/(#{x}?)/([^/.?]+)\Z},
|
11
|
+
'/:controller' => %r{\A/(#{x}?)\Z},
|
12
|
+
'/:controller(/:action(/:id))' => %r{\A/(#{x}?)(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z},
|
13
|
+
'/:controller/:action.xml' => %r{\A/(#{x}?)/([^/.?]+)\.xml\Z},
|
14
|
+
'/:controller.:format' => %r{\A/(#{x}?)\.([^/.?]+)\Z},
|
15
|
+
'/:controller(.:format)' => %r{\A/(#{x}?)(?:\.([^/.?]+))?\Z},
|
16
|
+
'/:controller/*foo' => %r{\A/(#{x}?)/(.+)\Z},
|
17
|
+
'/:controller/*foo/bar' => %r{\A/(#{x}?)/(.+)/bar\Z},
|
18
|
+
}.each do |path, expected|
|
19
|
+
define_method(:"test_to_regexp_#{path}") do
|
20
|
+
strexp = Router::Strexp.new(
|
21
|
+
path,
|
22
|
+
{ :controller => /.+/ },
|
23
|
+
["/", ".", "?"]
|
24
|
+
)
|
25
|
+
path = Pattern.new strexp
|
26
|
+
assert_equal(expected, path.send(:to_regexp))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
{
|
31
|
+
'/:controller(/:action)' => %r{\A/(#{x}?)(?:/([^/.?]+))?},
|
32
|
+
'/:controller/foo' => %r{\A/(#{x}?)/foo},
|
33
|
+
'/:controller/:action' => %r{\A/(#{x}?)/([^/.?]+)},
|
34
|
+
'/:controller' => %r{\A/(#{x}?)},
|
35
|
+
'/:controller(/:action(/:id))' => %r{\A/(#{x}?)(?:/([^/.?]+)(?:/([^/.?]+))?)?},
|
36
|
+
'/:controller/:action.xml' => %r{\A/(#{x}?)/([^/.?]+)\.xml},
|
37
|
+
'/:controller.:format' => %r{\A/(#{x}?)\.([^/.?]+)},
|
38
|
+
'/:controller(.:format)' => %r{\A/(#{x}?)(?:\.([^/.?]+))?},
|
39
|
+
'/:controller/*foo' => %r{\A/(#{x}?)/(.+)},
|
40
|
+
'/:controller/*foo/bar' => %r{\A/(#{x}?)/(.+)/bar},
|
41
|
+
}.each do |path, expected|
|
42
|
+
define_method(:"test_to_non_anchored_regexp_#{path}") do
|
43
|
+
strexp = Router::Strexp.new(
|
44
|
+
path,
|
45
|
+
{ :controller => /.+/ },
|
46
|
+
["/", ".", "?"],
|
47
|
+
false
|
48
|
+
)
|
49
|
+
path = Pattern.new strexp
|
50
|
+
assert_equal(expected, path.send(:to_regexp))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
{
|
55
|
+
'/:controller(/:action)' => %w{ controller action },
|
56
|
+
'/:controller/foo' => %w{ controller },
|
57
|
+
'/:controller/:action' => %w{ controller action },
|
58
|
+
'/:controller' => %w{ controller },
|
59
|
+
'/:controller(/:action(/:id))' => %w{ controller action id },
|
60
|
+
'/:controller/:action.xml' => %w{ controller action },
|
61
|
+
'/:controller.:format' => %w{ controller format },
|
62
|
+
'/:controller(.:format)' => %w{ controller format },
|
63
|
+
'/:controller/*foo' => %w{ controller foo },
|
64
|
+
'/:controller/*foo/bar' => %w{ controller foo },
|
65
|
+
}.each do |path, expected|
|
66
|
+
define_method(:"test_names_#{path}") do
|
67
|
+
strexp = Router::Strexp.new(
|
68
|
+
path,
|
69
|
+
{ :controller => /.+/ },
|
70
|
+
["/", ".", "?"]
|
71
|
+
)
|
72
|
+
path = Pattern.new strexp
|
73
|
+
assert_equal(expected, path.names)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_to_regexp_with_extended_group
|
78
|
+
strexp = Router::Strexp.new(
|
79
|
+
'/page/:name',
|
80
|
+
{ :name => /
|
81
|
+
#ROFL
|
82
|
+
(tender|love
|
83
|
+
#MAO
|
84
|
+
)/x },
|
85
|
+
["/", ".", "?"]
|
86
|
+
)
|
87
|
+
path = Pattern.new strexp
|
88
|
+
assert_match('/page/tender', path)
|
89
|
+
assert_match('/page/love', path)
|
90
|
+
refute_match('/page/loving', path)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_optional_names
|
94
|
+
[
|
95
|
+
['/:foo(/:bar(/:baz))', %w{ bar baz }],
|
96
|
+
['/:foo(/:bar)', %w{ bar }],
|
97
|
+
['/:foo(/:bar)/:lol(/:baz)', %w{ bar baz }],
|
98
|
+
].each do |pattern, list|
|
99
|
+
path = Pattern.new pattern
|
100
|
+
assert_equal list.sort, path.optional_names.sort
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_to_regexp_with_group
|
105
|
+
strexp = Router::Strexp.new(
|
106
|
+
'/page/:name',
|
107
|
+
{ :name => /(tender|love)/ },
|
108
|
+
["/", ".", "?"]
|
109
|
+
)
|
110
|
+
path = Pattern.new strexp
|
111
|
+
assert_match('/page/tender', path)
|
112
|
+
assert_match('/page/love', path)
|
113
|
+
refute_match('/page/loving', path)
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_ast_sets_regular_expressions
|
117
|
+
requirements = { :name => /(tender|love)/, :value => /./ }
|
118
|
+
strexp = Router::Strexp.new(
|
119
|
+
'/page/:name/:value',
|
120
|
+
requirements,
|
121
|
+
["/", ".", "?"]
|
122
|
+
)
|
123
|
+
|
124
|
+
assert_equal requirements, strexp.requirements
|
125
|
+
|
126
|
+
path = Pattern.new strexp
|
127
|
+
nodes = path.ast.grep(Nodes::Symbol)
|
128
|
+
assert_equal 2, nodes.length
|
129
|
+
nodes.each do |node|
|
130
|
+
assert_equal requirements[node.to_sym], node.regexp
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_match_data_with_group
|
135
|
+
strexp = Router::Strexp.new(
|
136
|
+
'/page/:name',
|
137
|
+
{ :name => /(tender|love)/ },
|
138
|
+
["/", ".", "?"]
|
139
|
+
)
|
140
|
+
path = Pattern.new strexp
|
141
|
+
match = path.match '/page/tender'
|
142
|
+
assert_equal 'tender', match[1]
|
143
|
+
assert_equal 2, match.length
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_match_data_with_multi_group
|
147
|
+
strexp = Router::Strexp.new(
|
148
|
+
'/page/:name/:id',
|
149
|
+
{ :name => /t(((ender|love)))()/ },
|
150
|
+
["/", ".", "?"]
|
151
|
+
)
|
152
|
+
path = Pattern.new strexp
|
153
|
+
match = path.match '/page/tender/10'
|
154
|
+
assert_equal 'tender', match[1]
|
155
|
+
assert_equal '10', match[2]
|
156
|
+
assert_equal 3, match.length
|
157
|
+
assert_equal %w{ tender 10 }, match.captures
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_insensitive_regexp_with_group
|
161
|
+
strexp = Router::Strexp.new(
|
162
|
+
'/page/:name/aaron',
|
163
|
+
{ :name => /(tender|love)/i },
|
164
|
+
["/", ".", "?"]
|
165
|
+
)
|
166
|
+
path = Pattern.new strexp
|
167
|
+
assert_match('/page/TENDER/aaron', path)
|
168
|
+
assert_match('/page/loVE/aaron', path)
|
169
|
+
refute_match('/page/loVE/AAron', path)
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_to_regexp_with_strexp
|
173
|
+
strexp = Router::Strexp.new('/:controller', { }, ["/", ".", "?"])
|
174
|
+
path = Pattern.new strexp
|
175
|
+
x = %r{\A/([^/.?]+)\Z}
|
176
|
+
|
177
|
+
assert_equal(x.source, path.source)
|
178
|
+
end
|
179
|
+
|
180
|
+
def test_to_regexp_defaults
|
181
|
+
path = Pattern.new '/:controller(/:action(/:id))'
|
182
|
+
expected = %r{\A/([^/.?]+)(?:/([^/.?]+)(?:/([^/.?]+))?)?\Z}
|
183
|
+
assert_equal expected, path.send(:to_regexp)
|
184
|
+
end
|
185
|
+
|
186
|
+
def test_failed_match
|
187
|
+
path = Pattern.new '/:controller(/:action(/:id(.:format)))'
|
188
|
+
uri = 'content'
|
189
|
+
|
190
|
+
refute path =~ uri
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_match_controller
|
194
|
+
path = Pattern.new '/:controller(/:action(/:id(.:format)))'
|
195
|
+
uri = '/content'
|
196
|
+
|
197
|
+
match = path =~ uri
|
198
|
+
assert_equal %w{ controller action id format }, match.names
|
199
|
+
assert_equal 'content', match[1]
|
200
|
+
assert_nil match[2]
|
201
|
+
assert_nil match[3]
|
202
|
+
assert_nil match[4]
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_match_controller_action
|
206
|
+
path = Pattern.new '/:controller(/:action(/:id(.:format)))'
|
207
|
+
uri = '/content/list'
|
208
|
+
|
209
|
+
match = path =~ uri
|
210
|
+
assert_equal %w{ controller action id format }, match.names
|
211
|
+
assert_equal 'content', match[1]
|
212
|
+
assert_equal 'list', match[2]
|
213
|
+
assert_nil match[3]
|
214
|
+
assert_nil match[4]
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_match_controller_action_id
|
218
|
+
path = Pattern.new '/:controller(/:action(/:id(.:format)))'
|
219
|
+
uri = '/content/list/10'
|
220
|
+
|
221
|
+
match = path =~ uri
|
222
|
+
assert_equal %w{ controller action id format }, match.names
|
223
|
+
assert_equal 'content', match[1]
|
224
|
+
assert_equal 'list', match[2]
|
225
|
+
assert_equal '10', match[3]
|
226
|
+
assert_nil match[4]
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_match_literal
|
230
|
+
path = Path::Pattern.new "/books(/:action(.:format))"
|
231
|
+
|
232
|
+
uri = '/books'
|
233
|
+
match = path =~ uri
|
234
|
+
assert_equal %w{ action format }, match.names
|
235
|
+
assert_nil match[1]
|
236
|
+
assert_nil match[2]
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_match_literal_with_action
|
240
|
+
path = Path::Pattern.new "/books(/:action(.:format))"
|
241
|
+
|
242
|
+
uri = '/books/list'
|
243
|
+
match = path =~ uri
|
244
|
+
assert_equal %w{ action format }, match.names
|
245
|
+
assert_equal 'list', match[1]
|
246
|
+
assert_nil match[2]
|
247
|
+
end
|
248
|
+
|
249
|
+
def test_match_literal_with_action_and_format
|
250
|
+
path = Path::Pattern.new "/books(/:action(.:format))"
|
251
|
+
|
252
|
+
uri = '/books/list.rss'
|
253
|
+
match = path =~ uri
|
254
|
+
assert_equal %w{ action format }, match.names
|
255
|
+
assert_equal 'list', match[1]
|
256
|
+
assert_equal 'rss', match[2]
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|