actionpack 3.2.22.5 → 4.0.0.beta1

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 (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +641 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller.rb +1 -8
  6. data/lib/abstract_controller/asset_paths.rb +2 -2
  7. data/lib/abstract_controller/base.rb +39 -37
  8. data/lib/abstract_controller/callbacks.rb +101 -82
  9. data/lib/abstract_controller/collector.rb +7 -3
  10. data/lib/abstract_controller/helpers.rb +23 -11
  11. data/lib/abstract_controller/layouts.rb +68 -73
  12. data/lib/abstract_controller/logger.rb +1 -2
  13. data/lib/abstract_controller/rendering.rb +22 -13
  14. data/lib/abstract_controller/translation.rb +16 -1
  15. data/lib/abstract_controller/url_for.rb +6 -6
  16. data/lib/abstract_controller/view_paths.rb +1 -1
  17. data/lib/action_controller.rb +15 -6
  18. data/lib/action_controller/base.rb +46 -22
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/caching/fragments.rb +23 -53
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  23. data/lib/action_controller/log_subscriber.rb +11 -8
  24. data/lib/action_controller/metal.rb +16 -30
  25. data/lib/action_controller/metal/conditional_get.rb +76 -32
  26. data/lib/action_controller/metal/data_streaming.rb +20 -26
  27. data/lib/action_controller/metal/exceptions.rb +19 -6
  28. data/lib/action_controller/metal/flash.rb +24 -9
  29. data/lib/action_controller/metal/force_ssl.rb +32 -9
  30. data/lib/action_controller/metal/head.rb +25 -4
  31. data/lib/action_controller/metal/helpers.rb +6 -9
  32. data/lib/action_controller/metal/hide_actions.rb +1 -2
  33. data/lib/action_controller/metal/http_authentication.rb +105 -87
  34. data/lib/action_controller/metal/implicit_render.rb +1 -1
  35. data/lib/action_controller/metal/instrumentation.rb +2 -1
  36. data/lib/action_controller/metal/live.rb +141 -0
  37. data/lib/action_controller/metal/mime_responds.rb +161 -47
  38. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  39. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  40. data/lib/action_controller/metal/redirecting.rb +15 -20
  41. data/lib/action_controller/metal/renderers.rb +11 -9
  42. data/lib/action_controller/metal/rendering.rb +8 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  44. data/lib/action_controller/metal/responder.rb +20 -19
  45. data/lib/action_controller/metal/streaming.rb +12 -18
  46. data/lib/action_controller/metal/strong_parameters.rb +516 -0
  47. data/lib/action_controller/metal/testing.rb +13 -18
  48. data/lib/action_controller/metal/url_for.rb +27 -25
  49. data/lib/action_controller/model_naming.rb +12 -0
  50. data/lib/action_controller/railtie.rb +33 -17
  51. data/lib/action_controller/railties/helpers.rb +22 -0
  52. data/lib/action_controller/record_identifier.rb +18 -72
  53. data/lib/action_controller/test_case.rb +215 -123
  54. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  55. data/lib/action_dispatch.rb +27 -19
  56. data/lib/action_dispatch/http/cache.rb +63 -11
  57. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  59. data/lib/action_dispatch/http/headers.rb +27 -19
  60. data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
  61. data/lib/action_dispatch/http/mime_type.rb +145 -113
  62. data/lib/action_dispatch/http/mime_types.rb +1 -1
  63. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  64. data/lib/action_dispatch/http/parameters.rb +12 -5
  65. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  66. data/lib/action_dispatch/http/request.rb +49 -18
  67. data/lib/action_dispatch/http/response.rb +129 -35
  68. data/lib/action_dispatch/http/upload.rb +60 -17
  69. data/lib/action_dispatch/http/url.rb +53 -31
  70. data/lib/action_dispatch/journey.rb +5 -0
  71. data/lib/action_dispatch/journey/backwards.rb +5 -0
  72. data/lib/action_dispatch/journey/formatter.rb +146 -0
  73. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  74. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  75. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  76. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  77. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  78. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  79. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  80. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  81. data/lib/action_dispatch/journey/parser.rb +206 -0
  82. data/lib/action_dispatch/journey/parser.y +47 -0
  83. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  84. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  85. data/lib/action_dispatch/journey/route.rb +116 -0
  86. data/lib/action_dispatch/journey/router.rb +164 -0
  87. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  88. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  89. data/lib/action_dispatch/journey/routes.rb +75 -0
  90. data/lib/action_dispatch/journey/scanner.rb +61 -0
  91. data/lib/action_dispatch/journey/visitors.rb +189 -0
  92. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  93. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  94. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  95. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  96. data/lib/action_dispatch/middleware/cookies.rb +168 -57
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
  99. data/lib/action_dispatch/middleware/flash.rb +58 -58
  100. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
  102. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  103. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  104. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  110. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  111. data/lib/action_dispatch/middleware/stack.rb +6 -1
  112. data/lib/action_dispatch/middleware/static.rb +5 -24
  113. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  114. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  116. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  117. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  124. data/lib/action_dispatch/railtie.rb +16 -6
  125. data/lib/action_dispatch/request/session.rb +181 -0
  126. data/lib/action_dispatch/routing.rb +41 -40
  127. data/lib/action_dispatch/routing/inspector.rb +240 -0
  128. data/lib/action_dispatch/routing/mapper.rb +501 -273
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  130. data/lib/action_dispatch/routing/redirection.rb +46 -29
  131. data/lib/action_dispatch/routing/route_set.rb +203 -164
  132. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  133. data/lib/action_dispatch/routing/url_for.rb +48 -33
  134. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  135. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  136. data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
  137. data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
  138. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  139. data/lib/action_dispatch/testing/integration.rb +41 -22
  140. data/lib/action_dispatch/testing/test_process.rb +9 -6
  141. data/lib/action_dispatch/testing/test_request.rb +7 -3
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_pack/version.rb +4 -4
  144. data/lib/action_view.rb +17 -8
  145. data/lib/action_view/base.rb +15 -34
  146. data/lib/action_view/buffers.rb +1 -1
  147. data/lib/action_view/context.rb +4 -4
  148. data/lib/action_view/dependency_tracker.rb +91 -0
  149. data/lib/action_view/digestor.rb +85 -0
  150. data/lib/action_view/flows.rb +1 -4
  151. data/lib/action_view/helpers.rb +2 -4
  152. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  153. data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
  154. data/lib/action_view/helpers/asset_url_helper.rb +354 -0
  155. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  156. data/lib/action_view/helpers/cache_helper.rb +150 -18
  157. data/lib/action_view/helpers/capture_helper.rb +42 -29
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  159. data/lib/action_view/helpers/date_helper.rb +268 -247
  160. data/lib/action_view/helpers/debug_helper.rb +10 -11
  161. data/lib/action_view/helpers/form_helper.rb +904 -547
  162. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  163. data/lib/action_view/helpers/form_tag_helper.rb +188 -88
  164. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  165. data/lib/action_view/helpers/number_helper.rb +148 -354
  166. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  167. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  168. data/lib/action_view/helpers/rendering_helper.rb +2 -4
  169. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  170. data/lib/action_view/helpers/tag_helper.rb +43 -37
  171. data/lib/action_view/helpers/tags.rb +39 -0
  172. data/lib/action_view/helpers/tags/base.rb +148 -0
  173. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  174. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  175. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  176. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  177. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  178. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  179. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  180. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  181. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  182. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  183. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  184. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  185. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  186. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  187. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  188. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  189. data/lib/action_view/helpers/tags/label.rb +65 -0
  190. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  191. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  192. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  193. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  194. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  195. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  196. data/lib/action_view/helpers/tags/select.rb +41 -0
  197. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  198. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  199. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  200. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  201. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  202. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  203. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  204. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  205. data/lib/action_view/helpers/text_helper.rb +126 -113
  206. data/lib/action_view/helpers/translation_helper.rb +32 -16
  207. data/lib/action_view/helpers/url_helper.rb +200 -271
  208. data/lib/action_view/locale/en.yml +1 -105
  209. data/lib/action_view/log_subscriber.rb +6 -4
  210. data/lib/action_view/lookup_context.rb +15 -39
  211. data/lib/action_view/model_naming.rb +12 -0
  212. data/lib/action_view/path_set.rb +9 -39
  213. data/lib/action_view/railtie.rb +6 -22
  214. data/lib/action_view/record_identifier.rb +84 -0
  215. data/lib/action_view/renderer/abstract_renderer.rb +10 -19
  216. data/lib/action_view/renderer/partial_renderer.rb +144 -81
  217. data/lib/action_view/renderer/renderer.rb +2 -19
  218. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  219. data/lib/action_view/renderer/template_renderer.rb +14 -13
  220. data/lib/action_view/routing_url_for.rb +107 -0
  221. data/lib/action_view/template.rb +22 -21
  222. data/lib/action_view/template/error.rb +22 -12
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/handlers/builder.rb +1 -1
  225. data/lib/action_view/template/handlers/erb.rb +11 -16
  226. data/lib/action_view/template/handlers/raw.rb +11 -0
  227. data/lib/action_view/template/resolver.rb +111 -83
  228. data/lib/action_view/template/text.rb +12 -8
  229. data/lib/action_view/template/types.rb +57 -0
  230. data/lib/action_view/test_case.rb +66 -43
  231. data/lib/action_view/testing/resolvers.rb +3 -2
  232. data/lib/action_view/vendor/html-scanner.rb +20 -0
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  235. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
  236. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
  237. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  238. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  239. metadata +135 -125
  240. data/lib/action_controller/caching/actions.rb +0 -185
  241. data/lib/action_controller/caching/pages.rb +0 -187
  242. data/lib/action_controller/caching/sweeping.rb +0 -97
  243. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  244. data/lib/action_controller/metal/compatibility.rb +0 -65
  245. data/lib/action_controller/metal/session_management.rb +0 -14
  246. data/lib/action_controller/railties/paths.rb +0 -25
  247. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  248. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  249. data/lib/action_dispatch/middleware/head.rb +0 -18
  250. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  251. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  252. data/lib/action_view/asset_paths.rb +0 -142
  253. data/lib/action_view/helpers/asset_paths.rb +0 -7
  254. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  255. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  256. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  257. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  258. data/lib/sprockets/assets.rake +0 -99
  259. data/lib/sprockets/bootstrap.rb +0 -37
  260. data/lib/sprockets/compressors.rb +0 -83
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  263. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  264. data/lib/sprockets/railtie.rb +0 -62
  265. data/lib/sprockets/static_compiler.rb +0 -56
@@ -0,0 +1,116 @@
1
+ module ActionDispatch
2
+ module Journey # :nodoc:
3
+ class Route # :nodoc:
4
+ attr_reader :app, :path, :defaults, :name
5
+
6
+ attr_reader :constraints
7
+ alias :conditions :constraints
8
+
9
+ attr_accessor :precedence
10
+
11
+ ##
12
+ # +path+ is a path constraint.
13
+ # +constraints+ is a hash of constraints to be applied to this route.
14
+ def initialize(name, app, path, constraints, defaults = {})
15
+ @name = name
16
+ @app = app
17
+ @path = path
18
+
19
+ @constraints = constraints
20
+ @defaults = defaults
21
+ @required_defaults = nil
22
+ @required_parts = nil
23
+ @parts = nil
24
+ @decorated_ast = nil
25
+ @precedence = 0
26
+ end
27
+
28
+ def ast
29
+ @decorated_ast ||= begin
30
+ decorated_ast = path.ast
31
+ decorated_ast.grep(Nodes::Terminal).each { |n| n.memo = self }
32
+ decorated_ast
33
+ end
34
+ end
35
+
36
+ def requirements # :nodoc:
37
+ # needed for rails `rake routes`
38
+ path.requirements.merge(@defaults).delete_if { |_,v|
39
+ /.+?/ == v
40
+ }
41
+ end
42
+
43
+ def segments
44
+ path.names
45
+ end
46
+
47
+ def required_keys
48
+ required_parts + required_defaults.keys
49
+ end
50
+
51
+ def score(constraints)
52
+ required_keys = path.required_names
53
+ supplied_keys = constraints.map { |k,v| v && k.to_s }.compact
54
+
55
+ return -1 unless (required_keys - supplied_keys).empty?
56
+
57
+ score = (supplied_keys & path.names).length
58
+ score + (required_defaults.length * 2)
59
+ end
60
+
61
+ def parts
62
+ @parts ||= segments.map { |n| n.to_sym }
63
+ end
64
+ alias :segment_keys :parts
65
+
66
+ def format(path_options)
67
+ path_options.delete_if do |key, value|
68
+ value.to_s == defaults[key].to_s && !required_parts.include?(key)
69
+ end
70
+
71
+ Visitors::Formatter.new(path_options).accept(path.spec)
72
+ end
73
+
74
+ def optional_parts
75
+ path.optional_names.map { |n| n.to_sym }
76
+ end
77
+
78
+ def required_parts
79
+ @required_parts ||= path.required_names.map { |n| n.to_sym }
80
+ end
81
+
82
+ def required_default?(key)
83
+ (constraints[:required_defaults] || []).include?(key)
84
+ end
85
+
86
+ def required_defaults
87
+ @required_defaults ||= @defaults.dup.delete_if do |k,_|
88
+ parts.include?(k) || !required_default?(k)
89
+ end
90
+ end
91
+
92
+ def matches?(request)
93
+ constraints.all? do |method, value|
94
+ next true unless request.respond_to?(method)
95
+
96
+ case value
97
+ when Regexp, String
98
+ value === request.send(method).to_s
99
+ when Array
100
+ value.include?(request.send(method))
101
+ else
102
+ value === request.send(method)
103
+ end
104
+ end
105
+ end
106
+
107
+ def ip
108
+ constraints[:ip] || //
109
+ end
110
+
111
+ def verb
112
+ constraints[:request_method] || //
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,164 @@
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
+ class NullReq # :nodoc:
24
+ attr_reader :env
25
+ def initialize(env)
26
+ @env = env
27
+ end
28
+
29
+ def request_method
30
+ env['REQUEST_METHOD']
31
+ end
32
+
33
+ def path_info
34
+ env['PATH_INFO']
35
+ end
36
+
37
+ def ip
38
+ env['REMOTE_ADDR']
39
+ end
40
+
41
+ def [](k); env[k]; end
42
+ end
43
+
44
+ attr_reader :request_class, :formatter
45
+ attr_accessor :routes
46
+
47
+ def initialize(routes, options)
48
+ @options = options
49
+ @params_key = options[:parameters_key]
50
+ @request_class = options[:request_class] || NullReq
51
+ @routes = routes
52
+ end
53
+
54
+ def call(env)
55
+ env['PATH_INFO'] = Utils.normalize_path(env['PATH_INFO'])
56
+
57
+ find_routes(env).each do |match, parameters, route|
58
+ script_name, path_info, set_params = env.values_at('SCRIPT_NAME',
59
+ 'PATH_INFO',
60
+ @params_key)
61
+
62
+ unless route.path.anchored
63
+ env['SCRIPT_NAME'] = (script_name.to_s + match.to_s).chomp('/')
64
+ env['PATH_INFO'] = match.post_match
65
+ end
66
+
67
+ env[@params_key] = (set_params || {}).merge parameters
68
+
69
+ status, headers, body = route.app.call(env)
70
+
71
+ if 'pass' == headers['X-Cascade']
72
+ env['SCRIPT_NAME'] = script_name
73
+ env['PATH_INFO'] = path_info
74
+ env[@params_key] = set_params
75
+ next
76
+ end
77
+
78
+ return [status, headers, body]
79
+ end
80
+
81
+ return [404, {'X-Cascade' => 'pass'}, ['Not Found']]
82
+ end
83
+
84
+ def recognize(req)
85
+ find_routes(req.env).each do |match, parameters, route|
86
+ unless route.path.anchored
87
+ req.env['SCRIPT_NAME'] = match.to_s
88
+ req.env['PATH_INFO'] = match.post_match.sub(/^([^\/])/, '/\1')
89
+ end
90
+
91
+ yield(route, nil, parameters)
92
+ end
93
+ end
94
+
95
+ def visualizer
96
+ tt = GTG::Builder.new(ast).transition_table
97
+ groups = partitioned_routes.first.map(&:ast).group_by { |a| a.to_s }
98
+ asts = groups.values.map { |v| v.first }
99
+ tt.visualizer(asts)
100
+ end
101
+
102
+ private
103
+
104
+ def partitioned_routes
105
+ routes.partitioned_routes
106
+ end
107
+
108
+ def ast
109
+ routes.ast
110
+ end
111
+
112
+ def simulator
113
+ routes.simulator
114
+ end
115
+
116
+ def custom_routes
117
+ partitioned_routes.last
118
+ end
119
+
120
+ def filter_routes(path)
121
+ return [] unless ast
122
+ data = simulator.match(path)
123
+ data ? data.memos : []
124
+ end
125
+
126
+ def find_routes env
127
+ req = request_class.new(env)
128
+
129
+ routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
130
+ r.path.match(req.path_info)
131
+ }
132
+ routes.concat get_routes_as_head(routes)
133
+
134
+ routes.sort_by!(&:precedence).select! { |r| r.matches?(req) }
135
+
136
+ routes.map! { |r|
137
+ match_data = r.path.match(req.path_info)
138
+ match_names = match_data.names.map { |n| n.to_sym }
139
+ match_values = match_data.captures.map { |v| v && Utils.unescape_uri(v) }
140
+ info = Hash[match_names.zip(match_values).find_all { |_, y| y }]
141
+
142
+ [match_data, r.defaults.merge(info), r]
143
+ }
144
+ end
145
+
146
+ def get_routes_as_head(routes)
147
+ precedence = (routes.map(&:precedence).max || 0) + 1
148
+ routes = routes.select { |r|
149
+ r.verb === "GET" && !(r.verb === "HEAD")
150
+ }.map! { |r|
151
+ Route.new(r.name,
152
+ r.app,
153
+ r.path,
154
+ r.conditions.merge(request_method: "HEAD"),
155
+ r.defaults).tap do |route|
156
+ route.precedence = r.precedence + precedence
157
+ end
158
+ }
159
+ routes.flatten!
160
+ routes
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,24 @@
1
+ module ActionDispatch
2
+ module Journey # :nodoc:
3
+ class Router # :nodoc:
4
+ class Strexp # :nodoc:
5
+ class << self
6
+ alias :compile :new
7
+ end
8
+
9
+ attr_reader :path, :requirements, :separators, :anchor
10
+
11
+ def initialize(path, requirements, separators, anchor = true)
12
+ @path = path
13
+ @requirements = requirements
14
+ @separators = separators
15
+ @anchor = anchor
16
+ end
17
+
18
+ def names
19
+ @path.scan(/:\w+/).map { |s| s.tr(':', '') }
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,54 @@
1
+ require 'uri'
2
+
3
+ module ActionDispatch
4
+ module Journey # :nodoc:
5
+ class Router # :nodoc:
6
+ class Utils # :nodoc:
7
+ # Normalizes URI path.
8
+ #
9
+ # Strips off trailing slash and ensures there is a leading slash.
10
+ #
11
+ # normalize_path("/foo") # => "/foo"
12
+ # normalize_path("/foo/") # => "/foo"
13
+ # normalize_path("foo") # => "/foo"
14
+ # normalize_path("") # => "/"
15
+ def self.normalize_path(path)
16
+ path = "/#{path}"
17
+ path.squeeze!('/')
18
+ path.sub!(%r{/+\Z}, '')
19
+ path = '/' if path == ''
20
+ path
21
+ end
22
+
23
+ # URI path and fragment escaping
24
+ # http://tools.ietf.org/html/rfc3986
25
+ module UriEscape # :nodoc:
26
+ # Symbol captures can generate multiple path segments, so include /.
27
+ reserved_segment = '/'
28
+ reserved_fragment = '/?'
29
+ reserved_pchar = ':@&=+$,;%'
30
+
31
+ safe_pchar = "#{URI::REGEXP::PATTERN::UNRESERVED}#{reserved_pchar}"
32
+ safe_segment = "#{safe_pchar}#{reserved_segment}"
33
+ safe_fragment = "#{safe_pchar}#{reserved_fragment}"
34
+ UNSAFE_SEGMENT = Regexp.new("[^#{safe_segment}]", false).freeze
35
+ UNSAFE_FRAGMENT = Regexp.new("[^#{safe_fragment}]", false).freeze
36
+ end
37
+
38
+ Parser = URI.const_defined?(:Parser) ? URI::Parser.new : URI
39
+
40
+ def self.escape_path(path)
41
+ Parser.escape(path.to_s, UriEscape::UNSAFE_SEGMENT)
42
+ end
43
+
44
+ def self.escape_fragment(fragment)
45
+ Parser.escape(fragment.to_s, UriEscape::UNSAFE_FRAGMENT)
46
+ end
47
+
48
+ def self.unescape_uri(uri)
49
+ Parser.unescape(uri)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,75 @@
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 length
19
+ routes.length
20
+ end
21
+ alias :size :length
22
+
23
+ def last
24
+ routes.last
25
+ end
26
+
27
+ def each(&block)
28
+ routes.each(&block)
29
+ end
30
+
31
+ def clear
32
+ routes.clear
33
+ end
34
+
35
+ def partitioned_routes
36
+ @partitioned_routes ||= routes.partition do |r|
37
+ r.path.anchored && r.ast.grep(Nodes::Symbol).all?(&:default_regexp?)
38
+ end
39
+ end
40
+
41
+ def ast
42
+ @ast ||= begin
43
+ asts = partitioned_routes.first.map(&:ast)
44
+ Nodes::Or.new(asts) unless asts.empty?
45
+ end
46
+ end
47
+
48
+ def simulator
49
+ @simulator ||= begin
50
+ gtg = GTG::Builder.new(ast).transition_table
51
+ GTG::Simulator.new(gtg)
52
+ end
53
+ end
54
+
55
+ # Add a route to the routing table.
56
+ def add_route(app, path, conditions, defaults, name = nil)
57
+ route = Route.new(name, app, path, conditions, defaults)
58
+
59
+ route.precedence = routes.length
60
+ routes << route
61
+ named_routes[name] = route if name && !named_routes[name]
62
+ clear_cache!
63
+ route
64
+ end
65
+
66
+ private
67
+
68
+ def clear_cache!
69
+ @ast = nil
70
+ @partitioned_routes = nil
71
+ @simulator = nil
72
+ end
73
+ end
74
+ end
75
+ 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]
54
+ # any char
55
+ when text = @ss.scan(/./)
56
+ [:LITERAL, text]
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end