journey 1.0.0.rc1
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/.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
|