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,286 @@
1
+ module ActionController #:nodoc:
2
+ module Layout #:nodoc:
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ base.class_eval do
6
+ class << self
7
+ alias_method_chain :inherited, :layout
8
+ end
9
+ end
10
+ end
11
+
12
+ # Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
13
+ # repeated setups. The inclusion pattern has pages that look like this:
14
+ #
15
+ # <%= render "shared/header" %>
16
+ # Hello World
17
+ # <%= render "shared/footer" %>
18
+ #
19
+ # This approach is a decent way of keeping common structures isolated from the changing content, but it's verbose
20
+ # and if you ever want to change the structure of these two includes, you'll have to change all the templates.
21
+ #
22
+ # With layouts, you can flip it around and have the common structure know where to insert changing content. This means
23
+ # that the header and footer are only mentioned in one place, like this:
24
+ #
25
+ # // The header part of this layout
26
+ # <%= yield %>
27
+ # // The footer part of this layout
28
+ #
29
+ # And then you have content pages that look like this:
30
+ #
31
+ # hello world
32
+ #
33
+ # At rendering time, the content page is computed and then inserted in the layout, like this:
34
+ #
35
+ # // The header part of this layout
36
+ # hello world
37
+ # // The footer part of this layout
38
+ #
39
+ # NOTE: The old notation for rendering the view from a layout was to expose the magic <tt>@content_for_layout</tt> instance
40
+ # variable. The preferred notation now is to use <tt>yield</tt>, as documented above.
41
+ #
42
+ # == Accessing shared variables
43
+ #
44
+ # Layouts have access to variables specified in the content pages and vice versa. This allows you to have layouts with
45
+ # references that won't materialize before rendering time:
46
+ #
47
+ # <h1><%= @page_title %></h1>
48
+ # <%= yield %>
49
+ #
50
+ # ...and content pages that fulfill these references _at_ rendering time:
51
+ #
52
+ # <% @page_title = "Welcome" %>
53
+ # Off-world colonies offers you a chance to start a new life
54
+ #
55
+ # The result after rendering is:
56
+ #
57
+ # <h1>Welcome</h1>
58
+ # Off-world colonies offers you a chance to start a new life
59
+ #
60
+ # == Automatic layout assignment
61
+ #
62
+ # If there is a template in <tt>app/views/layouts/</tt> with the same name as the current controller then it will be automatically
63
+ # set as that controller's layout unless explicitly told otherwise. Say you have a WeblogController, for example. If a template named
64
+ # <tt>app/views/layouts/weblog.erb</tt> or <tt>app/views/layouts/weblog.builder</tt> exists then it will be automatically set as
65
+ # the layout for your WeblogController. You can create a layout with the name <tt>application.erb</tt> or <tt>application.builder</tt>
66
+ # and this will be set as the default controller if there is no layout with the same name as the current controller and there is
67
+ # no layout explicitly assigned with the +layout+ method. Nested controllers use the same folder structure for automatic layout.
68
+ # assignment. So an Admin::WeblogController will look for a template named <tt>app/views/layouts/admin/weblog.erb</tt>.
69
+ # Setting a layout explicitly will always override the automatic behaviour for the controller where the layout is set.
70
+ # Explicitly setting the layout in a parent class, though, will not override the child class's layout assignment if the child
71
+ # class has a layout with the same name.
72
+ #
73
+ # == Inheritance for layouts
74
+ #
75
+ # Layouts are shared downwards in the inheritance hierarchy, but not upwards. Examples:
76
+ #
77
+ # class BankController < ActionController::Base
78
+ # layout "bank_standard"
79
+ #
80
+ # class InformationController < BankController
81
+ #
82
+ # class VaultController < BankController
83
+ # layout :access_level_layout
84
+ #
85
+ # class EmployeeController < BankController
86
+ # layout nil
87
+ #
88
+ # The InformationController uses "bank_standard" inherited from the BankController, the VaultController overwrites
89
+ # and picks the layout dynamically, and the EmployeeController doesn't want to use a layout at all.
90
+ #
91
+ # == Types of layouts
92
+ #
93
+ # Layouts are basically just regular templates, but the name of this template needs not be specified statically. Sometimes
94
+ # you want to alternate layouts depending on runtime information, such as whether someone is logged in or not. This can
95
+ # be done either by specifying a method reference as a symbol or using an inline method (as a proc).
96
+ #
97
+ # The method reference is the preferred approach to variable layouts and is used like this:
98
+ #
99
+ # class WeblogController < ActionController::Base
100
+ # layout :writers_and_readers
101
+ #
102
+ # def index
103
+ # # fetching posts
104
+ # end
105
+ #
106
+ # private
107
+ # def writers_and_readers
108
+ # logged_in? ? "writer_layout" : "reader_layout"
109
+ # end
110
+ #
111
+ # Now when a new request for the index action is processed, the layout will vary depending on whether the person accessing
112
+ # is logged in or not.
113
+ #
114
+ # If you want to use an inline method, such as a proc, do something like this:
115
+ #
116
+ # class WeblogController < ActionController::Base
117
+ # layout proc{ |controller| controller.logged_in? ? "writer_layout" : "reader_layout" }
118
+ #
119
+ # Of course, the most common way of specifying a layout is still just as a plain template name:
120
+ #
121
+ # class WeblogController < ActionController::Base
122
+ # layout "weblog_standard"
123
+ #
124
+ # If no directory is specified for the template name, the template will by default be looked for in <tt>app/views/layouts/</tt>.
125
+ # Otherwise, it will be looked up relative to the template root.
126
+ #
127
+ # == Conditional layouts
128
+ #
129
+ # If you have a layout that by default is applied to all the actions of a controller, you still have the option of rendering
130
+ # a given action or set of actions without a layout, or restricting a layout to only a single action or a set of actions. The
131
+ # <tt>:only</tt> and <tt>:except</tt> options can be passed to the layout call. For example:
132
+ #
133
+ # class WeblogController < ActionController::Base
134
+ # layout "weblog_standard", :except => :rss
135
+ #
136
+ # # ...
137
+ #
138
+ # end
139
+ #
140
+ # This will assign "weblog_standard" as the WeblogController's layout except for the +rss+ action, which will not wrap a layout
141
+ # around the rendered view.
142
+ #
143
+ # Both the <tt>:only</tt> and <tt>:except</tt> condition can accept an arbitrary number of method references, so
144
+ # #<tt>:except => [ :rss, :text_only ]</tt> is valid, as is <tt>:except => :rss</tt>.
145
+ #
146
+ # == Using a different layout in the action render call
147
+ #
148
+ # If most of your actions use the same layout, it makes perfect sense to define a controller-wide layout as described above.
149
+ # Sometimes you'll have exceptions where one action wants to use a different layout than the rest of the controller.
150
+ # You can do this by passing a <tt>:layout</tt> option to the <tt>render</tt> call. For example:
151
+ #
152
+ # class WeblogController < ActionController::Base
153
+ # layout "weblog_standard"
154
+ #
155
+ # def help
156
+ # render :action => "help", :layout => "help"
157
+ # end
158
+ # end
159
+ #
160
+ # This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout.
161
+ module ClassMethods
162
+ # If a layout is specified, all rendered actions will have their result rendered
163
+ # when the layout <tt>yield</tt>s. This layout can itself depend on instance variables assigned during action
164
+ # performance and have access to them as any normal template would.
165
+ def layout(template_name, conditions = {}, auto = false)
166
+ add_layout_conditions(conditions)
167
+ write_inheritable_attribute(:layout, template_name)
168
+ write_inheritable_attribute(:auto_layout, auto)
169
+ end
170
+
171
+ def layout_conditions #:nodoc:
172
+ @layout_conditions ||= read_inheritable_attribute(:layout_conditions)
173
+ end
174
+
175
+ def layout_list #:nodoc:
176
+ Array(view_paths).sum([]) { |path| Dir["#{path.to_str}/layouts/**/*"] }
177
+ end
178
+
179
+ private
180
+ def inherited_with_layout(child)
181
+ inherited_without_layout(child)
182
+ unless child.name.blank?
183
+ layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers\//, '')
184
+ child.layout(layout_match, {}, true) unless child.layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
185
+ end
186
+ end
187
+
188
+ def add_layout_conditions(conditions)
189
+ write_inheritable_hash(:layout_conditions, normalize_conditions(conditions))
190
+ end
191
+
192
+ def normalize_conditions(conditions)
193
+ conditions.inject({}) {|hash, (key, value)| hash.merge(key => [value].flatten.map {|action| action.to_s})}
194
+ end
195
+ end
196
+
197
+ def initialize(*args)
198
+ super
199
+ @real_format = nil
200
+ end
201
+
202
+ # Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
203
+ # is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
204
+ # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
205
+ # weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
206
+ def active_layout(passed_layout = nil, options = {})
207
+ layout = passed_layout || default_layout
208
+ return layout if layout.respond_to?(:render)
209
+
210
+ active_layout = case layout
211
+ when Symbol then __send__(layout)
212
+ when Proc then layout.call(self)
213
+ else layout
214
+ end
215
+
216
+ find_layout(active_layout, default_template_format, options[:html_fallback]) if active_layout
217
+ end
218
+
219
+ private
220
+ def default_layout #:nodoc:
221
+ layout = self.class.read_inheritable_attribute(:layout)
222
+ return layout unless self.class.read_inheritable_attribute(:auto_layout)
223
+ find_layout(layout, default_template_format)
224
+ rescue ActionView::MissingTemplate
225
+ nil
226
+ end
227
+
228
+ def find_layout(layout, format, html_fallback=false) #:nodoc:
229
+ view_paths.find_template(layout.to_s =~ /\A\/|layouts\// ? layout : "layouts/#{layout}", format, html_fallback)
230
+ rescue ActionView::MissingTemplate
231
+ raise if Mime::Type.lookup_by_extension(format.to_s).html?
232
+ end
233
+
234
+ def pick_layout(options)
235
+ if options.has_key?(:layout)
236
+ case layout = options.delete(:layout)
237
+ when FalseClass
238
+ nil
239
+ when NilClass, TrueClass
240
+ active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name)
241
+ else
242
+ active_layout(layout, :html_fallback => true)
243
+ end
244
+ else
245
+ active_layout if action_has_layout? && candidate_for_layout?(options)
246
+ end
247
+ end
248
+
249
+ def action_has_layout?
250
+ if conditions = self.class.layout_conditions
251
+ case
252
+ when only = conditions[:only]
253
+ only.include?(action_name)
254
+ when except = conditions[:except]
255
+ !except.include?(action_name)
256
+ else
257
+ true
258
+ end
259
+ else
260
+ true
261
+ end
262
+ end
263
+
264
+ def candidate_for_layout?(options)
265
+ template = options[:template] || default_template(options[:action])
266
+ if options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty?
267
+ begin
268
+ template_object = self.view_paths.find_template(template, default_template_format)
269
+ # this restores the behavior from 2.2.2, where response.template.template_format was reset
270
+ # to :html for :js requests with a matching html template.
271
+ # see v2.2.2, ActionView::Base, lines 328-330
272
+ @real_format = :html if response.template.template_format == :js && template_object.format == "html"
273
+ !template_object.exempt_from_layout?
274
+ rescue ActionView::MissingTemplate
275
+ true
276
+ end
277
+ end
278
+ rescue ActionView::MissingTemplate
279
+ false
280
+ end
281
+
282
+ def default_template_format
283
+ @real_format || response.template.template_format
284
+ end
285
+ end
286
+ end
@@ -0,0 +1,119 @@
1
+ module ActionController
2
+ class MiddlewareStack < Array
3
+ class Middleware
4
+ def self.new(klass, *args, &block)
5
+ if klass.is_a?(self)
6
+ klass
7
+ else
8
+ super
9
+ end
10
+ end
11
+
12
+ attr_reader :args, :block
13
+
14
+ def initialize(klass, *args, &block)
15
+ @klass = klass
16
+
17
+ options = args.extract_options!
18
+ if options.has_key?(:if)
19
+ @conditional = options.delete(:if)
20
+ else
21
+ @conditional = true
22
+ end
23
+ args << options unless options.empty?
24
+
25
+ @args = args
26
+ @block = block
27
+ end
28
+
29
+ def klass
30
+ if @klass.respond_to?(:call)
31
+ @klass.call
32
+ elsif @klass.is_a?(Class)
33
+ @klass
34
+ else
35
+ @klass.to_s.constantize
36
+ end
37
+ rescue NameError
38
+ @klass
39
+ end
40
+
41
+ def active?
42
+ return false unless klass
43
+
44
+ if @conditional.respond_to?(:call)
45
+ @conditional.call
46
+ else
47
+ @conditional
48
+ end
49
+ end
50
+
51
+ def ==(middleware)
52
+ case middleware
53
+ when Middleware
54
+ klass == middleware.klass
55
+ when Class
56
+ klass == middleware
57
+ else
58
+ klass == middleware.to_s.constantize
59
+ end
60
+ end
61
+
62
+ def inspect
63
+ str = klass.to_s
64
+ args.each { |arg| str += ", #{arg.inspect}" }
65
+ str
66
+ end
67
+
68
+ def build(app)
69
+ if block
70
+ klass.new(app, *build_args, &block)
71
+ else
72
+ klass.new(app, *build_args)
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def build_args
79
+ Array(args).map { |arg| arg.respond_to?(:call) ? arg.call : arg }
80
+ end
81
+ end
82
+
83
+ def initialize(*args, &block)
84
+ super(*args)
85
+ block.call(self) if block_given?
86
+ end
87
+
88
+ def insert(index, *args, &block)
89
+ index = self.index(index) unless index.is_a?(Integer)
90
+ middleware = Middleware.new(*args, &block)
91
+ super(index, middleware)
92
+ end
93
+
94
+ alias_method :insert_before, :insert
95
+
96
+ def insert_after(index, *args, &block)
97
+ index = self.index(index) unless index.is_a?(Integer)
98
+ insert(index + 1, *args, &block)
99
+ end
100
+
101
+ def swap(target, *args, &block)
102
+ insert_before(target, *args, &block)
103
+ delete(target)
104
+ end
105
+
106
+ def use(*args, &block)
107
+ middleware = Middleware.new(*args, &block)
108
+ push(middleware)
109
+ end
110
+
111
+ def active
112
+ find_all { |middleware| middleware.active? }
113
+ end
114
+
115
+ def build(app)
116
+ active.reverse.inject(app) { |a, e| e.build(a) }
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,14 @@
1
+ use "Rack::Lock", :if => lambda {
2
+ !ActionController::Base.allow_concurrency
3
+ }
4
+
5
+ use "ActionController::Failsafe"
6
+
7
+ use lambda { ActionController::Base.session_store },
8
+ lambda { ActionController::Base.session_options }
9
+
10
+ use "ActionController::ParamsParser"
11
+ use "Rack::MethodOverride"
12
+ use "Rack::Head"
13
+
14
+ use "ActionController::StringCoercion"
@@ -0,0 +1,193 @@
1
+ module ActionController #:nodoc:
2
+ module MimeResponds #:nodoc:
3
+ def self.included(base)
4
+ base.module_eval do
5
+ include ActionController::MimeResponds::InstanceMethods
6
+ end
7
+ end
8
+
9
+ module InstanceMethods
10
+ # Without web-service support, an action which collects the data for displaying a list of people
11
+ # might look something like this:
12
+ #
13
+ # def index
14
+ # @people = Person.find(:all)
15
+ # end
16
+ #
17
+ # Here's the same action, with web-service support baked in:
18
+ #
19
+ # def index
20
+ # @people = Person.find(:all)
21
+ #
22
+ # respond_to do |format|
23
+ # format.html
24
+ # format.xml { render :xml => @people.to_xml }
25
+ # end
26
+ # end
27
+ #
28
+ # What that says is, "if the client wants HTML in response to this action, just respond as we
29
+ # would have before, but if the client wants XML, return them the list of people in XML format."
30
+ # (Rails determines the desired response format from the HTTP Accept header submitted by the client.)
31
+ #
32
+ # Supposing you have an action that adds a new person, optionally creating their company
33
+ # (by name) if it does not already exist, without web-services, it might look like this:
34
+ #
35
+ # def create
36
+ # @company = Company.find_or_create_by_name(params[:company][:name])
37
+ # @person = @company.people.create(params[:person])
38
+ #
39
+ # redirect_to(person_list_url)
40
+ # end
41
+ #
42
+ # Here's the same action, with web-service support baked in:
43
+ #
44
+ # def create
45
+ # company = params[:person].delete(:company)
46
+ # @company = Company.find_or_create_by_name(company[:name])
47
+ # @person = @company.people.create(params[:person])
48
+ #
49
+ # respond_to do |format|
50
+ # format.html { redirect_to(person_list_url) }
51
+ # format.js
52
+ # format.xml { render :xml => @person.to_xml(:include => @company) }
53
+ # end
54
+ # end
55
+ #
56
+ # If the client wants HTML, we just redirect them back to the person list. If they want Javascript
57
+ # (format.js), then it is an RJS request and we render the RJS template associated with this action.
58
+ # Lastly, if the client wants XML, we render the created person as XML, but with a twist: we also
59
+ # include the person's company in the rendered XML, so you get something like this:
60
+ #
61
+ # <person>
62
+ # <id>...</id>
63
+ # ...
64
+ # <company>
65
+ # <id>...</id>
66
+ # <name>...</name>
67
+ # ...
68
+ # </company>
69
+ # </person>
70
+ #
71
+ # Note, however, the extra bit at the top of that action:
72
+ #
73
+ # company = params[:person].delete(:company)
74
+ # @company = Company.find_or_create_by_name(company[:name])
75
+ #
76
+ # This is because the incoming XML document (if a web-service request is in process) can only contain a
77
+ # single root-node. So, we have to rearrange things so that the request looks like this (url-encoded):
78
+ #
79
+ # person[name]=...&person[company][name]=...&...
80
+ #
81
+ # And, like this (xml-encoded):
82
+ #
83
+ # <person>
84
+ # <name>...</name>
85
+ # <company>
86
+ # <name>...</name>
87
+ # </company>
88
+ # </person>
89
+ #
90
+ # In other words, we make the request so that it operates on a single entity's person. Then, in the action,
91
+ # we extract the company data from the request, find or create the company, and then create the new person
92
+ # with the remaining data.
93
+ #
94
+ # Note that you can define your own XML parameter parser which would allow you to describe multiple entities
95
+ # in a single request (i.e., by wrapping them all in a single root node), but if you just go with the flow
96
+ # and accept Rails' defaults, life will be much easier.
97
+ #
98
+ # If you need to use a MIME type which isn't supported by default, you can register your own handlers in
99
+ # environment.rb as follows.
100
+ #
101
+ # Mime::Type.register "image/jpg", :jpg
102
+ def respond_to(*types, &block)
103
+ raise ArgumentError, "respond_to takes either types or a block, never both" unless types.any? ^ block
104
+ block ||= lambda { |responder| types.each { |type| responder.send(type) } }
105
+ responder = Responder.new(self)
106
+ block.call(responder)
107
+ responder.respond
108
+ end
109
+ end
110
+
111
+ class Responder #:nodoc:
112
+ def initialize(controller)
113
+ @controller = controller
114
+ @request = controller.request
115
+ @response = controller.response
116
+
117
+ if ActionController::Base.use_accept_header
118
+ @mime_type_priority = Array(Mime::Type.lookup_by_extension(@request.parameters[:format]) || @request.accepts)
119
+ else
120
+ @mime_type_priority = [@request.format]
121
+ end
122
+
123
+ @order = []
124
+ @responses = {}
125
+ end
126
+
127
+ def custom(mime_type, &block)
128
+ mime_type = mime_type.is_a?(Mime::Type) ? mime_type : Mime::Type.lookup(mime_type.to_s)
129
+
130
+ @order << mime_type
131
+
132
+ @responses[mime_type] ||= Proc.new do
133
+ @response.template.template_format = mime_type.to_sym
134
+ @response.content_type = mime_type.to_s
135
+ block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
136
+ end
137
+ end
138
+
139
+ def any(*args, &block)
140
+ if args.any?
141
+ args.each { |type| send(type, &block) }
142
+ else
143
+ custom(@mime_type_priority.first, &block)
144
+ end
145
+ end
146
+
147
+ def self.generate_method_for_mime(mime)
148
+ sym = mime.is_a?(Symbol) ? mime : mime.to_sym
149
+ const = sym.to_s.upcase
150
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
151
+ def #{sym}(&block) # def html(&block)
152
+ custom(Mime::#{const}, &block) # custom(Mime::HTML, &block)
153
+ end # end
154
+ RUBY
155
+ end
156
+
157
+ Mime::SET.each do |mime|
158
+ generate_method_for_mime(mime)
159
+ end
160
+
161
+ def method_missing(symbol, &block)
162
+ mime_constant = Mime.const_get(symbol.to_s.upcase)
163
+
164
+ if Mime::SET.include?(mime_constant)
165
+ self.class.generate_method_for_mime(mime_constant)
166
+ send(symbol, &block)
167
+ else
168
+ super
169
+ end
170
+ end
171
+
172
+ def respond
173
+ for priority in @mime_type_priority
174
+ if priority == Mime::ALL
175
+ @responses[@order.first].call
176
+ return
177
+ else
178
+ if @responses[priority]
179
+ @responses[priority].call
180
+ return # mime type match found, be happy and return
181
+ end
182
+ end
183
+ end
184
+
185
+ if @order.include?(Mime::ALL)
186
+ @responses[Mime::ALL].call
187
+ else
188
+ @controller.send :head, :not_acceptable
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end