actionpack 1.13.6 → 2.0.0

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 (317) hide show
  1. data/CHANGELOG +1400 -20
  2. data/MIT-LICENSE +1 -1
  3. data/README +5 -5
  4. data/RUNNING_UNIT_TESTS +4 -5
  5. data/Rakefile +5 -6
  6. data/install.rb +2 -2
  7. data/lib/action_controller.rb +11 -15
  8. data/lib/action_controller/assertions.rb +12 -25
  9. data/lib/action_controller/assertions/dom_assertions.rb +18 -4
  10. data/lib/action_controller/assertions/model_assertions.rb +8 -1
  11. data/lib/action_controller/assertions/response_assertions.rb +35 -12
  12. data/lib/action_controller/assertions/routing_assertions.rb +56 -12
  13. data/lib/action_controller/assertions/selector_assertions.rb +105 -38
  14. data/lib/action_controller/assertions/tag_assertions.rb +28 -15
  15. data/lib/action_controller/base.rb +318 -250
  16. data/lib/action_controller/benchmarking.rb +33 -29
  17. data/lib/action_controller/caching.rb +130 -64
  18. data/lib/action_controller/cgi_ext.rb +16 -0
  19. data/lib/action_controller/cgi_ext/{cookie_performance_fix.rb → cookie.rb} +25 -40
  20. data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
  21. data/lib/action_controller/cgi_ext/session.rb +73 -0
  22. data/lib/action_controller/cgi_ext/stdinput.rb +23 -0
  23. data/lib/action_controller/cgi_process.rb +34 -57
  24. data/lib/action_controller/components.rb +19 -36
  25. data/lib/action_controller/cookies.rb +10 -9
  26. data/lib/action_controller/dispatcher.rb +195 -0
  27. data/lib/action_controller/filters.rb +35 -34
  28. data/lib/action_controller/flash.rb +30 -35
  29. data/lib/action_controller/helpers.rb +121 -47
  30. data/lib/action_controller/http_authentication.rb +126 -0
  31. data/lib/action_controller/integration.rb +105 -101
  32. data/lib/action_controller/layout.rb +59 -47
  33. data/lib/action_controller/mime_responds.rb +57 -68
  34. data/lib/action_controller/mime_type.rb +43 -80
  35. data/lib/action_controller/mime_types.rb +20 -0
  36. data/lib/action_controller/polymorphic_routes.rb +88 -0
  37. data/lib/action_controller/record_identifier.rb +91 -0
  38. data/lib/action_controller/request.rb +553 -88
  39. data/lib/action_controller/request_forgery_protection.rb +126 -0
  40. data/lib/action_controller/request_profiler.rb +138 -0
  41. data/lib/action_controller/rescue.rb +185 -69
  42. data/lib/action_controller/resources.rb +211 -172
  43. data/lib/action_controller/response.rb +49 -8
  44. data/lib/action_controller/routing.rb +359 -236
  45. data/lib/action_controller/routing_optimisation.rb +119 -0
  46. data/lib/action_controller/session/active_record_store.rb +3 -2
  47. data/lib/action_controller/session/cookie_store.rb +161 -0
  48. data/lib/action_controller/session/mem_cache_store.rb +9 -16
  49. data/lib/action_controller/session_management.rb +17 -8
  50. data/lib/action_controller/streaming.rb +6 -3
  51. data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
  52. data/lib/action_controller/templates/rescues/{_trace.rhtml → _trace.erb} +0 -0
  53. data/lib/action_controller/templates/rescues/{diagnostics.rhtml → diagnostics.erb} +2 -2
  54. data/lib/action_controller/templates/rescues/{layout.rhtml → layout.erb} +0 -0
  55. data/lib/action_controller/templates/rescues/{missing_template.rhtml → missing_template.erb} +0 -0
  56. data/lib/action_controller/templates/rescues/{routing_error.rhtml → routing_error.erb} +0 -0
  57. data/lib/action_controller/templates/rescues/{template_error.rhtml → template_error.erb} +2 -2
  58. data/lib/action_controller/templates/rescues/{unknown_action.rhtml → unknown_action.erb} +0 -0
  59. data/lib/action_controller/test_case.rb +53 -0
  60. data/lib/action_controller/test_process.rb +59 -46
  61. data/lib/action_controller/url_rewriter.rb +48 -24
  62. data/lib/action_controller/vendor/html-scanner/html/document.rb +7 -4
  63. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
  64. data/lib/action_controller/vendor/html-scanner/html/selector.rb +11 -6
  65. data/lib/action_controller/verification.rb +27 -21
  66. data/lib/action_pack.rb +1 -1
  67. data/lib/action_pack/version.rb +4 -4
  68. data/lib/action_view.rb +2 -3
  69. data/lib/action_view/base.rb +218 -63
  70. data/lib/action_view/compiled_templates.rb +1 -2
  71. data/lib/action_view/helpers/active_record_helper.rb +35 -17
  72. data/lib/action_view/helpers/asset_tag_helper.rb +395 -87
  73. data/lib/action_view/helpers/atom_feed_helper.rb +111 -0
  74. data/lib/action_view/helpers/benchmark_helper.rb +12 -5
  75. data/lib/action_view/helpers/cache_helper.rb +29 -0
  76. data/lib/action_view/helpers/capture_helper.rb +97 -63
  77. data/lib/action_view/helpers/date_helper.rb +295 -35
  78. data/lib/action_view/helpers/debug_helper.rb +6 -2
  79. data/lib/action_view/helpers/form_helper.rb +354 -111
  80. data/lib/action_view/helpers/form_options_helper.rb +171 -109
  81. data/lib/action_view/helpers/form_tag_helper.rb +332 -76
  82. data/lib/action_view/helpers/javascript_helper.rb +35 -11
  83. data/lib/action_view/helpers/javascripts/controls.js +484 -354
  84. data/lib/action_view/helpers/javascripts/dragdrop.js +88 -58
  85. data/lib/action_view/helpers/javascripts/effects.js +396 -364
  86. data/lib/action_view/helpers/javascripts/prototype.js +2817 -1107
  87. data/lib/action_view/helpers/number_helper.rb +84 -60
  88. data/lib/action_view/helpers/prototype_helper.rb +419 -43
  89. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  90. data/lib/action_view/helpers/record_tag_helper.rb +59 -0
  91. data/lib/action_view/helpers/sanitize_helper.rb +223 -0
  92. data/lib/action_view/helpers/scriptaculous_helper.rb +63 -4
  93. data/lib/action_view/helpers/tag_helper.rb +69 -39
  94. data/lib/action_view/helpers/text_helper.rb +221 -148
  95. data/lib/action_view/helpers/url_helper.rb +283 -165
  96. data/lib/action_view/partials.rb +134 -62
  97. data/lib/action_view/template_error.rb +4 -12
  98. data/lib/actionpack.rb +1 -0
  99. data/test/abstract_unit.rb +21 -1
  100. data/test/action_view_test.rb +26 -0
  101. data/test/active_record_unit.rb +12 -20
  102. data/test/activerecord/active_record_store_test.rb +2 -2
  103. data/test/activerecord/render_partial_with_record_identification_test.rb +74 -0
  104. data/test/controller/action_pack_assertions_test.rb +21 -152
  105. data/test/controller/addresses_render_test.rb +2 -7
  106. data/test/controller/assert_select_test.rb +120 -14
  107. data/test/controller/base_test.rb +11 -13
  108. data/test/controller/caching_test.rb +125 -5
  109. data/test/controller/capture_test.rb +23 -16
  110. data/test/controller/cgi_test.rb +66 -391
  111. data/test/controller/components_test.rb +31 -42
  112. data/test/controller/content_type_test.rb +1 -1
  113. data/test/controller/cookie_test.rb +42 -14
  114. data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -42
  115. data/test/controller/dispatcher_test.rb +123 -0
  116. data/test/controller/fake_models.rb +5 -0
  117. data/test/controller/filters_test.rb +44 -7
  118. data/test/controller/flash_test.rb +46 -2
  119. data/test/controller/fragment_store_setting_test.rb +10 -8
  120. data/test/controller/helper_test.rb +19 -2
  121. data/test/controller/html-scanner/document_test.rb +124 -0
  122. data/test/controller/html-scanner/node_test.rb +69 -0
  123. data/test/controller/html-scanner/sanitizer_test.rb +250 -0
  124. data/test/controller/html-scanner/tag_node_test.rb +239 -0
  125. data/test/controller/html-scanner/text_node_test.rb +51 -0
  126. data/test/controller/html-scanner/tokenizer_test.rb +125 -0
  127. data/test/controller/http_authentication_test.rb +54 -0
  128. data/test/controller/integration_test.rb +12 -26
  129. data/test/controller/layout_test.rb +64 -12
  130. data/test/controller/mime_responds_test.rb +193 -38
  131. data/test/controller/mime_type_test.rb +30 -8
  132. data/test/controller/new_render_test.rb +104 -22
  133. data/test/controller/polymorphic_routes_test.rb +98 -0
  134. data/test/controller/record_identifier_test.rb +103 -0
  135. data/test/controller/redirect_test.rb +120 -18
  136. data/test/controller/render_test.rb +195 -45
  137. data/test/controller/request_forgery_protection_test.rb +217 -0
  138. data/test/controller/request_test.rb +545 -27
  139. data/test/controller/rescue_test.rb +501 -0
  140. data/test/controller/resources_test.rb +258 -132
  141. data/test/controller/routing_test.rb +502 -106
  142. data/test/controller/selector_test.rb +5 -5
  143. data/test/controller/send_file_test.rb +17 -7
  144. data/test/controller/session/cookie_store_test.rb +246 -0
  145. data/test/controller/session/mem_cache_store_test.rb +182 -0
  146. data/test/controller/session_fixation_test.rb +8 -11
  147. data/test/controller/session_management_test.rb +7 -7
  148. data/test/controller/test_test.rb +150 -38
  149. data/test/controller/url_rewriter_test.rb +87 -12
  150. data/test/controller/verification_test.rb +11 -0
  151. data/test/controller/view_paths_test.rb +137 -0
  152. data/test/controller/webservice_test.rb +11 -75
  153. data/test/fixtures/addresses/{list.rhtml → list.erb} +0 -0
  154. data/test/fixtures/db_definitions/sqlite.sql +2 -1
  155. data/test/fixtures/developer.rb +2 -0
  156. data/test/fixtures/fun/games/{hello_world.rhtml → hello_world.erb} +0 -0
  157. data/test/fixtures/helpers/fun/pdf_helper.rb +1 -1
  158. data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
  159. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
  160. data/test/fixtures/layouts/{builder.rxml → builder.builder} +0 -0
  161. data/test/fixtures/layouts/{standard.rhtml → standard.erb} +0 -0
  162. data/test/fixtures/layouts/{talk_from_action.rhtml → talk_from_action.erb} +0 -0
  163. data/test/fixtures/layouts/{yield.rhtml → yield.erb} +0 -0
  164. data/test/fixtures/multipart/binary_file +0 -0
  165. data/test/fixtures/multipart/bracketed_param +5 -0
  166. data/test/fixtures/override/test/hello_world.erb +1 -0
  167. data/test/fixtures/override2/layouts/test/sub.erb +1 -0
  168. data/test/fixtures/post_test/layouts/post.html.erb +1 -0
  169. data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
  170. data/test/fixtures/post_test/post/index.html.erb +1 -0
  171. data/test/fixtures/post_test/post/index.iphone.erb +1 -0
  172. data/test/fixtures/post_test/super_post/index.html.erb +1 -0
  173. data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
  174. data/test/fixtures/public/404.html +1 -0
  175. data/test/fixtures/public/500.html +1 -0
  176. data/test/fixtures/public/javascripts/application.js +0 -1
  177. data/test/fixtures/public/javascripts/bank.js +1 -0
  178. data/test/fixtures/public/javascripts/robber.js +1 -0
  179. data/test/fixtures/public/stylesheets/bank.css +1 -0
  180. data/test/fixtures/public/stylesheets/robber.css +1 -0
  181. data/test/fixtures/replies.yml +2 -0
  182. data/test/fixtures/reply.rb +2 -1
  183. data/test/fixtures/respond_to/{all_types_with_layout.rhtml → all_types_with_layout.html.erb} +0 -0
  184. data/test/fixtures/respond_to/{all_types_with_layout.rjs → all_types_with_layout.js.rjs} +0 -0
  185. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
  186. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
  187. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
  188. data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
  189. data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
  190. data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
  191. data/test/fixtures/respond_to/{using_defaults.rhtml → using_defaults.html.erb} +0 -0
  192. data/test/fixtures/respond_to/{using_defaults.rjs → using_defaults.js.rjs} +0 -0
  193. data/test/fixtures/respond_to/{using_defaults.rxml → using_defaults.xml.builder} +0 -0
  194. data/test/fixtures/respond_to/{using_defaults_with_type_list.rhtml → using_defaults_with_type_list.html.erb} +0 -0
  195. data/test/fixtures/respond_to/{using_defaults_with_type_list.rjs → using_defaults_with_type_list.js.rjs} +0 -0
  196. data/test/fixtures/respond_to/{using_defaults_with_type_list.rxml → using_defaults_with_type_list.xml.builder} +0 -0
  197. data/test/fixtures/scope/test/{modgreet.rhtml → modgreet.erb} +0 -0
  198. data/test/fixtures/test/{_customer.rhtml → _customer.erb} +0 -0
  199. data/test/fixtures/test/{_customer_greeting.rhtml → _customer_greeting.erb} +0 -0
  200. data/test/fixtures/test/_hash_greeting.erb +1 -0
  201. data/test/fixtures/test/_hash_object.erb +2 -0
  202. data/test/fixtures/test/{_hello.rxml → _hello.builder} +0 -0
  203. data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
  204. data/test/fixtures/test/_partial.erb +1 -0
  205. data/test/fixtures/test/_partial.html.erb +1 -0
  206. data/test/fixtures/test/_partial.js.erb +1 -0
  207. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
  208. data/test/fixtures/test/{_partial_only.rhtml → _partial_only.erb} +0 -0
  209. data/test/fixtures/test/{_person.rhtml → _person.erb} +0 -0
  210. data/test/fixtures/test/{action_talk_to_layout.rhtml → action_talk_to_layout.erb} +0 -0
  211. data/test/fixtures/test/{block_content_for.rhtml → block_content_for.erb} +0 -0
  212. data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
  213. data/test/fixtures/test/{capturing.rhtml → capturing.erb} +0 -0
  214. data/test/fixtures/test/{content_for.rhtml → content_for.erb} +0 -0
  215. data/test/fixtures/test/content_for_concatenated.erb +3 -0
  216. data/test/fixtures/test/content_for_with_parameter.erb +2 -0
  217. data/test/fixtures/test/dot.directory/{render_file_with_ivar.rhtml → render_file_with_ivar.erb} +0 -0
  218. data/test/fixtures/test/{erb_content_for.rhtml → erb_content_for.erb} +0 -0
  219. data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
  220. data/test/fixtures/test/formatted_xml_erb.builder +1 -0
  221. data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
  222. data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
  223. data/test/fixtures/test/{greeting.rhtml → greeting.erb} +0 -0
  224. data/test/fixtures/test/{hello.rxml → hello.builder} +0 -0
  225. data/test/fixtures/test/{hello_world.rxml → hello_world.builder} +0 -0
  226. data/test/fixtures/test/{hello_world.rhtml → hello_world.erb} +0 -0
  227. data/test/fixtures/test/{hello_world_container.rxml → hello_world_container.builder} +0 -0
  228. data/test/fixtures/test/{hello_world_with_layout_false.rhtml → hello_world_with_layout_false.erb} +0 -0
  229. data/test/fixtures/test/{hello_xml_world.rxml → hello_xml_world.builder} +0 -0
  230. data/test/fixtures/test/list.erb +1 -0
  231. data/test/fixtures/test/{non_erb_block_content_for.rxml → non_erb_block_content_for.builder} +0 -0
  232. data/test/fixtures/test/{potential_conflicts.rhtml → potential_conflicts.erb} +0 -0
  233. data/test/fixtures/test/{render_file_with_ivar.rhtml → render_file_with_ivar.erb} +0 -0
  234. data/test/fixtures/test/{render_file_with_locals.rhtml → render_file_with_locals.erb} +0 -0
  235. data/test/fixtures/test/{render_to_string_test.rhtml → render_to_string_test.erb} +0 -0
  236. data/test/fixtures/test/{update_element_with_capture.rhtml → update_element_with_capture.erb} +0 -0
  237. data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
  238. data/test/fixtures/topic.rb +1 -1
  239. data/test/template/active_record_helper_test.rb +67 -20
  240. data/test/template/asset_tag_helper_test.rb +222 -54
  241. data/test/template/atom_feed_helper_test.rb +101 -0
  242. data/test/template/benchmark_helper_test.rb +2 -2
  243. data/test/template/compiled_templates_test.rb +76 -32
  244. data/test/template/date_helper_test.rb +125 -9
  245. data/test/template/form_helper_test.rb +326 -33
  246. data/test/template/form_options_helper_test.rb +822 -15
  247. data/test/template/form_tag_helper_test.rb +96 -30
  248. data/test/template/javascript_helper_test.rb +61 -13
  249. data/test/template/number_helper_test.rb +12 -11
  250. data/test/template/prototype_helper_test.rb +185 -24
  251. data/test/template/sanitize_helper_test.rb +49 -0
  252. data/test/template/scriptaculous_helper_test.rb +9 -3
  253. data/test/template/tag_helper_test.rb +13 -2
  254. data/test/template/text_helper_test.rb +38 -52
  255. data/test/template/url_helper_test.rb +216 -46
  256. metadata +144 -116
  257. data/examples/.htaccess +0 -24
  258. data/examples/address_book/index.rhtml +0 -33
  259. data/examples/address_book/layout.rhtml +0 -8
  260. data/examples/address_book_controller.cgi +0 -9
  261. data/examples/address_book_controller.fcgi +0 -6
  262. data/examples/address_book_controller.rb +0 -52
  263. data/examples/address_book_controller.rbx +0 -4
  264. data/examples/benchmark.rb +0 -52
  265. data/examples/benchmark_with_ar.fcgi +0 -89
  266. data/examples/blog_controller.cgi +0 -53
  267. data/examples/debate/index.rhtml +0 -14
  268. data/examples/debate/new_topic.rhtml +0 -22
  269. data/examples/debate/topic.rhtml +0 -32
  270. data/examples/debate_controller.cgi +0 -57
  271. data/lib/action_controller/assertions/deprecated_assertions.rb +0 -228
  272. data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -36
  273. data/lib/action_controller/cgi_ext/cgi_methods.rb +0 -211
  274. data/lib/action_controller/cgi_ext/pstore_performance_fix.rb +0 -30
  275. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +0 -95
  276. data/lib/action_controller/cgi_ext/session_performance_fix.rb +0 -30
  277. data/lib/action_controller/deprecated_dependencies.rb +0 -65
  278. data/lib/action_controller/deprecated_redirects.rb +0 -17
  279. data/lib/action_controller/deprecated_request_methods.rb +0 -34
  280. data/lib/action_controller/macros/auto_complete.rb +0 -53
  281. data/lib/action_controller/macros/in_place_editing.rb +0 -33
  282. data/lib/action_controller/pagination.rb +0 -408
  283. data/lib/action_controller/scaffolding.rb +0 -189
  284. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +0 -44
  285. data/lib/action_controller/templates/scaffolds/edit.rhtml +0 -7
  286. data/lib/action_controller/templates/scaffolds/layout.rhtml +0 -69
  287. data/lib/action_controller/templates/scaffolds/list.rhtml +0 -27
  288. data/lib/action_controller/templates/scaffolds/new.rhtml +0 -6
  289. data/lib/action_controller/templates/scaffolds/show.rhtml +0 -9
  290. data/lib/action_controller/vendor/xml_node.rb +0 -97
  291. data/lib/action_view/helpers/deprecated_helper.rb +0 -37
  292. data/lib/action_view/helpers/java_script_macros_helper.rb +0 -233
  293. data/lib/action_view/helpers/pagination_helper.rb +0 -86
  294. data/test/activerecord/active_record_assertions_test.rb +0 -92
  295. data/test/activerecord/pagination_test.rb +0 -165
  296. data/test/controller/deprecated_instance_variables_test.rb +0 -48
  297. data/test/controller/raw_post_test.rb +0 -68
  298. data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +0 -1
  299. data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +0 -1
  300. data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +0 -1
  301. data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +0 -1
  302. data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +0 -1
  303. data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +0 -1
  304. data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +0 -1
  305. data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +0 -1
  306. data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +0 -1
  307. data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +0 -1
  308. data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +0 -1
  309. data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +0 -1
  310. data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +0 -1
  311. data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +0 -1
  312. data/test/fixtures/respond_to/layouts/standard.rhtml +0 -1
  313. data/test/fixtures/test/_hash_object.rhtml +0 -1
  314. data/test/fixtures/test/list.rhtml +0 -1
  315. data/test/template/deprecated_helper_test.rb +0 -36
  316. data/test/template/deprecated_instance_variables_test.rb +0 -43
  317. data/test/template/java_script_macros_helper_test.rb +0 -109
@@ -1,5 +1,7 @@
1
1
  module ActionController #:nodoc:
2
2
  module Helpers #:nodoc:
3
+ HELPERS_DIR = (defined?(RAILS_ROOT) ? "#{RAILS_ROOT}/app/helpers" : "app/helpers")
4
+
3
5
  def self.included(base)
4
6
  # Initialize the base module to aggregate its helpers.
5
7
  base.class_inheritable_accessor :master_helper_module
@@ -16,64 +18,120 @@ module ActionController #:nodoc:
16
18
  end
17
19
  end
18
20
 
19
- # The template helpers serve to relieve the templates from including the same inline code again and again. It's a
20
- # set of standardized methods for working with forms (FormHelper), dates (DateHelper), texts (TextHelper), and
21
- # Active Records (ActiveRecordHelper) that's available to all templates by default.
21
+ # The Rails framework provides a large number of helpers for working with +assets+, +dates+, +forms+,
22
+ # +numbers+ and +ActiveRecord+ objects, to name a few. These helpers are available to all templates
23
+ # by default.
22
24
  #
23
- # It's also really easy to make your own helpers and it's much encouraged to keep the template files free
24
- # from complicated logic. It's even encouraged to bundle common compositions of methods from other helpers
25
- # (often the common helpers) as they're used by the specific application.
25
+ # In addition to using the standard template helpers provided in the Rails framework, creating custom helpers to
26
+ # extract complicated logic or reusable functionality is strongly encouraged. By default, the controller will
27
+ # include a helper whose name matches that of the controller, e.g., <tt>MyController</tt> will automatically
28
+ # include <tt>MyHelper</tt>.
26
29
  #
27
- # module MyHelper
28
- # def hello_world() "hello world" end
30
+ # Additional helpers can be specified using the +helper+ class method in <tt>ActionController::Base</tt> or any
31
+ # controller which inherits from it.
32
+ #
33
+ # ==== Examples
34
+ # The +to_s+ method from the +Time+ class can be wrapped in a helper method to display a custom message if
35
+ # the Time object is blank:
36
+ #
37
+ # module FormattedTimeHelper
38
+ # def format_time(time, format=:long, blank_message="&nbsp;")
39
+ # time.blank? ? blank_message : time.to_s(format)
40
+ # end
29
41
  # end
30
- #
31
- # MyHelper can now be included in a controller, like this:
32
- #
33
- # class MyController < ActionController::Base
34
- # helper :my_helper
42
+ #
43
+ # +FormattedTimeHelper+ can now be included in a controller, using the +helper+ class method:
44
+ #
45
+ # class EventsController < ActionController::Base
46
+ # helper FormattedTimeHelper
47
+ # def index
48
+ # @events = Event.find(:all)
49
+ # end
35
50
  # end
36
- #
37
- # ...and, same as above, used in any template rendered from MyController, like this:
38
- #
39
- # Let's hear what the helper has to say: <tt><%= hello_world %></tt>
51
+ #
52
+ # Then, in any view rendered by <tt>EventController</tt>, the <tt>format_time</tt> method can be called:
53
+ #
54
+ # <% @events.each do |event| -%>
55
+ # <p>
56
+ # <% format_time(event.time, :short, "N/A") %> | <%= event.name %>
57
+ # </p>
58
+ # <% end -%>
59
+ #
60
+ # Finally, assuming we have two event instances, one which has a time and one which does not,
61
+ # the output might look like this:
62
+ #
63
+ # 23 Aug 11:30 | Carolina Railhawks Soccer Match
64
+ # N/A | Carolina Railhaws Training Workshop
65
+ #
40
66
  module ClassMethods
41
67
  # Makes all the (instance) methods in the helper module available to templates rendered through this controller.
42
- # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
68
+ # See ActionView::Helpers (link:classes/ActionView/Helpers.html) for more about making your own helper modules
43
69
  # available to the templates.
44
70
  def add_template_helper(helper_module) #:nodoc:
45
- master_helper_module.send(:include, helper_module)
71
+ master_helper_module.module_eval { include helper_module }
46
72
  end
47
73
 
48
- # Declare a helper:
49
- # helper :foo
50
- # requires 'foo_helper' and includes FooHelper in the template class.
51
- # helper FooHelper
52
- # includes FooHelper in the template class.
53
- # helper { def foo() "#{bar} is the very best" end }
54
- # evaluates the block in the template class, adding method #foo.
74
+ # The +helper+ class method can take a series of helper module names, a block, or both.
75
+ #
76
+ # * <tt>*args</tt>: One or more +Modules+, +Strings+ or +Symbols+, or the special symbol <tt>:all</tt>.
77
+ # * <tt>&block</tt>: A block defining helper methods.
78
+ #
79
+ # ==== Examples
80
+ # When the argument is a +String+ or +Symbol+, the method will provide the "_helper" suffix, require the file
81
+ # and include the module in the template class. The second form illustrates how to include custom helpers
82
+ # when working with namespaced controllers, or other cases where the file containing the helper definition is not
83
+ # in one of Rails' standard load paths:
84
+ # helper :foo # => requires 'foo_helper' and includes FooHelper
85
+ # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
86
+ #
87
+ # When the argument is a +Module+, it will be included directly in the template class.
88
+ # helper FooHelper # => includes FooHelper
89
+ #
90
+ # When the argument is the symbol <tt>:all</tt>, the controller will include all helpers from
91
+ # <tt>app/helpers/**/*.rb</tt> under +RAILS_ROOT+.
92
+ # helper :all
93
+ #
94
+ # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
95
+ # to the template.
96
+ # # One line
97
+ # helper { def hello() "Hello, world!" end }
98
+ # # Multi-line
99
+ # helper do
100
+ # def foo(bar)
101
+ # "#{bar} is the very best"
102
+ # end
103
+ # end
104
+ #
105
+ # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
106
+ # +symbols+, +strings+, +modules+ and blocks.
55
107
  # helper(:three, BlindHelper) { def mice() 'mice' end }
56
- # does all three.
108
+ #
57
109
  def helper(*args, &block)
58
110
  args.flatten.each do |arg|
59
111
  case arg
60
112
  when Module
61
113
  add_template_helper(arg)
114
+ when :all
115
+ helper(all_application_helpers)
62
116
  when String, Symbol
63
117
  file_name = arg.to_s.underscore + '_helper'
64
118
  class_name = file_name.camelize
65
-
119
+
66
120
  begin
67
121
  require_dependency(file_name)
68
122
  rescue LoadError => load_error
69
123
  requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
70
- msg = (requiree == file_name) ? "Missing helper file helpers/#{file_name}.rb" : "Can't load file: #{requiree}"
71
- raise LoadError.new(msg).copy_blame!(load_error)
124
+ if requiree == file_name
125
+ msg = "Missing helper file helpers/#{file_name}.rb"
126
+ raise LoadError.new(msg).copy_blame!(load_error)
127
+ else
128
+ raise
129
+ end
72
130
  end
73
131
 
74
132
  add_template_helper(class_name.constantize)
75
133
  else
76
- raise ArgumentError, 'helper expects String, Symbol, or Module argument'
134
+ raise ArgumentError, "helper expects String, Symbol, or Module argument (was: #{args.inspect})"
77
135
  end
78
136
  end
79
137
 
@@ -81,10 +139,14 @@ module ActionController #:nodoc:
81
139
  master_helper_module.module_eval(&block) if block_given?
82
140
  end
83
141
 
84
- # Declare a controller method as a helper. For example,
85
- # helper_method :link_to
86
- # def link_to(name, options) ... end
87
- # makes the link_to controller method available in the view.
142
+ # Declare a controller method as a helper. For example, the following
143
+ # makes the +current_user+ controller method available to the view:
144
+ # class ApplicationController < ActionController::Base
145
+ # helper_method :current_user
146
+ # def current_user
147
+ # @current_user ||= User.find(session[:user])
148
+ # end
149
+ # end
88
150
  def helper_method(*methods)
89
151
  methods.flatten.each do |method|
90
152
  master_helper_module.module_eval <<-end_eval
@@ -95,37 +157,49 @@ module ActionController #:nodoc:
95
157
  end
96
158
  end
97
159
 
98
- # Declare a controller attribute as a helper. For example,
160
+ # Declares helper accessors for controller attributes. For example, the
161
+ # following adds new +name+ and <tt>name=</tt> instance methods to a
162
+ # controller and makes them available to the view:
99
163
  # helper_attr :name
100
164
  # attr_accessor :name
101
- # makes the name and name= controller methods available in the view.
102
- # The is a convenience wrapper for helper_method.
103
165
  def helper_attr(*attrs)
104
166
  attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
105
167
  end
106
168
 
107
- private
169
+
170
+ private
108
171
  def default_helper_module!
109
- module_name = name.sub(/Controller$|$/, 'Helper')
110
- module_path = module_name.split('::').map { |m| m.underscore }.join('/')
111
- require_dependency module_path
112
- helper module_name.constantize
113
- rescue LoadError
172
+ unless name.blank?
173
+ module_name = name.sub(/Controller$|$/, 'Helper')
174
+ module_path = module_name.split('::').map { |m| m.underscore }.join('/')
175
+ require_dependency module_path
176
+ helper module_name.constantize
177
+ end
178
+ rescue MissingSourceFile => e
179
+ raise unless e.is_missing? module_path
114
180
  logger.debug("#{name}: missing default helper path #{module_path}") if logger
115
- rescue NameError
181
+ rescue NameError => e
182
+ raise unless e.missing_name? module_name
116
183
  logger.debug("#{name}: missing default helper module #{module_name}") if logger
117
184
  end
118
185
 
119
186
  def inherited_with_helper(child)
120
187
  inherited_without_helper(child)
188
+
121
189
  begin
122
190
  child.master_helper_module = Module.new
123
- child.master_helper_module.send :include, master_helper_module
124
- child.send :default_helper_module!
191
+ child.master_helper_module.send! :include, master_helper_module
192
+ child.send! :default_helper_module!
125
193
  rescue MissingSourceFile => e
126
194
  raise unless e.is_missing?("helpers/#{child.controller_path}_helper")
127
195
  end
128
196
  end
197
+
198
+ # Extract helper names from files in app/helpers/**/*.rb
199
+ def all_application_helpers
200
+ extract = /^#{Regexp.quote(HELPERS_DIR)}\/?(.*)_helper.rb$/
201
+ Dir["#{HELPERS_DIR}/**/*_helper.rb"].map { |file| file.sub extract, '\1' }
202
+ end
129
203
  end
130
204
  end
131
205
  end
@@ -0,0 +1,126 @@
1
+ require 'base64'
2
+
3
+ module ActionController
4
+ module HttpAuthentication
5
+ # Makes it dead easy to do HTTP Basic authentication.
6
+ #
7
+ # Simple Basic example:
8
+ #
9
+ # class PostsController < ApplicationController
10
+ # USER_NAME, PASSWORD = "dhh", "secret"
11
+ #
12
+ # before_filter :authenticate, :except => [ :index ]
13
+ #
14
+ # def index
15
+ # render :text => "Everyone can see me!"
16
+ # end
17
+ #
18
+ # def edit
19
+ # render :text => "I'm only accessible if you know the password"
20
+ # end
21
+ #
22
+ # private
23
+ # def authenticate
24
+ # authenticate_or_request_with_http_basic do |user_name, password|
25
+ # user_name == USER_NAME && password == PASSWORD
26
+ # end
27
+ # end
28
+ # end
29
+ #
30
+ #
31
+ # Here is a more advanced Basic example where only Atom feeds and the XML API is protected by HTTP authentication,
32
+ # the regular HTML interface is protected by a session approach:
33
+ #
34
+ # class ApplicationController < ActionController::Base
35
+ # before_filter :set_account, :authenticate
36
+ #
37
+ # protected
38
+ # def set_account
39
+ # @account = Account.find_by_url_name(request.subdomains.first)
40
+ # end
41
+ #
42
+ # def authenticate
43
+ # case request.format
44
+ # when Mime::XML, Mime::ATOM
45
+ # if user = authenticate_with_http_basic { |u, p| @account.users.authenticate(u, p) }
46
+ # @current_user = user
47
+ # else
48
+ # request_http_basic_authentication
49
+ # end
50
+ # else
51
+ # if session_authenticated?
52
+ # @current_user = @account.users.find(session[:authenticated][:user_id])
53
+ # else
54
+ # redirect_to(login_url) and return false
55
+ # end
56
+ # end
57
+ # end
58
+ # end
59
+ #
60
+ #
61
+ # In your integration tests, you can do something like this:
62
+ #
63
+ # def test_access_granted_from_xml
64
+ # get(
65
+ # "/notes/1.xml", nil,
66
+ # :authorization => ActionController::HttpAuthentication::Basic.encode_credentials(users(:dhh).name, users(:dhh).password)
67
+ # )
68
+ #
69
+ # assert_equal 200, status
70
+ # end
71
+ #
72
+ #
73
+ # On shared hosts, Apache sometimes doesn't pass authentication headers to
74
+ # FCGI instances. If your environment matches this description and you cannot
75
+ # authenticate, try this rule in public/.htaccess (replace the plain one):
76
+ #
77
+ # RewriteRule ^(.*)$ dispatch.fcgi [E=X-HTTP_AUTHORIZATION:%{HTTP:Authorization},QSA,L]
78
+ module Basic
79
+ extend self
80
+
81
+ module ControllerMethods
82
+ def authenticate_or_request_with_http_basic(realm = "Application", &login_procedure)
83
+ authenticate_with_http_basic(&login_procedure) || request_http_basic_authentication(realm)
84
+ end
85
+
86
+ def authenticate_with_http_basic(&login_procedure)
87
+ HttpAuthentication::Basic.authenticate(self, &login_procedure)
88
+ end
89
+
90
+ def request_http_basic_authentication(realm = "Application")
91
+ HttpAuthentication::Basic.authentication_request(self, realm)
92
+ end
93
+ end
94
+
95
+ def authenticate(controller, &login_procedure)
96
+ unless authorization(controller.request).blank?
97
+ login_procedure.call(*user_name_and_password(controller.request))
98
+ end
99
+ end
100
+
101
+ def user_name_and_password(request)
102
+ decode_credentials(request).split(/:/, 2)
103
+ end
104
+
105
+ def authorization(request)
106
+ request.env['HTTP_AUTHORIZATION'] ||
107
+ request.env['X-HTTP_AUTHORIZATION'] ||
108
+ request.env['X_HTTP_AUTHORIZATION'] ||
109
+ request.env['REDIRECT_X_HTTP_AUTHORIZATION']
110
+ end
111
+
112
+ def decode_credentials(request)
113
+ Base64.decode64(authorization(request).split.last || '')
114
+ end
115
+
116
+ def encode_credentials(user_name, password)
117
+ "Basic #{Base64.encode64("#{user_name}:#{password}")}"
118
+ end
119
+
120
+ def authentication_request(controller, realm)
121
+ controller.headers["WWW-Authenticate"] = %(Basic realm="#{realm.gsub(/"/, "")}")
122
+ controller.send! :render, :text => "HTTP Basic: Access denied.\n", :status => :unauthorized
123
+ end
124
+ end
125
+ end
126
+ end
@@ -51,7 +51,10 @@ module ActionController
51
51
  # A reference to the response instance used by the last request.
52
52
  attr_reader :response
53
53
 
54
- # Create an initialize a new Session instance.
54
+ # A running counter of the number of requests processed.
55
+ attr_accessor :request_count
56
+
57
+ # Create and initialize a new +Session+ instance.
55
58
  def initialize
56
59
  reset!
57
60
  end
@@ -67,19 +70,20 @@ module ActionController
67
70
  @https = false
68
71
  @cookies = {}
69
72
  @controller = @request = @response = nil
73
+ @request_count = 0
70
74
 
71
75
  self.host = "www.example.com"
72
76
  self.remote_addr = "127.0.0.1"
73
77
  self.accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
74
78
 
75
- unless @named_routes_configured
79
+ unless defined? @named_routes_configured
76
80
  # install the named routes in this session instance.
77
81
  klass = class<<self; self; end
78
- Routing::Routes.named_routes.install(klass)
82
+ Routing::Routes.install_helpers(klass)
79
83
 
80
84
  # the helpers are made protected by default--we make them public for
81
85
  # easier access during testing and troubleshooting.
82
- klass.send(:public, *Routing::Routes.named_routes.helpers)
86
+ klass.module_eval { public *Routing::Routes.named_routes.helpers }
83
87
  @named_routes_configured = true
84
88
  end
85
89
  end
@@ -120,17 +124,18 @@ module ActionController
120
124
  # Performs a GET request, following any subsequent redirect. Note that
121
125
  # the redirects are followed until the response is not a redirect--this
122
126
  # means you may run into an infinite loop if your redirect loops back to
123
- # itself.
124
- def get_via_redirect(path, args={})
125
- get path, args
127
+ # itself. Headers are treated in the same way as #get.
128
+ def get_via_redirect(path, args={}, headers = {})
129
+ get path, args, headers
126
130
  follow_redirect! while redirect?
127
131
  status
128
132
  end
129
133
 
130
134
  # Performs a POST request, following any subsequent redirect. This is
131
- # vulnerable to infinite loops, the same as #get_via_redirect.
132
- def post_via_redirect(path, args={})
133
- post path, args
135
+ # vulnerable to infinite loops, the same as #get_via_redirect. Headers are
136
+ # treated in the same way as #get.
137
+ def post_via_redirect(path, args={}, headers = {})
138
+ post path, args, headers
134
139
  follow_redirect! while redirect?
135
140
  status
136
141
  end
@@ -148,27 +153,27 @@ module ActionController
148
153
  #
149
154
  # You can also perform POST, PUT, DELETE, and HEAD requests with #post,
150
155
  # #put, #delete, and #head.
151
- def get(path, parameters=nil, headers=nil)
156
+ def get(path, parameters = nil, headers = nil)
152
157
  process :get, path, parameters, headers
153
158
  end
154
159
 
155
160
  # Performs a POST request with the given parameters. See get() for more details.
156
- def post(path, parameters=nil, headers=nil)
161
+ def post(path, parameters = nil, headers = nil)
157
162
  process :post, path, parameters, headers
158
163
  end
159
164
 
160
165
  # Performs a PUT request with the given parameters. See get() for more details.
161
- def put(path, parameters=nil, headers=nil)
166
+ def put(path, parameters = nil, headers = nil)
162
167
  process :put, path, parameters, headers
163
168
  end
164
169
 
165
170
  # Performs a DELETE request with the given parameters. See get() for more details.
166
- def delete(path, parameters=nil, headers=nil)
171
+ def delete(path, parameters = nil, headers = nil)
167
172
  process :delete, path, parameters, headers
168
173
  end
169
174
 
170
175
  # Performs a HEAD request with the given parameters. See get() for more details.
171
- def head(path, parameters=nil, headers=nil)
176
+ def head(path, parameters = nil, headers = nil)
172
177
  process :head, path, parameters, headers
173
178
  end
174
179
 
@@ -179,16 +184,7 @@ module ActionController
179
184
  # parameters are +nil+, a hash, or a url-encoded or multipart string;
180
185
  # the headers are a hash. Keys are automatically upcased and prefixed
181
186
  # with 'HTTP_' if not already.
182
- #
183
- # This method used to omit the request_method parameter, assuming it
184
- # was :post. This was deprecated in Rails 1.2.4. Always pass the request
185
- # method as the first argument.
186
187
  def xml_http_request(request_method, path, parameters = nil, headers = nil)
187
- unless request_method.is_a?(Symbol)
188
- ActiveSupport::Deprecation.warn 'xml_http_request now takes the request_method (:get, :post, etc.) as the first argument. It used to assume :post, so add the :post argument to your existing method calls to silence this warning.'
189
- request_method, path, parameters, headers = :post, request_method, path, parameters
190
- end
191
-
192
188
  headers ||= {}
193
189
  headers['X-Requested-With'] = 'XMLHttpRequest'
194
190
  headers['Accept'] = 'text/javascript, text/html, application/xml, text/xml, */*'
@@ -204,15 +200,16 @@ module ActionController
204
200
  end
205
201
 
206
202
  private
207
- class MockCGI < CGI #:nodoc:
203
+ class StubCGI < CGI #:nodoc:
208
204
  attr_accessor :stdinput, :stdoutput, :env_table
209
205
 
210
- def initialize(env, input=nil)
206
+ def initialize(env, stdinput = nil)
211
207
  self.env_table = env
212
- self.stdinput = StringIO.new(input || "")
213
208
  self.stdoutput = StringIO.new
214
209
 
215
- super()
210
+ super
211
+
212
+ @stdinput = stdinput.is_a?(IO) ? stdinput : StringIO.new(stdinput || '')
216
213
  end
217
214
  end
218
215
 
@@ -226,7 +223,7 @@ module ActionController
226
223
  end
227
224
 
228
225
  # Performs the actual request.
229
- def process(method, path, parameters=nil, headers=nil)
226
+ def process(method, path, parameters = nil, headers = nil)
230
227
  data = requestify(parameters)
231
228
  path = interpret_uri(path) if path =~ %r{://}
232
229
  path = "/#{path}" unless path[0] == ?/
@@ -258,14 +255,15 @@ module ActionController
258
255
  end
259
256
 
260
257
  unless ActionController::Base.respond_to?(:clear_last_instantiation!)
261
- ActionController::Base.send(:include, ControllerCapture)
258
+ ActionController::Base.module_eval { include ControllerCapture }
262
259
  end
263
260
 
264
261
  ActionController::Base.clear_last_instantiation!
265
262
 
266
- cgi = MockCGI.new(env, data)
263
+ cgi = StubCGI.new(env, data)
267
264
  Dispatcher.dispatch(cgi, ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, cgi.stdoutput)
268
265
  @result = cgi.stdoutput.string
266
+ @request_count += 1
269
267
 
270
268
  @controller = ActionController::Base.last_instantiation
271
269
  @request = @controller.request
@@ -294,7 +292,7 @@ module ActionController
294
292
  end
295
293
 
296
294
  (@headers['set-cookie'] || [] ).each do |string|
297
- name, value = string.match(/^(.*?)=(.*?);/)[1,2]
295
+ name, value = string.match(/^([^=]*)=([^;]*);/)[1,2]
298
296
  @cookies[name] = value
299
297
  end
300
298
 
@@ -310,14 +308,14 @@ module ActionController
310
308
  end
311
309
  end
312
310
 
313
- # Get a temporarly URL writer object
311
+ # Get a temporary URL writer object
314
312
  def generic_url_rewriter
315
- cgi = MockCGI.new('REQUEST_METHOD' => "GET",
313
+ cgi = StubCGI.new('REQUEST_METHOD' => "GET",
316
314
  'QUERY_STRING' => "",
317
315
  "REQUEST_URI" => "/",
318
316
  "HTTP_HOST" => host,
319
317
  "SERVER_PORT" => https? ? "443" : "80",
320
- "HTTPS" => https? ? "on" : "off")
318
+ "HTTPS" => https? ? "on" : "off")
321
319
  ActionController::UrlRewriter.new(ActionController::CgiRequest.new(cgi), {})
322
320
  end
323
321
 
@@ -339,7 +337,6 @@ module ActionController
339
337
  "#{CGI.escape(prefix)}=#{CGI.escape(parameters.to_s)}"
340
338
  end
341
339
  end
342
-
343
340
  end
344
341
 
345
342
  # A module used to extend ActionController::Base, so that integration tests
@@ -368,6 +365,76 @@ module ActionController
368
365
  end
369
366
  end
370
367
  end
368
+
369
+ module Runner
370
+ # Reset the current session. This is useful for testing multiple sessions
371
+ # in a single test case.
372
+ def reset!
373
+ @integration_session = open_session
374
+ end
375
+
376
+ %w(get post put head delete cookies assigns
377
+ xml_http_request get_via_redirect post_via_redirect).each do |method|
378
+ define_method(method) do |*args|
379
+ reset! unless @integration_session
380
+ # reset the html_document variable, but only for new get/post calls
381
+ @html_document = nil unless %w(cookies assigns).include?(method)
382
+ returning @integration_session.send!(method, *args) do
383
+ copy_session_variables!
384
+ end
385
+ end
386
+ end
387
+
388
+ # Open a new session instance. If a block is given, the new session is
389
+ # yielded to the block before being returned.
390
+ #
391
+ # session = open_session do |sess|
392
+ # sess.extend(CustomAssertions)
393
+ # end
394
+ #
395
+ # By default, a single session is automatically created for you, but you
396
+ # can use this method to open multiple sessions that ought to be tested
397
+ # simultaneously.
398
+ def open_session
399
+ session = Integration::Session.new
400
+
401
+ # delegate the fixture accessors back to the test instance
402
+ extras = Module.new { attr_accessor :delegate, :test_result }
403
+ if self.class.respond_to?(:fixture_table_names)
404
+ self.class.fixture_table_names.each do |table_name|
405
+ name = table_name.tr(".", "_")
406
+ next unless respond_to?(name)
407
+ extras.send!(:define_method, name) { |*args| delegate.send(name, *args) }
408
+ end
409
+ end
410
+
411
+ # delegate add_assertion to the test case
412
+ extras.send!(:define_method, :add_assertion) { test_result.add_assertion }
413
+ session.extend(extras)
414
+ session.delegate = self
415
+ session.test_result = @_result
416
+
417
+ yield session if block_given?
418
+ session
419
+ end
420
+
421
+ # Copy the instance variables from the current session instance into the
422
+ # test instance.
423
+ def copy_session_variables! #:nodoc:
424
+ return unless @integration_session
425
+ %w(controller response request).each do |var|
426
+ instance_variable_set("@#{var}", @integration_session.send!(var))
427
+ end
428
+ end
429
+
430
+ # Delegate unhandled messages to the current session instance.
431
+ def method_missing(sym, *args, &block)
432
+ reset! unless @integration_session
433
+ returning @integration_session.send!(sym, *args, &block) do
434
+ copy_session_variables!
435
+ end
436
+ end
437
+ end
371
438
  end
372
439
 
373
440
  # An IntegrationTest is one that spans multiple controllers and actions,
@@ -446,6 +513,8 @@ module ActionController
446
513
  # end
447
514
  # end
448
515
  class IntegrationTest < Test::Unit::TestCase
516
+ include Integration::Runner
517
+
449
518
  # Work around a bug in test/unit caused by the default test being named
450
519
  # as a symbol (:default_test), which causes regex test filters
451
520
  # (like "ruby test.rb -n /foo/") to fail because =~ doesn't work on
@@ -493,70 +562,5 @@ module ActionController
493
562
  superclass.use_instantiated_fixtures
494
563
  end
495
564
  end
496
-
497
- # Reset the current session. This is useful for testing multiple sessions
498
- # in a single test case.
499
- def reset!
500
- @integration_session = open_session
501
- end
502
-
503
- %w(get post put head delete cookies assigns xml_http_request).each do |method|
504
- define_method(method) do |*args|
505
- reset! unless @integration_session
506
- # reset the html_document variable, but only for new get/post calls
507
- @html_document = nil unless %w(cookies assigns).include?(method)
508
- returning @integration_session.send(method, *args) do
509
- copy_session_variables!
510
- end
511
- end
512
- end
513
-
514
- # Open a new session instance. If a block is given, the new session is
515
- # yielded to the block before being returned.
516
- #
517
- # session = open_session do |sess|
518
- # sess.extend(CustomAssertions)
519
- # end
520
- #
521
- # By default, a single session is automatically created for you, but you
522
- # can use this method to open multiple sessions that ought to be tested
523
- # simultaneously.
524
- def open_session
525
- session = Integration::Session.new
526
-
527
- # delegate the fixture accessors back to the test instance
528
- extras = Module.new { attr_accessor :delegate, :test_result }
529
- self.class.fixture_table_names.each do |table_name|
530
- name = table_name.tr(".", "_")
531
- next unless respond_to?(name)
532
- extras.send(:define_method, name) { |*args| delegate.send(name, *args) }
533
- end
534
-
535
- # delegate add_assertion to the test case
536
- extras.send(:define_method, :add_assertion) { test_result.add_assertion }
537
- session.extend(extras)
538
- session.delegate = self
539
- session.test_result = @_result
540
-
541
- yield session if block_given?
542
- session
543
- end
544
-
545
- # Copy the instance variables from the current session instance into the
546
- # test instance.
547
- def copy_session_variables! #:nodoc:
548
- return unless @integration_session
549
- %w(controller response request).each do |var|
550
- instance_variable_set("@#{var}", @integration_session.send(var))
551
- end
552
- end
553
-
554
- # Delegate unhandled messages to the current session instance.
555
- def method_missing(sym, *args, &block)
556
- reset! unless @integration_session
557
- returning @integration_session.send(sym, *args, &block) do
558
- copy_session_variables!
559
- end
560
- end
561
565
  end
562
566
  end