actionpack 3.2.19 → 4.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 (263) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +850 -401
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller/asset_paths.rb +2 -2
  6. data/lib/abstract_controller/base.rb +39 -37
  7. data/lib/abstract_controller/callbacks.rb +101 -82
  8. data/lib/abstract_controller/collector.rb +7 -3
  9. data/lib/abstract_controller/helpers.rb +25 -13
  10. data/lib/abstract_controller/layouts.rb +74 -74
  11. data/lib/abstract_controller/logger.rb +1 -2
  12. data/lib/abstract_controller/rendering.rb +30 -13
  13. data/lib/abstract_controller/translation.rb +16 -1
  14. data/lib/abstract_controller/url_for.rb +6 -6
  15. data/lib/abstract_controller/view_paths.rb +1 -1
  16. data/lib/abstract_controller.rb +1 -8
  17. data/lib/action_controller/base.rb +46 -22
  18. data/lib/action_controller/caching/fragments.rb +23 -53
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/log_subscriber.rb +16 -8
  23. data/lib/action_controller/metal/conditional_get.rb +76 -32
  24. data/lib/action_controller/metal/data_streaming.rb +20 -26
  25. data/lib/action_controller/metal/exceptions.rb +19 -6
  26. data/lib/action_controller/metal/flash.rb +24 -9
  27. data/lib/action_controller/metal/force_ssl.rb +70 -12
  28. data/lib/action_controller/metal/head.rb +25 -4
  29. data/lib/action_controller/metal/helpers.rb +5 -9
  30. data/lib/action_controller/metal/hide_actions.rb +0 -1
  31. data/lib/action_controller/metal/http_authentication.rb +107 -83
  32. data/lib/action_controller/metal/implicit_render.rb +1 -1
  33. data/lib/action_controller/metal/instrumentation.rb +2 -1
  34. data/lib/action_controller/metal/live.rb +175 -0
  35. data/lib/action_controller/metal/mime_responds.rb +161 -47
  36. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  37. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  38. data/lib/action_controller/metal/redirecting.rb +15 -20
  39. data/lib/action_controller/metal/renderers.rb +11 -9
  40. data/lib/action_controller/metal/rendering.rb +9 -1
  41. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  42. data/lib/action_controller/metal/responder.rb +20 -19
  43. data/lib/action_controller/metal/streaming.rb +12 -18
  44. data/lib/action_controller/metal/strong_parameters.rb +520 -0
  45. data/lib/action_controller/metal/testing.rb +13 -18
  46. data/lib/action_controller/metal/url_for.rb +28 -25
  47. data/lib/action_controller/metal.rb +17 -32
  48. data/lib/action_controller/model_naming.rb +12 -0
  49. data/lib/action_controller/railtie.rb +33 -17
  50. data/lib/action_controller/railties/helpers.rb +22 -0
  51. data/lib/action_controller/record_identifier.rb +18 -72
  52. data/lib/action_controller/test_case.rb +251 -131
  53. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  54. data/lib/action_controller.rb +15 -6
  55. data/lib/action_dispatch/http/cache.rb +63 -11
  56. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  57. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  58. data/lib/action_dispatch/http/headers.rb +49 -17
  59. data/lib/action_dispatch/http/mime_negotiation.rb +24 -1
  60. data/lib/action_dispatch/http/mime_type.rb +154 -100
  61. data/lib/action_dispatch/http/mime_types.rb +1 -1
  62. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  63. data/lib/action_dispatch/http/parameters.rb +28 -28
  64. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  65. data/lib/action_dispatch/http/request.rb +64 -18
  66. data/lib/action_dispatch/http/response.rb +130 -35
  67. data/lib/action_dispatch/http/upload.rb +63 -20
  68. data/lib/action_dispatch/http/url.rb +98 -35
  69. data/lib/action_dispatch/journey/backwards.rb +5 -0
  70. data/lib/action_dispatch/journey/formatter.rb +146 -0
  71. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  72. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  73. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  74. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  75. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  76. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  77. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  78. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  79. data/lib/action_dispatch/journey/parser.rb +206 -0
  80. data/lib/action_dispatch/journey/parser.y +47 -0
  81. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  82. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  83. data/lib/action_dispatch/journey/route.rb +124 -0
  84. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  85. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  86. data/lib/action_dispatch/journey/router.rb +166 -0
  87. data/lib/action_dispatch/journey/routes.rb +75 -0
  88. data/lib/action_dispatch/journey/scanner.rb +61 -0
  89. data/lib/action_dispatch/journey/visitors.rb +197 -0
  90. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  91. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  92. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  93. data/lib/action_dispatch/journey.rb +5 -0
  94. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  95. data/lib/action_dispatch/middleware/cookies.rb +259 -114
  96. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  97. data/lib/action_dispatch/middleware/exception_wrapper.rb +29 -3
  98. data/lib/action_dispatch/middleware/flash.rb +58 -58
  99. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  100. data/lib/action_dispatch/middleware/public_exceptions.rb +30 -14
  101. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  102. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  103. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  104. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  105. data/lib/action_dispatch/middleware/session/cookie_store.rb +82 -28
  106. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  107. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  108. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  109. data/lib/action_dispatch/middleware/stack.rb +6 -1
  110. data/lib/action_dispatch/middleware/static.rb +2 -1
  111. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  112. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +7 -9
  114. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  115. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +127 -5
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  117. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  118. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  119. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  120. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  121. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  122. data/lib/action_dispatch/railtie.rb +16 -6
  123. data/lib/action_dispatch/request/session.rb +181 -0
  124. data/lib/action_dispatch/routing/inspector.rb +240 -0
  125. data/lib/action_dispatch/routing/mapper.rb +540 -291
  126. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  127. data/lib/action_dispatch/routing/redirection.rb +46 -29
  128. data/lib/action_dispatch/routing/route_set.rb +207 -164
  129. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  130. data/lib/action_dispatch/routing/url_for.rb +48 -33
  131. data/lib/action_dispatch/routing.rb +48 -83
  132. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  133. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  134. data/lib/action_dispatch/testing/assertions/routing.rb +42 -41
  135. data/lib/action_dispatch/testing/assertions/selector.rb +17 -22
  136. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  137. data/lib/action_dispatch/testing/integration.rb +65 -51
  138. data/lib/action_dispatch/testing/test_process.rb +9 -6
  139. data/lib/action_dispatch/testing/test_request.rb +7 -3
  140. data/lib/action_dispatch.rb +21 -15
  141. data/lib/action_pack/version.rb +7 -6
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_view/base.rb +15 -34
  144. data/lib/action_view/buffers.rb +7 -1
  145. data/lib/action_view/context.rb +4 -4
  146. data/lib/action_view/dependency_tracker.rb +93 -0
  147. data/lib/action_view/digestor.rb +85 -0
  148. data/lib/action_view/flows.rb +1 -4
  149. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  150. data/lib/action_view/helpers/asset_tag_helper.rb +215 -352
  151. data/lib/action_view/helpers/asset_url_helper.rb +355 -0
  152. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  153. data/lib/action_view/helpers/cache_helper.rb +150 -18
  154. data/lib/action_view/helpers/capture_helper.rb +44 -31
  155. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  156. data/lib/action_view/helpers/date_helper.rb +269 -248
  157. data/lib/action_view/helpers/debug_helper.rb +10 -11
  158. data/lib/action_view/helpers/form_helper.rb +931 -537
  159. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  160. data/lib/action_view/helpers/form_tag_helper.rb +190 -90
  161. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  162. data/lib/action_view/helpers/number_helper.rb +148 -329
  163. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  164. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  165. data/lib/action_view/helpers/rendering_helper.rb +2 -2
  166. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  167. data/lib/action_view/helpers/tag_helper.rb +46 -33
  168. data/lib/action_view/helpers/tags/base.rb +147 -0
  169. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  170. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  171. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  172. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  173. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  174. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  175. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  176. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  177. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  178. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  179. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  180. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  181. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  182. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  183. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  184. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  185. data/lib/action_view/helpers/tags/label.rb +65 -0
  186. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  187. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  188. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  189. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  190. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  191. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  192. data/lib/action_view/helpers/tags/select.rb +40 -0
  193. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  194. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  195. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  196. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  197. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  198. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  199. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  200. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  201. data/lib/action_view/helpers/tags.rb +39 -0
  202. data/lib/action_view/helpers/text_helper.rb +130 -114
  203. data/lib/action_view/helpers/translation_helper.rb +32 -16
  204. data/lib/action_view/helpers/url_helper.rb +211 -270
  205. data/lib/action_view/helpers.rb +2 -4
  206. data/lib/action_view/locale/en.yml +1 -105
  207. data/lib/action_view/log_subscriber.rb +6 -4
  208. data/lib/action_view/lookup_context.rb +15 -28
  209. data/lib/action_view/model_naming.rb +12 -0
  210. data/lib/action_view/path_set.rb +8 -20
  211. data/lib/action_view/railtie.rb +6 -22
  212. data/lib/action_view/record_identifier.rb +84 -0
  213. data/lib/action_view/renderer/abstract_renderer.rb +25 -19
  214. data/lib/action_view/renderer/partial_renderer.rb +158 -81
  215. data/lib/action_view/renderer/renderer.rb +8 -12
  216. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  217. data/lib/action_view/renderer/template_renderer.rb +12 -10
  218. data/lib/action_view/routing_url_for.rb +107 -0
  219. data/lib/action_view/template/error.rb +22 -12
  220. data/lib/action_view/template/handlers/builder.rb +1 -1
  221. data/lib/action_view/template/handlers/erb.rb +40 -19
  222. data/lib/action_view/template/handlers/raw.rb +11 -0
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/resolver.rb +107 -53
  225. data/lib/action_view/template/text.rb +12 -8
  226. data/lib/action_view/template/types.rb +57 -0
  227. data/lib/action_view/template.rb +25 -23
  228. data/lib/action_view/test_case.rb +67 -42
  229. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  230. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  231. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +13 -2
  232. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +9 -9
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  235. data/lib/action_view/vendor/html-scanner.rb +20 -0
  236. data/lib/action_view.rb +17 -8
  237. metadata +184 -214
  238. data/lib/action_controller/caching/actions.rb +0 -185
  239. data/lib/action_controller/caching/pages.rb +0 -187
  240. data/lib/action_controller/caching/sweeping.rb +0 -97
  241. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  242. data/lib/action_controller/metal/compatibility.rb +0 -65
  243. data/lib/action_controller/metal/session_management.rb +0 -14
  244. data/lib/action_controller/railties/paths.rb +0 -25
  245. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  246. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  247. data/lib/action_dispatch/middleware/head.rb +0 -18
  248. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  249. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  250. data/lib/action_view/asset_paths.rb +0 -142
  251. data/lib/action_view/helpers/asset_paths.rb +0 -7
  252. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  253. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  254. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  255. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  256. data/lib/sprockets/assets.rake +0 -99
  257. data/lib/sprockets/bootstrap.rb +0 -37
  258. data/lib/sprockets/compressors.rb +0 -83
  259. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  260. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/railtie.rb +0 -62
  263. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,8 +1,7 @@
1
1
  require 'rack/session/abstract/id'
2
- require 'active_support/core_ext/object/blank'
3
2
  require 'active_support/core_ext/object/to_query'
4
- require 'active_support/core_ext/class/attribute'
5
3
  require 'active_support/core_ext/module/anonymous'
4
+ require 'active_support/core_ext/hash/keys'
6
5
 
7
6
  module ActionController
8
7
  module TemplateAssertions
@@ -14,30 +13,41 @@ module ActionController
14
13
  end
15
14
 
16
15
  def setup_subscriptions
17
- @partials = Hash.new(0)
18
- @templates = Hash.new(0)
19
- @layouts = Hash.new(0)
16
+ @_partials = Hash.new(0)
17
+ @_templates = Hash.new(0)
18
+ @_layouts = Hash.new(0)
19
+ @_files = Hash.new(0)
20
20
 
21
- ActiveSupport::Notifications.subscribe("render_template.action_view") do |name, start, finish, id, payload|
21
+ ActiveSupport::Notifications.subscribe("render_template.action_view") do |_name, _start, _finish, _id, payload|
22
22
  path = payload[:layout]
23
23
  if path
24
- @layouts[path] += 1
24
+ @_layouts[path] += 1
25
25
  if path =~ /^layouts\/(.*)/
26
- @layouts[$1] += 1
26
+ @_layouts[$1] += 1
27
27
  end
28
28
  end
29
29
  end
30
30
 
31
- ActiveSupport::Notifications.subscribe("!render_template.action_view") do |name, start, finish, id, payload|
31
+ ActiveSupport::Notifications.subscribe("!render_template.action_view") do |_name, _start, _finish, _id, payload|
32
32
  path = payload[:virtual_path]
33
33
  next unless path
34
34
  partial = path =~ /^.*\/_[^\/]*$/
35
+
35
36
  if partial
36
- @partials[path] += 1
37
- @partials[path.split("/").last] += 1
38
- @templates[path] += 1
39
- else
40
- @templates[path] += 1
37
+ @_partials[path] += 1
38
+ @_partials[path.split("/").last] += 1
39
+ end
40
+
41
+ @_templates[path] += 1
42
+ end
43
+
44
+ ActiveSupport::Notifications.subscribe("!render_template.action_view") do |_name, _start, _finish, _id, payload|
45
+ next if payload[:virtual_path] # files don't have virtual path
46
+
47
+ path = payload[:identifier]
48
+ if path
49
+ @_files[path] += 1
50
+ @_files[path.split("/").last] += 1
41
51
  end
42
52
  end
43
53
  end
@@ -48,107 +58,125 @@ module ActionController
48
58
  end
49
59
 
50
60
  def process(*args)
51
- @partials = Hash.new(0)
52
- @templates = Hash.new(0)
53
- @layouts = Hash.new(0)
61
+ @_partials = Hash.new(0)
62
+ @_templates = Hash.new(0)
63
+ @_layouts = Hash.new(0)
54
64
  super
55
65
  end
56
66
 
57
67
  # Asserts that the request was rendered with the appropriate template file or partials.
58
68
  #
59
- # ==== Examples
60
- #
61
69
  # # assert that the "new" view template was rendered
62
70
  # assert_template "new"
63
71
  #
72
+ # # assert that the exact template "admin/posts/new" was rendered
73
+ # assert_template %r{\Aadmin/posts/new\Z}
74
+ #
64
75
  # # assert that the layout 'admin' was rendered
65
- # assert_template :layout => 'admin'
66
- # assert_template :layout => 'layouts/admin'
67
- # assert_template :layout => :admin
76
+ # assert_template layout: 'admin'
77
+ # assert_template layout: 'layouts/admin'
78
+ # assert_template layout: :admin
68
79
  #
69
80
  # # assert that no layout was rendered
70
- # assert_template :layout => nil
71
- # assert_template :layout => false
81
+ # assert_template layout: nil
82
+ # assert_template layout: false
72
83
  #
73
84
  # # assert that the "_customer" partial was rendered twice
74
- # assert_template :partial => '_customer', :count => 2
85
+ # assert_template partial: '_customer', count: 2
75
86
  #
76
87
  # # assert that no partials were rendered
77
- # assert_template :partial => false
88
+ # assert_template partial: false
78
89
  #
79
90
  # In a view test case, you can also assert that specific locals are passed
80
91
  # to partials:
81
92
  #
82
93
  # # assert that the "_customer" partial was rendered with a specific object
83
- # assert_template :partial => '_customer', :locals => { :customer => @customer }
84
- #
94
+ # assert_template partial: '_customer', locals: { customer: @customer }
85
95
  def assert_template(options = {}, message = nil)
86
- validate_request!
87
- # Force body to be read in case the template is being streamed
96
+ # Force body to be read in case the template is being streamed.
88
97
  response.body
89
98
 
90
99
  case options
91
- when NilClass, String, Symbol
100
+ when NilClass, Regexp, String, Symbol
92
101
  options = options.to_s if Symbol === options
93
- rendered = @templates
94
- msg = build_message(message,
95
- "expecting <?> but rendering with <?>",
96
- options, rendered.keys.join(', '))
97
- assert_block(msg) do
98
- if options
102
+ rendered = @_templates
103
+ msg = message || sprintf("expecting <%s> but rendering with <%s>",
104
+ options.inspect, rendered.keys)
105
+ matches_template =
106
+ case options
107
+ when String
108
+ !options.empty? && rendered.any? do |t, num|
109
+ options_splited = options.split(File::SEPARATOR)
110
+ t_splited = t.split(File::SEPARATOR)
111
+ t_splited.last(options_splited.size) == options_splited
112
+ end
113
+ when Regexp
99
114
  rendered.any? { |t,num| t.match(options) }
100
- else
101
- @templates.blank?
115
+ when NilClass
116
+ rendered.blank?
102
117
  end
103
- end
118
+ assert matches_template, msg
104
119
  when Hash
120
+ options.assert_valid_keys(:layout, :partial, :locals, :count, :file)
121
+
105
122
  if options.key?(:layout)
106
123
  expected_layout = options[:layout]
107
- msg = build_message(message,
108
- "expecting layout <?> but action rendered <?>",
109
- expected_layout, @layouts.keys)
124
+ msg = message || sprintf("expecting layout <%s> but action rendered <%s>",
125
+ expected_layout, @_layouts.keys)
110
126
 
111
127
  case expected_layout
112
128
  when String, Symbol
113
- assert(@layouts.keys.include?(expected_layout.to_s), msg)
129
+ assert_includes @_layouts.keys, expected_layout.to_s, msg
114
130
  when Regexp
115
- assert(@layouts.keys.any? {|l| l =~ expected_layout }, msg)
131
+ assert(@_layouts.keys.any? {|l| l =~ expected_layout }, msg)
116
132
  when nil, false
117
- assert(@layouts.empty?, msg)
133
+ assert(@_layouts.empty?, msg)
118
134
  end
119
135
  end
120
136
 
137
+ if options[:file]
138
+ assert_includes @_files.keys, options[:file]
139
+ end
140
+
121
141
  if expected_partial = options[:partial]
122
142
  if expected_locals = options[:locals]
123
- if defined?(@locals)
124
- actual_locals = @locals[expected_partial.to_s.sub(/^_/,'')]
125
- expected_locals.each_pair do |k,v|
126
- assert_equal(v, actual_locals[k])
127
- end
143
+ if defined?(@_rendered_views)
144
+ view = expected_partial.to_s.sub(/^_/, '').sub(/\/_(?=[^\/]+\z)/, '/')
145
+
146
+ partial_was_not_rendered_msg = "expected %s to be rendered but it was not." % view
147
+ assert_includes @_rendered_views.rendered_views, view, partial_was_not_rendered_msg
148
+
149
+ msg = 'expecting %s to be rendered with %s but was with %s' % [expected_partial,
150
+ expected_locals,
151
+ @_rendered_views.locals_for(view)]
152
+ assert(@_rendered_views.view_rendered?(view, options[:locals]), msg)
128
153
  else
129
154
  warn "the :locals option to #assert_template is only supported in a ActionView::TestCase"
130
155
  end
131
156
  elsif expected_count = options[:count]
132
- actual_count = @partials[expected_partial]
133
- msg = build_message(message,
134
- "expecting ? to be rendered ? time(s) but rendered ? time(s)",
157
+ actual_count = @_partials[expected_partial]
158
+ msg = message || sprintf("expecting %s to be rendered %s time(s) but rendered %s time(s)",
135
159
  expected_partial, expected_count, actual_count)
136
160
  assert(actual_count == expected_count.to_i, msg)
137
161
  else
138
- msg = build_message(message,
139
- "expecting partial <?> but action rendered <?>",
140
- options[:partial], @partials.keys)
141
- assert(@partials.include?(expected_partial), msg)
162
+ msg = message || sprintf("expecting partial <%s> but action rendered <%s>",
163
+ options[:partial], @_partials.keys)
164
+ assert_includes @_partials, expected_partial, msg
142
165
  end
143
166
  elsif options.key?(:partial)
144
- assert @partials.empty?,
167
+ assert @_partials.empty?,
145
168
  "Expected no partials to be rendered"
146
169
  end
170
+ else
171
+ raise ArgumentError, "assert_template only accepts a String, Symbol, Hash, Regexp, or nil"
147
172
  end
148
173
  end
149
174
  end
150
175
 
151
176
  class TestRequest < ActionDispatch::TestRequest #:nodoc:
177
+ DEFAULT_ENV = ActionDispatch::TestRequest::DEFAULT_ENV.dup
178
+ DEFAULT_ENV.delete 'PATH_INFO'
179
+
152
180
  def initialize(env = {})
153
181
  super
154
182
 
@@ -156,13 +184,6 @@ module ActionController
156
184
  self.session_options = TestSession::DEFAULT_OPTIONS.merge(:id => SecureRandom.hex(16))
157
185
  end
158
186
 
159
- class Result < ::Array #:nodoc:
160
- def to_s() join '/' end
161
- def self.new_escaped(strings)
162
- new strings.collect {|str| uri_parser.unescape str}
163
- end
164
- end
165
-
166
187
  def assign_parameters(routes, controller_path, action, parameters = {})
167
188
  parameters = parameters.symbolize_keys.merge(:controller => controller_path, :action => action)
168
189
  extra_keys = routes.extra_keys(parameters)
@@ -180,7 +201,7 @@ module ActionController
180
201
  non_path_parameters[key] = value
181
202
  else
182
203
  if value.is_a?(Array)
183
- value = Result.new(value.map(&:to_param))
204
+ value = value.map(&:to_param)
184
205
  else
185
206
  value = value.to_param
186
207
  end
@@ -220,33 +241,53 @@ module ActionController
220
241
  cookie_jar.update(@set_cookies)
221
242
  cookie_jar.recycle!
222
243
  end
244
+
245
+ private
246
+
247
+ def default_env
248
+ DEFAULT_ENV
249
+ end
223
250
  end
224
251
 
225
252
  class TestResponse < ActionDispatch::TestResponse
226
253
  def recycle!
227
- @status = 200
228
- @header = {}
229
- @writer = lambda { |x| @body << x }
230
- @block = nil
231
- @length = 0
232
- @body = []
233
- @charset = @content_type = nil
234
- @request = @template = nil
254
+ initialize
235
255
  end
236
256
  end
237
257
 
258
+ # Methods #destroy and #load! are overridden to avoid calling methods on the
259
+ # @store object, which does not exist for the TestSession class.
238
260
  class TestSession < Rack::Session::Abstract::SessionHash #:nodoc:
239
261
  DEFAULT_OPTIONS = Rack::Session::Abstract::ID::DEFAULT_OPTIONS
240
262
 
241
263
  def initialize(session = {})
242
264
  super(nil, nil)
243
- replace(session.stringify_keys)
265
+ @id = SecureRandom.hex(16)
266
+ @data = stringify_keys(session)
244
267
  @loaded = true
245
268
  end
246
269
 
247
270
  def exists?
248
271
  true
249
272
  end
273
+
274
+ def keys
275
+ @data.keys
276
+ end
277
+
278
+ def values
279
+ @data.values
280
+ end
281
+
282
+ def destroy
283
+ clear
284
+ end
285
+
286
+ private
287
+
288
+ def load!
289
+ @id
290
+ end
250
291
  end
251
292
 
252
293
  # Superclass for ActionController functional tests. Functional tests allow you to
@@ -258,7 +299,7 @@ module ActionController
258
299
  # == Basic example
259
300
  #
260
301
  # Functional tests are written as follows:
261
- # 1. First, one uses the +get+, +post+, +put+, +delete+ or +head+ method to simulate
302
+ # 1. First, one uses the +get+, +post+, +patch+, +put+, +delete+ or +head+ method to simulate
262
303
  # an HTTP request.
263
304
  # 2. Then, one asserts whether the current state is as expected. "State" can be anything:
264
305
  # the controller's HTTP response, the database contents, etc.
@@ -268,17 +309,24 @@ module ActionController
268
309
  # class BooksControllerTest < ActionController::TestCase
269
310
  # def test_create
270
311
  # # Simulate a POST response with the given HTTP parameters.
271
- # post(:create, :book => { :title => "Love Hina" })
312
+ # post(:create, book: { title: "Love Hina" })
272
313
  #
273
314
  # # Assert that the controller tried to redirect us to
274
315
  # # the created book's URI.
275
316
  # assert_response :found
276
317
  #
277
318
  # # Assert that the controller really put the book in the database.
278
- # assert_not_nil Book.find_by_title("Love Hina")
319
+ # assert_not_nil Book.find_by(title: "Love Hina")
279
320
  # end
280
321
  # end
281
322
  #
323
+ # You can also send a real document in the simulated HTTP request.
324
+ #
325
+ # def test_create
326
+ # json = {book: { title: "Love Hina" }}.to_json
327
+ # post :create, json
328
+ # end
329
+ #
282
330
  # == Special instance variables
283
331
  #
284
332
  # ActionController::TestCase will also automatically provide the following instance
@@ -349,29 +397,28 @@ module ActionController
349
397
  # == \Testing named routes
350
398
  #
351
399
  # If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
352
- # Example:
353
400
  #
354
- # assert_redirected_to page_url(:title => 'foo')
401
+ # assert_redirected_to page_url(title: 'foo')
355
402
  class TestCase < ActiveSupport::TestCase
356
403
  module Behavior
357
404
  extend ActiveSupport::Concern
358
405
  include ActionDispatch::TestProcess
406
+ include ActiveSupport::Testing::ConstantLookup
359
407
 
360
408
  attr_reader :response, :request
361
409
 
362
410
  module ClassMethods
363
411
 
364
412
  # Sets the controller class name. Useful if the name can't be inferred from test class.
365
- # Normalizes +controller_class+ before using. Examples:
413
+ # Normalizes +controller_class+ before using.
366
414
  #
367
415
  # tests WidgetController
368
416
  # tests :widget
369
417
  # tests 'widget'
370
- #
371
418
  def tests(controller_class)
372
419
  case controller_class
373
420
  when String, Symbol
374
- self.controller_class = "#{controller_class.to_s.underscore}_controller".camelize.constantize
421
+ self.controller_class = "#{controller_class.to_s.camelize}Controller".constantize
375
422
  when Class
376
423
  self.controller_class = controller_class
377
424
  else
@@ -393,7 +440,9 @@ module ActionController
393
440
  end
394
441
 
395
442
  def determine_default_controller_class(name)
396
- name.sub(/Test$/, '').safe_constantize
443
+ determine_constant_from_test_name(name) do |constant|
444
+ Class === constant && constant < ActionController::Metal
445
+ end
397
446
  end
398
447
 
399
448
  def prepare_controller_class(new_class)
@@ -402,29 +451,52 @@ module ActionController
402
451
 
403
452
  end
404
453
 
405
- # Executes a request simulating GET HTTP method and set/volley the response
406
- def get(action, parameters = nil, session = nil, flash = nil)
407
- process(action, parameters, session, flash, "GET")
454
+ # Simulate a GET request with the given parameters.
455
+ #
456
+ # - +action+: The controller action to call.
457
+ # - +parameters+: The HTTP parameters that you want to pass. This may
458
+ # be +nil+, a hash, or a string that is appropriately encoded
459
+ # (<tt>application/x-www-form-urlencoded</tt> or <tt>multipart/form-data</tt>).
460
+ # - +session+: A hash of parameters to store in the session. This may be +nil+.
461
+ # - +flash+: A hash of parameters to store in the flash. This may be +nil+.
462
+ #
463
+ # You can also simulate POST, PATCH, PUT, DELETE, HEAD, and OPTIONS requests with
464
+ # +post+, +patch+, +put+, +delete+, +head+, and +options+.
465
+ #
466
+ # Note that the request method is not verified. The different methods are
467
+ # available to make the tests more expressive.
468
+ def get(action, *args)
469
+ process(action, "GET", *args)
470
+ end
471
+
472
+ # Simulate a POST request with the given parameters and set/volley the response.
473
+ # See +get+ for more details.
474
+ def post(action, *args)
475
+ process(action, "POST", *args)
408
476
  end
409
477
 
410
- # Executes a request simulating POST HTTP method and set/volley the response
411
- def post(action, parameters = nil, session = nil, flash = nil)
412
- process(action, parameters, session, flash, "POST")
478
+ # Simulate a PATCH request with the given parameters and set/volley the response.
479
+ # See +get+ for more details.
480
+ def patch(action, *args)
481
+ process(action, "PATCH", *args)
413
482
  end
414
483
 
415
- # Executes a request simulating PUT HTTP method and set/volley the response
416
- def put(action, parameters = nil, session = nil, flash = nil)
417
- process(action, parameters, session, flash, "PUT")
484
+ # Simulate a PUT request with the given parameters and set/volley the response.
485
+ # See +get+ for more details.
486
+ def put(action, *args)
487
+ process(action, "PUT", *args)
418
488
  end
419
489
 
420
- # Executes a request simulating DELETE HTTP method and set/volley the response
421
- def delete(action, parameters = nil, session = nil, flash = nil)
422
- process(action, parameters, session, flash, "DELETE")
490
+ # Simulate a DELETE request with the given parameters and set/volley the response.
491
+ # See +get+ for more details.
492
+ def delete(action, *args)
493
+ process(action, "DELETE", *args)
423
494
  end
424
495
 
425
- # Executes a request simulating HEAD HTTP method and set/volley the response
426
- def head(action, parameters = nil, session = nil, flash = nil)
427
- process(action, parameters, session, flash, "HEAD")
496
+ # Simulate a HEAD request with the given parameters and set/volley the response.
497
+ # See +get+ for more details.
498
+ def head(action, *args)
499
+ process(action, "HEAD", *args)
428
500
  end
429
501
 
430
502
  def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
@@ -450,65 +522,94 @@ module ActionController
450
522
  end
451
523
  end
452
524
 
453
- def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
525
+ def process(action, http_method = 'GET', *args)
526
+ check_required_ivars
527
+ http_method, args = handle_old_process_api(http_method, args, caller)
528
+
529
+ if args.first.is_a?(String) && http_method != 'HEAD'
530
+ @request.env['RAW_POST_DATA'] = args.shift
531
+ end
532
+
533
+ parameters, session, flash = args
534
+
454
535
  # Ensure that numbers and symbols passed as params are converted to
455
536
  # proper params, as is the case when engaging rack.
456
537
  parameters = paramify_values(parameters) if html_format?(parameters)
457
538
 
458
- # Sanity check for required instance variables so we can give an
459
- # understandable error message.
460
- %w(@routes @controller @request @response).each do |iv_name|
461
- if !(instance_variable_names.include?(iv_name) || instance_variable_names.include?(iv_name.to_sym)) || instance_variable_get(iv_name).nil?
462
- raise "#{iv_name} is nil: make sure you set it in your test's setup method."
463
- end
539
+ @html_document = nil
540
+
541
+ unless @controller.respond_to?(:recycle!)
542
+ @controller.extend(Testing::Functional)
543
+ @controller.class.class_eval { include Testing }
464
544
  end
465
545
 
466
546
  @request.recycle!
467
547
  @response.recycle!
468
- @controller.response_body = nil
469
- @controller.formats = nil
470
- @controller.params = nil
548
+ @controller.recycle!
471
549
 
472
- @html_document = nil
473
550
  @request.env['REQUEST_METHOD'] = http_method
474
551
 
475
552
  parameters ||= {}
476
553
  controller_class_name = @controller.class.anonymous? ?
477
- "anonymous_controller" :
478
- @controller.class.controller_path
554
+ "anonymous" :
555
+ @controller.class.name.underscore.sub(/_controller$/, '')
479
556
 
480
557
  @request.assign_parameters(@routes, controller_class_name, action.to_s, parameters)
481
558
 
482
- @request.session = ActionController::TestSession.new(session) if session
483
- @request.session["flash"] = @request.flash.update(flash || {})
484
- @request.session["flash"].sweep
559
+ @request.session.update(session) if session
560
+ @request.flash.update(flash || {})
561
+
562
+ @controller.request = @request
563
+ @controller.response = @response
485
564
 
486
- @controller.request = @request
487
565
  build_request_uri(action, parameters)
488
- @controller.class.class_eval { include Testing }
489
- @controller.recycle!
490
- @controller.process_with_new_base_test(@request, @response)
566
+
567
+ name = @request.parameters[:action]
568
+
569
+ @controller.process(name)
570
+
571
+ if cookies = @request.env['action_dispatch.cookies']
572
+ cookies.write(@response)
573
+ end
574
+ @response.prepare!
575
+
491
576
  @assigns = @controller.respond_to?(:view_assigns) ? @controller.view_assigns : {}
577
+ @request.session['flash'] = @request.flash.to_session_value
492
578
  @request.session.delete('flash') if @request.session['flash'].blank?
493
579
  @response
494
580
  end
495
581
 
496
582
  def setup_controller_request_and_response
497
- @request = TestRequest.new
498
- @response = TestResponse.new
583
+ @request = build_request
584
+ @response = build_response
585
+ @response.request = @request
586
+
587
+ @controller = nil unless defined? @controller
499
588
 
500
589
  if klass = self.class.controller_class
501
- @controller ||= klass.new rescue nil
590
+ unless @controller
591
+ begin
592
+ @controller = klass.new
593
+ rescue
594
+ warn "could not construct controller #{klass}" if $VERBOSE
595
+ end
596
+ end
502
597
  end
503
598
 
504
- @request.env.delete('PATH_INFO')
505
-
506
- if defined?(@controller) && @controller
599
+ if @controller
507
600
  @controller.request = @request
508
601
  @controller.params = {}
509
602
  end
510
603
  end
511
604
 
605
+ def build_request
606
+ TestRequest.new
607
+ end
608
+
609
+ def build_response
610
+ TestResponse.new
611
+ end
612
+
512
613
  included do
513
614
  include ActionController::TemplateAssertions
514
615
  include ActionDispatch::Assertions
@@ -516,7 +617,27 @@ module ActionController
516
617
  setup :setup_controller_request_and_response
517
618
  end
518
619
 
519
- private
620
+ private
621
+ def check_required_ivars
622
+ # Sanity check for required instance variables so we can give an
623
+ # understandable error message.
624
+ [:@routes, :@controller, :@request, :@response].each do |iv_name|
625
+ if !instance_variable_defined?(iv_name) || instance_variable_get(iv_name).nil?
626
+ raise "#{iv_name} is nil: make sure you set it in your test's setup method."
627
+ end
628
+ end
629
+ end
630
+
631
+ def handle_old_process_api(http_method, args, callstack)
632
+ # 4.0: Remove this method.
633
+ if http_method.is_a?(Hash)
634
+ ActiveSupport::Deprecation.warn("TestCase#process now expects the HTTP method as second argument: process(action, http_method, params, session, flash)", callstack)
635
+ args.unshift(http_method)
636
+ http_method = args.last.is_a?(String) ? args.last : "GET"
637
+ end
638
+
639
+ [http_method, args]
640
+ end
520
641
 
521
642
  def build_request_uri(action, parameters)
522
643
  unless @request.env["PATH_INFO"]
@@ -525,7 +646,7 @@ module ActionController
525
646
  :only_path => true,
526
647
  :action => action,
527
648
  :relative_url_root => nil,
528
- :_path_segments => @request.symbolized_path_parameters)
649
+ :_recall => @request.symbolized_path_parameters)
529
650
 
530
651
  url, query_string = @routes.url_for(options).split("?", 2)
531
652
 
@@ -537,8 +658,7 @@ module ActionController
537
658
 
538
659
  def html_format?(parameters)
539
660
  return true unless parameters.is_a?(Hash)
540
- format = Mime[parameters[:format]]
541
- format.nil? || format.html?
661
+ Mime.fetch(parameters[:format]) { Mime['html'] }.html?
542
662
  end
543
663
  end
544
664
 
@@ -549,7 +669,7 @@ module ActionController
549
669
  #
550
670
  # The exception is stored in the exception accessor for further inspection.
551
671
  module RaiseActionExceptions
552
- def self.included(base)
672
+ def self.included(base) #:nodoc:
553
673
  unless base.method_defined?(:exception) && base.method_defined?(:exception=)
554
674
  base.class_eval do
555
675
  attr_accessor :exception
@@ -1,20 +1,5 @@
1
- $LOAD_PATH << "#{File.dirname(__FILE__)}/html-scanner"
1
+ require 'action_view/vendor/html-scanner'
2
+ require 'active_support/deprecation'
2
3
 
3
- module HTML
4
- extend ActiveSupport::Autoload
5
-
6
- eager_autoload do
7
- autoload :CDATA, 'html/node'
8
- autoload :Document, 'html/document'
9
- autoload :FullSanitizer, 'html/sanitizer'
10
- autoload :LinkSanitizer, 'html/sanitizer'
11
- autoload :Node, 'html/node'
12
- autoload :Sanitizer, 'html/sanitizer'
13
- autoload :Selector, 'html/selector'
14
- autoload :Tag, 'html/node'
15
- autoload :Text, 'html/node'
16
- autoload :Tokenizer, 'html/tokenizer'
17
- autoload :Version, 'html/version'
18
- autoload :WhiteListSanitizer, 'html/sanitizer'
19
- end
20
- end
4
+ ActiveSupport::Deprecation.warn 'Vendored html-scanner was moved to action_view, please require "action_view/vendor/html-scanner" instead. ' +
5
+ 'This file will be removed in Rails 4.1'