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,587 @@
1
+ require 'action_view/helpers/tag_helper'
2
+
3
+ module ActionView
4
+ module Helpers #:nodoc:
5
+ # The TextHelper module provides a set of methods for filtering, formatting
6
+ # and transforming strings, which can reduce the amount of inline Ruby code in
7
+ # your views. These helper methods extend ActionView making them callable
8
+ # within your template files.
9
+ module TextHelper
10
+ # The preferred method of outputting text in your views is to use the
11
+ # <%= "text" %> eRuby syntax. The regular _puts_ and _print_ methods
12
+ # do not operate as expected in an eRuby code block. If you absolutely must
13
+ # output text within a non-output code block (i.e., <% %>), you can use the concat method.
14
+ #
15
+ # ==== Examples
16
+ # <%
17
+ # concat "hello"
18
+ # # is the equivalent of <%= "hello" %>
19
+ #
20
+ # if (logged_in == true):
21
+ # concat "Logged in!"
22
+ # else
23
+ # concat link_to('login', :action => login)
24
+ # end
25
+ # # will either display "Logged in!" or a login link
26
+ # %>
27
+ def concat(string, unused_binding = nil)
28
+ if unused_binding
29
+ ActiveSupport::Deprecation.warn("The binding argument of #concat is no longer needed. Please remove it from your views and helpers.", caller)
30
+ end
31
+
32
+ output_buffer << string
33
+ end
34
+
35
+ # Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt>
36
+ # (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...")
37
+ # for a total length not exceeding <tt>:length</tt>.
38
+ #
39
+ # ==== Examples
40
+ #
41
+ # truncate("Once upon a time in a world far far away")
42
+ # # => Once upon a time in a world...
43
+ #
44
+ # truncate("Once upon a time in a world far far away", :length => 14)
45
+ # # => Once upon a...
46
+ #
47
+ # truncate("And they found that many people were sleeping better.", :length => 25, "(clipped)")
48
+ # # => And they found t(clipped)
49
+ #
50
+ # truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 25)
51
+ # # => And they f... (continued)
52
+ #
53
+ # You can still use <tt>truncate</tt> with the old API that accepts the
54
+ # +length+ as its optional second and the +ellipsis+ as its
55
+ # optional third parameter:
56
+ # truncate("Once upon a time in a world far far away", 14)
57
+ # # => Once upon a...
58
+ #
59
+ # truncate("And they found that many people were sleeping better.", 25, "... (continued)")
60
+ # # => And they f... (continued)
61
+ def truncate(text, *args)
62
+ options = args.extract_options!
63
+ unless args.empty?
64
+ ActiveSupport::Deprecation.warn('truncate takes an option hash instead of separate ' +
65
+ 'length and omission arguments', caller)
66
+
67
+ options[:length] = args[0] || 30
68
+ options[:omission] = args[1] || "..."
69
+ end
70
+ options.reverse_merge!(:length => 30, :omission => "...")
71
+
72
+ if text
73
+ l = options[:length] - options[:omission].mb_chars.length
74
+ chars = text.mb_chars
75
+ (chars.length > options[:length] ? chars[0...l] + options[:omission] : text).to_s
76
+ end
77
+ end
78
+
79
+ # Highlights one or more +phrases+ everywhere in +text+ by inserting it into
80
+ # a <tt>:highlighter</tt> string. The highlighter can be specialized by passing <tt>:highlighter</tt>
81
+ # as a single-quoted string with \1 where the phrase is to be inserted (defaults to
82
+ # '<strong class="highlight">\1</strong>')
83
+ #
84
+ # ==== Examples
85
+ # highlight('You searched for: rails', 'rails')
86
+ # # => You searched for: <strong class="highlight">rails</strong>
87
+ #
88
+ # highlight('You searched for: ruby, rails, dhh', 'actionpack')
89
+ # # => You searched for: ruby, rails, dhh
90
+ #
91
+ # highlight('You searched for: rails', ['for', 'rails'], :highlighter => '<em>\1</em>')
92
+ # # => You searched <em>for</em>: <em>rails</em>
93
+ #
94
+ # highlight('You searched for: rails', 'rails', :highlighter => '<a href="search?q=\1">\1</a>')
95
+ # # => You searched for: <a href="search?q=rails">rails</a>
96
+ #
97
+ # You can still use <tt>highlight</tt> with the old API that accepts the
98
+ # +highlighter+ as its optional third parameter:
99
+ # highlight('You searched for: rails', 'rails', '<a href="search?q=\1">\1</a>') # => You searched for: <a href="search?q=rails">rails</a>
100
+ def highlight(text, phrases, *args)
101
+ options = args.extract_options!
102
+ unless args.empty?
103
+ options[:highlighter] = args[0] || '<strong class="highlight">\1</strong>'
104
+ end
105
+ options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
106
+
107
+ if text.blank? || phrases.blank?
108
+ text
109
+ else
110
+ match = Array(phrases).map { |p| Regexp.escape(p) }.join('|')
111
+ text.gsub(/(#{match})(?!(?:[^<]*?)(?:["'])[^<>]*>)/i, options[:highlighter])
112
+ end
113
+ end
114
+
115
+ # Extracts an excerpt from +text+ that matches the first instance of +phrase+.
116
+ # The <tt>:radius</tt> option expands the excerpt on each side of the first occurrence of +phrase+ by the number of characters
117
+ # defined in <tt>:radius</tt> (which defaults to 100). If the excerpt radius overflows the beginning or end of the +text+,
118
+ # then the <tt>:omission</tt> option (which defaults to "...") will be prepended/appended accordingly. The resulting string
119
+ # will be stripped in any case. If the +phrase+ isn't found, nil is returned.
120
+ #
121
+ # ==== Examples
122
+ # excerpt('This is an example', 'an', :radius => 5)
123
+ # # => ...s is an exam...
124
+ #
125
+ # excerpt('This is an example', 'is', :radius => 5)
126
+ # # => This is a...
127
+ #
128
+ # excerpt('This is an example', 'is')
129
+ # # => This is an example
130
+ #
131
+ # excerpt('This next thing is an example', 'ex', :radius => 2)
132
+ # # => ...next...
133
+ #
134
+ # excerpt('This is also an example', 'an', :radius => 8, :omission => '<chop> ')
135
+ # # => <chop> is also an example
136
+ #
137
+ # You can still use <tt>excerpt</tt> with the old API that accepts the
138
+ # +radius+ as its optional third and the +ellipsis+ as its
139
+ # optional forth parameter:
140
+ # excerpt('This is an example', 'an', 5) # => ...s is an exam...
141
+ # excerpt('This is also an example', 'an', 8, '<chop> ') # => <chop> is also an example
142
+ def excerpt(text, phrase, *args)
143
+ options = args.extract_options!
144
+ unless args.empty?
145
+ options[:radius] = args[0] || 100
146
+ options[:omission] = args[1] || "..."
147
+ end
148
+ options.reverse_merge!(:radius => 100, :omission => "...")
149
+
150
+ if text && phrase
151
+ phrase = Regexp.escape(phrase)
152
+
153
+ if found_pos = text.mb_chars =~ /(#{phrase})/i
154
+ start_pos = [ found_pos - options[:radius], 0 ].max
155
+ end_pos = [ [ found_pos + phrase.mb_chars.length + options[:radius] - 1, 0].max, text.mb_chars.length ].min
156
+
157
+ prefix = start_pos > 0 ? options[:omission] : ""
158
+ postfix = end_pos < text.mb_chars.length - 1 ? options[:omission] : ""
159
+
160
+ prefix + text.mb_chars[start_pos..end_pos].strip + postfix
161
+ else
162
+ nil
163
+ end
164
+ end
165
+ end
166
+
167
+ # Attempts to pluralize the +singular+ word unless +count+ is 1. If
168
+ # +plural+ is supplied, it will use that when count is > 1, otherwise
169
+ # it will use the Inflector to determine the plural form
170
+ #
171
+ # ==== Examples
172
+ # pluralize(1, 'person')
173
+ # # => 1 person
174
+ #
175
+ # pluralize(2, 'person')
176
+ # # => 2 people
177
+ #
178
+ # pluralize(3, 'person', 'users')
179
+ # # => 3 users
180
+ #
181
+ # pluralize(0, 'person')
182
+ # # => 0 people
183
+ def pluralize(count, singular, plural = nil)
184
+ "#{count || 0} " + ((count == 1 || count == '1') ? singular : (plural || singular.pluralize))
185
+ end
186
+
187
+ # Wraps the +text+ into lines no longer than +line_width+ width. This method
188
+ # breaks on the first whitespace character that does not exceed +line_width+
189
+ # (which is 80 by default).
190
+ #
191
+ # ==== Examples
192
+ #
193
+ # word_wrap('Once upon a time')
194
+ # # => Once upon a time
195
+ #
196
+ # word_wrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
197
+ # # => Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\n a successor to the throne turned out to be more trouble than anyone could have\n imagined...
198
+ #
199
+ # word_wrap('Once upon a time', :line_width => 8)
200
+ # # => Once upon\na time
201
+ #
202
+ # word_wrap('Once upon a time', :line_width => 1)
203
+ # # => Once\nupon\na\ntime
204
+ #
205
+ # You can still use <tt>word_wrap</tt> with the old API that accepts the
206
+ # +line_width+ as its optional second parameter:
207
+ # word_wrap('Once upon a time', 8) # => Once upon\na time
208
+ def word_wrap(text, *args)
209
+ options = args.extract_options!
210
+ unless args.blank?
211
+ options[:line_width] = args[0] || 80
212
+ end
213
+ options.reverse_merge!(:line_width => 80)
214
+
215
+ text.split("\n").collect do |line|
216
+ line.length > options[:line_width] ? line.gsub(/(.{1,#{options[:line_width]}})(\s+|$)/, "\\1\n").strip : line
217
+ end * "\n"
218
+ end
219
+
220
+ # Returns the text with all the Textile[http://www.textism.com/tools/textile] codes turned into HTML tags.
221
+ #
222
+ # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
223
+ # <i>This method is only available if RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
224
+ # is available</i>.
225
+ #
226
+ # ==== Examples
227
+ # textilize("*This is Textile!* Rejoice!")
228
+ # # => "<p><strong>This is Textile!</strong> Rejoice!</p>"
229
+ #
230
+ # textilize("I _love_ ROR(Ruby on Rails)!")
231
+ # # => "<p>I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!</p>"
232
+ #
233
+ # textilize("h2. Textile makes markup -easy- simple!")
234
+ # # => "<h2>Textile makes markup <del>easy</del> simple!</h2>"
235
+ #
236
+ # textilize("Visit the Rails website "here":http://www.rubyonrails.org/.)
237
+ # # => "<p>Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>.</p>"
238
+ #
239
+ # textilize("This is worded <strong>strongly</strong>")
240
+ # # => "<p>This is worded <strong>strongly</strong></p>"
241
+ #
242
+ # textilize("This is worded <strong>strongly</strong>", :filter_html)
243
+ # # => "<p>This is worded &lt;strong&gt;strongly&lt;/strong&gt;</p>"
244
+ #
245
+ def textilize(text, *options)
246
+ options ||= [:hard_breaks]
247
+
248
+ if text.blank?
249
+ ""
250
+ else
251
+ textilized = RedCloth.new(text, options)
252
+ textilized.to_html
253
+ end
254
+ end
255
+
256
+ # Returns the text with all the Textile codes turned into HTML tags,
257
+ # but without the bounding <p> tag that RedCloth adds.
258
+ #
259
+ # You can learn more about Textile's syntax at its website[http://www.textism.com/tools/textile].
260
+ # <i>This method is requires RedCloth[http://whytheluckystiff.net/ruby/redcloth/]
261
+ # to be available</i>.
262
+ #
263
+ # ==== Examples
264
+ # textilize_without_paragraph("*This is Textile!* Rejoice!")
265
+ # # => "<strong>This is Textile!</strong> Rejoice!"
266
+ #
267
+ # textilize_without_paragraph("I _love_ ROR(Ruby on Rails)!")
268
+ # # => "I <em>love</em> <acronym title="Ruby on Rails">ROR</acronym>!"
269
+ #
270
+ # textilize_without_paragraph("h2. Textile makes markup -easy- simple!")
271
+ # # => "<h2>Textile makes markup <del>easy</del> simple!</h2>"
272
+ #
273
+ # textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
274
+ # # => "Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>."
275
+ def textilize_without_paragraph(text)
276
+ textiled = textilize(text)
277
+ if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end
278
+ if textiled[-4..-1] == "</p>" then textiled = textiled[0..-5] end
279
+ return textiled
280
+ end
281
+
282
+ # Returns the text with all the Markdown codes turned into HTML tags.
283
+ # <i>This method requires BlueCloth[http://www.deveiate.org/projects/BlueCloth] or another
284
+ # Markdown library to be installed.</i>.
285
+ #
286
+ # ==== Examples
287
+ # markdown("We are using __Markdown__ now!")
288
+ # # => "<p>We are using <strong>Markdown</strong> now!</p>"
289
+ #
290
+ # markdown("We like to _write_ `code`, not just _read_ it!")
291
+ # # => "<p>We like to <em>write</em> <code>code</code>, not just <em>read</em> it!</p>"
292
+ #
293
+ # markdown("The [Markdown website](http://daringfireball.net/projects/markdown/) has more information.")
294
+ # # => "<p>The <a href="http://daringfireball.net/projects/markdown/">Markdown website</a>
295
+ # # has more information.</p>"
296
+ #
297
+ # markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
298
+ # # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'
299
+ def markdown(text)
300
+ text.blank? ? "" : Markdown.new(text).to_html
301
+ end
302
+
303
+ # Returns +text+ transformed into HTML using simple formatting rules.
304
+ # Two or more consecutive newlines(<tt>\n\n</tt>) are considered as a
305
+ # paragraph and wrapped in <tt><p></tt> tags. One newline (<tt>\n</tt>) is
306
+ # considered as a linebreak and a <tt><br /></tt> tag is appended. This
307
+ # method does not remove the newlines from the +text+.
308
+ #
309
+ # You can pass any HTML attributes into <tt>html_options</tt>. These
310
+ # will be added to all created paragraphs.
311
+ # ==== Examples
312
+ # my_text = "Here is some basic text...\n...with a line break."
313
+ #
314
+ # simple_format(my_text)
315
+ # # => "<p>Here is some basic text...\n<br />...with a line break.</p>"
316
+ #
317
+ # more_text = "We want to put a paragraph...\n\n...right there."
318
+ #
319
+ # simple_format(more_text)
320
+ # # => "<p>We want to put a paragraph...</p>\n\n<p>...right there.</p>"
321
+ #
322
+ # simple_format("Look ma! A class!", :class => 'description')
323
+ # # => "<p class='description'>Look ma! A class!</p>"
324
+ def simple_format(text, html_options={})
325
+ start_tag = tag('p', html_options, true)
326
+ text = text.to_s.dup
327
+ text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
328
+ text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
329
+ text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
330
+ text.insert 0, start_tag
331
+ text << "</p>"
332
+ end
333
+
334
+ # Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
335
+ # will limit what should be linked. You can add HTML attributes to the links using
336
+ # <tt>:href_options</tt>. Possible values for <tt>:link</tt> are <tt>:all</tt> (default),
337
+ # <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
338
+ # e-mail address is yielded and the result is used as the link text.
339
+ #
340
+ # ==== Examples
341
+ # auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
342
+ # # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
343
+ # # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
344
+ #
345
+ # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls)
346
+ # # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
347
+ # # or e-mail david@loudthinking.com"
348
+ #
349
+ # auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
350
+ # # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
351
+ #
352
+ # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
353
+ # auto_link(post_body, :href_options => { :target => '_blank' }) do |text|
354
+ # truncate(text, 15)
355
+ # end
356
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
357
+ # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
358
+ #
359
+ #
360
+ # You can still use <tt>auto_link</tt> with the old API that accepts the
361
+ # +link+ as its optional second parameter and the +html_options+ hash
362
+ # as its optional third parameter:
363
+ # post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
364
+ # auto_link(post_body, :urls) # => Once upon\na time
365
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>.
366
+ # Please e-mail me at me@email.com."
367
+ #
368
+ # auto_link(post_body, :all, :target => "_blank") # => Once upon\na time
369
+ # # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
370
+ # Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
371
+ def auto_link(text, *args, &block)#link = :all, href_options = {}, &block)
372
+ return '' if text.blank?
373
+
374
+ options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
375
+ unless args.empty?
376
+ options[:link] = args[0] || :all
377
+ options[:html] = args[1] || {}
378
+ end
379
+ options.reverse_merge!(:link => :all, :html => {})
380
+
381
+ case options[:link].to_sym
382
+ when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], &block), options[:html], &block)
383
+ when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
384
+ when :urls then auto_link_urls(text, options[:html], &block)
385
+ end
386
+ end
387
+
388
+ # Creates a Cycle object whose _to_s_ method cycles through elements of an
389
+ # array every time it is called. This can be used for example, to alternate
390
+ # classes for table rows. You can use named cycles to allow nesting in loops.
391
+ # Passing a Hash as the last parameter with a <tt>:name</tt> key will create a
392
+ # named cycle. The default name for a cycle without a +:name+ key is
393
+ # <tt>"default"</tt>. You can manually reset a cycle by calling reset_cycle
394
+ # and passing the name of the cycle. The current cycle string can be obtained
395
+ # anytime using the current_cycle method.
396
+ #
397
+ # ==== Examples
398
+ # # Alternate CSS classes for even and odd numbers...
399
+ # @items = [1,2,3,4]
400
+ # <table>
401
+ # <% @items.each do |item| %>
402
+ # <tr class="<%= cycle("even", "odd") -%>">
403
+ # <td>item</td>
404
+ # </tr>
405
+ # <% end %>
406
+ # </table>
407
+ #
408
+ #
409
+ # # Cycle CSS classes for rows, and text colors for values within each row
410
+ # @items = x = [{:first => 'Robert', :middle => 'Daniel', :last => 'James'},
411
+ # {:first => 'Emily', :middle => 'Shannon', :maiden => 'Pike', :last => 'Hicks'},
412
+ # {:first => 'June', :middle => 'Dae', :last => 'Jones'}]
413
+ # <% @items.each do |item| %>
414
+ # <tr class="<%= cycle("even", "odd", :name => "row_class") -%>">
415
+ # <td>
416
+ # <% item.values.each do |value| %>
417
+ # <%# Create a named cycle "colors" %>
418
+ # <span style="color:<%= cycle("red", "green", "blue", :name => "colors") -%>">
419
+ # <%= value %>
420
+ # </span>
421
+ # <% end %>
422
+ # <% reset_cycle("colors") %>
423
+ # </td>
424
+ # </tr>
425
+ # <% end %>
426
+ def cycle(first_value, *values)
427
+ if (values.last.instance_of? Hash)
428
+ params = values.pop
429
+ name = params[:name]
430
+ else
431
+ name = "default"
432
+ end
433
+ values.unshift(first_value)
434
+
435
+ cycle = get_cycle(name)
436
+ if (cycle.nil? || cycle.values != values)
437
+ cycle = set_cycle(name, Cycle.new(*values))
438
+ end
439
+ return cycle.to_s
440
+ end
441
+
442
+ # Returns the current cycle string after a cycle has been started. Useful
443
+ # for complex table highlighing or any other design need which requires
444
+ # the current cycle string in more than one place.
445
+ #
446
+ # ==== Example
447
+ # # Alternate background colors
448
+ # @items = [1,2,3,4]
449
+ # <% @items.each do |item| %>
450
+ # <div style="background-color:<%= cycle("red","white","blue") %>">
451
+ # <span style="background-color:<%= current_cycle %>"><%= item %></span>
452
+ # </div>
453
+ # <% end %>
454
+ def current_cycle(name = "default")
455
+ cycle = get_cycle(name)
456
+ cycle.current_value unless cycle.nil?
457
+ end
458
+
459
+ # Resets a cycle so that it starts from the first element the next time
460
+ # it is called. Pass in +name+ to reset a named cycle.
461
+ #
462
+ # ==== Example
463
+ # # Alternate CSS classes for even and odd numbers...
464
+ # @items = [[1,2,3,4], [5,6,3], [3,4,5,6,7,4]]
465
+ # <table>
466
+ # <% @items.each do |item| %>
467
+ # <tr class="<%= cycle("even", "odd") -%>">
468
+ # <% item.each do |value| %>
469
+ # <span style="color:<%= cycle("#333", "#666", "#999", :name => "colors") -%>">
470
+ # <%= value %>
471
+ # </span>
472
+ # <% end %>
473
+ #
474
+ # <% reset_cycle("colors") %>
475
+ # </tr>
476
+ # <% end %>
477
+ # </table>
478
+ def reset_cycle(name = "default")
479
+ cycle = get_cycle(name)
480
+ cycle.reset unless cycle.nil?
481
+ end
482
+
483
+ class Cycle #:nodoc:
484
+ attr_reader :values
485
+
486
+ def initialize(first_value, *values)
487
+ @values = values.unshift(first_value)
488
+ reset
489
+ end
490
+
491
+ def reset
492
+ @index = 0
493
+ end
494
+
495
+ def current_value
496
+ @values[previous_index].to_s
497
+ end
498
+
499
+ def to_s
500
+ value = @values[@index].to_s
501
+ @index = next_index
502
+ return value
503
+ end
504
+
505
+ private
506
+
507
+ def next_index
508
+ step_index(1)
509
+ end
510
+
511
+ def previous_index
512
+ step_index(-1)
513
+ end
514
+
515
+ def step_index(n)
516
+ (@index + n) % @values.size
517
+ end
518
+ end
519
+
520
+ private
521
+ # The cycle helpers need to store the cycles in a place that is
522
+ # guaranteed to be reset every time a page is rendered, so it
523
+ # uses an instance variable of ActionView::Base.
524
+ def get_cycle(name)
525
+ @_cycles = Hash.new unless defined?(@_cycles)
526
+ return @_cycles[name]
527
+ end
528
+
529
+ def set_cycle(name, cycle_object)
530
+ @_cycles = Hash.new unless defined?(@_cycles)
531
+ @_cycles[name] = cycle_object
532
+ end
533
+
534
+ AUTO_LINK_RE = %r{
535
+ ( https?:// | www\. )
536
+ [^\s<]+
537
+ }x unless const_defined?(:AUTO_LINK_RE)
538
+
539
+ BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
540
+
541
+ # Turns all urls into clickable links. If a block is given, each url
542
+ # is yielded and the result is used as the link text.
543
+ def auto_link_urls(text, html_options = {})
544
+ link_attributes = html_options.stringify_keys
545
+ text.gsub(AUTO_LINK_RE) do
546
+ href = $&
547
+ punctuation = ''
548
+ left, right = $`, $'
549
+ # detect already linked URLs and URLs in the middle of a tag
550
+ if left =~ /<[^>]+$/ && right =~ /^[^>]*>/
551
+ # do not change string; URL is alreay linked
552
+ href
553
+ else
554
+ # don't include trailing punctuation character as part of the URL
555
+ if href.sub!(/[^\w\/-]$/, '') and punctuation = $& and opening = BRACKETS[punctuation]
556
+ if href.scan(opening).size > href.scan(punctuation).size
557
+ href << punctuation
558
+ punctuation = ''
559
+ end
560
+ end
561
+
562
+ link_text = block_given?? yield(href) : href
563
+ href = 'http://' + href unless href.index('http') == 0
564
+
565
+ content_tag(:a, h(link_text), link_attributes.merge('href' => href)) + punctuation
566
+ end
567
+ end
568
+ end
569
+
570
+ # Turns all email addresses into clickable links. If a block is given,
571
+ # each email is yielded and the result is used as the link text.
572
+ def auto_link_email_addresses(text, html_options = {})
573
+ body = text.dup
574
+ text.gsub(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
575
+ text = $1
576
+
577
+ if body.match(/<a\b[^>]*>(.*)(#{Regexp.escape(text)})(.*)<\/a>/)
578
+ text
579
+ else
580
+ display_text = (block_given?) ? yield(text) : text
581
+ mail_to text, display_text, html_options
582
+ end
583
+ end
584
+ end
585
+ end
586
+ end
587
+ end
@@ -0,0 +1,39 @@
1
+ require 'action_view/helpers/tag_helper'
2
+
3
+ module ActionView
4
+ module Helpers
5
+ module TranslationHelper
6
+ # Delegates to I18n#translate but also performs two additional functions. First, it'll catch MissingTranslationData exceptions
7
+ # and turn them into inline spans that contains the missing key, such that you can see in a view what is missing where.
8
+ #
9
+ # Second, it'll scope the key by the current partial if the key starts with a period. So if you call translate(".foo") from the
10
+ # people/index.html.erb template, you'll actually be calling I18n.translate("people.index.foo"). This makes it less repetitive
11
+ # to translate many keys within the same partials and gives you a simple framework for scoping them consistently. If you don't
12
+ # prepend the key with a period, nothing is converted.
13
+ def translate(key, options = {})
14
+ options[:raise] = true
15
+ I18n.translate(scope_key_by_partial(key), options)
16
+ rescue I18n::MissingTranslationData => e
17
+ keys = I18n.send(:normalize_translation_keys, e.locale, e.key, e.options[:scope])
18
+ content_tag('span', keys.join(', '), :class => 'translation_missing')
19
+ end
20
+ alias :t :translate
21
+
22
+ # Delegates to I18n.localize with no additional functionality.
23
+ def localize(*args)
24
+ I18n.localize(*args)
25
+ end
26
+ alias :l :localize
27
+
28
+
29
+ private
30
+ def scope_key_by_partial(key)
31
+ if key.to_s.first == "."
32
+ template.path_without_format_and_extension.gsub(%r{/_?}, ".") + key.to_s
33
+ else
34
+ key
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end