actionpack 2.2.3 → 2.3.2

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 (264) hide show
  1. data/CHANGELOG +433 -375
  2. data/MIT-LICENSE +1 -1
  3. data/README +21 -75
  4. data/Rakefile +1 -1
  5. data/lib/action_controller.rb +80 -43
  6. data/lib/action_controller/assertions/model_assertions.rb +1 -0
  7. data/lib/action_controller/assertions/response_assertions.rb +43 -16
  8. data/lib/action_controller/assertions/routing_assertions.rb +1 -1
  9. data/lib/action_controller/assertions/selector_assertions.rb +17 -12
  10. data/lib/action_controller/assertions/tag_assertions.rb +1 -4
  11. data/lib/action_controller/base.rb +153 -82
  12. data/lib/action_controller/benchmarking.rb +9 -9
  13. data/lib/action_controller/caching.rb +9 -11
  14. data/lib/action_controller/caching/actions.rb +11 -18
  15. data/lib/action_controller/caching/fragments.rb +28 -20
  16. data/lib/action_controller/caching/pages.rb +13 -15
  17. data/lib/action_controller/caching/sweeping.rb +2 -2
  18. data/lib/action_controller/cgi_ext.rb +0 -1
  19. data/lib/action_controller/cgi_ext/cookie.rb +2 -0
  20. data/lib/action_controller/cgi_process.rb +54 -162
  21. data/lib/action_controller/cookies.rb +13 -25
  22. data/lib/action_controller/dispatcher.rb +43 -122
  23. data/lib/action_controller/failsafe.rb +52 -0
  24. data/lib/action_controller/flash.rb +38 -47
  25. data/lib/action_controller/helpers.rb +13 -9
  26. data/lib/action_controller/http_authentication.rb +203 -23
  27. data/lib/action_controller/integration.rb +126 -70
  28. data/lib/action_controller/layout.rb +36 -39
  29. data/lib/action_controller/middleware_stack.rb +119 -0
  30. data/lib/action_controller/middlewares.rb +13 -0
  31. data/lib/action_controller/mime_responds.rb +19 -4
  32. data/lib/action_controller/mime_type.rb +8 -0
  33. data/lib/action_controller/params_parser.rb +71 -0
  34. data/lib/action_controller/performance_test.rb +0 -1
  35. data/lib/action_controller/polymorphic_routes.rb +36 -30
  36. data/lib/action_controller/reloader.rb +14 -0
  37. data/lib/action_controller/request.rb +107 -499
  38. data/lib/action_controller/request_forgery_protection.rb +7 -39
  39. data/lib/action_controller/rescue.rb +55 -35
  40. data/lib/action_controller/resources.rb +34 -31
  41. data/lib/action_controller/response.rb +99 -57
  42. data/lib/action_controller/rewindable_input.rb +28 -0
  43. data/lib/action_controller/routing.rb +7 -7
  44. data/lib/action_controller/routing/builder.rb +4 -1
  45. data/lib/action_controller/routing/optimisations.rb +1 -1
  46. data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
  47. data/lib/action_controller/routing/route.rb +15 -5
  48. data/lib/action_controller/routing/route_set.rb +82 -35
  49. data/lib/action_controller/routing/segments.rb +35 -0
  50. data/lib/action_controller/session/abstract_store.rb +181 -0
  51. data/lib/action_controller/session/cookie_store.rb +197 -175
  52. data/lib/action_controller/session/mem_cache_store.rb +36 -83
  53. data/lib/action_controller/session_management.rb +26 -134
  54. data/lib/action_controller/streaming.rb +24 -7
  55. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  56. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  57. data/lib/action_controller/test_case.rb +87 -30
  58. data/lib/action_controller/test_process.rb +145 -104
  59. data/lib/action_controller/uploaded_file.rb +44 -0
  60. data/lib/action_controller/url_rewriter.rb +3 -6
  61. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  62. data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
  63. data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
  64. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
  65. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
  66. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
  67. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
  68. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
  69. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
  73. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
  74. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
  75. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
  76. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
  77. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
  78. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
  79. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
  80. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
  81. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
  82. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
  83. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
  84. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
  85. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
  86. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
  87. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
  93. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
  94. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
  95. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
  96. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
  97. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
  98. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
  99. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
  100. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
  101. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
  102. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
  103. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
  104. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
  105. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
  106. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
  107. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
  108. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
  109. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
  110. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
  111. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
  112. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
  113. data/lib/action_controller/verification.rb +1 -1
  114. data/lib/action_pack.rb +1 -1
  115. data/lib/action_pack/version.rb +2 -2
  116. data/lib/action_view.rb +22 -17
  117. data/lib/action_view/base.rb +53 -79
  118. data/lib/action_view/erb/util.rb +38 -0
  119. data/lib/action_view/helpers.rb +24 -5
  120. data/lib/action_view/helpers/active_record_helper.rb +2 -2
  121. data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
  122. data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
  123. data/lib/action_view/helpers/benchmark_helper.rb +26 -5
  124. data/lib/action_view/helpers/date_helper.rb +82 -7
  125. data/lib/action_view/helpers/form_helper.rb +295 -64
  126. data/lib/action_view/helpers/form_options_helper.rb +160 -18
  127. data/lib/action_view/helpers/form_tag_helper.rb +2 -2
  128. data/lib/action_view/helpers/number_helper.rb +31 -18
  129. data/lib/action_view/helpers/prototype_helper.rb +2 -12
  130. data/lib/action_view/helpers/sanitize_helper.rb +0 -10
  131. data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
  132. data/lib/action_view/helpers/tag_helper.rb +3 -4
  133. data/lib/action_view/helpers/text_helper.rb +99 -122
  134. data/lib/action_view/helpers/translation_helper.rb +19 -1
  135. data/lib/action_view/helpers/url_helper.rb +25 -2
  136. data/lib/action_view/inline_template.rb +1 -1
  137. data/lib/action_view/locale/en.yml +19 -1
  138. data/lib/action_view/partials.rb +46 -9
  139. data/lib/action_view/paths.rb +28 -84
  140. data/lib/action_view/reloadable_template.rb +117 -0
  141. data/lib/action_view/renderable.rb +28 -35
  142. data/lib/action_view/renderable_partial.rb +3 -4
  143. data/lib/action_view/template.rb +172 -31
  144. data/lib/action_view/template_error.rb +8 -9
  145. data/lib/action_view/template_handler.rb +1 -1
  146. data/lib/action_view/template_handlers.rb +9 -6
  147. data/lib/action_view/template_handlers/erb.rb +2 -39
  148. data/lib/action_view/template_handlers/rjs.rb +1 -0
  149. data/lib/action_view/test_case.rb +27 -1
  150. data/test/abstract_unit.rb +23 -17
  151. data/test/active_record_unit.rb +5 -4
  152. data/test/activerecord/active_record_store_test.rb +139 -106
  153. data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
  154. data/test/controller/action_pack_assertions_test.rb +25 -23
  155. data/test/controller/addresses_render_test.rb +3 -6
  156. data/test/controller/assert_select_test.rb +83 -70
  157. data/test/controller/base_test.rb +11 -13
  158. data/test/controller/benchmark_test.rb +3 -3
  159. data/test/controller/caching_test.rb +34 -24
  160. data/test/controller/capture_test.rb +3 -6
  161. data/test/controller/content_type_test.rb +3 -6
  162. data/test/controller/cookie_test.rb +31 -66
  163. data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
  164. data/test/controller/dispatcher_test.rb +23 -28
  165. data/test/controller/fake_models.rb +8 -0
  166. data/test/controller/filters_test.rb +6 -2
  167. data/test/controller/flash_test.rb +2 -6
  168. data/test/controller/helper_test.rb +15 -1
  169. data/test/controller/html-scanner/document_test.rb +1 -1
  170. data/test/controller/html-scanner/sanitizer_test.rb +1 -1
  171. data/test/controller/http_basic_authentication_test.rb +88 -0
  172. data/test/controller/http_digest_authentication_test.rb +178 -0
  173. data/test/controller/integration_test.rb +56 -52
  174. data/test/controller/layout_test.rb +46 -44
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +7 -11
  177. data/test/controller/mime_type_test.rb +9 -0
  178. data/test/controller/polymorphic_routes_test.rb +235 -151
  179. data/test/controller/rack_test.rb +52 -81
  180. data/test/controller/redirect_test.rb +6 -14
  181. data/test/controller/render_test.rb +273 -60
  182. data/test/controller/request/json_params_parsing_test.rb +45 -0
  183. data/test/controller/request/multipart_params_parsing_test.rb +223 -0
  184. data/test/controller/request/query_string_parsing_test.rb +120 -0
  185. data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
  186. data/test/controller/request/xml_params_parsing_test.rb +88 -0
  187. data/test/controller/request_forgery_protection_test.rb +17 -98
  188. data/test/controller/request_test.rb +45 -530
  189. data/test/controller/rescue_test.rb +45 -22
  190. data/test/controller/resources_test.rb +112 -37
  191. data/test/controller/routing_test.rb +1442 -1384
  192. data/test/controller/selector_test.rb +3 -3
  193. data/test/controller/send_file_test.rb +30 -3
  194. data/test/controller/session/cookie_store_test.rb +169 -240
  195. data/test/controller/session/mem_cache_store_test.rb +94 -148
  196. data/test/controller/session/test_session_test.rb +58 -0
  197. data/test/controller/test_test.rb +32 -13
  198. data/test/controller/url_rewriter_test.rb +54 -4
  199. data/test/controller/verification_test.rb +1 -1
  200. data/test/controller/view_paths_test.rb +15 -15
  201. data/test/controller/webservice_test.rb +178 -147
  202. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  203. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  204. data/test/fixtures/layouts/default_html.html.erb +1 -0
  205. data/test/fixtures/layouts/xhr.html.erb +2 -0
  206. data/test/fixtures/multipart/empty +10 -0
  207. data/test/fixtures/multipart/hello.txt +1 -0
  208. data/test/fixtures/multipart/none +9 -0
  209. data/test/fixtures/public/500.da.html +1 -0
  210. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  211. data/test/fixtures/replies.yml +1 -1
  212. data/test/fixtures/test/_one.html.erb +1 -0
  213. data/test/fixtures/test/_two.html.erb +1 -0
  214. data/test/fixtures/test/dont_pick_me +1 -0
  215. data/test/fixtures/test/hello.builder +1 -1
  216. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  217. data/test/fixtures/test/hello_world.erb~ +1 -0
  218. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  219. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  220. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  221. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  222. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  223. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  224. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  225. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  226. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  227. data/test/fixtures/test/utf8.html.erb +2 -0
  228. data/test/template/active_record_helper_i18n_test.rb +31 -33
  229. data/test/template/active_record_helper_test.rb +34 -0
  230. data/test/template/asset_tag_helper_test.rb +52 -14
  231. data/test/template/atom_feed_helper_test.rb +3 -5
  232. data/test/template/benchmark_helper_test.rb +50 -24
  233. data/test/template/compiled_templates_test.rb +177 -33
  234. data/test/template/date_helper_i18n_test.rb +88 -81
  235. data/test/template/date_helper_test.rb +427 -43
  236. data/test/template/form_helper_test.rb +243 -44
  237. data/test/template/form_options_helper_test.rb +631 -565
  238. data/test/template/form_tag_helper_test.rb +9 -2
  239. data/test/template/javascript_helper_test.rb +0 -5
  240. data/test/template/number_helper_i18n_test.rb +60 -48
  241. data/test/template/number_helper_test.rb +1 -0
  242. data/test/template/render_test.rb +117 -35
  243. data/test/template/test_test.rb +4 -6
  244. data/test/template/text_helper_test.rb +129 -50
  245. data/test/template/translation_helper_test.rb +23 -19
  246. data/test/template/url_helper_test.rb +35 -2
  247. data/test/view/test_case_test.rb +8 -0
  248. metadata +197 -23
  249. data/lib/action_controller/assertions.rb +0 -69
  250. data/lib/action_controller/caching/sql_cache.rb +0 -18
  251. data/lib/action_controller/cgi_ext/session.rb +0 -53
  252. data/lib/action_controller/components.rb +0 -169
  253. data/lib/action_controller/rack_process.rb +0 -297
  254. data/lib/action_controller/request_profiler.rb +0 -169
  255. data/lib/action_controller/session/active_record_store.rb +0 -340
  256. data/lib/action_controller/session/drb_server.rb +0 -32
  257. data/lib/action_controller/session/drb_store.rb +0 -35
  258. data/test/controller/cgi_test.rb +0 -269
  259. data/test/controller/components_test.rb +0 -156
  260. data/test/controller/http_authentication_test.rb +0 -54
  261. data/test/controller/integration_upload_test.rb +0 -43
  262. data/test/controller/session_fixation_test.rb +0 -89
  263. data/test/controller/session_management_test.rb +0 -178
  264. data/test/fixtures/test/hello_world.js +0 -1
@@ -1,17 +1,8 @@
1
- require 'action_controller/session/cookie_store'
2
- require 'action_controller/session/drb_store'
3
- require 'action_controller/session/mem_cache_store'
4
- if Object.const_defined?(:ActiveRecord)
5
- require 'action_controller/session/active_record_store'
6
- end
7
-
8
1
  module ActionController #:nodoc:
9
2
  module SessionManagement #:nodoc:
10
3
  def self.included(base)
11
4
  base.class_eval do
12
5
  extend ClassMethods
13
- alias_method_chain :process, :session_management_support
14
- alias_method_chain :process_cleanup, :session_management_support
15
6
  end
16
7
  end
17
8
 
@@ -19,144 +10,45 @@ module ActionController #:nodoc:
19
10
  # Set the session store to be used for keeping the session data between requests.
20
11
  # By default, sessions are stored in browser cookies (<tt>:cookie_store</tt>),
21
12
  # but you can also specify one of the other included stores (<tt>:active_record_store</tt>,
22
- # <tt>:p_store</tt>, <tt>:drb_store</tt>, <tt>:mem_cache_store</tt>, or
23
- # <tt>:memory_store</tt>) or your own custom class.
13
+ # <tt>:mem_cache_store</tt>, or your own custom class.
24
14
  def session_store=(store)
25
- ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager] =
26
- store.is_a?(Symbol) ? CGI::Session.const_get(store == :drb_store ? "DRbStore" : store.to_s.camelize) : store
15
+ if store == :active_record_store
16
+ self.session_store = ActiveRecord::SessionStore
17
+ else
18
+ @@session_store = store.is_a?(Symbol) ?
19
+ Session.const_get(store.to_s.camelize) :
20
+ store
21
+ end
27
22
  end
28
23
 
29
24
  # Returns the session store class currently used.
30
25
  def session_store
31
- ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager]
26
+ if defined? @@session_store
27
+ @@session_store
28
+ else
29
+ Session::CookieStore
30
+ end
31
+ end
32
+
33
+ def session=(options = {})
34
+ self.session_store = nil if options.delete(:disabled)
35
+ session_options.merge!(options)
32
36
  end
33
37
 
34
38
  # Returns the hash used to configure the session. Example use:
35
39
  #
36
- # ActionController::Base.session_options[:session_secure] = true # session only available over HTTPS
40
+ # ActionController::Base.session_options[:secure] = true # session only available over HTTPS
37
41
  def session_options
38
- ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS
39
- end
40
-
41
- # Specify how sessions ought to be managed for a subset of the actions on
42
- # the controller. Like filters, you can specify <tt>:only</tt> and
43
- # <tt>:except</tt> clauses to restrict the subset, otherwise options
44
- # apply to all actions on this controller.
45
- #
46
- # The session options are inheritable, as well, so if you specify them in
47
- # a parent controller, they apply to controllers that extend the parent.
48
- #
49
- # Usage:
50
- #
51
- # # turn off session management for all actions.
52
- # session :off
53
- #
54
- # # turn off session management for all actions _except_ foo and bar.
55
- # session :off, :except => %w(foo bar)
56
- #
57
- # # turn off session management for only the foo and bar actions.
58
- # session :off, :only => %w(foo bar)
59
- #
60
- # # the session will only work over HTTPS, but only for the foo action
61
- # session :only => :foo, :session_secure => true
62
- #
63
- # # the session by default uses HttpOnly sessions for security reasons.
64
- # # this can be switched off.
65
- # session :only => :foo, :session_http_only => false
66
- #
67
- # # the session will only be disabled for 'foo', and only if it is
68
- # # requested as a web service
69
- # session :off, :only => :foo,
70
- # :if => Proc.new { |req| req.parameters[:ws] }
71
- #
72
- # # the session will be disabled for non html/ajax requests
73
- # session :off,
74
- # :if => Proc.new { |req| !(req.format.html? || req.format.js?) }
75
- #
76
- # # turn the session back on, useful when it was turned off in the
77
- # # application controller, and you need it on in another controller
78
- # session :on
79
- #
80
- # All session options described for ActionController::Base.process_cgi
81
- # are valid arguments.
82
- def session(*args)
83
- options = args.extract_options!
84
-
85
- options[:disabled] = false if args.delete(:on)
86
- options[:disabled] = true if !args.empty?
87
- options[:only] = [*options[:only]].map { |o| o.to_s } if options[:only]
88
- options[:except] = [*options[:except]].map { |o| o.to_s } if options[:except]
89
- if options[:only] && options[:except]
90
- raise ArgumentError, "only one of either :only or :except are allowed"
91
- end
92
-
93
- write_inheritable_array(:session_options, [options])
94
- end
95
-
96
- # So we can declare session options in the Rails initializer.
97
- alias_method :session=, :session
98
-
99
- def cached_session_options #:nodoc:
100
- @session_options ||= read_inheritable_attribute(:session_options) || []
42
+ @session_options ||= {}
101
43
  end
102
44
 
103
- def session_options_for(request, action) #:nodoc:
104
- if (session_options = cached_session_options).empty?
105
- {}
106
- else
107
- options = {}
108
-
109
- action = action.to_s
110
- session_options.each do |opts|
111
- next if opts[:if] && !opts[:if].call(request)
112
- if opts[:only] && opts[:only].include?(action)
113
- options.merge!(opts)
114
- elsif opts[:except] && !opts[:except].include?(action)
115
- options.merge!(opts)
116
- elsif !opts[:only] && !opts[:except]
117
- options.merge!(opts)
118
- end
119
- end
120
-
121
- if options.empty? then options
122
- else
123
- options.delete :only
124
- options.delete :except
125
- options.delete :if
126
- options[:disabled] ? false : options
127
- end
128
- end
45
+ def session(*args)
46
+ ActiveSupport::Deprecation.warn(
47
+ "Disabling sessions for a single controller has been deprecated. " +
48
+ "Sessions are now lazy loaded. So if you don't access them, " +
49
+ "consider them off. You can still modify the session cookie " +
50
+ "options with request.session_options.", caller)
129
51
  end
130
52
  end
131
-
132
- def process_with_session_management_support(request, response, method = :perform_action, *arguments) #:nodoc:
133
- set_session_options(request)
134
- process_without_session_management_support(request, response, method, *arguments)
135
- end
136
-
137
- private
138
- def set_session_options(request)
139
- request.session_options = self.class.session_options_for(request, request.parameters["action"] || "index")
140
- end
141
-
142
- def process_cleanup_with_session_management_support
143
- clear_persistent_model_associations
144
- process_cleanup_without_session_management_support
145
- end
146
-
147
- # Clear cached associations in session data so they don't overflow
148
- # the database field. Only applies to ActiveRecordStore since there
149
- # is not a standard way to iterate over session data.
150
- def clear_persistent_model_associations #:doc:
151
- if defined?(@_session) && @_session.respond_to?(:data)
152
- session_data = @_session.data
153
-
154
- if session_data && session_data.respond_to?(:each_value)
155
- session_data.each_value do |obj|
156
- obj.clear_association_cache if obj.respond_to?(:clear_association_cache)
157
- end
158
- end
159
- end
160
- end
161
53
  end
162
54
  end
@@ -1,5 +1,6 @@
1
1
  module ActionController #:nodoc:
2
- # Methods for sending files and streams to the browser instead of rendering.
2
+ # Methods for sending arbitrary data and for streaming files to the browser,
3
+ # instead of rendering.
3
4
  module Streaming
4
5
  DEFAULT_SEND_FILE_OPTIONS = {
5
6
  :type => 'application/octet-stream'.freeze,
@@ -24,7 +25,8 @@ module ActionController #:nodoc:
24
25
  # Options:
25
26
  # * <tt>:filename</tt> - suggests a filename for the browser to use.
26
27
  # Defaults to <tt>File.basename(path)</tt>.
27
- # * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'.
28
+ # * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
29
+ # either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
28
30
  # * <tt>:length</tt> - used to manually override the length (in bytes) of the content that
29
31
  # is going to be sent to the client. Defaults to <tt>File.size(path)</tt>.
30
32
  # * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
@@ -102,12 +104,16 @@ module ActionController #:nodoc:
102
104
  end
103
105
  end
104
106
 
105
- # Send binary data to the user as a file download. May set content type, apparent file name,
106
- # and specify whether to show data inline or download as an attachment.
107
+ # Sends the given binary data to the browser. This method is similar to
108
+ # <tt>render :text => data</tt>, but also allows you to specify whether
109
+ # the browser should display the response as a file attachment (i.e. in a
110
+ # download dialog) or as inline data. You may also set the content type,
111
+ # the apparent file name, and other things.
107
112
  #
108
113
  # Options:
109
114
  # * <tt>:filename</tt> - suggests a filename for the browser to use.
110
- # * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'.
115
+ # * <tt>:type</tt> - specifies an HTTP content type. Defaults to 'application/octet-stream'. You can specify
116
+ # either a string or a symbol for a registered type register with <tt>Mime::Type.register</tt>, for example :json
111
117
  # * <tt>:disposition</tt> - specifies whether the file will be shown inline or downloaded.
112
118
  # Valid values are 'inline' and 'attachment' (default).
113
119
  # * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
@@ -125,6 +131,10 @@ module ActionController #:nodoc:
125
131
  # send_data image.data, :type => image.content_type, :disposition => 'inline'
126
132
  #
127
133
  # See +send_file+ for more information on HTTP Content-* headers and caching.
134
+ #
135
+ # <b>Tip:</b> if you want to stream large amounts of on-the-fly generated
136
+ # data to the browser, then use <tt>render :text => proc { ... }</tt>
137
+ # instead. See ActionController::Base#render for more information.
128
138
  def send_data(data, options = {}) #:doc:
129
139
  logger.info "Sending data #{options[:filename]}" if logger
130
140
  send_file_headers! options.merge(:length => data.size)
@@ -143,9 +153,16 @@ module ActionController #:nodoc:
143
153
 
144
154
  disposition <<= %(; filename="#{options[:filename]}") if options[:filename]
145
155
 
146
- headers.update(
156
+ content_type = options[:type]
157
+ if content_type.is_a?(Symbol)
158
+ raise ArgumentError, "Unknown MIME type #{options[:type]}" unless Mime::EXTENSION_LOOKUP.has_key?(content_type.to_s)
159
+ content_type = Mime::Type.lookup_by_extension(content_type.to_s)
160
+ end
161
+ content_type = content_type.to_s.strip # fixes a problem with extra '\r' with some browsers
162
+
163
+ headers.merge!(
147
164
  'Content-Length' => options[:length],
148
- 'Content-Type' => options[:type].to_s.strip, # fixes a problem with extra '\r' with some browsers
165
+ 'Content-Type' => content_type,
149
166
  'Content-Disposition' => disposition,
150
167
  'Content-Transfer-Encoding' => 'binary'
151
168
  )
@@ -6,6 +6,6 @@
6
6
  </h1>
7
7
  <pre><%=h @exception.clean_message %></pre>
8
8
 
9
- <%= render(:file => @rescues_path + "/_trace.erb") %>
9
+ <%= render :file => @rescues_path["rescues/_trace.erb"] %>
10
10
 
11
- <%= render(:file => @rescues_path + "/_request_and_response.erb") %>
11
+ <%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
@@ -15,7 +15,7 @@
15
15
 
16
16
  <% @real_exception = @exception
17
17
  @exception = @exception.original_exception || @exception %>
18
- <%= render(:file => @rescues_path + "/_trace.erb") %>
18
+ <%= render :file => @rescues_path["rescues/_trace.erb"] %>
19
19
  <% @exception = @real_exception %>
20
20
 
21
- <%= render(:file => @rescues_path + "/_request_and_response.erb") %>
21
+ <%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
@@ -1,20 +1,7 @@
1
1
  require 'active_support/test_case'
2
+ require 'action_controller/test_process'
2
3
 
3
4
  module ActionController
4
- class NonInferrableControllerError < ActionControllerError
5
- def initialize(name)
6
- @name = name
7
- super "Unable to determine the controller to test from #{name}. " +
8
- "You'll need to specify it using 'tests YourController' in your " +
9
- "test case definition. This could mean that #{inferred_controller_name} does not exist " +
10
- "or it contains syntax errors"
11
- end
12
-
13
- def inferred_controller_name
14
- @name.sub(/Test$/, '')
15
- end
16
- end
17
-
18
5
  # Superclass for ActionController functional tests. Functional tests allow you to
19
6
  # test a single controller action per test method. This should not be confused with
20
7
  # integration tests (see ActionController::IntegrationTest), which are more like
@@ -74,7 +61,65 @@ module ActionController
74
61
  # class SpecialEdgeCaseWidgetsControllerTest < ActionController::TestCase
75
62
  # tests WidgetController
76
63
  # end
64
+ #
65
+ # == Testing controller internals
66
+ #
67
+ # In addition to these specific assertions, you also have easy access to various collections that the regular test/unit assertions
68
+ # can be used against. These collections are:
69
+ #
70
+ # * assigns: Instance variables assigned in the action that are available for the view.
71
+ # * session: Objects being saved in the session.
72
+ # * flash: The flash objects currently in the session.
73
+ # * cookies: Cookies being sent to the user on this request.
74
+ #
75
+ # These collections can be used just like any other hash:
76
+ #
77
+ # assert_not_nil assigns(:person) # makes sure that a @person instance variable was set
78
+ # assert_equal "Dave", cookies[:name] # makes sure that a cookie called :name was set as "Dave"
79
+ # assert flash.empty? # makes sure that there's nothing in the flash
80
+ #
81
+ # For historic reasons, the assigns hash uses string-based keys. So assigns[:person] won't work, but assigns["person"] will. To
82
+ # appease our yearning for symbols, though, an alternative accessor has been devised using a method call instead of index referencing.
83
+ # So assigns(:person) will work just like assigns["person"], but again, assigns[:person] will not work.
84
+ #
85
+ # On top of the collections, you have the complete url that a given action redirected to available in redirect_to_url.
86
+ #
87
+ # For redirects within the same controller, you can even call follow_redirect and the redirect will be followed, triggering another
88
+ # action call which can then be asserted against.
89
+ #
90
+ # == Manipulating the request collections
91
+ #
92
+ # The collections described above link to the response, so you can test if what the actions were expected to do happened. But
93
+ # sometimes you also want to manipulate these collections in the incoming request. This is really only relevant for sessions
94
+ # and cookies, though. For sessions, you just do:
95
+ #
96
+ # @request.session[:key] = "value"
97
+ # @request.cookies["key"] = "value"
98
+ #
99
+ # == Testing named routes
100
+ #
101
+ # If you're using named routes, they can be easily tested using the original named routes' methods straight in the test case.
102
+ # Example:
103
+ #
104
+ # assert_redirected_to page_url(:title => 'foo')
77
105
  class TestCase < ActiveSupport::TestCase
106
+ include TestProcess
107
+
108
+ module Assertions
109
+ %w(response selector tag dom routing model).each do |kind|
110
+ include ActionController::Assertions.const_get("#{kind.camelize}Assertions")
111
+ end
112
+
113
+ def clean_backtrace(&block)
114
+ yield
115
+ rescue ActiveSupport::TestCase::Assertion => error
116
+ framework_path = Regexp.new(File.expand_path("#{File.dirname(__FILE__)}/assertions"))
117
+ error.backtrace.reject! { |line| File.expand_path(line) =~ framework_path }
118
+ raise
119
+ end
120
+ end
121
+ include Assertions
122
+
78
123
  # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
79
124
  # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
80
125
  # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
@@ -82,17 +127,23 @@ module ActionController
82
127
  #
83
128
  # The exception is stored in the exception accessor for further inspection.
84
129
  module RaiseActionExceptions
85
- attr_accessor :exception
86
-
87
- def rescue_action_without_handler(e)
88
- self.exception = e
89
-
90
- if request.remote_addr == "0.0.0.0"
91
- raise(e)
92
- else
93
- super(e)
130
+ def self.included(base)
131
+ base.class_eval do
132
+ attr_accessor :exception
133
+ protected :exception, :exception=
94
134
  end
95
135
  end
136
+
137
+ protected
138
+ def rescue_action_without_handler(e)
139
+ self.exception = e
140
+
141
+ if request.remote_addr == "0.0.0.0"
142
+ raise(e)
143
+ else
144
+ super(e)
145
+ end
146
+ end
96
147
  end
97
148
 
98
149
  setup :setup_controller_request_and_response
@@ -107,7 +158,7 @@ module ActionController
107
158
  end
108
159
 
109
160
  def controller_class=(new_class)
110
- prepare_controller_class(new_class)
161
+ prepare_controller_class(new_class) if new_class
111
162
  write_inheritable_attribute(:controller_class, new_class)
112
163
  end
113
164
 
@@ -122,7 +173,7 @@ module ActionController
122
173
  def determine_default_controller_class(name)
123
174
  name.sub(/Test$/, '').constantize
124
175
  rescue NameError
125
- raise NonInferrableControllerError.new(name)
176
+ nil
126
177
  end
127
178
 
128
179
  def prepare_controller_class(new_class)
@@ -131,17 +182,23 @@ module ActionController
131
182
  end
132
183
 
133
184
  def setup_controller_request_and_response
134
- @controller = self.class.controller_class.new
135
- @controller.request = @request = TestRequest.new
185
+ @request = TestRequest.new
136
186
  @response = TestResponse.new
137
187
 
138
- @controller.params = {}
139
- @controller.send(:initialize_current_url)
188
+ if klass = self.class.controller_class
189
+ @controller ||= klass.new rescue nil
190
+ end
191
+
192
+ if @controller
193
+ @controller.request = @request
194
+ @controller.params = {}
195
+ @controller.send(:initialize_current_url)
196
+ end
140
197
  end
141
198
 
142
199
  # Cause the action to be rescued according to the regular rules for rescue_action when the visitor is not local
143
200
  def rescue_action_in_public!
144
201
  @request.remote_addr = '208.77.188.166' # example.com
145
202
  end
146
- end
203
+ end
147
204
  end
@@ -1,51 +1,25 @@
1
- require 'action_controller/assertions'
2
- require 'action_controller/test_case'
3
-
4
1
  module ActionController #:nodoc:
5
- class Base
6
- attr_reader :assigns
2
+ class TestRequest < Request #:nodoc:
3
+ attr_accessor :cookies, :session_options
4
+ attr_accessor :query_parameters, :path, :session
5
+ attr_accessor :host
7
6
 
8
- # Process a test request called with a TestRequest object.
9
- def self.process_test(request)
10
- new.process_test(request)
7
+ def self.new(env = {})
8
+ super
11
9
  end
12
10
 
13
- def process_test(request) #:nodoc:
14
- process(request, TestResponse.new)
15
- end
11
+ def initialize(env = {})
12
+ super(Rack::MockRequest.env_for("/").merge(env))
16
13
 
17
- def process_with_test(*args)
18
- returning process_without_test(*args) do
19
- @assigns = {}
20
- (instance_variable_names - @@protected_instance_variables).each do |var|
21
- value = instance_variable_get(var)
22
- @assigns[var[1..-1]] = value
23
- response.template.assigns[var[1..-1]] = value if response
24
- end
25
- end
26
- end
14
+ @query_parameters = {}
15
+ @session = TestSession.new
27
16
 
28
- alias_method_chain :process, :test
29
- end
30
-
31
- class TestRequest < AbstractRequest #:nodoc:
32
- attr_accessor :cookies, :session_options
33
- attr_accessor :query_parameters, :request_parameters, :path, :session
34
- attr_accessor :host, :user_agent
35
-
36
- def initialize(query_parameters = nil, request_parameters = nil, session = nil)
37
- @query_parameters = query_parameters || {}
38
- @request_parameters = request_parameters || {}
39
- @session = session || TestSession.new
40
-
41
- initialize_containers
42
17
  initialize_default_values
43
-
44
- super()
18
+ initialize_containers
45
19
  end
46
20
 
47
21
  def reset_session
48
- @session = TestSession.new
22
+ @session.reset
49
23
  end
50
24
 
51
25
  # Wraps raw_post in a StringIO.
@@ -56,12 +30,15 @@ module ActionController #:nodoc:
56
30
  # Either the RAW_POST_DATA environment variable or the URL-encoded request
57
31
  # parameters.
58
32
  def raw_post
59
- env['RAW_POST_DATA'] ||= returning(url_encoded_request_parameters) { |b| b.force_encoding(Encoding::BINARY) if b.respond_to?(:force_encoding) }
33
+ @env['RAW_POST_DATA'] ||= begin
34
+ data = url_encoded_request_parameters
35
+ data.force_encoding(Encoding::BINARY) if data.respond_to?(:force_encoding)
36
+ data
37
+ end
60
38
  end
61
39
 
62
40
  def port=(number)
63
41
  @env["SERVER_PORT"] = number.to_i
64
- port(true)
65
42
  end
66
43
 
67
44
  def action=(action_name)
@@ -75,8 +52,6 @@ module ActionController #:nodoc:
75
52
  @env["REQUEST_URI"] = value
76
53
  @request_uri = nil
77
54
  @path = nil
78
- request_uri(true)
79
- path(true)
80
55
  end
81
56
 
82
57
  def request_uri=(uri)
@@ -84,9 +59,13 @@ module ActionController #:nodoc:
84
59
  @path = uri.split("?").first
85
60
  end
86
61
 
62
+ def request_method=(method)
63
+ @request_method = method
64
+ end
65
+
87
66
  def accept=(mime_types)
88
67
  @env["HTTP_ACCEPT"] = Array(mime_types).collect { |mime_types| mime_types.to_s }.join(",")
89
- accepts(true)
68
+ @accepts = nil
90
69
  end
91
70
 
92
71
  def if_modified_since=(last_modified)
@@ -102,11 +81,11 @@ module ActionController #:nodoc:
102
81
  end
103
82
 
104
83
  def request_uri(*args)
105
- @request_uri || super
84
+ @request_uri || super()
106
85
  end
107
86
 
108
87
  def path(*args)
109
- @path || super
88
+ @path || super()
110
89
  end
111
90
 
112
91
  def assign_parameters(controller_path, action, parameters)
@@ -126,26 +105,30 @@ module ActionController #:nodoc:
126
105
  path_parameters[key.to_s] = value
127
106
  end
128
107
  end
108
+ raw_post # populate env['RAW_POST_DATA']
129
109
  @parameters = nil # reset TestRequest#parameters to use the new path_parameters
130
110
  end
131
111
 
132
112
  def recycle!
133
- self.request_parameters = {}
134
113
  self.query_parameters = {}
135
114
  self.path_parameters = {}
136
- unmemoize_all
115
+ @headers, @request_method, @accepts, @content_type = nil, nil, nil, nil
116
+ end
117
+
118
+ def user_agent=(user_agent)
119
+ @env['HTTP_USER_AGENT'] = user_agent
137
120
  end
138
121
 
139
122
  private
140
123
  def initialize_containers
141
- @env, @cookies = {}, {}
124
+ @cookies = {}
142
125
  end
143
126
 
144
127
  def initialize_default_values
145
128
  @host = "test.host"
146
129
  @request_uri = "/"
147
- @user_agent = "Rails Testing"
148
- self.remote_addr = "0.0.0.0"
130
+ @env['HTTP_USER_AGENT'] = "Rails Testing"
131
+ @env['REMOTE_ADDR'] = "0.0.0.0"
149
132
  @env["SERVER_PORT"] = 80
150
133
  @env['REQUEST_METHOD'] = "GET"
151
134
  end
@@ -167,7 +150,7 @@ module ActionController #:nodoc:
167
150
  module TestResponseBehavior #:nodoc:
168
151
  # The response code of the request
169
152
  def response_code
170
- status[0,3].to_i rescue 0
153
+ status.to_s[0,3].to_i rescue 0
171
154
  end
172
155
 
173
156
  # Returns a String to ensure compatibility with Net::HTTPResponse
@@ -201,6 +184,11 @@ module ActionController #:nodoc:
201
184
 
202
185
  alias_method :server_error?, :error?
203
186
 
187
+ # Was there a client client?
188
+ def client_error?
189
+ (400..499).include?(response_code)
190
+ end
191
+
204
192
  # Returns the redirection location or nil
205
193
  def redirect_url
206
194
  headers['Location']
@@ -217,8 +205,8 @@ module ActionController #:nodoc:
217
205
 
218
206
  # Returns the template of the file which was used to
219
207
  # render this response (or nil)
220
- def rendered_template
221
- template.instance_variable_get(:@_first_render)
208
+ def rendered
209
+ template.instance_variable_get(:@_rendered)
222
210
  end
223
211
 
224
212
  # A shortcut to the flash. Returns an empty hash if no session flash exists.
@@ -228,7 +216,7 @@ module ActionController #:nodoc:
228
216
 
229
217
  # Do we have a flash?
230
218
  def has_flash?
231
- !session['flash'].empty?
219
+ !flash.empty?
232
220
  end
233
221
 
234
222
  # Do we have a flash that has contents?
@@ -256,11 +244,16 @@ module ActionController #:nodoc:
256
244
  !template_objects[name].nil?
257
245
  end
258
246
 
259
- # Returns the response cookies, converted to a Hash of (name => CGI::Cookie) pairs
247
+ # Returns the response cookies, converted to a Hash of (name => value) pairs
260
248
  #
261
- # assert_equal ['AuthorOfNewPage'], r.cookies['author'].value
249
+ # assert_equal 'AuthorOfNewPage', r.cookies['author']
262
250
  def cookies
263
- headers['cookie'].inject({}) { |hash, cookie| hash[cookie.name] = cookie; hash }
251
+ cookies = {}
252
+ Array(headers['Set-Cookie']).each do |cookie|
253
+ key, value = cookie.split(";").first.split("=")
254
+ cookies[key] = value
255
+ end
256
+ cookies
264
257
  end
265
258
 
266
259
  # Returns binary content (downloadable file), converted to a String
@@ -281,48 +274,72 @@ module ActionController #:nodoc:
281
274
  # TestResponse, which represent the HTTP response results of the requested
282
275
  # controller actions.
283
276
  #
284
- # See AbstractResponse for more information on controller response objects.
285
- class TestResponse < AbstractResponse
277
+ # See Response for more information on controller response objects.
278
+ class TestResponse < Response
286
279
  include TestResponseBehavior
287
-
280
+
288
281
  def recycle!
289
282
  headers.delete('ETag')
290
283
  headers.delete('Last-Modified')
291
284
  end
292
285
  end
293
286
 
294
- class TestSession #:nodoc:
287
+ class TestSession < Hash #:nodoc:
295
288
  attr_accessor :session_id
296
289
 
297
290
  def initialize(attributes = nil)
298
- @session_id = ''
299
- @attributes = attributes.nil? ? nil : attributes.stringify_keys
300
- @saved_attributes = nil
291
+ reset_session_id
292
+ replace_attributes(attributes)
293
+ end
294
+
295
+ def reset
296
+ reset_session_id
297
+ replace_attributes({ })
301
298
  end
302
299
 
303
300
  def data
304
- @attributes ||= @saved_attributes || {}
301
+ to_hash
305
302
  end
306
303
 
307
304
  def [](key)
308
- data[key.to_s]
305
+ super(key.to_s)
309
306
  end
310
307
 
311
308
  def []=(key, value)
312
- data[key.to_s] = value
309
+ super(key.to_s, value)
313
310
  end
314
311
 
315
- def update
316
- @saved_attributes = @attributes
312
+ def update(hash = nil)
313
+ if hash.nil?
314
+ ActiveSupport::Deprecation.warn('use replace instead', caller)
315
+ replace({})
316
+ else
317
+ super(hash)
318
+ end
317
319
  end
318
320
 
319
- def delete
320
- @attributes = nil
321
+ def delete(key = nil)
322
+ if key.nil?
323
+ ActiveSupport::Deprecation.warn('use clear instead', caller)
324
+ clear
325
+ else
326
+ super(key.to_s)
327
+ end
321
328
  end
322
329
 
323
330
  def close
324
- update
325
- delete
331
+ ActiveSupport::Deprecation.warn('sessions should no longer be closed', caller)
332
+ end
333
+
334
+ private
335
+
336
+ def reset_session_id
337
+ @session_id = ''
338
+ end
339
+
340
+ def replace_attributes(attributes = nil)
341
+ attributes ||= {}
342
+ replace(attributes.stringify_keys)
326
343
  end
327
344
  end
328
345
 
@@ -333,10 +350,10 @@ module ActionController #:nodoc:
333
350
  # a file upload.
334
351
  #
335
352
  # Usage example, within a functional test:
336
- # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + '/files/spongebob.png', 'image/png')
353
+ # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png')
337
354
  #
338
355
  # Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows):
339
- # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary)
356
+ # post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary)
340
357
  require 'tempfile'
341
358
  class TestUploadedFile
342
359
  # The filename, *not* including the path, of the "uploaded" file
@@ -368,20 +385,33 @@ module ActionController #:nodoc:
368
385
 
369
386
  module TestProcess
370
387
  def self.included(base)
371
- # execute the request simulating a specific HTTP method and set/volley the response
372
- # TODO: this should be un-DRY'ed for the sake of API documentation.
373
- %w( get post put delete head ).each do |method|
374
- base.class_eval <<-EOV, __FILE__, __LINE__
375
- def #{method}(action, parameters = nil, session = nil, flash = nil)
376
- @request.env['REQUEST_METHOD'] = "#{method.upcase}" if defined?(@request)
377
- process(action, parameters, session, flash)
378
- end
379
- EOV
388
+ # Executes a request simulating GET HTTP method and set/volley the response
389
+ def get(action, parameters = nil, session = nil, flash = nil)
390
+ process(action, parameters, session, flash, "GET")
391
+ end
392
+
393
+ # Executes a request simulating POST HTTP method and set/volley the response
394
+ def post(action, parameters = nil, session = nil, flash = nil)
395
+ process(action, parameters, session, flash, "POST")
396
+ end
397
+
398
+ # Executes a request simulating PUT HTTP method and set/volley the response
399
+ def put(action, parameters = nil, session = nil, flash = nil)
400
+ process(action, parameters, session, flash, "PUT")
401
+ end
402
+
403
+ # Executes a request simulating DELETE HTTP method and set/volley the response
404
+ def delete(action, parameters = nil, session = nil, flash = nil)
405
+ process(action, parameters, session, flash, "DELETE")
406
+ end
407
+
408
+ # Executes a request simulating HEAD HTTP method and set/volley the response
409
+ def head(action, parameters = nil, session = nil, flash = nil)
410
+ process(action, parameters, session, flash, "HEAD")
380
411
  end
381
412
  end
382
413
 
383
- # execute the request and set/volley the response
384
- def process(action, parameters = nil, session = nil, flash = nil)
414
+ def process(action, parameters = nil, session = nil, flash = nil, http_method = 'GET')
385
415
  # Sanity check for required instance variables so we can give an
386
416
  # understandable error message.
387
417
  %w(@controller @request @response).each do |iv_name|
@@ -394,7 +424,7 @@ module ActionController #:nodoc:
394
424
  @response.recycle!
395
425
 
396
426
  @html_document = nil
397
- @request.env['REQUEST_METHOD'] ||= "GET"
427
+ @request.env['REQUEST_METHOD'] = http_method
398
428
 
399
429
  @request.action = action.to_s
400
430
 
@@ -404,12 +434,14 @@ module ActionController #:nodoc:
404
434
  @request.session = ActionController::TestSession.new(session) unless session.nil?
405
435
  @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash
406
436
  build_request_uri(action, parameters)
407
- @controller.process(@request, @response)
437
+
438
+ Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest
439
+ @controller.process_with_test(@request, @response)
408
440
  end
409
441
 
410
442
  def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil)
411
443
  @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
412
- @request.env['HTTP_ACCEPT'] = 'text/javascript, text/html, application/xml, text/xml, */*'
444
+ @request.env['HTTP_ACCEPT'] = [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
413
445
  returning __send__(request_method, action, parameters, session, flash) do
414
446
  @request.env.delete 'HTTP_X_REQUESTED_WITH'
415
447
  @request.env.delete 'HTTP_ACCEPT'
@@ -426,7 +458,7 @@ module ActionController #:nodoc:
426
458
  end
427
459
 
428
460
  def session
429
- @response.session
461
+ @request.session
430
462
  end
431
463
 
432
464
  def flash
@@ -464,15 +496,15 @@ module ActionController #:nodoc:
464
496
  html_document.find_all(conditions)
465
497
  end
466
498
 
467
- def method_missing(selector, *args)
468
- if ActionController::Routing::Routes.named_routes.helpers.include?(selector)
469
- @controller.send(selector, *args)
499
+ def method_missing(selector, *args, &block)
500
+ if @controller && ActionController::Routing::Routes.named_routes.helpers.include?(selector)
501
+ @controller.send(selector, *args, &block)
470
502
  else
471
503
  super
472
504
  end
473
505
  end
474
506
 
475
- # Shortcut for <tt>ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + path, type)</tt>:
507
+ # Shortcut for <tt>ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + path, type)</tt>:
476
508
  #
477
509
  # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png')
478
510
  #
@@ -481,11 +513,8 @@ module ActionController #:nodoc:
481
513
  #
482
514
  # post :change_avatar, :avatar => fixture_file_upload('/files/spongebob.png', 'image/png', :binary)
483
515
  def fixture_file_upload(path, mime_type = nil, binary = false)
484
- ActionController::TestUploadedFile.new(
485
- Test::Unit::TestCase.respond_to?(:fixture_path) ? Test::Unit::TestCase.fixture_path + path : path,
486
- mime_type,
487
- binary
488
- )
516
+ fixture_path = ActionController::TestCase.send(:fixture_path) if ActionController::TestCase.respond_to?(:fixture_path)
517
+ ActionController::TestUploadedFile.new("#{fixture_path}#{path}", mime_type, binary)
489
518
  end
490
519
 
491
520
  # A helper to make it easier to test different route configurations.
@@ -520,12 +549,24 @@ module ActionController #:nodoc:
520
549
  ActionController::Routing.const_set(:Routes, real_routes) if real_routes
521
550
  end
522
551
  end
523
- end
524
552
 
525
- module Test
526
- module Unit
527
- class TestCase #:nodoc:
528
- include ActionController::TestProcess
553
+ module ProcessWithTest #:nodoc:
554
+ def self.included(base)
555
+ base.class_eval { attr_reader :assigns }
556
+ end
557
+
558
+ def process_with_test(*args)
559
+ process(*args).tap { set_test_assigns }
529
560
  end
561
+
562
+ private
563
+ def set_test_assigns
564
+ @assigns = {}
565
+ (instance_variable_names - self.class.protected_instance_variables).each do |var|
566
+ name, value = var[1..-1], instance_variable_get(var)
567
+ @assigns[name] = value
568
+ response.template.assigns[name] = value if response
569
+ end
570
+ end
530
571
  end
531
572
  end