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,239 @@
1
+ require 'digest/md5'
2
+
3
+ module ActionController # :nodoc:
4
+ # Represents an HTTP response generated by a controller action. One can use
5
+ # an ActionController::Response object to retrieve the current state
6
+ # of the response, or customize the response. An Response object can
7
+ # either represent a "real" HTTP response (i.e. one that is meant to be sent
8
+ # back to the web browser) or a test response (i.e. one that is generated
9
+ # from integration tests). See CgiResponse and TestResponse, respectively.
10
+ #
11
+ # Response is mostly a Ruby on Rails framework implement detail, and
12
+ # should never be used directly in controllers. Controllers should use the
13
+ # methods defined in ActionController::Base instead. For example, if you want
14
+ # to set the HTTP response's content MIME type, then use
15
+ # ActionControllerBase#headers instead of Response#headers.
16
+ #
17
+ # Nevertheless, integration tests may want to inspect controller responses in
18
+ # more detail, and that's when Response can be useful for application
19
+ # developers. Integration test methods such as
20
+ # ActionController::Integration::Session#get and
21
+ # ActionController::Integration::Session#post return objects of type
22
+ # TestResponse (which are of course also of type Response).
23
+ #
24
+ # For example, the following demo integration "test" prints the body of the
25
+ # controller response to the console:
26
+ #
27
+ # class DemoControllerTest < ActionController::IntegrationTest
28
+ # def test_print_root_path_to_console
29
+ # get('/')
30
+ # puts @response.body
31
+ # end
32
+ # end
33
+ class Response < Rack::Response
34
+ DEFAULT_HEADERS = { "Cache-Control" => "no-cache" }
35
+ attr_accessor :request
36
+
37
+ attr_accessor :session, :assigns, :template, :layout
38
+ attr_accessor :redirected_to, :redirected_to_method_params
39
+
40
+ delegate :default_charset, :to => 'ActionController::Base'
41
+
42
+ def initialize
43
+ @status = 200
44
+ @header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS)
45
+
46
+ @writer = lambda { |x| @body << x }
47
+ @block = nil
48
+
49
+ @body = "",
50
+ @session = []
51
+ @assigns = []
52
+ end
53
+
54
+ def location; headers['Location'] end
55
+ def location=(url) headers['Location'] = url end
56
+
57
+
58
+ # Sets the HTTP response's content MIME type. For example, in the controller
59
+ # you could write this:
60
+ #
61
+ # response.content_type = "text/plain"
62
+ #
63
+ # If a character set has been defined for this response (see charset=) then
64
+ # the character set information will also be included in the content type
65
+ # information.
66
+ def content_type=(mime_type)
67
+ self.headers["Content-Type"] =
68
+ if mime_type =~ /charset/ || (c = charset).nil?
69
+ mime_type.to_s
70
+ else
71
+ "#{mime_type}; charset=#{c}"
72
+ end
73
+ end
74
+
75
+ # Returns the response's content MIME type, or nil if content type has been set.
76
+ def content_type
77
+ content_type = String(headers["Content-Type"] || headers["type"]).split(";")[0]
78
+ content_type.blank? ? nil : content_type
79
+ end
80
+
81
+ # Set the charset of the Content-Type header. Set to nil to remove it.
82
+ # If no content type is set, it defaults to HTML.
83
+ def charset=(charset)
84
+ headers["Content-Type"] =
85
+ if charset
86
+ "#{content_type || Mime::HTML}; charset=#{charset}"
87
+ else
88
+ content_type || Mime::HTML.to_s
89
+ end
90
+ end
91
+
92
+ def charset
93
+ charset = String(headers["Content-Type"] || headers["type"]).split(";")[1]
94
+ charset.blank? ? nil : charset.strip.split("=")[1]
95
+ end
96
+
97
+ def last_modified
98
+ if last = headers['Last-Modified']
99
+ Time.httpdate(last)
100
+ end
101
+ end
102
+
103
+ def last_modified?
104
+ headers.include?('Last-Modified')
105
+ end
106
+
107
+ def last_modified=(utc_time)
108
+ headers['Last-Modified'] = utc_time.httpdate
109
+ end
110
+
111
+ def etag
112
+ headers['ETag']
113
+ end
114
+
115
+ def etag?
116
+ headers.include?('ETag')
117
+ end
118
+
119
+ def etag=(etag)
120
+ if etag.blank?
121
+ headers.delete('ETag')
122
+ else
123
+ headers['ETag'] = %("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
124
+ end
125
+ end
126
+
127
+ def redirect(url, status)
128
+ self.status = status
129
+ self.location = url.gsub(/[\r\n]/, '')
130
+ self.body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>"
131
+ end
132
+
133
+ def sending_file?
134
+ headers["Content-Transfer-Encoding"] == "binary"
135
+ end
136
+
137
+ def assign_default_content_type_and_charset!
138
+ self.content_type ||= Mime::HTML
139
+ self.charset ||= default_charset unless sending_file?
140
+ end
141
+
142
+ def prepare!
143
+ assign_default_content_type_and_charset!
144
+ handle_conditional_get!
145
+ set_content_length!
146
+ convert_content_type!
147
+ convert_language!
148
+ convert_cookies!
149
+ end
150
+
151
+ def each(&callback)
152
+ if @body.respond_to?(:call)
153
+ @writer = lambda { |x| callback.call(x) }
154
+ @body.call(self, self)
155
+ elsif @body.respond_to?(:to_str)
156
+ yield @body
157
+ else
158
+ @body.each(&callback)
159
+ end
160
+
161
+ @writer = callback
162
+ @block.call(self) if @block
163
+ end
164
+
165
+ def write(str)
166
+ @writer.call str.to_s
167
+ str
168
+ end
169
+
170
+ def flush #:nodoc:
171
+ ActiveSupport::Deprecation.warn(
172
+ 'Calling output.flush is no longer needed for streaming output ' +
173
+ 'because ActionController::Response automatically handles it', caller)
174
+ end
175
+
176
+ def set_cookie(key, value)
177
+ if value.has_key?(:http_only)
178
+ ActiveSupport::Deprecation.warn(
179
+ "The :http_only option in ActionController::Response#set_cookie " +
180
+ "has been renamed. Please use :httponly instead.", caller)
181
+ value[:httponly] ||= value.delete(:http_only)
182
+ end
183
+
184
+ super(key, value)
185
+ end
186
+
187
+ private
188
+ def handle_conditional_get!
189
+ if etag? || last_modified?
190
+ set_conditional_cache_control!
191
+ elsif nonempty_ok_response?
192
+ self.etag = body
193
+
194
+ if request && request.etag_matches?(etag)
195
+ self.status = '304 Not Modified'
196
+ self.body = ''
197
+ end
198
+
199
+ set_conditional_cache_control!
200
+ end
201
+ end
202
+
203
+ def nonempty_ok_response?
204
+ ok = !status || status.to_s[0..2] == '200'
205
+ ok && body.is_a?(String) && !body.empty?
206
+ end
207
+
208
+ def set_conditional_cache_control!
209
+ if headers['Cache-Control'] == DEFAULT_HEADERS['Cache-Control']
210
+ headers['Cache-Control'] = 'private, max-age=0, must-revalidate'
211
+ end
212
+ end
213
+
214
+ def convert_content_type!
215
+ headers['Content-Type'] ||= "text/html"
216
+ headers['Content-Type'] += "; charset=" + headers.delete('charset') if headers['charset']
217
+ end
218
+
219
+ # Don't set the Content-Length for block-based bodies as that would mean
220
+ # reading it all into memory. Not nice for, say, a 2GB streaming file.
221
+ def set_content_length!
222
+ if status && status.to_s[0..2] == '204'
223
+ headers.delete('Content-Length')
224
+ elsif length = headers['Content-Length']
225
+ headers['Content-Length'] = length.to_s
226
+ elsif !body.respond_to?(:call) && (!status || status.to_s[0..2] != '304')
227
+ headers["Content-Length"] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
228
+ end
229
+ end
230
+
231
+ def convert_language!
232
+ headers["Content-Language"] = headers.delete("language") if headers["language"]
233
+ end
234
+
235
+ def convert_cookies!
236
+ headers['Set-Cookie'] = Array(headers['Set-Cookie']).compact
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,197 @@
1
+ module ActionController
2
+ module Routing
3
+ class RouteBuilder #:nodoc:
4
+ attr_reader :separators, :optional_separators
5
+ attr_reader :separator_regexp, :nonseparator_regexp, :interval_regexp
6
+
7
+ def initialize
8
+ @separators = Routing::SEPARATORS
9
+ @optional_separators = %w( / )
10
+
11
+ @separator_regexp = /[#{Regexp.escape(separators.join)}]/
12
+ @nonseparator_regexp = /\A([^#{Regexp.escape(separators.join)}]+)/
13
+ @interval_regexp = /(.*?)(#{separator_regexp}|$)/
14
+ end
15
+
16
+ # Accepts a "route path" (a string defining a route), and returns the array
17
+ # of segments that corresponds to it. Note that the segment array is only
18
+ # partially initialized--the defaults and requirements, for instance, need
19
+ # to be set separately, via the +assign_route_options+ method, and the
20
+ # <tt>optional?</tt> method for each segment will not be reliable until after
21
+ # +assign_route_options+ is called, as well.
22
+ def segments_for_route_path(path)
23
+ rest, segments = path, []
24
+
25
+ until rest.empty?
26
+ segment, rest = segment_for(rest)
27
+ segments << segment
28
+ end
29
+ segments
30
+ end
31
+
32
+ # A factory method that returns a new segment instance appropriate for the
33
+ # format of the given string.
34
+ def segment_for(string)
35
+ segment =
36
+ case string
37
+ when /\A\.(:format)?\//
38
+ OptionalFormatSegment.new
39
+ when /\A:(\w+)/
40
+ key = $1.to_sym
41
+ key == :controller ? ControllerSegment.new(key) : DynamicSegment.new(key)
42
+ when /\A\*(\w+)/
43
+ PathSegment.new($1.to_sym, :optional => true)
44
+ when /\A\?(.*?)\?/
45
+ StaticSegment.new($1, :optional => true)
46
+ when nonseparator_regexp
47
+ StaticSegment.new($1)
48
+ when separator_regexp
49
+ DividerSegment.new($&, :optional => optional_separators.include?($&))
50
+ end
51
+ [segment, $~.post_match]
52
+ end
53
+
54
+ # Split the given hash of options into requirement and default hashes. The
55
+ # segments are passed alongside in order to distinguish between default values
56
+ # and requirements.
57
+ def divide_route_options(segments, options)
58
+ options = options.except(:path_prefix, :name_prefix)
59
+
60
+ if options[:namespace]
61
+ options[:controller] = "#{options.delete(:namespace).sub(/\/$/, '')}/#{options[:controller]}"
62
+ end
63
+
64
+ requirements = (options.delete(:requirements) || {}).dup
65
+ defaults = (options.delete(:defaults) || {}).dup
66
+ conditions = (options.delete(:conditions) || {}).dup
67
+
68
+ validate_route_conditions(conditions)
69
+
70
+ path_keys = segments.collect { |segment| segment.key if segment.respond_to?(:key) }.compact
71
+ options.each do |key, value|
72
+ hash = (path_keys.include?(key) && ! value.is_a?(Regexp)) ? defaults : requirements
73
+ hash[key] = value
74
+ end
75
+
76
+ [defaults, requirements, conditions]
77
+ end
78
+
79
+ # Takes a hash of defaults and a hash of requirements, and assigns them to
80
+ # the segments. Any unused requirements (which do not correspond to a segment)
81
+ # are returned as a hash.
82
+ def assign_route_options(segments, defaults, requirements)
83
+ route_requirements = {} # Requirements that do not belong to a segment
84
+
85
+ segment_named = Proc.new do |key|
86
+ segments.detect { |segment| segment.key == key if segment.respond_to?(:key) }
87
+ end
88
+
89
+ requirements.each do |key, requirement|
90
+ segment = segment_named[key]
91
+ if segment
92
+ raise TypeError, "#{key}: requirements on a path segment must be regular expressions" unless requirement.is_a?(Regexp)
93
+ if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
94
+ raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
95
+ end
96
+ if requirement.multiline?
97
+ raise ArgumentError, "Regexp multiline option not allowed in routing requirements: #{requirement.inspect}"
98
+ end
99
+ segment.regexp = requirement
100
+ else
101
+ route_requirements[key] = requirement
102
+ end
103
+ end
104
+
105
+ defaults.each do |key, default|
106
+ segment = segment_named[key]
107
+ raise ArgumentError, "#{key}: No matching segment exists; cannot assign default" unless segment
108
+ segment.is_optional = true
109
+ segment.default = default.to_param if default
110
+ end
111
+
112
+ assign_default_route_options(segments)
113
+ ensure_required_segments(segments)
114
+ route_requirements
115
+ end
116
+
117
+ # Assign default options, such as 'index' as a default for <tt>:action</tt>. This
118
+ # method must be run *after* user supplied requirements and defaults have
119
+ # been applied to the segments.
120
+ def assign_default_route_options(segments)
121
+ segments.each do |segment|
122
+ next unless segment.is_a? DynamicSegment
123
+ case segment.key
124
+ when :action
125
+ if segment.regexp.nil? || segment.regexp.match('index').to_s == 'index'
126
+ segment.default ||= 'index'
127
+ segment.is_optional = true
128
+ end
129
+ when :id
130
+ if segment.default.nil? && segment.regexp.nil? || segment.regexp =~ ''
131
+ segment.is_optional = true
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ # Makes sure that there are no optional segments that precede a required
138
+ # segment. If any are found that precede a required segment, they are
139
+ # made required.
140
+ def ensure_required_segments(segments)
141
+ allow_optional = true
142
+ segments.reverse_each do |segment|
143
+ allow_optional &&= segment.optional?
144
+ if !allow_optional && segment.optional?
145
+ unless segment.optionality_implied?
146
+ warn "Route segment \"#{segment.to_s}\" cannot be optional because it precedes a required segment. This segment will be required."
147
+ end
148
+ segment.is_optional = false
149
+ elsif allow_optional && segment.respond_to?(:default) && segment.default
150
+ # if a segment has a default, then it is optional
151
+ segment.is_optional = true
152
+ end
153
+ end
154
+ end
155
+
156
+ # Construct and return a route with the given path and options.
157
+ def build(path, options)
158
+ # Wrap the path with slashes
159
+ path = "/#{path}" unless path[0] == ?/
160
+ path = "#{path}/" unless path[-1] == ?/
161
+
162
+ prefix = options[:path_prefix].to_s.gsub(/^\//,'')
163
+ path = "/#{prefix}#{path}" unless prefix.blank?
164
+
165
+ segments = segments_for_route_path(path)
166
+ defaults, requirements, conditions = divide_route_options(segments, options)
167
+ requirements = assign_route_options(segments, defaults, requirements)
168
+
169
+ # TODO: Segments should be frozen on initialize
170
+ segments.each { |segment| segment.freeze }
171
+
172
+ route = Route.new(segments, requirements, conditions)
173
+
174
+ if !route.significant_keys.include?(:controller)
175
+ raise ArgumentError, "Illegal route: the :controller must be specified!"
176
+ end
177
+
178
+ route.freeze
179
+ end
180
+
181
+ private
182
+ def validate_route_conditions(conditions)
183
+ if method = conditions[:method]
184
+ [method].flatten.each do |m|
185
+ if m == :head
186
+ raise ArgumentError, "HTTP method HEAD is invalid in route conditions. Rails processes HEAD requests the same as GETs, returning just the response headers"
187
+ end
188
+
189
+ unless HTTP_METHODS.include?(m.to_sym)
190
+ raise ArgumentError, "Invalid HTTP method specified in route conditions: #{conditions.inspect}"
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,130 @@
1
+ module ActionController
2
+ module Routing
3
+ # Much of the slow performance from routes comes from the
4
+ # complexity of expiry, <tt>:requirements</tt> matching, defaults providing
5
+ # and figuring out which url pattern to use. With named routes
6
+ # we can avoid the expense of finding the right route. So if
7
+ # they've provided the right number of arguments, and have no
8
+ # <tt>:requirements</tt>, we can just build up a string and return it.
9
+ #
10
+ # To support building optimisations for other common cases, the
11
+ # generation code is separated into several classes
12
+ module Optimisation
13
+ def generate_optimisation_block(route, kind)
14
+ return "" unless route.optimise?
15
+ OPTIMISERS.inject("") do |memo, klazz|
16
+ memo << klazz.new(route, kind).source_code
17
+ memo
18
+ end
19
+ end
20
+
21
+ class Optimiser
22
+ attr_reader :route, :kind
23
+ GLOBAL_GUARD_CONDITIONS = [
24
+ "(!defined?(default_url_options) || default_url_options.blank?)",
25
+ "(!defined?(controller.default_url_options) || controller.default_url_options.blank?)",
26
+ "defined?(request)",
27
+ "request"
28
+ ]
29
+
30
+ def initialize(route, kind)
31
+ @route = route
32
+ @kind = kind
33
+ end
34
+
35
+ def guard_conditions
36
+ ["false"]
37
+ end
38
+
39
+ def generation_code
40
+ 'nil'
41
+ end
42
+
43
+ def source_code
44
+ if applicable?
45
+ guard_condition = (GLOBAL_GUARD_CONDITIONS + guard_conditions).join(" && ")
46
+ "return #{generation_code} if #{guard_condition}\n"
47
+ else
48
+ "\n"
49
+ end
50
+ end
51
+
52
+ # Temporarily disabled <tt>:url</tt> optimisation pending proper solution to
53
+ # Issues around request.host etc.
54
+ def applicable?
55
+ true
56
+ end
57
+ end
58
+
59
+ # Given a route
60
+ #
61
+ # map.person '/people/:id'
62
+ #
63
+ # If the user calls <tt>person_url(@person)</tt>, we can simply
64
+ # return a string like "/people/#{@person.to_param}"
65
+ # rather than triggering the expensive logic in +url_for+.
66
+ class PositionalArguments < Optimiser
67
+ def guard_conditions
68
+ number_of_arguments = route.required_segment_keys.size
69
+ # if they're using foo_url(:id=>2) it's one
70
+ # argument, but we don't want to generate /foos/id2
71
+ if number_of_arguments == 1
72
+ ["args.size == 1", "!args.first.is_a?(Hash)"]
73
+ else
74
+ ["args.size == #{number_of_arguments}"]
75
+ end
76
+ end
77
+
78
+ def generation_code
79
+ elements = []
80
+ idx = 0
81
+
82
+ if kind == :url
83
+ elements << '#{request.protocol}'
84
+ elements << '#{request.host_with_port}'
85
+ end
86
+
87
+ elements << '#{ActionController::Base.relative_url_root if ActionController::Base.relative_url_root}'
88
+
89
+ # The last entry in <tt>route.segments</tt> appears to *always* be a
90
+ # 'divider segment' for '/' but we have assertions to ensure that
91
+ # we don't include the trailing slashes, so skip them.
92
+ (route.segments.size == 1 ? route.segments : route.segments[0..-2]).each do |segment|
93
+ if segment.is_a?(DynamicSegment)
94
+ elements << segment.interpolation_chunk("args[#{idx}].to_param")
95
+ idx += 1
96
+ else
97
+ elements << segment.interpolation_chunk
98
+ end
99
+ end
100
+ %("#{elements * ''}")
101
+ end
102
+ end
103
+
104
+ # This case is mostly the same as the positional arguments case
105
+ # above, but it supports additional query parameters as the last
106
+ # argument
107
+ class PositionalArgumentsWithAdditionalParams < PositionalArguments
108
+ def guard_conditions
109
+ ["args.size == #{route.segment_keys.size + 1}"] +
110
+ UrlRewriter::RESERVED_OPTIONS.collect{ |key| "!args.last.has_key?(:#{key})" }
111
+ end
112
+
113
+ # This case uses almost the same code as positional arguments,
114
+ # but add a question mark and args.last.to_query on the end,
115
+ # unless the last arg is empty
116
+ def generation_code
117
+ super.insert(-2, '#{\'?\' + args.last.to_query unless args.last.empty?}')
118
+ end
119
+
120
+ # To avoid generating "http://localhost/?host=foo.example.com" we
121
+ # can't use this optimisation on routes without any segments
122
+ def applicable?
123
+ super && route.segment_keys.size > 0
124
+ end
125
+ end
126
+
127
+ OPTIMISERS = [PositionalArguments, PositionalArgumentsWithAdditionalParams]
128
+ end
129
+ end
130
+ end