actionpack_csi 2.3.5.p6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (429) hide show
  1. data/CHANGELOG +5184 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +409 -0
  4. data/RUNNING_UNIT_TESTS +24 -0
  5. data/Rakefile +160 -0
  6. data/install.rb +30 -0
  7. data/lib/action_controller/assertions/dom_assertions.rb +55 -0
  8. data/lib/action_controller/assertions/model_assertions.rb +21 -0
  9. data/lib/action_controller/assertions/response_assertions.rb +160 -0
  10. data/lib/action_controller/assertions/routing_assertions.rb +146 -0
  11. data/lib/action_controller/assertions/selector_assertions.rb +638 -0
  12. data/lib/action_controller/assertions/tag_assertions.rb +127 -0
  13. data/lib/action_controller/base.rb +1423 -0
  14. data/lib/action_controller/benchmarking.rb +107 -0
  15. data/lib/action_controller/caching/actions.rb +177 -0
  16. data/lib/action_controller/caching/fragments.rb +120 -0
  17. data/lib/action_controller/caching/pages.rb +152 -0
  18. data/lib/action_controller/caching/sweeper.rb +45 -0
  19. data/lib/action_controller/caching/sweeping.rb +55 -0
  20. data/lib/action_controller/caching.rb +71 -0
  21. data/lib/action_controller/cgi_ext/cookie.rb +112 -0
  22. data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
  23. data/lib/action_controller/cgi_ext/stdinput.rb +24 -0
  24. data/lib/action_controller/cgi_ext.rb +15 -0
  25. data/lib/action_controller/cgi_process.rb +77 -0
  26. data/lib/action_controller/cookies.rb +95 -0
  27. data/lib/action_controller/dispatcher.rb +133 -0
  28. data/lib/action_controller/failsafe.rb +86 -0
  29. data/lib/action_controller/filters.rb +680 -0
  30. data/lib/action_controller/flash.rb +171 -0
  31. data/lib/action_controller/headers.rb +33 -0
  32. data/lib/action_controller/helpers.rb +225 -0
  33. data/lib/action_controller/http_authentication.rb +309 -0
  34. data/lib/action_controller/integration.rb +692 -0
  35. data/lib/action_controller/layout.rb +286 -0
  36. data/lib/action_controller/middleware_stack.rb +119 -0
  37. data/lib/action_controller/middlewares.rb +14 -0
  38. data/lib/action_controller/mime_responds.rb +193 -0
  39. data/lib/action_controller/mime_type.rb +212 -0
  40. data/lib/action_controller/mime_types.rb +21 -0
  41. data/lib/action_controller/params_parser.rb +77 -0
  42. data/lib/action_controller/performance_test.rb +15 -0
  43. data/lib/action_controller/polymorphic_routes.rb +189 -0
  44. data/lib/action_controller/rack_lint_patch.rb +36 -0
  45. data/lib/action_controller/record_identifier.rb +104 -0
  46. data/lib/action_controller/reloader.rb +54 -0
  47. data/lib/action_controller/request.rb +493 -0
  48. data/lib/action_controller/request_forgery_protection.rb +113 -0
  49. data/lib/action_controller/rescue.rb +183 -0
  50. data/lib/action_controller/resources.rb +682 -0
  51. data/lib/action_controller/response.rb +239 -0
  52. data/lib/action_controller/routing/builder.rb +197 -0
  53. data/lib/action_controller/routing/optimisations.rb +130 -0
  54. data/lib/action_controller/routing/recognition_optimisation.rb +167 -0
  55. data/lib/action_controller/routing/route.rb +265 -0
  56. data/lib/action_controller/routing/route_set.rb +502 -0
  57. data/lib/action_controller/routing/routing_ext.rb +49 -0
  58. data/lib/action_controller/routing/segments.rb +343 -0
  59. data/lib/action_controller/routing.rb +388 -0
  60. data/lib/action_controller/session/abstract_store.rb +181 -0
  61. data/lib/action_controller/session/cookie_store.rb +221 -0
  62. data/lib/action_controller/session/mem_cache_store.rb +51 -0
  63. data/lib/action_controller/session_management.rb +54 -0
  64. data/lib/action_controller/status_codes.rb +88 -0
  65. data/lib/action_controller/streaming.rb +181 -0
  66. data/lib/action_controller/string_coercion.rb +29 -0
  67. data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
  68. data/lib/action_controller/templates/rescues/_trace.erb +26 -0
  69. data/lib/action_controller/templates/rescues/diagnostics.erb +11 -0
  70. data/lib/action_controller/templates/rescues/layout.erb +29 -0
  71. data/lib/action_controller/templates/rescues/missing_template.erb +2 -0
  72. data/lib/action_controller/templates/rescues/routing_error.erb +10 -0
  73. data/lib/action_controller/templates/rescues/template_error.erb +21 -0
  74. data/lib/action_controller/templates/rescues/unknown_action.erb +2 -0
  75. data/lib/action_controller/test_case.rb +209 -0
  76. data/lib/action_controller/test_process.rb +580 -0
  77. data/lib/action_controller/translation.rb +13 -0
  78. data/lib/action_controller/uploaded_file.rb +44 -0
  79. data/lib/action_controller/url_rewriter.rb +216 -0
  80. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  81. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  82. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
  83. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  84. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  85. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  86. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  87. data/lib/action_controller/verification.rb +130 -0
  88. data/lib/action_controller.rb +113 -0
  89. data/lib/action_pack/version.rb +9 -0
  90. data/lib/action_pack.rb +24 -0
  91. data/lib/action_view/base.rb +362 -0
  92. data/lib/action_view/erb/util.rb +44 -0
  93. data/lib/action_view/helpers/active_record_helper.rb +305 -0
  94. data/lib/action_view/helpers/asset_tag_helper.rb +694 -0
  95. data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
  96. data/lib/action_view/helpers/benchmark_helper.rb +54 -0
  97. data/lib/action_view/helpers/cache_helper.rb +39 -0
  98. data/lib/action_view/helpers/capture_helper.rb +136 -0
  99. data/lib/action_view/helpers/date_helper.rb +988 -0
  100. data/lib/action_view/helpers/debug_helper.rb +38 -0
  101. data/lib/action_view/helpers/form_helper.rb +1074 -0
  102. data/lib/action_view/helpers/form_options_helper.rb +600 -0
  103. data/lib/action_view/helpers/form_tag_helper.rb +487 -0
  104. data/lib/action_view/helpers/javascript_helper.rb +208 -0
  105. data/lib/action_view/helpers/number_helper.rb +308 -0
  106. data/lib/action_view/helpers/prototype_helper.rb +1305 -0
  107. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  108. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  109. data/lib/action_view/helpers/record_tag_helper.rb +58 -0
  110. data/lib/action_view/helpers/sanitize_helper.rb +259 -0
  111. data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
  112. data/lib/action_view/helpers/tag_helper.rb +150 -0
  113. data/lib/action_view/helpers/text_helper.rb +587 -0
  114. data/lib/action_view/helpers/translation_helper.rb +39 -0
  115. data/lib/action_view/helpers/url_helper.rb +639 -0
  116. data/lib/action_view/helpers.rb +59 -0
  117. data/lib/action_view/inline_template.rb +19 -0
  118. data/lib/action_view/locale/en.yml +117 -0
  119. data/lib/action_view/partials.rb +240 -0
  120. data/lib/action_view/paths.rb +69 -0
  121. data/lib/action_view/reloadable_template.rb +117 -0
  122. data/lib/action_view/renderable.rb +95 -0
  123. data/lib/action_view/renderable_partial.rb +47 -0
  124. data/lib/action_view/safe_buffer.rb +28 -0
  125. data/lib/action_view/template.rb +252 -0
  126. data/lib/action_view/template_error.rb +99 -0
  127. data/lib/action_view/template_handler.rb +34 -0
  128. data/lib/action_view/template_handlers/builder.rb +17 -0
  129. data/lib/action_view/template_handlers/erb.rb +22 -0
  130. data/lib/action_view/template_handlers/rjs.rb +13 -0
  131. data/lib/action_view/template_handlers.rb +48 -0
  132. data/lib/action_view/test_case.rb +162 -0
  133. data/lib/action_view.rb +58 -0
  134. data/lib/actionpack.rb +2 -0
  135. data/test/abstract_unit.rb +61 -0
  136. data/test/active_record_unit.rb +104 -0
  137. data/test/activerecord/active_record_store_test.rb +174 -0
  138. data/test/activerecord/render_partial_with_record_identification_test.rb +188 -0
  139. data/test/adv_attr_test.rb +20 -0
  140. data/test/controller/action_pack_assertions_test.rb +543 -0
  141. data/test/controller/addresses_render_test.rb +37 -0
  142. data/test/controller/assert_select_test.rb +734 -0
  143. data/test/controller/base_test.rb +217 -0
  144. data/test/controller/benchmark_test.rb +32 -0
  145. data/test/controller/caching_test.rb +729 -0
  146. data/test/controller/capture_test.rb +66 -0
  147. data/test/controller/content_type_test.rb +168 -0
  148. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  149. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  150. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  151. data/test/controller/cookie_test.rb +134 -0
  152. data/test/controller/deprecation/deprecated_base_methods_test.rb +32 -0
  153. data/test/controller/dispatcher_test.rb +144 -0
  154. data/test/controller/dom_assertions_test.rb +53 -0
  155. data/test/controller/failsafe_test.rb +60 -0
  156. data/test/controller/fake_controllers.rb +33 -0
  157. data/test/controller/fake_models.rb +19 -0
  158. data/test/controller/filter_params_test.rb +52 -0
  159. data/test/controller/filters_test.rb +885 -0
  160. data/test/controller/flash_test.rb +147 -0
  161. data/test/controller/header_test.rb +14 -0
  162. data/test/controller/helper_test.rb +224 -0
  163. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  164. data/test/controller/html-scanner/document_test.rb +148 -0
  165. data/test/controller/html-scanner/node_test.rb +89 -0
  166. data/test/controller/html-scanner/sanitizer_test.rb +274 -0
  167. data/test/controller/html-scanner/tag_node_test.rb +238 -0
  168. data/test/controller/html-scanner/text_node_test.rb +50 -0
  169. data/test/controller/html-scanner/tokenizer_test.rb +131 -0
  170. data/test/controller/http_basic_authentication_test.rb +113 -0
  171. data/test/controller/http_digest_authentication_test.rb +254 -0
  172. data/test/controller/integration_test.rb +483 -0
  173. data/test/controller/layout_test.rb +215 -0
  174. data/test/controller/logging_test.rb +46 -0
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +536 -0
  177. data/test/controller/mime_type_test.rb +93 -0
  178. data/test/controller/polymorphic_routes_test.rb +297 -0
  179. data/test/controller/rack_test.rb +311 -0
  180. data/test/controller/record_identifier_test.rb +139 -0
  181. data/test/controller/redirect_test.rb +285 -0
  182. data/test/controller/reloader_test.rb +124 -0
  183. data/test/controller/render_test.rb +1762 -0
  184. data/test/controller/request/json_params_parsing_test.rb +65 -0
  185. data/test/controller/request/multipart_params_parsing_test.rb +162 -0
  186. data/test/controller/request/query_string_parsing_test.rb +120 -0
  187. data/test/controller/request/test_request_test.rb +35 -0
  188. data/test/controller/request/url_encoded_params_parsing_test.rb +146 -0
  189. data/test/controller/request/xml_params_parsing_test.rb +103 -0
  190. data/test/controller/request_forgery_protection_test.rb +265 -0
  191. data/test/controller/request_test.rb +395 -0
  192. data/test/controller/rescue_test.rb +536 -0
  193. data/test/controller/resources_test.rb +1393 -0
  194. data/test/controller/routing_test.rb +2591 -0
  195. data/test/controller/selector_test.rb +628 -0
  196. data/test/controller/send_file_test.rb +171 -0
  197. data/test/controller/session/cookie_store_test.rb +216 -0
  198. data/test/controller/session/mem_cache_store_test.rb +127 -0
  199. data/test/controller/session/test_session_test.rb +58 -0
  200. data/test/controller/test_test.rb +700 -0
  201. data/test/controller/translation_test.rb +26 -0
  202. data/test/controller/url_rewriter_test.rb +385 -0
  203. data/test/controller/verification_test.rb +270 -0
  204. data/test/controller/view_paths_test.rb +141 -0
  205. data/test/controller/webservice_test.rb +273 -0
  206. data/test/fixtures/_top_level_partial.html.erb +1 -0
  207. data/test/fixtures/_top_level_partial_only.erb +1 -0
  208. data/test/fixtures/addresses/list.erb +1 -0
  209. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  210. data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
  211. data/test/fixtures/companies.yml +24 -0
  212. data/test/fixtures/company.rb +10 -0
  213. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
  214. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
  215. data/test/fixtures/content_type/render_default_for_rjs.rjs +1 -0
  216. data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
  217. data/test/fixtures/customers/_customer.html.erb +1 -0
  218. data/test/fixtures/db_definitions/sqlite.sql +49 -0
  219. data/test/fixtures/developer.rb +9 -0
  220. data/test/fixtures/developers/_developer.erb +1 -0
  221. data/test/fixtures/developers.yml +21 -0
  222. data/test/fixtures/developers_projects.yml +13 -0
  223. data/test/fixtures/failsafe/500.html +1 -0
  224. data/test/fixtures/fun/games/_game.erb +1 -0
  225. data/test/fixtures/fun/games/hello_world.erb +1 -0
  226. data/test/fixtures/fun/serious/games/_game.erb +1 -0
  227. data/test/fixtures/functional_caching/_partial.erb +3 -0
  228. data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
  229. data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
  230. data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
  231. data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
  232. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
  233. data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
  234. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
  235. data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
  236. data/test/fixtures/helpers/abc_helper.rb +5 -0
  237. data/test/fixtures/helpers/fun/games_helper.rb +3 -0
  238. data/test/fixtures/helpers/fun/pdf_helper.rb +3 -0
  239. data/test/fixtures/layout_tests/abs_path_layout.rhtml +1 -0
  240. data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
  241. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  242. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  243. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  244. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  245. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
  246. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  247. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  248. data/test/fixtures/layouts/_column.html.erb +2 -0
  249. data/test/fixtures/layouts/block_with_layout.erb +3 -0
  250. data/test/fixtures/layouts/builder.builder +3 -0
  251. data/test/fixtures/layouts/default_html.html.erb +1 -0
  252. data/test/fixtures/layouts/partial_with_layout.erb +3 -0
  253. data/test/fixtures/layouts/standard.erb +1 -0
  254. data/test/fixtures/layouts/talk_from_action.erb +2 -0
  255. data/test/fixtures/layouts/xhr.html.erb +2 -0
  256. data/test/fixtures/layouts/yield.erb +2 -0
  257. data/test/fixtures/mascot.rb +3 -0
  258. data/test/fixtures/mascots/_mascot.html.erb +1 -0
  259. data/test/fixtures/mascots.yml +4 -0
  260. data/test/fixtures/multipart/binary_file +0 -0
  261. data/test/fixtures/multipart/boundary_problem_file +10 -0
  262. data/test/fixtures/multipart/bracketed_param +5 -0
  263. data/test/fixtures/multipart/empty +10 -0
  264. data/test/fixtures/multipart/hello.txt +1 -0
  265. data/test/fixtures/multipart/large_text_file +10 -0
  266. data/test/fixtures/multipart/mixed_files +0 -0
  267. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  268. data/test/fixtures/multipart/none +9 -0
  269. data/test/fixtures/multipart/single_parameter +5 -0
  270. data/test/fixtures/multipart/text_file +10 -0
  271. data/test/fixtures/override/test/hello_world.erb +1 -0
  272. data/test/fixtures/override2/layouts/test/sub.erb +1 -0
  273. data/test/fixtures/post_test/layouts/post.html.erb +1 -0
  274. data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
  275. data/test/fixtures/post_test/post/index.html.erb +1 -0
  276. data/test/fixtures/post_test/post/index.iphone.erb +1 -0
  277. data/test/fixtures/post_test/super_post/index.html.erb +1 -0
  278. data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
  279. data/test/fixtures/project.rb +3 -0
  280. data/test/fixtures/projects/_project.erb +1 -0
  281. data/test/fixtures/projects.yml +7 -0
  282. data/test/fixtures/public/404.html +1 -0
  283. data/test/fixtures/public/500.da.html +1 -0
  284. data/test/fixtures/public/500.html +1 -0
  285. data/test/fixtures/public/absolute/test.css +23 -0
  286. data/test/fixtures/public/absolute/test.js +63 -0
  287. data/test/fixtures/public/images/rails.png +0 -0
  288. data/test/fixtures/public/javascripts/application.js +1 -0
  289. data/test/fixtures/public/javascripts/bank.js +1 -0
  290. data/test/fixtures/public/javascripts/controls.js +1 -0
  291. data/test/fixtures/public/javascripts/dragdrop.js +1 -0
  292. data/test/fixtures/public/javascripts/effects.js +1 -0
  293. data/test/fixtures/public/javascripts/prototype.js +1 -0
  294. data/test/fixtures/public/javascripts/robber.js +1 -0
  295. data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
  296. data/test/fixtures/public/javascripts/version.1.0.js +1 -0
  297. data/test/fixtures/public/stylesheets/bank.css +1 -0
  298. data/test/fixtures/public/stylesheets/robber.css +1 -0
  299. data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
  300. data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
  301. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  302. data/test/fixtures/replies/_reply.erb +1 -0
  303. data/test/fixtures/replies.yml +15 -0
  304. data/test/fixtures/reply.rb +7 -0
  305. data/test/fixtures/respond_to/all_types_with_layout.html.erb +1 -0
  306. data/test/fixtures/respond_to/all_types_with_layout.js.rjs +1 -0
  307. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
  308. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
  309. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
  310. data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
  311. data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
  312. data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
  313. data/test/fixtures/respond_to/using_defaults.html.erb +1 -0
  314. data/test/fixtures/respond_to/using_defaults.js.rjs +1 -0
  315. data/test/fixtures/respond_to/using_defaults.xml.builder +1 -0
  316. data/test/fixtures/respond_to/using_defaults_with_type_list.html.erb +1 -0
  317. data/test/fixtures/respond_to/using_defaults_with_type_list.js.rjs +1 -0
  318. data/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder +1 -0
  319. data/test/fixtures/scope/test/modgreet.erb +1 -0
  320. data/test/fixtures/shared.html.erb +1 -0
  321. data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
  322. data/test/fixtures/test/_counter.html.erb +1 -0
  323. data/test/fixtures/test/_customer.erb +1 -0
  324. data/test/fixtures/test/_customer_counter.erb +1 -0
  325. data/test/fixtures/test/_customer_greeting.erb +1 -0
  326. data/test/fixtures/test/_customer_with_var.erb +1 -0
  327. data/test/fixtures/test/_form.erb +1 -0
  328. data/test/fixtures/test/_from_helper.erb +1 -0
  329. data/test/fixtures/test/_hash_greeting.erb +1 -0
  330. data/test/fixtures/test/_hash_object.erb +2 -0
  331. data/test/fixtures/test/_hello.builder +1 -0
  332. data/test/fixtures/test/_labelling_form.erb +1 -0
  333. data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
  334. data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
  335. data/test/fixtures/test/_local_inspector.html.erb +1 -0
  336. data/test/fixtures/test/_one.html.erb +1 -0
  337. data/test/fixtures/test/_partial.erb +1 -0
  338. data/test/fixtures/test/_partial.html.erb +1 -0
  339. data/test/fixtures/test/_partial.js.erb +1 -0
  340. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
  341. data/test/fixtures/test/_partial_only.erb +1 -0
  342. data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
  343. data/test/fixtures/test/_person.erb +2 -0
  344. data/test/fixtures/test/_raise.html.erb +1 -0
  345. data/test/fixtures/test/_two.html.erb +1 -0
  346. data/test/fixtures/test/action_talk_to_layout.erb +2 -0
  347. data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
  348. data/test/fixtures/test/capturing.erb +4 -0
  349. data/test/fixtures/test/content_for.erb +2 -0
  350. data/test/fixtures/test/content_for_concatenated.erb +3 -0
  351. data/test/fixtures/test/content_for_with_parameter.erb +2 -0
  352. data/test/fixtures/test/delete_with_js.rjs +2 -0
  353. data/test/fixtures/test/dont_pick_me +1 -0
  354. data/test/fixtures/test/dot.directory/render_file_with_ivar.erb +1 -0
  355. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  356. data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
  357. data/test/fixtures/test/formatted_xml_erb.builder +1 -0
  358. data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
  359. data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
  360. data/test/fixtures/test/greeting.erb +1 -0
  361. data/test/fixtures/test/greeting.js.rjs +1 -0
  362. data/test/fixtures/test/hello.builder +4 -0
  363. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  364. data/test/fixtures/test/hello_world.erb +1 -0
  365. data/test/fixtures/test/hello_world.erb~ +1 -0
  366. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  367. data/test/fixtures/test/hello_world_container.builder +3 -0
  368. data/test/fixtures/test/hello_world_from_rxml.builder +4 -0
  369. data/test/fixtures/test/hello_world_with_layout_false.erb +1 -0
  370. data/test/fixtures/test/hello_xml_world.builder +11 -0
  371. data/test/fixtures/test/hyphen-ated.erb +1 -0
  372. data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
  373. data/test/fixtures/test/list.erb +1 -0
  374. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  375. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  376. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  377. data/test/fixtures/test/nested_layout.erb +3 -0
  378. data/test/fixtures/test/non_erb_block_content_for.builder +4 -0
  379. data/test/fixtures/test/potential_conflicts.erb +4 -0
  380. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  381. data/test/fixtures/test/render_file_from_template.html.erb +1 -0
  382. data/test/fixtures/test/render_file_with_ivar.erb +1 -0
  383. data/test/fixtures/test/render_file_with_locals.erb +1 -0
  384. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  385. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  386. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  387. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  388. data/test/fixtures/test/render_to_string_test.erb +1 -0
  389. data/test/fixtures/test/sub_template_raise.html.erb +1 -0
  390. data/test/fixtures/test/template.erb +1 -0
  391. data/test/fixtures/test/update_element_with_capture.erb +9 -0
  392. data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
  393. data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
  394. data/test/fixtures/test/utf8.html.erb +2 -0
  395. data/test/fixtures/topic.rb +3 -0
  396. data/test/fixtures/topics/_topic.html.erb +1 -0
  397. data/test/fixtures/topics.yml +22 -0
  398. data/test/template/active_record_helper_i18n_test.rb +44 -0
  399. data/test/template/active_record_helper_test.rb +302 -0
  400. data/test/template/asset_tag_helper_test.rb +771 -0
  401. data/test/template/atom_feed_helper_test.rb +315 -0
  402. data/test/template/benchmark_helper_test.rb +86 -0
  403. data/test/template/compiled_templates_test.rb +204 -0
  404. data/test/template/date_helper_i18n_test.rb +121 -0
  405. data/test/template/date_helper_test.rb +2485 -0
  406. data/test/template/erb_util_test.rb +24 -0
  407. data/test/template/form_helper_test.rb +1393 -0
  408. data/test/template/form_options_helper_i18n_test.rb +27 -0
  409. data/test/template/form_options_helper_test.rb +807 -0
  410. data/test/template/form_tag_helper_test.rb +344 -0
  411. data/test/template/javascript_helper_test.rb +106 -0
  412. data/test/template/number_helper_i18n_test.rb +69 -0
  413. data/test/template/number_helper_test.rb +132 -0
  414. data/test/template/prototype_helper_test.rb +639 -0
  415. data/test/template/raw_output_helper_test.rb +21 -0
  416. data/test/template/record_tag_helper_test.rb +58 -0
  417. data/test/template/render_test.rb +290 -0
  418. data/test/template/sanitize_helper_test.rb +57 -0
  419. data/test/template/scriptaculous_helper_test.rb +90 -0
  420. data/test/template/tag_helper_test.rb +98 -0
  421. data/test/template/template_test.rb +32 -0
  422. data/test/template/test_test.rb +54 -0
  423. data/test/template/text_helper_test.rb +543 -0
  424. data/test/template/translation_helper_test.rb +32 -0
  425. data/test/template/url_helper_test.rb +622 -0
  426. data/test/testing_sandbox.rb +15 -0
  427. data/test/view/safe_buffer_test.rb +36 -0
  428. data/test/view/test_case_test.rb +176 -0
  429. metadata +531 -0
@@ -0,0 +1,680 @@
1
+ module ActionController #:nodoc:
2
+ module Filters #:nodoc:
3
+ def self.included(base)
4
+ base.class_eval do
5
+ extend ClassMethods
6
+ include ActionController::Filters::InstanceMethods
7
+ end
8
+ end
9
+
10
+ class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
11
+ def append_filter_to_chain(filters, filter_type, &block)
12
+ pos = find_filter_append_position(filters, filter_type)
13
+ update_filter_chain(filters, filter_type, pos, &block)
14
+ end
15
+
16
+ def prepend_filter_to_chain(filters, filter_type, &block)
17
+ pos = find_filter_prepend_position(filters, filter_type)
18
+ update_filter_chain(filters, filter_type, pos, &block)
19
+ end
20
+
21
+ def create_filters(filters, filter_type, &block)
22
+ filters, conditions = extract_options(filters, &block)
23
+ filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
24
+ filters
25
+ end
26
+
27
+ def skip_filter_in_chain(*filters, &test)
28
+ filters, conditions = extract_options(filters)
29
+ filters.each do |filter|
30
+ if callback = find(filter) then delete(callback) end
31
+ end if conditions.empty?
32
+ update_filter_in_chain(filters, :skip => conditions, &test)
33
+ end
34
+
35
+ private
36
+ def update_filter_chain(filters, filter_type, pos, &block)
37
+ new_filters = create_filters(filters, filter_type, &block)
38
+ insert(pos, new_filters).flatten!
39
+ end
40
+
41
+ def find_filter_append_position(filters, filter_type)
42
+ # appending an after filter puts it at the end of the call chain
43
+ # before and around filters go before the first after filter in the chain
44
+ unless filter_type == :after
45
+ each_with_index do |f,i|
46
+ return i if f.after?
47
+ end
48
+ end
49
+ return -1
50
+ end
51
+
52
+ def find_filter_prepend_position(filters, filter_type)
53
+ # prepending a before or around filter puts it at the front of the call chain
54
+ # after filters go before the first after filter in the chain
55
+ if filter_type == :after
56
+ each_with_index do |f,i|
57
+ return i if f.after?
58
+ end
59
+ return -1
60
+ end
61
+ return 0
62
+ end
63
+
64
+ def find_or_create_filter(filter, filter_type, options = {})
65
+ update_filter_in_chain([filter], options)
66
+
67
+ if found_filter = find(filter) { |f| f.type == filter_type }
68
+ found_filter
69
+ else
70
+ filter_kind = case
71
+ when filter.respond_to?(:before) && filter_type == :before
72
+ :before
73
+ when filter.respond_to?(:after) && filter_type == :after
74
+ :after
75
+ else
76
+ :filter
77
+ end
78
+
79
+ case filter_type
80
+ when :before
81
+ BeforeFilter.new(filter_kind, filter, options)
82
+ when :after
83
+ AfterFilter.new(filter_kind, filter, options)
84
+ else
85
+ AroundFilter.new(filter_kind, filter, options)
86
+ end
87
+ end
88
+ end
89
+
90
+ def update_filter_in_chain(filters, options, &test)
91
+ filters.map! { |f| block_given? ? find(f, &test) : find(f) }
92
+ filters.compact!
93
+
94
+ map! do |filter|
95
+ if filters.include?(filter)
96
+ new_filter = filter.dup
97
+ new_filter.update_options!(options)
98
+ new_filter
99
+ else
100
+ filter
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
107
+ def initialize(kind, method, options = {})
108
+ super
109
+ update_options! options
110
+ end
111
+
112
+ # override these to return true in appropriate subclass
113
+ def before?
114
+ false
115
+ end
116
+
117
+ def after?
118
+ false
119
+ end
120
+
121
+ def around?
122
+ false
123
+ end
124
+
125
+ # Make sets of strings from :only/:except options
126
+ def update_options!(other)
127
+ if other
128
+ convert_only_and_except_options_to_sets_of_strings(other)
129
+ if other[:skip]
130
+ convert_only_and_except_options_to_sets_of_strings(other[:skip])
131
+ end
132
+ end
133
+
134
+ options.update(other)
135
+ end
136
+
137
+ private
138
+ def should_not_skip?(controller)
139
+ if options[:skip]
140
+ !included_in_action?(controller, options[:skip])
141
+ else
142
+ true
143
+ end
144
+ end
145
+
146
+ def included_in_action?(controller, options)
147
+ if options[:only]
148
+ options[:only].include?(controller.action_name)
149
+ elsif options[:except]
150
+ !options[:except].include?(controller.action_name)
151
+ else
152
+ true
153
+ end
154
+ end
155
+
156
+ def should_run_callback?(controller)
157
+ should_not_skip?(controller) && included_in_action?(controller, options) && super
158
+ end
159
+
160
+ def convert_only_and_except_options_to_sets_of_strings(opts)
161
+ [:only, :except].each do |key|
162
+ if values = opts[key]
163
+ opts[key] = Array(values).map(&:to_s).to_set
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ class AroundFilter < Filter #:nodoc:
170
+ def type
171
+ :around
172
+ end
173
+
174
+ def around?
175
+ true
176
+ end
177
+
178
+ def call(controller, &block)
179
+ if should_run_callback?(controller)
180
+ method = filter_responds_to_before_and_after? ? around_proc : self.method
181
+
182
+ # For around_filter do |controller, action|
183
+ if method.is_a?(Proc) && method.arity == 2
184
+ evaluate_method(method, controller, block)
185
+ else
186
+ evaluate_method(method, controller, &block)
187
+ end
188
+ else
189
+ block.call
190
+ end
191
+ end
192
+
193
+ private
194
+ def filter_responds_to_before_and_after?
195
+ method.respond_to?(:before) && method.respond_to?(:after)
196
+ end
197
+
198
+ def around_proc
199
+ Proc.new do |controller, action|
200
+ method.before(controller)
201
+
202
+ if controller.__send__(:performed?)
203
+ controller.__send__(:halt_filter_chain, method, :rendered_or_redirected)
204
+ else
205
+ begin
206
+ action.call
207
+ ensure
208
+ method.after(controller)
209
+ end
210
+ end
211
+ end
212
+ end
213
+ end
214
+
215
+ class BeforeFilter < Filter #:nodoc:
216
+ def type
217
+ :before
218
+ end
219
+
220
+ def before?
221
+ true
222
+ end
223
+
224
+ def call(controller, &block)
225
+ super
226
+ if controller.__send__(:performed?)
227
+ controller.__send__(:halt_filter_chain, method, :rendered_or_redirected)
228
+ end
229
+ end
230
+ end
231
+
232
+ class AfterFilter < Filter #:nodoc:
233
+ def type
234
+ :after
235
+ end
236
+
237
+ def after?
238
+ true
239
+ end
240
+ end
241
+
242
+ # Filters enable controllers to run shared pre- and post-processing code for its actions. These filters can be used to do
243
+ # authentication, caching, or auditing before the intended action is performed. Or to do localization or output
244
+ # compression after the action has been performed. Filters have access to the request, response, and all the instance
245
+ # variables set by other filters in the chain or by the action (in the case of after filters).
246
+ #
247
+ # == Filter inheritance
248
+ #
249
+ # Controller inheritance hierarchies share filters downwards, but subclasses can also add or skip filters without
250
+ # affecting the superclass. For example:
251
+ #
252
+ # class BankController < ActionController::Base
253
+ # before_filter :audit
254
+ #
255
+ # private
256
+ # def audit
257
+ # # record the action and parameters in an audit log
258
+ # end
259
+ # end
260
+ #
261
+ # class VaultController < BankController
262
+ # before_filter :verify_credentials
263
+ #
264
+ # private
265
+ # def verify_credentials
266
+ # # make sure the user is allowed into the vault
267
+ # end
268
+ # end
269
+ #
270
+ # Now any actions performed on the BankController will have the audit method called before. On the VaultController,
271
+ # first the audit method is called, then the verify_credentials method. If the audit method renders or redirects, then
272
+ # verify_credentials and the intended action are never called.
273
+ #
274
+ # == Filter types
275
+ #
276
+ # A filter can take one of three forms: method reference (symbol), external class, or inline method (proc). The first
277
+ # is the most common and works by referencing a protected or private method somewhere in the inheritance hierarchy of
278
+ # the controller by use of a symbol. In the bank example above, both BankController and VaultController use this form.
279
+ #
280
+ # Using an external class makes for more easily reused generic filters, such as output compression. External filter classes
281
+ # are implemented by having a static +filter+ method on any class and then passing this class to the filter method. Example:
282
+ #
283
+ # class OutputCompressionFilter
284
+ # def self.filter(controller)
285
+ # controller.response.body = compress(controller.response.body)
286
+ # end
287
+ # end
288
+ #
289
+ # class NewspaperController < ActionController::Base
290
+ # after_filter OutputCompressionFilter
291
+ # end
292
+ #
293
+ # The filter method is passed the controller instance and is hence granted access to all aspects of the controller and can
294
+ # manipulate them as it sees fit.
295
+ #
296
+ # The inline method (using a proc) can be used to quickly do something small that doesn't require a lot of explanation.
297
+ # Or just as a quick test. It works like this:
298
+ #
299
+ # class WeblogController < ActionController::Base
300
+ # before_filter { |controller| head(400) if controller.params["stop_action"] }
301
+ # end
302
+ #
303
+ # As you can see, the block expects to be passed the controller after it has assigned the request to the internal variables.
304
+ # This means that the block has access to both the request and response objects complete with convenience methods for params,
305
+ # session, template, and assigns. Note: The inline method doesn't strictly have to be a block; any object that responds to call
306
+ # and returns 1 or -1 on arity will do (such as a Proc or an Method object).
307
+ #
308
+ # Please note that around_filters function a little differently than the normal before and after filters with regard to filter
309
+ # types. Please see the section dedicated to around_filters below.
310
+ #
311
+ # == Filter chain ordering
312
+ #
313
+ # Using <tt>before_filter</tt> and <tt>after_filter</tt> appends the specified filters to the existing chain. That's usually
314
+ # just fine, but some times you care more about the order in which the filters are executed. When that's the case, you
315
+ # can use <tt>prepend_before_filter</tt> and <tt>prepend_after_filter</tt>. Filters added by these methods will be put at the
316
+ # beginning of their respective chain and executed before the rest. For example:
317
+ #
318
+ # class ShoppingController < ActionController::Base
319
+ # before_filter :verify_open_shop
320
+ #
321
+ # class CheckoutController < ShoppingController
322
+ # prepend_before_filter :ensure_items_in_cart, :ensure_items_in_stock
323
+ #
324
+ # The filter chain for the CheckoutController is now <tt>:ensure_items_in_cart, :ensure_items_in_stock,</tt>
325
+ # <tt>:verify_open_shop</tt>. So if either of the ensure filters renders or redirects, we'll never get around to see if the shop
326
+ # is open or not.
327
+ #
328
+ # You may pass multiple filter arguments of each type as well as a filter block.
329
+ # If a block is given, it is treated as the last argument.
330
+ #
331
+ # == Around filters
332
+ #
333
+ # Around filters wrap an action, executing code both before and after.
334
+ # They may be declared as method references, blocks, or objects responding
335
+ # to +filter+ or to both +before+ and +after+.
336
+ #
337
+ # To use a method as an +around_filter+, pass a symbol naming the Ruby method.
338
+ # Yield (or <tt>block.call</tt>) within the method to run the action.
339
+ #
340
+ # around_filter :catch_exceptions
341
+ #
342
+ # private
343
+ # def catch_exceptions
344
+ # yield
345
+ # rescue => exception
346
+ # logger.debug "Caught exception! #{exception}"
347
+ # raise
348
+ # end
349
+ #
350
+ # To use a block as an +around_filter+, pass a block taking as args both
351
+ # the controller and the action block. You can't call yield directly from
352
+ # an +around_filter+ block; explicitly call the action block instead:
353
+ #
354
+ # around_filter do |controller, action|
355
+ # logger.debug "before #{controller.action_name}"
356
+ # action.call
357
+ # logger.debug "after #{controller.action_name}"
358
+ # end
359
+ #
360
+ # To use a filter object with +around_filter+, pass an object responding
361
+ # to <tt>:filter</tt> or both <tt>:before</tt> and <tt>:after</tt>. With a
362
+ # filter method, yield to the block as above:
363
+ #
364
+ # around_filter BenchmarkingFilter
365
+ #
366
+ # class BenchmarkingFilter
367
+ # def self.filter(controller, &block)
368
+ # Benchmark.measure(&block)
369
+ # end
370
+ # end
371
+ #
372
+ # With +before+ and +after+ methods:
373
+ #
374
+ # around_filter Authorizer.new
375
+ #
376
+ # class Authorizer
377
+ # # This will run before the action. Redirecting aborts the action.
378
+ # def before(controller)
379
+ # unless user.authorized?
380
+ # redirect_to(login_url)
381
+ # end
382
+ # end
383
+ #
384
+ # # This will run after the action if and only if before did not render or redirect.
385
+ # def after(controller)
386
+ # end
387
+ # end
388
+ #
389
+ # If the filter has +before+ and +after+ methods, the +before+ method will be
390
+ # called before the action. If +before+ renders or redirects, the filter chain is
391
+ # halted and +after+ will not be run. See Filter Chain Halting below for
392
+ # an example.
393
+ #
394
+ # == Filter chain skipping
395
+ #
396
+ # Declaring a filter on a base class conveniently applies to its subclasses,
397
+ # but sometimes a subclass should skip some of its superclass' filters:
398
+ #
399
+ # class ApplicationController < ActionController::Base
400
+ # before_filter :authenticate
401
+ # around_filter :catch_exceptions
402
+ # end
403
+ #
404
+ # class WeblogController < ApplicationController
405
+ # # Will run the :authenticate and :catch_exceptions filters.
406
+ # end
407
+ #
408
+ # class SignupController < ApplicationController
409
+ # # Skip :authenticate, run :catch_exceptions.
410
+ # skip_before_filter :authenticate
411
+ # end
412
+ #
413
+ # class ProjectsController < ApplicationController
414
+ # # Skip :catch_exceptions, run :authenticate.
415
+ # skip_filter :catch_exceptions
416
+ # end
417
+ #
418
+ # class ClientsController < ApplicationController
419
+ # # Skip :catch_exceptions and :authenticate unless action is index.
420
+ # skip_filter :catch_exceptions, :authenticate, :except => :index
421
+ # end
422
+ #
423
+ # == Filter conditions
424
+ #
425
+ # Filters may be limited to specific actions by declaring the actions to
426
+ # include or exclude. Both options accept single actions
427
+ # (<tt>:only => :index</tt>) or arrays of actions
428
+ # (<tt>:except => [:foo, :bar]</tt>).
429
+ #
430
+ # class Journal < ActionController::Base
431
+ # # Require authentication for edit and delete.
432
+ # before_filter :authorize, :only => [:edit, :delete]
433
+ #
434
+ # # Passing options to a filter with a block.
435
+ # around_filter(:except => :index) do |controller, action_block|
436
+ # results = Profiler.run(&action_block)
437
+ # controller.response.sub! "</body>", "#{results}</body>"
438
+ # end
439
+ #
440
+ # private
441
+ # def authorize
442
+ # # Redirect to login unless authenticated.
443
+ # end
444
+ # end
445
+ #
446
+ # == Filter Chain Halting
447
+ #
448
+ # <tt>before_filter</tt> and <tt>around_filter</tt> may halt the request
449
+ # before a controller action is run. This is useful, for example, to deny
450
+ # access to unauthenticated users or to redirect from HTTP to HTTPS.
451
+ # Simply call render or redirect. After filters will not be executed if the filter
452
+ # chain is halted.
453
+ #
454
+ # Around filters halt the request unless the action block is called.
455
+ # Given these filters
456
+ # after_filter :after
457
+ # around_filter :around
458
+ # before_filter :before
459
+ #
460
+ # The filter chain will look like:
461
+ #
462
+ # ...
463
+ # . \
464
+ # . #around (code before yield)
465
+ # . . \
466
+ # . . #before (actual filter code is run)
467
+ # . . . \
468
+ # . . . execute controller action
469
+ # . . . /
470
+ # . . ...
471
+ # . . /
472
+ # . #around (code after yield)
473
+ # . /
474
+ # #after (actual filter code is run, unless the around filter does not yield)
475
+ #
476
+ # If +around+ returns before yielding, +after+ will still not be run. The +before+
477
+ # filter and controller action will not be run. If +before+ renders or redirects,
478
+ # the second half of +around+ and will still run but +after+ and the
479
+ # action will not. If +around+ fails to yield, +after+ will not be run.
480
+ module ClassMethods
481
+ # The passed <tt>filters</tt> will be appended to the filter_chain and
482
+ # will execute before the action on this controller is performed.
483
+ def append_before_filter(*filters, &block)
484
+ filter_chain.append_filter_to_chain(filters, :before, &block)
485
+ end
486
+
487
+ # The passed <tt>filters</tt> will be prepended to the filter_chain and
488
+ # will execute before the action on this controller is performed.
489
+ def prepend_before_filter(*filters, &block)
490
+ filter_chain.prepend_filter_to_chain(filters, :before, &block)
491
+ end
492
+
493
+ # Shorthand for append_before_filter since it's the most common.
494
+ alias :before_filter :append_before_filter
495
+
496
+ # The passed <tt>filters</tt> will be appended to the array of filters
497
+ # that run _after_ actions on this controller are performed.
498
+ def append_after_filter(*filters, &block)
499
+ filter_chain.append_filter_to_chain(filters, :after, &block)
500
+ end
501
+
502
+ # The passed <tt>filters</tt> will be prepended to the array of filters
503
+ # that run _after_ actions on this controller are performed.
504
+ def prepend_after_filter(*filters, &block)
505
+ filter_chain.prepend_filter_to_chain(filters, :after, &block)
506
+ end
507
+
508
+ # Shorthand for append_after_filter since it's the most common.
509
+ alias :after_filter :append_after_filter
510
+
511
+ # If you <tt>append_around_filter A.new, B.new</tt>, the filter chain looks like
512
+ #
513
+ # B#before
514
+ # A#before
515
+ # # run the action
516
+ # A#after
517
+ # B#after
518
+ #
519
+ # With around filters which yield to the action block, +before+ and +after+
520
+ # are the code before and after the yield.
521
+ def append_around_filter(*filters, &block)
522
+ filter_chain.append_filter_to_chain(filters, :around, &block)
523
+ end
524
+
525
+ # If you <tt>prepend_around_filter A.new, B.new</tt>, the filter chain looks like:
526
+ #
527
+ # A#before
528
+ # B#before
529
+ # # run the action
530
+ # B#after
531
+ # A#after
532
+ #
533
+ # With around filters which yield to the action block, +before+ and +after+
534
+ # are the code before and after the yield.
535
+ def prepend_around_filter(*filters, &block)
536
+ filter_chain.prepend_filter_to_chain(filters, :around, &block)
537
+ end
538
+
539
+ # Shorthand for +append_around_filter+ since it's the most common.
540
+ alias :around_filter :append_around_filter
541
+
542
+ # Removes the specified filters from the +before+ filter chain. Note that this only works for skipping method-reference
543
+ # filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out
544
+ # of many sub-controllers need a different hierarchy.
545
+ #
546
+ # You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
547
+ # just like when you apply the filters.
548
+ def skip_before_filter(*filters)
549
+ filter_chain.skip_filter_in_chain(*filters, &:before?)
550
+ end
551
+
552
+ # Removes the specified filters from the +after+ filter chain. Note that this only works for skipping method-reference
553
+ # filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out
554
+ # of many sub-controllers need a different hierarchy.
555
+ #
556
+ # You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
557
+ # just like when you apply the filters.
558
+ def skip_after_filter(*filters)
559
+ filter_chain.skip_filter_in_chain(*filters, &:after?)
560
+ end
561
+
562
+ # Removes the specified filters from the filter chain. This only works for method reference (symbol)
563
+ # filters, not procs. This method is different from skip_after_filter and skip_before_filter in that
564
+ # it will match any before, after or yielding around filter.
565
+ #
566
+ # You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
567
+ # just like when you apply the filters.
568
+ def skip_filter(*filters)
569
+ filter_chain.skip_filter_in_chain(*filters)
570
+ end
571
+
572
+ # Returns an array of Filter objects for this controller.
573
+ def filter_chain
574
+ if chain = read_inheritable_attribute('filter_chain')
575
+ return chain
576
+ else
577
+ write_inheritable_attribute('filter_chain', FilterChain.new)
578
+ return filter_chain
579
+ end
580
+ end
581
+
582
+ # Returns all the before filters for this class and all its ancestors.
583
+ # This method returns the actual filter that was assigned in the controller to maintain existing functionality.
584
+ def before_filters #:nodoc:
585
+ filter_chain.select(&:before?).map(&:method)
586
+ end
587
+
588
+ # Returns all the after filters for this class and all its ancestors.
589
+ # This method returns the actual filter that was assigned in the controller to maintain existing functionality.
590
+ def after_filters #:nodoc:
591
+ filter_chain.select(&:after?).map(&:method)
592
+ end
593
+ end
594
+
595
+ module InstanceMethods # :nodoc:
596
+ def self.included(base)
597
+ base.class_eval do
598
+ alias_method_chain :perform_action, :filters
599
+ alias_method_chain :process, :filters
600
+ end
601
+ end
602
+
603
+ protected
604
+ def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc:
605
+ @before_filter_chain_aborted = false
606
+ process_without_filters(request, response, method, *arguments)
607
+ end
608
+
609
+ def perform_action_with_filters
610
+ call_filters(self.class.filter_chain, 0, 0)
611
+ end
612
+
613
+ private
614
+ def call_filters(chain, index, nesting)
615
+ index = run_before_filters(chain, index, nesting)
616
+ aborted = @before_filter_chain_aborted
617
+ perform_action_without_filters unless performed? || aborted
618
+ return index if nesting != 0 || aborted
619
+ run_after_filters(chain, index)
620
+ end
621
+
622
+ def run_before_filters(chain, index, nesting)
623
+ while chain[index]
624
+ filter, index = chain[index], index
625
+ break unless filter # end of call chain reached
626
+
627
+ case filter
628
+ when BeforeFilter
629
+ filter.call(self) # invoke before filter
630
+ index = index.next
631
+ break if @before_filter_chain_aborted
632
+ when AroundFilter
633
+ yielded = false
634
+
635
+ filter.call(self) do
636
+ yielded = true
637
+ # all remaining before and around filters will be run in this call
638
+ index = call_filters(chain, index.next, nesting.next)
639
+ end
640
+
641
+ halt_filter_chain(filter, :did_not_yield) unless yielded
642
+
643
+ break
644
+ else
645
+ break # no before or around filters left
646
+ end
647
+ end
648
+
649
+ index
650
+ end
651
+
652
+ def run_after_filters(chain, index)
653
+ seen_after_filter = false
654
+
655
+ while chain[index]
656
+ filter, index = chain[index], index
657
+ break unless filter # end of call chain reached
658
+
659
+ case filter
660
+ when AfterFilter
661
+ seen_after_filter = true
662
+ filter.call(self) # invoke after filter
663
+ else
664
+ # implementation error or someone has mucked with the filter chain
665
+ raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter
666
+ end
667
+
668
+ index = index.next
669
+ end
670
+
671
+ index.next
672
+ end
673
+
674
+ def halt_filter_chain(filter, reason)
675
+ @before_filter_chain_aborted = true
676
+ logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger
677
+ end
678
+ end
679
+ end
680
+ end