actionpack 3.2.19 → 4.2.11.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (244) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +412 -503
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +11 -294
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +52 -18
  7. data/lib/abstract_controller/callbacks.rb +87 -89
  8. data/lib/abstract_controller/collector.rb +17 -3
  9. data/lib/abstract_controller/helpers.rb +41 -14
  10. data/lib/abstract_controller/logger.rb +1 -2
  11. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  12. data/lib/abstract_controller/rendering.rb +65 -118
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +7 -7
  15. data/lib/abstract_controller.rb +2 -10
  16. data/lib/action_controller/base.rb +61 -28
  17. data/lib/action_controller/caching/fragments.rb +30 -54
  18. data/lib/action_controller/caching.rb +38 -35
  19. data/lib/action_controller/log_subscriber.rb +35 -18
  20. data/lib/action_controller/metal/conditional_get.rb +103 -34
  21. data/lib/action_controller/metal/data_streaming.rb +20 -26
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  23. data/lib/action_controller/metal/exceptions.rb +19 -6
  24. data/lib/action_controller/metal/flash.rb +41 -9
  25. data/lib/action_controller/metal/force_ssl.rb +70 -12
  26. data/lib/action_controller/metal/head.rb +30 -7
  27. data/lib/action_controller/metal/helpers.rb +11 -11
  28. data/lib/action_controller/metal/hide_actions.rb +0 -1
  29. data/lib/action_controller/metal/http_authentication.rb +140 -94
  30. data/lib/action_controller/metal/implicit_render.rb +1 -1
  31. data/lib/action_controller/metal/instrumentation.rb +11 -7
  32. data/lib/action_controller/metal/live.rb +328 -0
  33. data/lib/action_controller/metal/mime_responds.rb +161 -152
  34. data/lib/action_controller/metal/params_wrapper.rb +126 -81
  35. data/lib/action_controller/metal/rack_delegation.rb +10 -4
  36. data/lib/action_controller/metal/redirecting.rb +44 -41
  37. data/lib/action_controller/metal/renderers.rb +48 -19
  38. data/lib/action_controller/metal/rendering.rb +46 -11
  39. data/lib/action_controller/metal/request_forgery_protection.rb +250 -29
  40. data/lib/action_controller/metal/streaming.rb +30 -38
  41. data/lib/action_controller/metal/strong_parameters.rb +669 -0
  42. data/lib/action_controller/metal/testing.rb +12 -18
  43. data/lib/action_controller/metal/url_for.rb +31 -29
  44. data/lib/action_controller/metal.rb +31 -40
  45. data/lib/action_controller/model_naming.rb +12 -0
  46. data/lib/action_controller/railtie.rb +38 -18
  47. data/lib/action_controller/railties/helpers.rb +22 -0
  48. data/lib/action_controller/test_case.rb +359 -173
  49. data/lib/action_controller.rb +9 -16
  50. data/lib/action_dispatch/http/cache.rb +64 -11
  51. data/lib/action_dispatch/http/filter_parameters.rb +20 -10
  52. data/lib/action_dispatch/http/filter_redirect.rb +38 -0
  53. data/lib/action_dispatch/http/headers.rb +85 -17
  54. data/lib/action_dispatch/http/mime_negotiation.rb +55 -5
  55. data/lib/action_dispatch/http/mime_type.rb +167 -114
  56. data/lib/action_dispatch/http/mime_types.rb +2 -1
  57. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  58. data/lib/action_dispatch/http/parameters.rb +30 -46
  59. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  60. data/lib/action_dispatch/http/request.rb +108 -45
  61. data/lib/action_dispatch/http/response.rb +247 -48
  62. data/lib/action_dispatch/http/upload.rb +60 -29
  63. data/lib/action_dispatch/http/url.rb +135 -45
  64. data/lib/action_dispatch/journey/backwards.rb +5 -0
  65. data/lib/action_dispatch/journey/formatter.rb +166 -0
  66. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  67. data/lib/action_dispatch/journey/gtg/simulator.rb +47 -0
  68. data/lib/action_dispatch/journey/gtg/transition_table.rb +157 -0
  69. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  70. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  71. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  72. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  73. data/lib/action_dispatch/journey/nodes/node.rb +128 -0
  74. data/lib/action_dispatch/journey/parser.rb +198 -0
  75. data/lib/action_dispatch/journey/parser.y +49 -0
  76. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  77. data/lib/action_dispatch/journey/path/pattern.rb +193 -0
  78. data/lib/action_dispatch/journey/route.rb +125 -0
  79. data/lib/action_dispatch/journey/router/strexp.rb +27 -0
  80. data/lib/action_dispatch/journey/router/utils.rb +93 -0
  81. data/lib/action_dispatch/journey/router.rb +144 -0
  82. data/lib/action_dispatch/journey/routes.rb +80 -0
  83. data/lib/action_dispatch/journey/scanner.rb +61 -0
  84. data/lib/action_dispatch/journey/visitors.rb +221 -0
  85. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  86. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  87. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  88. data/lib/action_dispatch/journey.rb +5 -0
  89. data/lib/action_dispatch/middleware/callbacks.rb +16 -11
  90. data/lib/action_dispatch/middleware/cookies.rb +346 -125
  91. data/lib/action_dispatch/middleware/debug_exceptions.rb +52 -24
  92. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -9
  93. data/lib/action_dispatch/middleware/flash.rb +85 -72
  94. data/lib/action_dispatch/middleware/params_parser.rb +16 -31
  95. data/lib/action_dispatch/middleware/public_exceptions.rb +39 -14
  96. data/lib/action_dispatch/middleware/reloader.rb +16 -7
  97. data/lib/action_dispatch/middleware/remote_ip.rb +132 -40
  98. data/lib/action_dispatch/middleware/request_id.rb +3 -7
  99. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  100. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  101. data/lib/action_dispatch/middleware/session/cookie_store.rb +84 -29
  102. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  103. data/lib/action_dispatch/middleware/show_exceptions.rb +15 -44
  104. data/lib/action_dispatch/middleware/ssl.rb +72 -0
  105. data/lib/action_dispatch/middleware/stack.rb +6 -1
  106. data/lib/action_dispatch/middleware/static.rb +80 -23
  107. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +34 -0
  108. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +27 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  111. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  112. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +133 -5
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  125. data/lib/action_dispatch/railtie.rb +19 -6
  126. data/lib/action_dispatch/request/session.rb +193 -0
  127. data/lib/action_dispatch/request/utils.rb +35 -0
  128. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  129. data/lib/action_dispatch/routing/inspector.rb +234 -0
  130. data/lib/action_dispatch/routing/mapper.rb +897 -436
  131. data/lib/action_dispatch/routing/polymorphic_routes.rb +213 -92
  132. data/lib/action_dispatch/routing/redirection.rb +97 -37
  133. data/lib/action_dispatch/routing/route_set.rb +432 -239
  134. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  135. data/lib/action_dispatch/routing/url_for.rb +63 -34
  136. data/lib/action_dispatch/routing.rb +57 -89
  137. data/lib/action_dispatch/testing/assertions/dom.rb +2 -36
  138. data/lib/action_dispatch/testing/assertions/response.rb +24 -38
  139. data/lib/action_dispatch/testing/assertions/routing.rb +55 -54
  140. data/lib/action_dispatch/testing/assertions/selector.rb +2 -434
  141. data/lib/action_dispatch/testing/assertions/tag.rb +2 -137
  142. data/lib/action_dispatch/testing/assertions.rb +11 -7
  143. data/lib/action_dispatch/testing/integration.rb +88 -72
  144. data/lib/action_dispatch/testing/test_process.rb +9 -6
  145. data/lib/action_dispatch/testing/test_request.rb +13 -9
  146. data/lib/action_dispatch/testing/test_response.rb +1 -5
  147. data/lib/action_dispatch.rb +24 -21
  148. data/lib/action_pack/gem_version.rb +15 -0
  149. data/lib/action_pack/version.rb +5 -7
  150. data/lib/action_pack.rb +1 -1
  151. metadata +181 -292
  152. data/lib/abstract_controller/layouts.rb +0 -423
  153. data/lib/abstract_controller/view_paths.rb +0 -96
  154. data/lib/action_controller/caching/actions.rb +0 -185
  155. data/lib/action_controller/caching/pages.rb +0 -187
  156. data/lib/action_controller/caching/sweeping.rb +0 -97
  157. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  158. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  159. data/lib/action_controller/deprecated.rb +0 -3
  160. data/lib/action_controller/metal/compatibility.rb +0 -65
  161. data/lib/action_controller/metal/responder.rb +0 -286
  162. data/lib/action_controller/metal/session_management.rb +0 -14
  163. data/lib/action_controller/railties/paths.rb +0 -25
  164. data/lib/action_controller/record_identifier.rb +0 -85
  165. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  166. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  167. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  168. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  169. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  170. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  171. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  172. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  173. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  174. data/lib/action_dispatch/middleware/head.rb +0 -18
  175. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  176. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  177. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  178. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  179. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  180. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  181. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  182. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  183. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  184. data/lib/action_view/asset_paths.rb +0 -142
  185. data/lib/action_view/base.rb +0 -220
  186. data/lib/action_view/buffers.rb +0 -43
  187. data/lib/action_view/context.rb +0 -36
  188. data/lib/action_view/flows.rb +0 -79
  189. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  190. data/lib/action_view/helpers/asset_paths.rb +0 -7
  191. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  192. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  193. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  194. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  195. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  196. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  197. data/lib/action_view/helpers/cache_helper.rb +0 -64
  198. data/lib/action_view/helpers/capture_helper.rb +0 -203
  199. data/lib/action_view/helpers/controller_helper.rb +0 -25
  200. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  201. data/lib/action_view/helpers/date_helper.rb +0 -1062
  202. data/lib/action_view/helpers/debug_helper.rb +0 -40
  203. data/lib/action_view/helpers/form_helper.rb +0 -1486
  204. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  205. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  206. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  207. data/lib/action_view/helpers/number_helper.rb +0 -622
  208. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  209. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  210. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  211. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  212. data/lib/action_view/helpers/tag_helper.rb +0 -160
  213. data/lib/action_view/helpers/text_helper.rb +0 -426
  214. data/lib/action_view/helpers/translation_helper.rb +0 -91
  215. data/lib/action_view/helpers/url_helper.rb +0 -693
  216. data/lib/action_view/helpers.rb +0 -60
  217. data/lib/action_view/locale/en.yml +0 -160
  218. data/lib/action_view/log_subscriber.rb +0 -28
  219. data/lib/action_view/lookup_context.rb +0 -254
  220. data/lib/action_view/path_set.rb +0 -89
  221. data/lib/action_view/railtie.rb +0 -55
  222. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  223. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  224. data/lib/action_view/renderer/renderer.rb +0 -54
  225. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  226. data/lib/action_view/renderer/template_renderer.rb +0 -94
  227. data/lib/action_view/template/error.rb +0 -128
  228. data/lib/action_view/template/handlers/builder.rb +0 -26
  229. data/lib/action_view/template/handlers/erb.rb +0 -125
  230. data/lib/action_view/template/handlers.rb +0 -50
  231. data/lib/action_view/template/resolver.rb +0 -272
  232. data/lib/action_view/template/text.rb +0 -30
  233. data/lib/action_view/template.rb +0 -337
  234. data/lib/action_view/test_case.rb +0 -245
  235. data/lib/action_view/testing/resolvers.rb +0 -50
  236. data/lib/action_view.rb +0 -84
  237. data/lib/sprockets/assets.rake +0 -99
  238. data/lib/sprockets/bootstrap.rb +0 -37
  239. data/lib/sprockets/compressors.rb +0 -83
  240. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  241. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  242. data/lib/sprockets/helpers.rb +0 -6
  243. data/lib/sprockets/railtie.rb +0 -62
  244. data/lib/sprockets/static_compiler.rb +0 -56
@@ -0,0 +1,144 @@
1
+ require 'action_dispatch/journey/router/utils'
2
+ require 'action_dispatch/journey/router/strexp'
3
+ require 'action_dispatch/journey/routes'
4
+ require 'action_dispatch/journey/formatter'
5
+
6
+ before = $-w
7
+ $-w = false
8
+ require 'action_dispatch/journey/parser'
9
+ $-w = before
10
+
11
+ require 'action_dispatch/journey/route'
12
+ require 'action_dispatch/journey/path/pattern'
13
+
14
+ module ActionDispatch
15
+ module Journey # :nodoc:
16
+ class Router # :nodoc:
17
+ class RoutingError < ::StandardError # :nodoc:
18
+ end
19
+
20
+ # :nodoc:
21
+ VERSION = '2.0.0'
22
+
23
+ attr_accessor :routes
24
+
25
+ def initialize(routes)
26
+ @routes = routes
27
+ end
28
+
29
+ def serve(req)
30
+ find_routes(req).each do |match, parameters, route|
31
+ set_params = req.path_parameters
32
+ path_info = req.path_info
33
+ script_name = req.script_name
34
+
35
+ unless route.path.anchored
36
+ req.script_name = (script_name.to_s + match.to_s).chomp('/')
37
+ req.path_info = match.post_match
38
+ req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
39
+ end
40
+
41
+ req.path_parameters = set_params.merge parameters
42
+
43
+ status, headers, body = route.app.serve(req)
44
+
45
+ if 'pass' == headers['X-Cascade']
46
+ req.script_name = script_name
47
+ req.path_info = path_info
48
+ req.path_parameters = set_params
49
+ next
50
+ end
51
+
52
+ return [status, headers, body]
53
+ end
54
+
55
+ return [404, {'X-Cascade' => 'pass'}, ['Not Found']]
56
+ end
57
+
58
+ def recognize(rails_req)
59
+ find_routes(rails_req).each do |match, parameters, route|
60
+ unless route.path.anchored
61
+ rails_req.script_name = match.to_s
62
+ rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
63
+ end
64
+
65
+ yield(route, parameters)
66
+ end
67
+ end
68
+
69
+ def visualizer
70
+ tt = GTG::Builder.new(ast).transition_table
71
+ groups = partitioned_routes.first.map(&:ast).group_by { |a| a.to_s }
72
+ asts = groups.values.map { |v| v.first }
73
+ tt.visualizer(asts)
74
+ end
75
+
76
+ private
77
+
78
+ def partitioned_routes
79
+ routes.partitioned_routes
80
+ end
81
+
82
+ def ast
83
+ routes.ast
84
+ end
85
+
86
+ def simulator
87
+ routes.simulator
88
+ end
89
+
90
+ def custom_routes
91
+ partitioned_routes.last
92
+ end
93
+
94
+ def filter_routes(path)
95
+ return [] unless ast
96
+ simulator.memos(path) { [] }
97
+ end
98
+
99
+ def find_routes req
100
+ routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
101
+ r.path.match(req.path_info)
102
+ }
103
+
104
+ routes =
105
+ if req.request_method == "HEAD"
106
+ match_head_routes(routes, req)
107
+ else
108
+ match_routes(routes, req)
109
+ end
110
+
111
+ routes.sort_by!(&:precedence)
112
+
113
+ routes.map! { |r|
114
+ match_data = r.path.match(req.path_info)
115
+ path_parameters = r.defaults.dup
116
+ match_data.names.zip(match_data.captures) { |name,val|
117
+ path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
118
+ }
119
+ [match_data, path_parameters, r]
120
+ }
121
+ end
122
+
123
+ def match_head_routes(routes, req)
124
+ verb_specific_routes = routes.reject { |route| route.verb == // }
125
+ head_routes = match_routes(verb_specific_routes, req)
126
+
127
+ if head_routes.empty?
128
+ begin
129
+ req.request_method = "GET"
130
+ match_routes(routes, req)
131
+ ensure
132
+ req.request_method = "HEAD"
133
+ end
134
+ else
135
+ head_routes
136
+ end
137
+ end
138
+
139
+ def match_routes(routes, req)
140
+ routes.select { |r| r.matches?(req) }
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,80 @@
1
+ module ActionDispatch
2
+ module Journey # :nodoc:
3
+ # The Routing table. Contains all routes for a system. Routes can be
4
+ # added to the table by calling Routes#add_route.
5
+ class Routes # :nodoc:
6
+ include Enumerable
7
+
8
+ attr_reader :routes, :named_routes
9
+
10
+ def initialize
11
+ @routes = []
12
+ @named_routes = {}
13
+ @ast = nil
14
+ @partitioned_routes = nil
15
+ @simulator = nil
16
+ end
17
+
18
+ def empty?
19
+ routes.empty?
20
+ end
21
+
22
+ def length
23
+ routes.length
24
+ end
25
+ alias :size :length
26
+
27
+ def last
28
+ routes.last
29
+ end
30
+
31
+ def each(&block)
32
+ routes.each(&block)
33
+ end
34
+
35
+ def clear
36
+ routes.clear
37
+ named_routes.clear
38
+ end
39
+
40
+ def partitioned_routes
41
+ @partitioned_routes ||= routes.partition do |r|
42
+ r.path.anchored && r.ast.grep(Nodes::Symbol).all?(&:default_regexp?)
43
+ end
44
+ end
45
+
46
+ def ast
47
+ @ast ||= begin
48
+ asts = partitioned_routes.first.map(&:ast)
49
+ Nodes::Or.new(asts) unless asts.empty?
50
+ end
51
+ end
52
+
53
+ def simulator
54
+ @simulator ||= begin
55
+ gtg = GTG::Builder.new(ast).transition_table
56
+ GTG::Simulator.new(gtg)
57
+ end
58
+ end
59
+
60
+ # Add a route to the routing table.
61
+ def add_route(app, path, conditions, defaults, name = nil)
62
+ route = Route.new(name, app, path, conditions, defaults)
63
+
64
+ route.precedence = routes.length
65
+ routes << route
66
+ named_routes[name] = route if name && !named_routes[name]
67
+ clear_cache!
68
+ route
69
+ end
70
+
71
+ private
72
+
73
+ def clear_cache!
74
+ @ast = nil
75
+ @partitioned_routes = nil
76
+ @simulator = nil
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,61 @@
1
+ require 'strscan'
2
+
3
+ module ActionDispatch
4
+ module Journey # :nodoc:
5
+ class Scanner # :nodoc:
6
+ def initialize
7
+ @ss = nil
8
+ end
9
+
10
+ def scan_setup(str)
11
+ @ss = StringScanner.new(str)
12
+ end
13
+
14
+ def eos?
15
+ @ss.eos?
16
+ end
17
+
18
+ def pos
19
+ @ss.pos
20
+ end
21
+
22
+ def pre_match
23
+ @ss.pre_match
24
+ end
25
+
26
+ def next_token
27
+ return if @ss.eos?
28
+
29
+ until token = scan || @ss.eos?; end
30
+ token
31
+ end
32
+
33
+ private
34
+
35
+ def scan
36
+ case
37
+ # /
38
+ when text = @ss.scan(/\//)
39
+ [:SLASH, text]
40
+ when text = @ss.scan(/\*\w+/)
41
+ [:STAR, text]
42
+ when text = @ss.scan(/(?<!\\)\(/)
43
+ [:LPAREN, text]
44
+ when text = @ss.scan(/(?<!\\)\)/)
45
+ [:RPAREN, text]
46
+ when text = @ss.scan(/\|/)
47
+ [:OR, text]
48
+ when text = @ss.scan(/\./)
49
+ [:DOT, text]
50
+ when text = @ss.scan(/(?<!\\):\w+/)
51
+ [:SYMBOL, text]
52
+ when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\:|\\\(|\\\))+/)
53
+ [:LITERAL, text.tr('\\', '')]
54
+ # any char
55
+ when text = @ss.scan(/./)
56
+ [:LITERAL, text]
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,221 @@
1
+ # encoding: utf-8
2
+
3
+ module ActionDispatch
4
+ module Journey # :nodoc:
5
+ class Format
6
+ ESCAPE_PATH = ->(value) { Router::Utils.escape_path(value) }
7
+ ESCAPE_SEGMENT = ->(value) { Router::Utils.escape_segment(value) }
8
+
9
+ class Parameter < Struct.new(:name, :escaper)
10
+ def escape(value); escaper.call value; end
11
+ end
12
+
13
+ def self.required_path(symbol)
14
+ Parameter.new symbol, ESCAPE_PATH
15
+ end
16
+
17
+ def self.required_segment(symbol)
18
+ Parameter.new symbol, ESCAPE_SEGMENT
19
+ end
20
+
21
+ def initialize(parts)
22
+ @parts = parts
23
+ @children = []
24
+ @parameters = []
25
+
26
+ parts.each_with_index do |object,i|
27
+ case object
28
+ when Journey::Format
29
+ @children << i
30
+ when Parameter
31
+ @parameters << i
32
+ end
33
+ end
34
+ end
35
+
36
+ def evaluate(hash)
37
+ parts = @parts.dup
38
+
39
+ @parameters.each do |index|
40
+ param = parts[index]
41
+ value = hash[param.name]
42
+ return ''.freeze unless value
43
+ parts[index] = param.escape value
44
+ end
45
+
46
+ @children.each { |index| parts[index] = parts[index].evaluate(hash) }
47
+
48
+ parts.join
49
+ end
50
+ end
51
+
52
+ module Visitors # :nodoc:
53
+ class Visitor # :nodoc:
54
+ DISPATCH_CACHE = {}
55
+
56
+ def accept(node)
57
+ visit(node)
58
+ end
59
+
60
+ private
61
+
62
+ def visit node
63
+ send(DISPATCH_CACHE[node.type], node)
64
+ end
65
+
66
+ def binary(node)
67
+ visit(node.left)
68
+ visit(node.right)
69
+ end
70
+ def visit_CAT(n); binary(n); end
71
+
72
+ def nary(node)
73
+ node.children.each { |c| visit(c) }
74
+ end
75
+ def visit_OR(n); nary(n); end
76
+
77
+ def unary(node)
78
+ visit(node.left)
79
+ end
80
+ def visit_GROUP(n); unary(n); end
81
+ def visit_STAR(n); unary(n); end
82
+
83
+ def terminal(node); end
84
+ def visit_LITERAL(n); terminal(n); end
85
+ def visit_SYMBOL(n); terminal(n); end
86
+ def visit_SLASH(n); terminal(n); end
87
+ def visit_DOT(n); terminal(n); end
88
+
89
+ private_instance_methods(false).each do |pim|
90
+ next unless pim =~ /^visit_(.*)$/
91
+ DISPATCH_CACHE[$1.to_sym] = pim
92
+ end
93
+ end
94
+
95
+ class FormatBuilder < Visitor # :nodoc:
96
+ def accept(node); Journey::Format.new(super); end
97
+ def terminal(node); [node.left]; end
98
+
99
+ def binary(node)
100
+ visit(node.left) + visit(node.right)
101
+ end
102
+
103
+ def visit_GROUP(n); [Journey::Format.new(unary(n))]; end
104
+
105
+ def visit_STAR(n)
106
+ [Journey::Format.required_path(n.left.to_sym)]
107
+ end
108
+
109
+ def visit_SYMBOL(n)
110
+ symbol = n.to_sym
111
+ if symbol == :controller
112
+ [Journey::Format.required_path(symbol)]
113
+ else
114
+ [Journey::Format.required_segment(symbol)]
115
+ end
116
+ end
117
+ end
118
+
119
+ # Loop through the requirements AST
120
+ class Each < Visitor # :nodoc:
121
+ attr_reader :block
122
+
123
+ def initialize(block)
124
+ @block = block
125
+ end
126
+
127
+ def visit(node)
128
+ block.call(node)
129
+ super
130
+ end
131
+ end
132
+
133
+ class String < Visitor # :nodoc:
134
+ private
135
+
136
+ def binary(node)
137
+ [visit(node.left), visit(node.right)].join
138
+ end
139
+
140
+ def nary(node)
141
+ node.children.map { |c| visit(c) }.join '|'
142
+ end
143
+
144
+ def terminal(node)
145
+ node.left
146
+ end
147
+
148
+ def visit_GROUP(node)
149
+ "(#{visit(node.left)})"
150
+ end
151
+ end
152
+
153
+ class Dot < Visitor # :nodoc:
154
+ def initialize
155
+ @nodes = []
156
+ @edges = []
157
+ end
158
+
159
+ def accept(node)
160
+ super
161
+ <<-eodot
162
+ digraph parse_tree {
163
+ size="8,5"
164
+ node [shape = none];
165
+ edge [dir = none];
166
+ #{@nodes.join "\n"}
167
+ #{@edges.join("\n")}
168
+ }
169
+ eodot
170
+ end
171
+
172
+ private
173
+
174
+ def binary(node)
175
+ node.children.each do |c|
176
+ @edges << "#{node.object_id} -> #{c.object_id};"
177
+ end
178
+ super
179
+ end
180
+
181
+ def nary(node)
182
+ node.children.each do |c|
183
+ @edges << "#{node.object_id} -> #{c.object_id};"
184
+ end
185
+ super
186
+ end
187
+
188
+ def unary(node)
189
+ @edges << "#{node.object_id} -> #{node.left.object_id};"
190
+ super
191
+ end
192
+
193
+ def visit_GROUP(node)
194
+ @nodes << "#{node.object_id} [label=\"()\"];"
195
+ super
196
+ end
197
+
198
+ def visit_CAT(node)
199
+ @nodes << "#{node.object_id} [label=\"○\"];"
200
+ super
201
+ end
202
+
203
+ def visit_STAR(node)
204
+ @nodes << "#{node.object_id} [label=\"*\"];"
205
+ super
206
+ end
207
+
208
+ def visit_OR(node)
209
+ @nodes << "#{node.object_id} [label=\"|\"];"
210
+ super
211
+ end
212
+
213
+ def terminal(node)
214
+ value = node.left
215
+
216
+ @nodes << "#{node.object_id} [label=\"#{value}\"];"
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,30 @@
1
+ body {
2
+ font-family: "Helvetica Neue", Helvetica, Arial, Sans-Serif;
3
+ margin: 0;
4
+ }
5
+
6
+ h1 {
7
+ font-size: 2.0em; font-weight: bold; text-align: center;
8
+ color: white; background-color: black;
9
+ padding: 5px 0;
10
+ margin: 0 0 20px;
11
+ }
12
+
13
+ h2 {
14
+ text-align: center;
15
+ display: none;
16
+ font-size: 0.5em;
17
+ }
18
+
19
+ .clearfix {display: inline-block; }
20
+ .input { overflow: show;}
21
+ .instruction { color: #666; padding: 0 30px 20px; font-size: 0.9em}
22
+ .instruction p { padding: 0 0 5px; }
23
+ .instruction li { padding: 0 10px 5px; }
24
+
25
+ .form { background: #EEE; padding: 20px 30px; border-radius: 5px; margin-left: auto; margin-right: auto; width: 500px; margin-bottom: 20px}
26
+ .form p, .form form { text-align: center }
27
+ .form form {padding: 0 10px 5px; }
28
+ .form .fun_routes { font-size: 0.9em;}
29
+ .form .fun_routes a { margin: 0 5px 0 0; }
30
+
@@ -0,0 +1,134 @@
1
+ function tokenize(input, callback) {
2
+ while(input.length > 0) {
3
+ callback(input.match(/^[\/\.\?]|[^\/\.\?]+/)[0]);
4
+ input = input.replace(/^[\/\.\?]|[^\/\.\?]+/, '');
5
+ }
6
+ }
7
+
8
+ var graph = d3.select("#chart-2 svg");
9
+ var svg_edges = {};
10
+ var svg_nodes = {};
11
+
12
+ graph.selectAll("g.edge").each(function() {
13
+ var node = d3.select(this);
14
+ var index = node.select("title").text().split("->");
15
+ var left = parseInt(index[0]);
16
+ var right = parseInt(index[1]);
17
+
18
+ if(!svg_edges[left]) { svg_edges[left] = {} }
19
+ svg_edges[left][right] = node;
20
+ });
21
+
22
+ graph.selectAll("g.node").each(function() {
23
+ var node = d3.select(this);
24
+ var index = parseInt(node.select("title").text());
25
+ svg_nodes[index] = node;
26
+ });
27
+
28
+ function reset_graph() {
29
+ for(var key in svg_edges) {
30
+ for(var mkey in svg_edges[key]) {
31
+ var node = svg_edges[key][mkey];
32
+ var path = node.select("path");
33
+ var arrow = node.select("polygon");
34
+ path.style("stroke", "black");
35
+ arrow.style("stroke", "black").style("fill", "black");
36
+ }
37
+ }
38
+
39
+ for(var key in svg_nodes) {
40
+ var node = svg_nodes[key];
41
+ node.select('ellipse').style("fill", "white");
42
+ node.select('polygon').style("fill", "white");
43
+ }
44
+ return false;
45
+ }
46
+
47
+ function highlight_edge(from, to) {
48
+ var node = svg_edges[from][to];
49
+ var path = node.select("path");
50
+ var arrow = node.select("polygon");
51
+
52
+ path
53
+ .transition().duration(500)
54
+ .style("stroke", "green");
55
+
56
+ arrow
57
+ .transition().duration(500)
58
+ .style("stroke", "green").style("fill", "green");
59
+ }
60
+
61
+ function highlight_state(index, color) {
62
+ if(!color) { color = "green"; }
63
+
64
+ svg_nodes[index].select('ellipse')
65
+ .style("fill", "white")
66
+ .transition().duration(500)
67
+ .style("fill", color);
68
+ }
69
+
70
+ function highlight_finish(index) {
71
+ svg_nodes[index].select('polygon')
72
+ .style("fill", "while")
73
+ .transition().duration(500)
74
+ .style("fill", "blue");
75
+ }
76
+
77
+ function match(input) {
78
+ reset_graph();
79
+ var table = tt();
80
+ var states = [0];
81
+ var regexp_states = table['regexp_states'];
82
+ var string_states = table['string_states'];
83
+ var accepting = table['accepting'];
84
+
85
+ highlight_state(0);
86
+
87
+ tokenize(input, function(token) {
88
+ var new_states = [];
89
+ for(var key in states) {
90
+ var state = states[key];
91
+
92
+ if(string_states[state] && string_states[state][token]) {
93
+ var new_state = string_states[state][token];
94
+ highlight_edge(state, new_state);
95
+ highlight_state(new_state);
96
+ new_states.push(new_state);
97
+ }
98
+
99
+ if(regexp_states[state]) {
100
+ for(var key in regexp_states[state]) {
101
+ var re = new RegExp("^" + key + "$");
102
+ if(re.test(token)) {
103
+ var new_state = regexp_states[state][key];
104
+ highlight_edge(state, new_state);
105
+ highlight_state(new_state);
106
+ new_states.push(new_state);
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ if(new_states.length == 0) {
113
+ return;
114
+ }
115
+ states = new_states;
116
+ });
117
+
118
+ for(var key in states) {
119
+ var state = states[key];
120
+ if(accepting[state]) {
121
+ for(var mkey in svg_edges[state]) {
122
+ if(!regexp_states[mkey] && !string_states[mkey]) {
123
+ highlight_edge(state, mkey);
124
+ highlight_finish(mkey);
125
+ }
126
+ }
127
+ } else {
128
+ highlight_state(state, "red");
129
+ }
130
+ }
131
+
132
+ return false;
133
+ }
134
+