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,208 @@
1
+ require 'action_view/helpers/tag_helper'
2
+ require 'action_view/helpers/prototype_helper'
3
+
4
+ module ActionView
5
+ module Helpers
6
+ # Provides functionality for working with JavaScript in your views.
7
+ #
8
+ # == Ajax, controls and visual effects
9
+ #
10
+ # * For information on using Ajax, see
11
+ # ActionView::Helpers::PrototypeHelper.
12
+ # * For information on using controls and visual effects, see
13
+ # ActionView::Helpers::ScriptaculousHelper.
14
+ #
15
+ # == Including the JavaScript libraries into your pages
16
+ #
17
+ # Rails includes the Prototype JavaScript framework and the Scriptaculous
18
+ # JavaScript controls and visual effects library. If you wish to use
19
+ # these libraries and their helpers (ActionView::Helpers::PrototypeHelper
20
+ # and ActionView::Helpers::ScriptaculousHelper), you must do one of the
21
+ # following:
22
+ #
23
+ # * Use <tt><%= javascript_include_tag :defaults %></tt> in the HEAD
24
+ # section of your page (recommended): This function will return
25
+ # references to the JavaScript files created by the +rails+ command in
26
+ # your <tt>public/javascripts</tt> directory. Using it is recommended as
27
+ # the browser can then cache the libraries instead of fetching all the
28
+ # functions anew on every request.
29
+ # * Use <tt><%= javascript_include_tag 'prototype' %></tt>: As above, but
30
+ # will only include the Prototype core library, which means you are able
31
+ # to use all basic AJAX functionality. For the Scriptaculous-based
32
+ # JavaScript helpers, like visual effects, autocompletion, drag and drop
33
+ # and so on, you should use the method described above.
34
+ #
35
+ # For documentation on +javascript_include_tag+ see
36
+ # ActionView::Helpers::AssetTagHelper.
37
+ module JavaScriptHelper
38
+ unless const_defined? :JAVASCRIPT_PATH
39
+ JAVASCRIPT_PATH = File.join(File.dirname(__FILE__), 'javascripts')
40
+ end
41
+
42
+ include PrototypeHelper
43
+
44
+ # Returns a link of the given +name+ that will trigger a JavaScript +function+ using the
45
+ # onclick handler and return false after the fact.
46
+ #
47
+ # The first argument +name+ is used as the link text.
48
+ #
49
+ # The next arguments are optional and may include the javascript function definition and a hash of html_options.
50
+ #
51
+ # The +function+ argument can be omitted in favor of an +update_page+
52
+ # block, which evaluates to a string when the template is rendered
53
+ # (instead of making an Ajax request first).
54
+ #
55
+ # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button"
56
+ #
57
+ # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil
58
+ #
59
+ #
60
+ # Examples:
61
+ # link_to_function "Greeting", "alert('Hello world!')"
62
+ # Produces:
63
+ # <a onclick="alert('Hello world!'); return false;" href="#">Greeting</a>
64
+ #
65
+ # link_to_function(image_tag("delete"), "if (confirm('Really?')) do_delete()")
66
+ # Produces:
67
+ # <a onclick="if (confirm('Really?')) do_delete(); return false;" href="#">
68
+ # <img src="/images/delete.png?" alt="Delete"/>
69
+ # </a>
70
+ #
71
+ # link_to_function("Show me more", nil, :id => "more_link") do |page|
72
+ # page[:details].visual_effect :toggle_blind
73
+ # page[:more_link].replace_html "Show me less"
74
+ # end
75
+ # Produces:
76
+ # <a href="#" id="more_link" onclick="try {
77
+ # $(&quot;details&quot;).visualEffect(&quot;toggle_blind&quot;);
78
+ # $(&quot;more_link&quot;).update(&quot;Show me less&quot;);
79
+ # }
80
+ # catch (e) {
81
+ # alert('RJS error:\n\n' + e.toString());
82
+ # alert('$(\&quot;details\&quot;).visualEffect(\&quot;toggle_blind\&quot;);
83
+ # \n$(\&quot;more_link\&quot;).update(\&quot;Show me less\&quot;);');
84
+ # throw e
85
+ # };
86
+ # return false;">Show me more</a>
87
+ #
88
+ def link_to_function(name, *args, &block)
89
+ html_options = args.extract_options!.symbolize_keys
90
+
91
+ function = block_given? ? update_page(&block) : args[0] || ''
92
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
93
+ href = html_options[:href] || '#'
94
+
95
+ content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
96
+ end
97
+
98
+ # Returns a button with the given +name+ text that'll trigger a JavaScript +function+ using the
99
+ # onclick handler.
100
+ #
101
+ # The first argument +name+ is used as the button's value or display text.
102
+ #
103
+ # The next arguments are optional and may include the javascript function definition and a hash of html_options.
104
+ #
105
+ # The +function+ argument can be omitted in favor of an +update_page+
106
+ # block, which evaluates to a string when the template is rendered
107
+ # (instead of making an Ajax request first).
108
+ #
109
+ # The +html_options+ will accept a hash of html attributes for the link tag. Some examples are :class => "nav_button", :id => "articles_nav_button"
110
+ #
111
+ # Note: if you choose to specify the javascript function in a block, but would like to pass html_options, set the +function+ parameter to nil
112
+ #
113
+ # Examples:
114
+ # button_to_function "Greeting", "alert('Hello world!')"
115
+ # button_to_function "Delete", "if (confirm('Really?')) do_delete()"
116
+ # button_to_function "Details" do |page|
117
+ # page[:details].visual_effect :toggle_slide
118
+ # end
119
+ # button_to_function "Details", :class => "details_button" do |page|
120
+ # page[:details].visual_effect :toggle_slide
121
+ # end
122
+ def button_to_function(name, *args, &block)
123
+ html_options = args.extract_options!.symbolize_keys
124
+
125
+ function = block_given? ? update_page(&block) : args[0] || ''
126
+ onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
127
+
128
+ tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
129
+ end
130
+
131
+ JS_ESCAPE_MAP = {
132
+ '\\' => '\\\\',
133
+ '</' => '<\/',
134
+ "\r\n" => '\n',
135
+ "\n" => '\n',
136
+ "\r" => '\n',
137
+ '"' => '\\"',
138
+ "'" => "\\'" }
139
+
140
+ # Escape carrier returns and single and double quotes for JavaScript segments.
141
+ def escape_javascript(javascript)
142
+ if javascript
143
+ javascript.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { JS_ESCAPE_MAP[$1] }
144
+ else
145
+ ''
146
+ end
147
+ end
148
+
149
+ # Returns a JavaScript tag with the +content+ inside. Example:
150
+ # javascript_tag "alert('All is good')"
151
+ #
152
+ # Returns:
153
+ # <script type="text/javascript">
154
+ # //<![CDATA[
155
+ # alert('All is good')
156
+ # //]]>
157
+ # </script>
158
+ #
159
+ # +html_options+ may be a hash of attributes for the <script> tag. Example:
160
+ # javascript_tag "alert('All is good')", :defer => 'defer'
161
+ # # => <script defer="defer" type="text/javascript">alert('All is good')</script>
162
+ #
163
+ # Instead of passing the content as an argument, you can also use a block
164
+ # in which case, you pass your +html_options+ as the first parameter.
165
+ # <% javascript_tag :defer => 'defer' do -%>
166
+ # alert('All is good')
167
+ # <% end -%>
168
+ def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)
169
+ content =
170
+ if block_given?
171
+ html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
172
+ capture(&block)
173
+ else
174
+ content_or_options_with_block
175
+ end
176
+
177
+ tag = content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
178
+
179
+ if block_called_from_erb?(block)
180
+ concat(tag)
181
+ else
182
+ tag
183
+ end
184
+ end
185
+
186
+ def javascript_cdata_section(content) #:nodoc:
187
+ "\n//#{cdata_section("\n#{content}\n//")}\n"
188
+ end
189
+
190
+ protected
191
+ def options_for_javascript(options)
192
+ if options.empty?
193
+ '{}'
194
+ else
195
+ "{#{options.keys.map { |k| "#{k}:#{options[k]}" }.sort.join(', ')}}"
196
+ end
197
+ end
198
+
199
+ def array_or_string_for_javascript(option)
200
+ if option.kind_of?(Array)
201
+ "['#{option.join('\',\'')}']"
202
+ elsif !option.nil?
203
+ "'#{option}'"
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,308 @@
1
+ module ActionView
2
+ module Helpers #:nodoc:
3
+ # Provides methods for converting numbers into formatted strings.
4
+ # Methods are provided for phone numbers, currency, percentage,
5
+ # precision, positional notation, and file size.
6
+ module NumberHelper
7
+ # Formats a +number+ into a US phone number (e.g., (555) 123-9876). You can customize the format
8
+ # in the +options+ hash.
9
+ #
10
+ # ==== Options
11
+ # * <tt>:area_code</tt> - Adds parentheses around the area code.
12
+ # * <tt>:delimiter</tt> - Specifies the delimiter to use (defaults to "-").
13
+ # * <tt>:extension</tt> - Specifies an extension to add to the end of the
14
+ # generated number.
15
+ # * <tt>:country_code</tt> - Sets the country code for the phone number.
16
+ #
17
+ # ==== Examples
18
+ # number_to_phone(5551234) # => 555-1234
19
+ # number_to_phone(1235551234) # => 123-555-1234
20
+ # number_to_phone(1235551234, :area_code => true) # => (123) 555-1234
21
+ # number_to_phone(1235551234, :delimiter => " ") # => 123 555 1234
22
+ # number_to_phone(1235551234, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
23
+ # number_to_phone(1235551234, :country_code => 1) # => +1-123-555-1234
24
+ #
25
+ # number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
26
+ # => +1.123.555.1234 x 1343
27
+ def number_to_phone(number, options = {})
28
+ number = number.to_s.strip unless number.nil?
29
+ options = options.symbolize_keys
30
+ area_code = options[:area_code] || nil
31
+ delimiter = options[:delimiter] || "-"
32
+ extension = options[:extension].to_s.strip || nil
33
+ country_code = options[:country_code] || nil
34
+
35
+ begin
36
+ str = ""
37
+ str << "+#{country_code}#{delimiter}" unless country_code.blank?
38
+ str << if area_code
39
+ number.gsub!(/([0-9]{1,3})([0-9]{3})([0-9]{4}$)/,"(\\1) \\2#{delimiter}\\3")
40
+ else
41
+ number.gsub!(/([0-9]{0,3})([0-9]{3})([0-9]{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
42
+ number.starts_with?('-') ? number.slice!(1..-1) : number
43
+ end
44
+ str << " x #{extension}" unless extension.blank?
45
+ str
46
+ rescue
47
+ number
48
+ end
49
+ end
50
+
51
+ # Formats a +number+ into a currency string (e.g., $13.65). You can customize the format
52
+ # in the +options+ hash.
53
+ #
54
+ # ==== Options
55
+ # * <tt>:precision</tt> - Sets the level of precision (defaults to 2).
56
+ # * <tt>:unit</tt> - Sets the denomination of the currency (defaults to "$").
57
+ # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
58
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ",").
59
+ # * <tt>:format</tt> - Sets the format of the output string (defaults to "%u%n"). The field types are:
60
+ #
61
+ # %u The currency unit
62
+ # %n The number
63
+ #
64
+ # ==== Examples
65
+ # number_to_currency(1234567890.50) # => $1,234,567,890.50
66
+ # number_to_currency(1234567890.506) # => $1,234,567,890.51
67
+ # number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506
68
+ #
69
+ # number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "")
70
+ # # => &pound;1234567890,50
71
+ # number_to_currency(1234567890.50, :unit => "&pound;", :separator => ",", :delimiter => "", :format => "%n %u")
72
+ # # => 1234567890,50 &pound;
73
+ def number_to_currency(number, options = {})
74
+ options.symbolize_keys!
75
+
76
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
77
+ currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :raise => true) rescue {}
78
+ defaults = defaults.merge(currency)
79
+
80
+ precision = options[:precision] || defaults[:precision]
81
+ unit = options[:unit] || defaults[:unit]
82
+ separator = options[:separator] || defaults[:separator]
83
+ delimiter = options[:delimiter] || defaults[:delimiter]
84
+ format = options[:format] || defaults[:format]
85
+ separator = '' if precision == 0
86
+
87
+ begin
88
+ format.gsub(/%n/, number_with_precision(number,
89
+ :precision => precision,
90
+ :delimiter => delimiter,
91
+ :separator => separator)
92
+ ).gsub(/%u/, unit)
93
+ rescue
94
+ number
95
+ end
96
+ end
97
+
98
+ # Formats a +number+ as a percentage string (e.g., 65%). You can customize the
99
+ # format in the +options+ hash.
100
+ #
101
+ # ==== Options
102
+ # * <tt>:precision</tt> - Sets the level of precision (defaults to 3).
103
+ # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
104
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
105
+ #
106
+ # ==== Examples
107
+ # number_to_percentage(100) # => 100.000%
108
+ # number_to_percentage(100, :precision => 0) # => 100%
109
+ # number_to_percentage(1000, :delimiter => '.', :separator => ',') # => 1.000,000%
110
+ # number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
111
+ def number_to_percentage(number, options = {})
112
+ options.symbolize_keys!
113
+
114
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
115
+ percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :raise => true) rescue {}
116
+ defaults = defaults.merge(percentage)
117
+
118
+ precision = options[:precision] || defaults[:precision]
119
+ separator = options[:separator] || defaults[:separator]
120
+ delimiter = options[:delimiter] || defaults[:delimiter]
121
+
122
+ begin
123
+ number_with_precision(number,
124
+ :precision => precision,
125
+ :separator => separator,
126
+ :delimiter => delimiter) + "%"
127
+ rescue
128
+ number
129
+ end
130
+ end
131
+
132
+ # Formats a +number+ with grouped thousands using +delimiter+ (e.g., 12,324). You can
133
+ # customize the format in the +options+ hash.
134
+ #
135
+ # ==== Options
136
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to ",").
137
+ # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
138
+ #
139
+ # ==== Examples
140
+ # number_with_delimiter(12345678) # => 12,345,678
141
+ # number_with_delimiter(12345678.05) # => 12,345,678.05
142
+ # number_with_delimiter(12345678, :delimiter => ".") # => 12.345.678
143
+ # number_with_delimiter(12345678, :separator => ",") # => 12,345,678
144
+ # number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
145
+ # # => 98 765 432,98
146
+ #
147
+ # You can still use <tt>number_with_delimiter</tt> with the old API that accepts the
148
+ # +delimiter+ as its optional second and the +separator+ as its
149
+ # optional third parameter:
150
+ # number_with_delimiter(12345678, " ") # => 12 345.678
151
+ # number_with_delimiter(12345678.05, ".", ",") # => 12.345.678,05
152
+ def number_with_delimiter(number, *args)
153
+ options = args.extract_options!
154
+ options.symbolize_keys!
155
+
156
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
157
+
158
+ unless args.empty?
159
+ ActiveSupport::Deprecation.warn('number_with_delimiter takes an option hash ' +
160
+ 'instead of separate delimiter and precision arguments.', caller)
161
+ delimiter = args[0] || defaults[:delimiter]
162
+ separator = args[1] || defaults[:separator]
163
+ end
164
+
165
+ delimiter ||= (options[:delimiter] || defaults[:delimiter])
166
+ separator ||= (options[:separator] || defaults[:separator])
167
+
168
+ begin
169
+ parts = number.to_s.split('.')
170
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
171
+ parts.join(separator)
172
+ rescue
173
+ number
174
+ end
175
+ end
176
+
177
+ # Formats a +number+ with the specified level of <tt>:precision</tt> (e.g., 112.32 has a precision of 2).
178
+ # You can customize the format in the +options+ hash.
179
+ #
180
+ # ==== Options
181
+ # * <tt>:precision</tt> - Sets the level of precision (defaults to 3).
182
+ # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
183
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
184
+ #
185
+ # ==== Examples
186
+ # number_with_precision(111.2345) # => 111.235
187
+ # number_with_precision(111.2345, :precision => 2) # => 111.23
188
+ # number_with_precision(13, :precision => 5) # => 13.00000
189
+ # number_with_precision(389.32314, :precision => 0) # => 389
190
+ # number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
191
+ # # => 1.111,23
192
+ #
193
+ # You can still use <tt>number_with_precision</tt> with the old API that accepts the
194
+ # +precision+ as its optional second parameter:
195
+ # number_with_precision(number_with_precision(111.2345, 2) # => 111.23
196
+ def number_with_precision(number, *args)
197
+ options = args.extract_options!
198
+ options.symbolize_keys!
199
+
200
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
201
+ precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale],
202
+ :raise => true) rescue {}
203
+ defaults = defaults.merge(precision_defaults)
204
+
205
+ unless args.empty?
206
+ ActiveSupport::Deprecation.warn('number_with_precision takes an option hash ' +
207
+ 'instead of a separate precision argument.', caller)
208
+ precision = args[0] || defaults[:precision]
209
+ end
210
+
211
+ precision ||= (options[:precision] || defaults[:precision])
212
+ separator ||= (options[:separator] || defaults[:separator])
213
+ delimiter ||= (options[:delimiter] || defaults[:delimiter])
214
+
215
+ begin
216
+ rounded_number = (Float(number) * (10 ** precision)).round.to_f / 10 ** precision
217
+ number_with_delimiter("%01.#{precision}f" % rounded_number,
218
+ :separator => separator,
219
+ :delimiter => delimiter)
220
+ rescue
221
+ number
222
+ end
223
+ end
224
+
225
+ STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb].freeze
226
+
227
+ # Formats the bytes in +size+ into a more understandable representation
228
+ # (e.g., giving it 1500 yields 1.5 KB). This method is useful for
229
+ # reporting file sizes to users. This method returns nil if
230
+ # +size+ cannot be converted into a number. You can customize the
231
+ # format in the +options+ hash.
232
+ #
233
+ # ==== Options
234
+ # * <tt>:precision</tt> - Sets the level of precision (defaults to 1).
235
+ # * <tt>:separator</tt> - Sets the separator between the units (defaults to ".").
236
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults to "").
237
+ #
238
+ # ==== Examples
239
+ # number_to_human_size(123) # => 123 Bytes
240
+ # number_to_human_size(1234) # => 1.2 KB
241
+ # number_to_human_size(12345) # => 12.1 KB
242
+ # number_to_human_size(1234567) # => 1.2 MB
243
+ # number_to_human_size(1234567890) # => 1.1 GB
244
+ # number_to_human_size(1234567890123) # => 1.1 TB
245
+ # number_to_human_size(1234567, :precision => 2) # => 1.18 MB
246
+ # number_to_human_size(483989, :precision => 0) # => 473 KB
247
+ # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,18 MB
248
+ #
249
+ # Zeros after the decimal point are always stripped out, regardless of the
250
+ # specified precision:
251
+ # helper.number_to_human_size(1234567890123, :precision => 5) # => "1.12283 TB"
252
+ # helper.number_to_human_size(524288000, :precision=>5) # => "500 MB"
253
+ #
254
+ # You can still use <tt>number_to_human_size</tt> with the old API that accepts the
255
+ # +precision+ as its optional second parameter:
256
+ # number_to_human_size(1234567, 2) # => 1.18 MB
257
+ # number_to_human_size(483989, 0) # => 473 KB
258
+ def number_to_human_size(number, *args)
259
+ return nil if number.nil?
260
+
261
+ options = args.extract_options!
262
+ options.symbolize_keys!
263
+
264
+ defaults = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
265
+ human = I18n.translate(:'number.human.format', :locale => options[:locale], :raise => true) rescue {}
266
+ defaults = defaults.merge(human)
267
+
268
+ unless args.empty?
269
+ ActiveSupport::Deprecation.warn('number_to_human_size takes an option hash ' +
270
+ 'instead of a separate precision argument.', caller)
271
+ precision = args[0] || defaults[:precision]
272
+ end
273
+
274
+ precision ||= (options[:precision] || defaults[:precision])
275
+ separator ||= (options[:separator] || defaults[:separator])
276
+ delimiter ||= (options[:delimiter] || defaults[:delimiter])
277
+
278
+ storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
279
+
280
+ if number.to_i < 1024
281
+ unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
282
+ storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit)
283
+ else
284
+ max_exp = STORAGE_UNITS.size - 1
285
+ number = Float(number)
286
+ exponent = (Math.log(number) / Math.log(1024)).to_i # Convert to base 1024
287
+ exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
288
+ number /= 1024 ** exponent
289
+
290
+ unit_key = STORAGE_UNITS[exponent]
291
+ unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
292
+
293
+ begin
294
+ escaped_separator = Regexp.escape(separator)
295
+ formatted_number = number_with_precision(number,
296
+ :precision => precision,
297
+ :separator => separator,
298
+ :delimiter => delimiter
299
+ ).sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '')
300
+ storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit)
301
+ rescue
302
+ number
303
+ end
304
+ end
305
+ end
306
+ end
307
+ end
308
+ end