andyjeffries-journey 1.0.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.
Files changed (51) hide show
  1. data/.autotest +8 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.rdoc +6 -0
  4. data/Gemfile +11 -0
  5. data/Manifest.txt +49 -0
  6. data/README.rdoc +48 -0
  7. data/Rakefile +31 -0
  8. data/journey.gemspec +42 -0
  9. data/lib/journey/backwards.rb +5 -0
  10. data/lib/journey/core-ext/hash.rb +11 -0
  11. data/lib/journey/formatter.rb +129 -0
  12. data/lib/journey/gtg/builder.rb +159 -0
  13. data/lib/journey/gtg/simulator.rb +44 -0
  14. data/lib/journey/gtg/transition_table.rb +152 -0
  15. data/lib/journey/nfa/builder.rb +74 -0
  16. data/lib/journey/nfa/dot.rb +34 -0
  17. data/lib/journey/nfa/simulator.rb +45 -0
  18. data/lib/journey/nfa/transition_table.rb +164 -0
  19. data/lib/journey/nodes/node.rb +104 -0
  20. data/lib/journey/parser.rb +204 -0
  21. data/lib/journey/parser.y +47 -0
  22. data/lib/journey/parser_extras.rb +21 -0
  23. data/lib/journey/path/pattern.rb +190 -0
  24. data/lib/journey/route.rb +92 -0
  25. data/lib/journey/router/strexp.rb +22 -0
  26. data/lib/journey/router/utils.rb +57 -0
  27. data/lib/journey/router.rb +138 -0
  28. data/lib/journey/routes.rb +74 -0
  29. data/lib/journey/scanner.rb +58 -0
  30. data/lib/journey/visitors.rb +186 -0
  31. data/lib/journey/visualizer/d3.min.js +2 -0
  32. data/lib/journey/visualizer/fsm.css +34 -0
  33. data/lib/journey/visualizer/fsm.js +134 -0
  34. data/lib/journey/visualizer/index.html.erb +50 -0
  35. data/lib/journey/visualizer/reset.css +48 -0
  36. data/lib/journey.rb +5 -0
  37. data/test/gtg/test_builder.rb +77 -0
  38. data/test/gtg/test_transition_table.rb +113 -0
  39. data/test/helper.rb +4 -0
  40. data/test/nfa/test_simulator.rb +96 -0
  41. data/test/nfa/test_transition_table.rb +70 -0
  42. data/test/nodes/test_symbol.rb +15 -0
  43. data/test/path/test_pattern.rb +260 -0
  44. data/test/route/definition/test_parser.rb +108 -0
  45. data/test/route/definition/test_scanner.rb +52 -0
  46. data/test/router/test_strexp.rb +30 -0
  47. data/test/router/test_utils.rb +19 -0
  48. data/test/test_route.rb +95 -0
  49. data/test/test_router.rb +464 -0
  50. data/test/test_routes.rb +38 -0
  51. metadata +171 -0
@@ -0,0 +1,464 @@
1
+ require 'helper'
2
+
3
+ module Journey
4
+ class TestRouter < MiniTest::Unit::TestCase
5
+ attr_reader :routes
6
+
7
+ def setup
8
+ @routes = Routes.new
9
+ @router = Router.new(@routes, {})
10
+ @formatter = Formatter.new(@routes)
11
+ end
12
+
13
+ def test_request_class_reader
14
+ klass = Object.new
15
+ router = Router.new(routes, :request_class => klass)
16
+ assert_equal klass, router.request_class
17
+ end
18
+
19
+ class FakeRequestFeeler < Struct.new(:env, :called)
20
+ def new env
21
+ self.env = env
22
+ self
23
+ end
24
+
25
+ def hello
26
+ self.called = true
27
+ 'world'
28
+ end
29
+ end
30
+
31
+ def test_dashes
32
+ klass = FakeRequestFeeler.new nil
33
+ router = Router.new(routes, {})
34
+
35
+ exp = Router::Strexp.new '/foo-bar-baz', {}, ['/.?']
36
+ path = Path::Pattern.new exp
37
+
38
+ routes.add_route nil, path, {}, {:id => nil}, {}
39
+
40
+ env = rails_env 'PATH_INFO' => '/foo-bar-baz'
41
+ called = false
42
+ router.recognize(env) do |r, _, params|
43
+ called = true
44
+ end
45
+ assert called
46
+ end
47
+
48
+ def test_request_class_and_requirements_success
49
+ klass = FakeRequestFeeler.new nil
50
+ router = Router.new(routes, {:request_class => klass })
51
+
52
+ requirements = { :hello => /world/ }
53
+
54
+ exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?']
55
+ path = Path::Pattern.new exp
56
+
57
+ routes.add_route nil, path, requirements, {:id => nil}, {}
58
+
59
+ env = rails_env 'PATH_INFO' => '/foo/10'
60
+ router.recognize(env) do |r, _, params|
61
+ assert_equal({:id => '10'}, params)
62
+ end
63
+
64
+ assert klass.called, 'hello should have been called'
65
+ assert_equal env.env, klass.env
66
+ end
67
+
68
+ def test_request_class_and_requirements_fail
69
+ klass = FakeRequestFeeler.new nil
70
+ router = Router.new(routes, {:request_class => klass })
71
+
72
+ requirements = { :hello => /mom/ }
73
+
74
+ exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?']
75
+ path = Path::Pattern.new exp
76
+
77
+ router.routes.add_route nil, path, requirements, {:id => nil}, {}
78
+
79
+ env = rails_env 'PATH_INFO' => '/foo/10'
80
+ router.recognize(env) do |r, _, params|
81
+ flunk 'route should not be found'
82
+ end
83
+
84
+ assert klass.called, 'hello should have been called'
85
+ assert_equal env.env, klass.env
86
+ end
87
+
88
+ def test_required_parts_verified_are_anchored
89
+ add_routes @router, [
90
+ Router::Strexp.new("/foo/:id", { :id => /\d/ }, ['/', '.', '?'], false)
91
+ ]
92
+
93
+ assert_raises(Router::RoutingError) do
94
+ @formatter.generate(:path_info, nil, { :id => '10' }, { })
95
+ end
96
+ end
97
+
98
+ def test_required_parts_are_verified_when_building
99
+ add_routes @router, [
100
+ Router::Strexp.new("/foo/:id", { :id => /\d+/ }, ['/', '.', '?'], false)
101
+ ]
102
+
103
+ path, _ = @formatter.generate(:path_info, nil, { :id => '10' }, { })
104
+ assert_equal '/foo/10', path
105
+
106
+ assert_raises(Router::RoutingError) do
107
+ @formatter.generate(:path_info, nil, { :id => 'aa' }, { })
108
+ end
109
+ end
110
+
111
+ def test_only_required_parts_are_verified
112
+ add_routes @router, [
113
+ Router::Strexp.new("/foo(/:id)", {:id => /\d/}, ['/', '.', '?'], false)
114
+ ]
115
+
116
+ path, _ = @formatter.generate(:path_info, nil, { :id => '10' }, { })
117
+ assert_equal '/foo/10', path
118
+
119
+ path, _ = @formatter.generate(:path_info, nil, { }, { })
120
+ assert_equal '/foo', path
121
+
122
+ path, _ = @formatter.generate(:path_info, nil, { :id => 'aa' }, { })
123
+ assert_equal '/foo/aa', path
124
+ end
125
+
126
+ def test_X_Cascade
127
+ add_routes @router, [ "/messages(.:format)" ]
128
+ resp = @router.call({ 'REQUEST_METHOD' => 'GET', 'PATH_INFO' => '/lol' })
129
+ assert_equal ['Not Found'], resp.last
130
+ assert_equal 'pass', resp[1]['X-Cascade']
131
+ assert_equal 404, resp.first
132
+ end
133
+
134
+ def test_defaults_merge_correctly
135
+ path = Path::Pattern.new '/foo(/:id)'
136
+ @router.routes.add_route nil, path, {}, {:id => nil}, {}
137
+
138
+ env = rails_env 'PATH_INFO' => '/foo/10'
139
+ @router.recognize(env) do |r, _, params|
140
+ assert_equal({:id => '10'}, params)
141
+ end
142
+
143
+ env = rails_env 'PATH_INFO' => '/foo'
144
+ @router.recognize(env) do |r, _, params|
145
+ assert_equal({:id => nil}, params)
146
+ end
147
+ end
148
+
149
+ def test_recognize_with_unbound_regexp
150
+ add_routes @router, [
151
+ Router::Strexp.new("/foo", { }, ['/', '.', '?'], false)
152
+ ]
153
+
154
+ env = rails_env 'PATH_INFO' => '/foo/bar'
155
+
156
+ @router.recognize(env) { |*_| }
157
+
158
+ assert_equal '/foo', env.env['SCRIPT_NAME']
159
+ assert_equal '/bar', env.env['PATH_INFO']
160
+ end
161
+
162
+ def test_bound_regexp_keeps_path_info
163
+ add_routes @router, [
164
+ Router::Strexp.new("/foo", { }, ['/', '.', '?'], true)
165
+ ]
166
+
167
+ env = rails_env 'PATH_INFO' => '/foo'
168
+
169
+ before = env.env['SCRIPT_NAME']
170
+
171
+ @router.recognize(env) { |*_| }
172
+
173
+ assert_equal before, env.env['SCRIPT_NAME']
174
+ assert_equal '/foo', env.env['PATH_INFO']
175
+ end
176
+
177
+ def test_path_not_found
178
+ add_routes @router, [
179
+ "/messages(.:format)",
180
+ "/messages/new(.:format)",
181
+ "/messages/:id/edit(.:format)",
182
+ "/messages/:id(.:format)"
183
+ ]
184
+ env = rails_env 'PATH_INFO' => '/messages/1.1.1'
185
+ yielded = false
186
+
187
+ @router.recognize(env) do |*whatever|
188
+ yielded = false
189
+ end
190
+ refute yielded
191
+ end
192
+
193
+ def test_required_part_in_recall
194
+ add_routes @router, [ "/messages/:a/:b" ]
195
+
196
+ path, _ = @formatter.generate(:path_info, nil, { :a => 'a' }, { :b => 'b' })
197
+ assert_equal "/messages/a/b", path
198
+ end
199
+
200
+ def test_splat_in_recall
201
+ add_routes @router, [ "/*path" ]
202
+
203
+ path, _ = @formatter.generate(:path_info, nil, { }, { :path => 'b' })
204
+ assert_equal "/b", path
205
+ end
206
+
207
+ def test_recall_should_be_used_when_scoring
208
+ add_routes @router, [
209
+ "/messages/:action(/:id(.:format))",
210
+ "/messages/:id(.:format)"
211
+ ]
212
+
213
+ path, _ = @formatter.generate(:path_info, nil, { :id => 10 }, { :action => 'index' })
214
+ assert_equal "/messages/index/10", path
215
+ end
216
+
217
+ def add_routes router, paths
218
+ paths.each do |path|
219
+ path = Path::Pattern.new path
220
+ router.routes.add_route nil, path, {}, {}, {}
221
+ end
222
+ end
223
+
224
+ def test_nil_path_parts_are_ignored
225
+ path = Path::Pattern.new "/:controller(/:action(.:format))"
226
+ @router.routes.add_route nil, path, {}, {}, {}
227
+
228
+ params = { :controller => "tasks", :format => nil }
229
+ extras = { :action => 'lol' }
230
+
231
+ path, _ = @formatter.generate(:path_info, nil, params, extras)
232
+ assert_equal '/tasks', path
233
+ end
234
+
235
+ def test_generate_slash
236
+ path = Path::Pattern.new '/'
237
+ @router.routes.add_route nil, path, {}, {}, {}
238
+
239
+ params = [ [:controller, "tasks"],
240
+ [:action, "show"] ]
241
+
242
+ path, _ = @formatter.generate(:path_info, nil, Hash[params], {})
243
+ assert_equal '/', path
244
+ end
245
+
246
+ def test_generate_calls_param_proc
247
+ path = Path::Pattern.new '/:controller(/:action)'
248
+ @router.routes.add_route nil, path, {}, {}, {}
249
+
250
+ parameterized = []
251
+ params = [ [:controller, "tasks"],
252
+ [:action, "show"] ]
253
+
254
+ @formatter.generate(
255
+ :path_info,
256
+ nil,
257
+ Hash[params],
258
+ {},
259
+ lambda { |k,v| parameterized << [k,v]; v })
260
+
261
+ assert_equal params.map(&:to_s).sort, parameterized.map(&:to_s).sort
262
+ end
263
+
264
+ def test_generate_id
265
+ path = Path::Pattern.new '/:controller(/:action)'
266
+ @router.routes.add_route nil, path, {}, {}, {}
267
+
268
+ path, params = @formatter.generate(
269
+ :path_info, nil, {:id=>1, :controller=>"tasks", :action=>"show"}, {})
270
+ assert_equal '/tasks/show', path
271
+ assert_equal({:id => 1}, params)
272
+ end
273
+
274
+ def test_generate_escapes
275
+ path = Path::Pattern.new '/:controller(/:action)'
276
+ @router.routes.add_route nil, path, {}, {}, {}
277
+
278
+ path, _ = @formatter.generate(:path_info,
279
+ nil, { :controller => "tasks",
280
+ :action => "a/b c+d",
281
+ }, {})
282
+ assert_equal '/tasks/a/b%20c+d', path
283
+ end
284
+
285
+ def test_generate_extra_params
286
+ path = Path::Pattern.new '/:controller(/:action)'
287
+ @router.routes.add_route nil, path, {}, {}, {}
288
+
289
+ path, params = @formatter.generate(:path_info,
290
+ nil, { :id => 1,
291
+ :controller => "tasks",
292
+ :action => "show",
293
+ :relative_url_root => nil
294
+ }, {})
295
+ assert_equal '/tasks/show', path
296
+ assert_equal({:id => 1, :relative_url_root => nil}, params)
297
+ end
298
+
299
+ def test_generate_uses_recall_if_needed
300
+ path = Path::Pattern.new '/:controller(/:action(/:id))'
301
+ @router.routes.add_route nil, path, {}, {}, {}
302
+
303
+ path, params = @formatter.generate(:path_info,
304
+ nil,
305
+ {:controller =>"tasks", :id => 10},
306
+ {:action =>"index"})
307
+ assert_equal '/tasks/index/10', path
308
+ assert_equal({}, params)
309
+ end
310
+
311
+ def test_generate_with_name
312
+ path = Path::Pattern.new '/:controller(/:action)'
313
+ @router.routes.add_route nil, path, {}, {}, {}
314
+
315
+ path, params = @formatter.generate(:path_info,
316
+ "tasks",
317
+ {:controller=>"tasks"},
318
+ {:controller=>"tasks", :action=>"index"})
319
+ assert_equal '/tasks', path
320
+ assert_equal({}, params)
321
+ end
322
+
323
+ {
324
+ '/content' => { :controller => 'content' },
325
+ '/content/list' => { :controller => 'content', :action => 'list' },
326
+ '/content/show/10' => { :controller => 'content', :action => 'show', :id => "10" },
327
+ }.each do |request_path, expected|
328
+ define_method("test_recognize_#{expected.keys.map(&:to_s).join('_')}") do
329
+ path = Path::Pattern.new "/:controller(/:action(/:id))"
330
+ app = Object.new
331
+ route = @router.routes.add_route(app, path, {}, {}, {})
332
+
333
+ env = rails_env 'PATH_INFO' => request_path
334
+ called = false
335
+
336
+ @router.recognize(env) do |r, _, params|
337
+ assert_equal route, r
338
+ assert_equal(expected, params)
339
+ called = true
340
+ end
341
+
342
+ assert called
343
+ end
344
+ end
345
+
346
+ {
347
+ :segment => ['/a%2Fb%20c+d/splat', { :segment => 'a/b c+d', :splat => 'splat' }],
348
+ :splat => ['/segment/a/b%20c+d', { :segment => 'segment', :splat => 'a/b c+d' }]
349
+ }.each do |name, (request_path, expected)|
350
+ define_method("test_recognize_#{name}") do
351
+ path = Path::Pattern.new '/:segment/*splat'
352
+ app = Object.new
353
+ route = @router.routes.add_route(app, path, {}, {}, {})
354
+
355
+ env = rails_env 'PATH_INFO' => request_path
356
+ called = false
357
+
358
+ @router.recognize(env) do |r, _, params|
359
+ assert_equal route, r
360
+ assert_equal(expected, params)
361
+ called = true
362
+ end
363
+
364
+ assert called
365
+ end
366
+ end
367
+
368
+ def test_namespaced_controller
369
+ strexp = Router::Strexp.new(
370
+ "/:controller(/:action(/:id))",
371
+ { :controller => /.+?/ },
372
+ ["/", ".", "?"]
373
+ )
374
+ path = Path::Pattern.new strexp
375
+ app = Object.new
376
+ route = @router.routes.add_route(app, path, {}, {}, {})
377
+
378
+ env = rails_env 'PATH_INFO' => '/admin/users/show/10'
379
+ called = false
380
+ expected = {
381
+ :controller => 'admin/users',
382
+ :action => 'show',
383
+ :id => '10'
384
+ }
385
+
386
+ @router.recognize(env) do |r, _, params|
387
+ assert_equal route, r
388
+ assert_equal(expected, params)
389
+ called = true
390
+ end
391
+ assert called
392
+ end
393
+
394
+ def test_recognize_literal
395
+ path = Path::Pattern.new "/books(/:action(.:format))"
396
+ app = Object.new
397
+ route = @router.routes.add_route(app, path, {}, {:controller => 'books'})
398
+
399
+ env = rails_env 'PATH_INFO' => '/books/list.rss'
400
+ expected = { :controller => 'books', :action => 'list', :format => 'rss' }
401
+ called = false
402
+ @router.recognize(env) do |r, _, params|
403
+ assert_equal route, r
404
+ assert_equal(expected, params)
405
+ called = true
406
+ end
407
+
408
+ assert called
409
+ end
410
+
411
+ def test_recognize_cares_about_verbs
412
+ path = Path::Pattern.new "/books(/:action(.:format))"
413
+ app = Object.new
414
+ conditions = {
415
+ :request_method => 'GET'
416
+ }
417
+ @router.routes.add_route(app, path, conditions, {})
418
+
419
+ conditions = conditions.dup
420
+ conditions[:request_method] = 'POST'
421
+
422
+ post = @router.routes.add_route(app, path, conditions, {})
423
+
424
+ env = rails_env 'PATH_INFO' => '/books/list.rss',
425
+ "REQUEST_METHOD" => "POST"
426
+
427
+ called = false
428
+ @router.recognize(env) do |r, _, params|
429
+ assert_equal post, r
430
+ called = true
431
+ end
432
+
433
+ assert called
434
+ end
435
+
436
+ private
437
+
438
+ RailsEnv = Struct.new(:env)
439
+
440
+ def rails_env env
441
+ RailsEnv.new rack_env env
442
+ end
443
+
444
+ def rack_env env
445
+ {
446
+ "rack.version" => [1, 1],
447
+ "rack.input" => StringIO.new,
448
+ "rack.errors" => StringIO.new,
449
+ "rack.multithread" => true,
450
+ "rack.multiprocess" => true,
451
+ "rack.run_once" => false,
452
+ "REQUEST_METHOD" => "GET",
453
+ "SERVER_NAME" => "example.org",
454
+ "SERVER_PORT" => "80",
455
+ "QUERY_STRING" => "",
456
+ "PATH_INFO" => "/content",
457
+ "rack.url_scheme" => "http",
458
+ "HTTPS" => "off",
459
+ "SCRIPT_NAME" => "",
460
+ "CONTENT_LENGTH" => "0"
461
+ }.merge env
462
+ end
463
+ end
464
+ end
@@ -0,0 +1,38 @@
1
+ require 'helper'
2
+
3
+ module Journey
4
+ class TestRoutes < MiniTest::Unit::TestCase
5
+ def test_clear
6
+ routes = Routes.new
7
+ exp = Router::Strexp.new '/foo(/:id)', {}, ['/.?']
8
+ path = Path::Pattern.new exp
9
+ requirements = { :hello => /world/ }
10
+
11
+ routes.add_route nil, path, requirements, {:id => nil}, {}
12
+ assert_equal 1, routes.length
13
+
14
+ routes.clear
15
+ assert_equal 0, routes.length
16
+ end
17
+
18
+ def test_ast
19
+ routes = Routes.new
20
+ path = Path::Pattern.new '/hello'
21
+
22
+ routes.add_route nil, path, {}, {}, {}
23
+ ast = routes.ast
24
+ routes.add_route nil, path, {}, {}, {}
25
+ refute_equal ast, routes.ast
26
+ end
27
+
28
+ def test_simulator_changes
29
+ routes = Routes.new
30
+ path = Path::Pattern.new '/hello'
31
+
32
+ routes.add_route nil, path, {}, {}, {}
33
+ sim = routes.simulator
34
+ routes.add_route nil, path, {}, {}, {}
35
+ refute_equal sim, routes.simulator
36
+ end
37
+ end
38
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: andyjeffries-journey
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Aaron Patterson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-23 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: minitest
16
+ requirement: &70141541897200 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.10'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70141541897200
25
+ - !ruby/object:Gem::Dependency
26
+ name: racc
27
+ requirement: &70141541896340 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.4.6
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70141541896340
36
+ - !ruby/object:Gem::Dependency
37
+ name: json
38
+ requirement: &70141541895820 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70141541895820
47
+ - !ruby/object:Gem::Dependency
48
+ name: rdoc
49
+ requirement: &70141541895120 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.10'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70141541895120
58
+ - !ruby/object:Gem::Dependency
59
+ name: hoe
60
+ requirement: &70141541894340 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '2.12'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70141541894340
69
+ description: Journey is a router. It routes requests.
70
+ email:
71
+ - aaron@tenderlovemaking.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - Manifest.txt
76
+ - CHANGELOG.rdoc
77
+ - README.rdoc
78
+ files:
79
+ - .autotest
80
+ - CHANGELOG.rdoc
81
+ - Gemfile
82
+ - Manifest.txt
83
+ - README.rdoc
84
+ - Rakefile
85
+ - journey.gemspec
86
+ - lib/journey.rb
87
+ - lib/journey/backwards.rb
88
+ - lib/journey/core-ext/hash.rb
89
+ - lib/journey/formatter.rb
90
+ - lib/journey/gtg/builder.rb
91
+ - lib/journey/gtg/simulator.rb
92
+ - lib/journey/gtg/transition_table.rb
93
+ - lib/journey/nfa/builder.rb
94
+ - lib/journey/nfa/dot.rb
95
+ - lib/journey/nfa/simulator.rb
96
+ - lib/journey/nfa/transition_table.rb
97
+ - lib/journey/nodes/node.rb
98
+ - lib/journey/parser.rb
99
+ - lib/journey/parser.y
100
+ - lib/journey/parser_extras.rb
101
+ - lib/journey/path/pattern.rb
102
+ - lib/journey/route.rb
103
+ - lib/journey/router.rb
104
+ - lib/journey/router/strexp.rb
105
+ - lib/journey/router/utils.rb
106
+ - lib/journey/routes.rb
107
+ - lib/journey/scanner.rb
108
+ - lib/journey/visitors.rb
109
+ - lib/journey/visualizer/d3.min.js
110
+ - lib/journey/visualizer/fsm.css
111
+ - lib/journey/visualizer/fsm.js
112
+ - lib/journey/visualizer/index.html.erb
113
+ - lib/journey/visualizer/reset.css
114
+ - test/gtg/test_builder.rb
115
+ - test/gtg/test_transition_table.rb
116
+ - test/helper.rb
117
+ - test/nfa/test_simulator.rb
118
+ - test/nfa/test_transition_table.rb
119
+ - test/nodes/test_symbol.rb
120
+ - test/path/test_pattern.rb
121
+ - test/route/definition/test_parser.rb
122
+ - test/route/definition/test_scanner.rb
123
+ - test/router/test_strexp.rb
124
+ - test/router/test_utils.rb
125
+ - test/test_route.rb
126
+ - test/test_router.rb
127
+ - test/test_routes.rb
128
+ - .gemtest
129
+ homepage: http://github.com/tenderlove/journey
130
+ licenses: []
131
+ post_install_message:
132
+ rdoc_options:
133
+ - --main
134
+ - README.rdoc
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ segments:
144
+ - 0
145
+ hash: 3858943851392941251
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project: andyjeffries-journey
154
+ rubygems_version: 1.8.10
155
+ signing_key:
156
+ specification_version: 3
157
+ summary: Journey is a router
158
+ test_files:
159
+ - test/gtg/test_builder.rb
160
+ - test/gtg/test_transition_table.rb
161
+ - test/nfa/test_simulator.rb
162
+ - test/nfa/test_transition_table.rb
163
+ - test/nodes/test_symbol.rb
164
+ - test/path/test_pattern.rb
165
+ - test/route/definition/test_parser.rb
166
+ - test/route/definition/test_scanner.rb
167
+ - test/router/test_strexp.rb
168
+ - test/router/test_utils.rb
169
+ - test/test_route.rb
170
+ - test/test_router.rb
171
+ - test/test_routes.rb