actionpack 3.2.22.5 → 4.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +641 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -288
  5. data/lib/abstract_controller.rb +1 -8
  6. data/lib/abstract_controller/asset_paths.rb +2 -2
  7. data/lib/abstract_controller/base.rb +39 -37
  8. data/lib/abstract_controller/callbacks.rb +101 -82
  9. data/lib/abstract_controller/collector.rb +7 -3
  10. data/lib/abstract_controller/helpers.rb +23 -11
  11. data/lib/abstract_controller/layouts.rb +68 -73
  12. data/lib/abstract_controller/logger.rb +1 -2
  13. data/lib/abstract_controller/rendering.rb +22 -13
  14. data/lib/abstract_controller/translation.rb +16 -1
  15. data/lib/abstract_controller/url_for.rb +6 -6
  16. data/lib/abstract_controller/view_paths.rb +1 -1
  17. data/lib/action_controller.rb +15 -6
  18. data/lib/action_controller/base.rb +46 -22
  19. data/lib/action_controller/caching.rb +46 -33
  20. data/lib/action_controller/caching/fragments.rb +23 -53
  21. data/lib/action_controller/deprecated.rb +5 -1
  22. data/lib/action_controller/deprecated/integration_test.rb +3 -0
  23. data/lib/action_controller/log_subscriber.rb +11 -8
  24. data/lib/action_controller/metal.rb +16 -30
  25. data/lib/action_controller/metal/conditional_get.rb +76 -32
  26. data/lib/action_controller/metal/data_streaming.rb +20 -26
  27. data/lib/action_controller/metal/exceptions.rb +19 -6
  28. data/lib/action_controller/metal/flash.rb +24 -9
  29. data/lib/action_controller/metal/force_ssl.rb +32 -9
  30. data/lib/action_controller/metal/head.rb +25 -4
  31. data/lib/action_controller/metal/helpers.rb +6 -9
  32. data/lib/action_controller/metal/hide_actions.rb +1 -2
  33. data/lib/action_controller/metal/http_authentication.rb +105 -87
  34. data/lib/action_controller/metal/implicit_render.rb +1 -1
  35. data/lib/action_controller/metal/instrumentation.rb +2 -1
  36. data/lib/action_controller/metal/live.rb +141 -0
  37. data/lib/action_controller/metal/mime_responds.rb +161 -47
  38. data/lib/action_controller/metal/params_wrapper.rb +112 -74
  39. data/lib/action_controller/metal/rack_delegation.rb +9 -3
  40. data/lib/action_controller/metal/redirecting.rb +15 -20
  41. data/lib/action_controller/metal/renderers.rb +11 -9
  42. data/lib/action_controller/metal/rendering.rb +8 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +112 -19
  44. data/lib/action_controller/metal/responder.rb +20 -19
  45. data/lib/action_controller/metal/streaming.rb +12 -18
  46. data/lib/action_controller/metal/strong_parameters.rb +516 -0
  47. data/lib/action_controller/metal/testing.rb +13 -18
  48. data/lib/action_controller/metal/url_for.rb +27 -25
  49. data/lib/action_controller/model_naming.rb +12 -0
  50. data/lib/action_controller/railtie.rb +33 -17
  51. data/lib/action_controller/railties/helpers.rb +22 -0
  52. data/lib/action_controller/record_identifier.rb +18 -72
  53. data/lib/action_controller/test_case.rb +215 -123
  54. data/lib/action_controller/vendor/html-scanner.rb +4 -19
  55. data/lib/action_dispatch.rb +27 -19
  56. data/lib/action_dispatch/http/cache.rb +63 -11
  57. data/lib/action_dispatch/http/filter_parameters.rb +18 -8
  58. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  59. data/lib/action_dispatch/http/headers.rb +27 -19
  60. data/lib/action_dispatch/http/mime_negotiation.rb +25 -2
  61. data/lib/action_dispatch/http/mime_type.rb +145 -113
  62. data/lib/action_dispatch/http/mime_types.rb +1 -1
  63. data/lib/action_dispatch/http/parameter_filter.rb +44 -46
  64. data/lib/action_dispatch/http/parameters.rb +12 -5
  65. data/lib/action_dispatch/http/rack_cache.rb +2 -3
  66. data/lib/action_dispatch/http/request.rb +49 -18
  67. data/lib/action_dispatch/http/response.rb +129 -35
  68. data/lib/action_dispatch/http/upload.rb +60 -17
  69. data/lib/action_dispatch/http/url.rb +53 -31
  70. data/lib/action_dispatch/journey.rb +5 -0
  71. data/lib/action_dispatch/journey/backwards.rb +5 -0
  72. data/lib/action_dispatch/journey/formatter.rb +146 -0
  73. data/lib/action_dispatch/journey/gtg/builder.rb +162 -0
  74. data/lib/action_dispatch/journey/gtg/simulator.rb +44 -0
  75. data/lib/action_dispatch/journey/gtg/transition_table.rb +156 -0
  76. data/lib/action_dispatch/journey/nfa/builder.rb +76 -0
  77. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  78. data/lib/action_dispatch/journey/nfa/simulator.rb +47 -0
  79. data/lib/action_dispatch/journey/nfa/transition_table.rb +163 -0
  80. data/lib/action_dispatch/journey/nodes/node.rb +124 -0
  81. data/lib/action_dispatch/journey/parser.rb +206 -0
  82. data/lib/action_dispatch/journey/parser.y +47 -0
  83. data/lib/action_dispatch/journey/parser_extras.rb +23 -0
  84. data/lib/action_dispatch/journey/path/pattern.rb +196 -0
  85. data/lib/action_dispatch/journey/route.rb +116 -0
  86. data/lib/action_dispatch/journey/router.rb +164 -0
  87. data/lib/action_dispatch/journey/router/strexp.rb +24 -0
  88. data/lib/action_dispatch/journey/router/utils.rb +54 -0
  89. data/lib/action_dispatch/journey/routes.rb +75 -0
  90. data/lib/action_dispatch/journey/scanner.rb +61 -0
  91. data/lib/action_dispatch/journey/visitors.rb +189 -0
  92. data/lib/action_dispatch/journey/visualizer/fsm.css +34 -0
  93. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  94. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  95. data/lib/action_dispatch/middleware/callbacks.rb +9 -4
  96. data/lib/action_dispatch/middleware/cookies.rb +168 -57
  97. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -17
  98. data/lib/action_dispatch/middleware/exception_wrapper.rb +27 -3
  99. data/lib/action_dispatch/middleware/flash.rb +58 -58
  100. data/lib/action_dispatch/middleware/params_parser.rb +14 -29
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +31 -14
  102. data/lib/action_dispatch/middleware/reloader.rb +6 -6
  103. data/lib/action_dispatch/middleware/remote_ip.rb +145 -39
  104. data/lib/action_dispatch/middleware/request_id.rb +2 -6
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +22 -20
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +81 -7
  108. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +8 -3
  109. data/lib/action_dispatch/middleware/show_exceptions.rb +12 -45
  110. data/lib/action_dispatch/middleware/ssl.rb +70 -0
  111. data/lib/action_dispatch/middleware/stack.rb +6 -1
  112. data/lib/action_dispatch/middleware/static.rb +5 -24
  113. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +14 -11
  114. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +25 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +3 -3
  116. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +15 -9
  117. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +7 -2
  119. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +30 -15
  120. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +39 -13
  121. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +6 -2
  122. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  123. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +144 -0
  124. data/lib/action_dispatch/railtie.rb +16 -6
  125. data/lib/action_dispatch/request/session.rb +181 -0
  126. data/lib/action_dispatch/routing.rb +41 -40
  127. data/lib/action_dispatch/routing/inspector.rb +240 -0
  128. data/lib/action_dispatch/routing/mapper.rb +501 -273
  129. data/lib/action_dispatch/routing/polymorphic_routes.rb +16 -20
  130. data/lib/action_dispatch/routing/redirection.rb +46 -29
  131. data/lib/action_dispatch/routing/route_set.rb +203 -164
  132. data/lib/action_dispatch/routing/routes_proxy.rb +2 -0
  133. data/lib/action_dispatch/routing/url_for.rb +48 -33
  134. data/lib/action_dispatch/testing/assertions/dom.rb +3 -13
  135. data/lib/action_dispatch/testing/assertions/response.rb +32 -40
  136. data/lib/action_dispatch/testing/assertions/routing.rb +40 -39
  137. data/lib/action_dispatch/testing/assertions/selector.rb +15 -20
  138. data/lib/action_dispatch/testing/assertions/tag.rb +20 -23
  139. data/lib/action_dispatch/testing/integration.rb +41 -22
  140. data/lib/action_dispatch/testing/test_process.rb +9 -6
  141. data/lib/action_dispatch/testing/test_request.rb +7 -3
  142. data/lib/action_pack.rb +1 -1
  143. data/lib/action_pack/version.rb +4 -4
  144. data/lib/action_view.rb +17 -8
  145. data/lib/action_view/base.rb +15 -34
  146. data/lib/action_view/buffers.rb +1 -1
  147. data/lib/action_view/context.rb +4 -4
  148. data/lib/action_view/dependency_tracker.rb +91 -0
  149. data/lib/action_view/digestor.rb +85 -0
  150. data/lib/action_view/flows.rb +1 -4
  151. data/lib/action_view/helpers.rb +2 -4
  152. data/lib/action_view/helpers/active_model_helper.rb +3 -4
  153. data/lib/action_view/helpers/asset_tag_helper.rb +211 -353
  154. data/lib/action_view/helpers/asset_url_helper.rb +354 -0
  155. data/lib/action_view/helpers/atom_feed_helper.rb +13 -10
  156. data/lib/action_view/helpers/cache_helper.rb +150 -18
  157. data/lib/action_view/helpers/capture_helper.rb +42 -29
  158. data/lib/action_view/helpers/csrf_helper.rb +0 -2
  159. data/lib/action_view/helpers/date_helper.rb +268 -247
  160. data/lib/action_view/helpers/debug_helper.rb +10 -11
  161. data/lib/action_view/helpers/form_helper.rb +904 -547
  162. data/lib/action_view/helpers/form_options_helper.rb +341 -166
  163. data/lib/action_view/helpers/form_tag_helper.rb +188 -88
  164. data/lib/action_view/helpers/javascript_helper.rb +23 -16
  165. data/lib/action_view/helpers/number_helper.rb +148 -354
  166. data/lib/action_view/helpers/output_safety_helper.rb +3 -3
  167. data/lib/action_view/helpers/record_tag_helper.rb +17 -22
  168. data/lib/action_view/helpers/rendering_helper.rb +2 -4
  169. data/lib/action_view/helpers/sanitize_helper.rb +3 -6
  170. data/lib/action_view/helpers/tag_helper.rb +43 -37
  171. data/lib/action_view/helpers/tags.rb +39 -0
  172. data/lib/action_view/helpers/tags/base.rb +148 -0
  173. data/lib/action_view/helpers/tags/check_box.rb +64 -0
  174. data/lib/action_view/helpers/tags/checkable.rb +16 -0
  175. data/lib/action_view/helpers/tags/collection_check_boxes.rb +43 -0
  176. data/lib/action_view/helpers/tags/collection_helpers.rb +83 -0
  177. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +36 -0
  178. data/lib/action_view/helpers/tags/collection_select.rb +28 -0
  179. data/lib/action_view/helpers/tags/color_field.rb +25 -0
  180. data/lib/action_view/helpers/tags/date_field.rb +13 -0
  181. data/lib/action_view/helpers/tags/date_select.rb +72 -0
  182. data/lib/action_view/helpers/tags/datetime_field.rb +22 -0
  183. data/lib/action_view/helpers/tags/datetime_local_field.rb +19 -0
  184. data/lib/action_view/helpers/tags/datetime_select.rb +8 -0
  185. data/lib/action_view/helpers/tags/email_field.rb +8 -0
  186. data/lib/action_view/helpers/tags/file_field.rb +8 -0
  187. data/lib/action_view/helpers/tags/grouped_collection_select.rb +29 -0
  188. data/lib/action_view/helpers/tags/hidden_field.rb +8 -0
  189. data/lib/action_view/helpers/tags/label.rb +65 -0
  190. data/lib/action_view/helpers/tags/month_field.rb +13 -0
  191. data/lib/action_view/helpers/tags/number_field.rb +18 -0
  192. data/lib/action_view/helpers/tags/password_field.rb +12 -0
  193. data/lib/action_view/helpers/tags/radio_button.rb +31 -0
  194. data/lib/action_view/helpers/tags/range_field.rb +8 -0
  195. data/lib/action_view/helpers/tags/search_field.rb +24 -0
  196. data/lib/action_view/helpers/tags/select.rb +41 -0
  197. data/lib/action_view/helpers/tags/tel_field.rb +8 -0
  198. data/lib/action_view/helpers/tags/text_area.rb +18 -0
  199. data/lib/action_view/helpers/tags/text_field.rb +29 -0
  200. data/lib/action_view/helpers/tags/time_field.rb +13 -0
  201. data/lib/action_view/helpers/tags/time_select.rb +8 -0
  202. data/lib/action_view/helpers/tags/time_zone_select.rb +20 -0
  203. data/lib/action_view/helpers/tags/url_field.rb +8 -0
  204. data/lib/action_view/helpers/tags/week_field.rb +13 -0
  205. data/lib/action_view/helpers/text_helper.rb +126 -113
  206. data/lib/action_view/helpers/translation_helper.rb +32 -16
  207. data/lib/action_view/helpers/url_helper.rb +200 -271
  208. data/lib/action_view/locale/en.yml +1 -105
  209. data/lib/action_view/log_subscriber.rb +6 -4
  210. data/lib/action_view/lookup_context.rb +15 -39
  211. data/lib/action_view/model_naming.rb +12 -0
  212. data/lib/action_view/path_set.rb +9 -39
  213. data/lib/action_view/railtie.rb +6 -22
  214. data/lib/action_view/record_identifier.rb +84 -0
  215. data/lib/action_view/renderer/abstract_renderer.rb +10 -19
  216. data/lib/action_view/renderer/partial_renderer.rb +144 -81
  217. data/lib/action_view/renderer/renderer.rb +2 -19
  218. data/lib/action_view/renderer/streaming_template_renderer.rb +2 -5
  219. data/lib/action_view/renderer/template_renderer.rb +14 -13
  220. data/lib/action_view/routing_url_for.rb +107 -0
  221. data/lib/action_view/template.rb +22 -21
  222. data/lib/action_view/template/error.rb +22 -12
  223. data/lib/action_view/template/handlers.rb +12 -9
  224. data/lib/action_view/template/handlers/builder.rb +1 -1
  225. data/lib/action_view/template/handlers/erb.rb +11 -16
  226. data/lib/action_view/template/handlers/raw.rb +11 -0
  227. data/lib/action_view/template/resolver.rb +111 -83
  228. data/lib/action_view/template/text.rb +12 -8
  229. data/lib/action_view/template/types.rb +57 -0
  230. data/lib/action_view/test_case.rb +66 -43
  231. data/lib/action_view/testing/resolvers.rb +3 -2
  232. data/lib/action_view/vendor/html-scanner.rb +20 -0
  233. data/lib/{action_controller → action_view}/vendor/html-scanner/html/document.rb +0 -0
  234. data/lib/{action_controller → action_view}/vendor/html-scanner/html/node.rb +12 -12
  235. data/lib/{action_controller → action_view}/vendor/html-scanner/html/sanitizer.rb +18 -7
  236. data/lib/{action_controller → action_view}/vendor/html-scanner/html/selector.rb +1 -1
  237. data/lib/{action_controller → action_view}/vendor/html-scanner/html/tokenizer.rb +1 -1
  238. data/lib/{action_controller → action_view}/vendor/html-scanner/html/version.rb +0 -0
  239. metadata +135 -125
  240. data/lib/action_controller/caching/actions.rb +0 -185
  241. data/lib/action_controller/caching/pages.rb +0 -187
  242. data/lib/action_controller/caching/sweeping.rb +0 -97
  243. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  244. data/lib/action_controller/metal/compatibility.rb +0 -65
  245. data/lib/action_controller/metal/session_management.rb +0 -14
  246. data/lib/action_controller/railties/paths.rb +0 -25
  247. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  248. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  249. data/lib/action_dispatch/middleware/head.rb +0 -18
  250. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  251. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  252. data/lib/action_view/asset_paths.rb +0 -142
  253. data/lib/action_view/helpers/asset_paths.rb +0 -7
  254. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  255. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  256. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  257. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  258. data/lib/sprockets/assets.rake +0 -99
  259. data/lib/sprockets/bootstrap.rb +0 -37
  260. data/lib/sprockets/compressors.rb +0 -83
  261. data/lib/sprockets/helpers.rb +0 -6
  262. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  263. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  264. data/lib/sprockets/railtie.rb +0 -62
  265. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,5 +1,4 @@
1
1
  require 'action_view/helpers/tag_helper'
2
- require 'active_support/core_ext/string/encoding'
3
2
 
4
3
  module ActionView
5
4
  module Helpers
@@ -14,20 +13,18 @@ module ActionView
14
13
  "'" => "\\'"
15
14
  }
16
15
 
17
- if "ruby".encoding_aware?
18
- JS_ESCAPE_MAP["\342\200\250".force_encoding('UTF-8').encode!] = '
'
19
- else
20
- JS_ESCAPE_MAP["\342\200\250"] = '
'
21
- end
16
+ JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = '
'
17
+ JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = '
'
22
18
 
23
19
  # Escapes carriage returns and single and double quotes for JavaScript segments.
24
20
  #
25
- # Also available through the alias j(). This is particularly helpful in JavaScript responses, like:
21
+ # Also available through the alias j(). This is particularly helpful in JavaScript
22
+ # responses, like:
26
23
  #
27
24
  # $('some_element').replaceWith('<%=j render 'some/element_template' %>');
28
25
  def escape_javascript(javascript)
29
26
  if javascript
30
- result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }
27
+ result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }
31
28
  javascript.html_safe? ? result.html_safe : result
32
29
  else
33
30
  ''
@@ -40,20 +37,22 @@ module ActionView
40
37
  # javascript_tag "alert('All is good')"
41
38
  #
42
39
  # Returns:
43
- # <script type="text/javascript">
40
+ # <script>
44
41
  # //<![CDATA[
45
42
  # alert('All is good')
46
43
  # //]]>
47
44
  # </script>
48
45
  #
49
46
  # +html_options+ may be a hash of attributes for the <tt>\<script></tt>
50
- # tag. Example:
51
- # javascript_tag "alert('All is good')", :defer => 'defer'
52
- # # => <script defer="defer" type="text/javascript">alert('All is good')</script>
47
+ # tag.
48
+ #
49
+ # javascript_tag "alert('All is good')", defer: 'defer'
50
+ # # => <script defer="defer">alert('All is good')</script>
53
51
  #
54
52
  # Instead of passing the content as an argument, you can also use a block
55
53
  # in which case, you pass your +html_options+ as the first parameter.
56
- # <%= javascript_tag :defer => 'defer' do -%>
54
+ #
55
+ # <%= javascript_tag defer: 'defer' do -%>
57
56
  # alert('All is good')
58
57
  # <% end -%>
59
58
  def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)
@@ -65,7 +64,7 @@ module ActionView
65
64
  content_or_options_with_block
66
65
  end
67
66
 
68
- content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
67
+ content_tag(:script, javascript_cdata_section(content), html_options)
69
68
  end
70
69
 
71
70
  def javascript_cdata_section(content) #:nodoc:
@@ -78,10 +77,14 @@ module ActionView
78
77
  # name is used as button label and the JavaScript code goes into its +onclick+ attribute.
79
78
  # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+.
80
79
  #
81
- # button_to_function "Greeting", "alert('Hello world!')", :class => "ok"
80
+ # button_to_function "Greeting", "alert('Hello world!')", class: "ok"
82
81
  # # => <input class="ok" onclick="alert('Hello world!');" type="button" value="Greeting" />
83
82
  #
84
83
  def button_to_function(name, function=nil, html_options={})
84
+ message = "button_to_function is deprecated and will be removed from Rails 4.1. We recomend to use Unobtrusive JavaScript instead. " +
85
+ "See http://guides.rubyonrails.org/working_with_javascript_in_rails.html#unobtrusive-javascript"
86
+ ActiveSupport::Deprecation.warn message
87
+
85
88
  onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
86
89
 
87
90
  tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
@@ -96,10 +99,14 @@ module ActionView
96
99
  #
97
100
  # The +href+ attribute of the tag is set to "#" unless +html_options+ has one.
98
101
  #
99
- # link_to_function "Greeting", "alert('Hello world!')", :class => "nav_link"
102
+ # link_to_function "Greeting", "alert('Hello world!')", class: "nav_link"
100
103
  # # => <a class="nav_link" href="#" onclick="alert('Hello world!'); return false;">Greeting</a>
101
104
  #
102
105
  def link_to_function(name, function, html_options={})
106
+ message = "link_to_function is deprecated and will be removed from Rails 4.1. We recomend to use Unobtrusive JavaScript instead. " +
107
+ "See http://guides.rubyonrails.org/working_with_javascript_in_rails.html#unobtrusive-javascript"
108
+ ActiveSupport::Deprecation.warn message
109
+
103
110
  onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
104
111
  href = html_options[:href] || '#'
105
112
 
@@ -1,11 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  require 'active_support/core_ext/hash/keys'
4
- require 'active_support/core_ext/hash/reverse_merge'
5
- require 'active_support/core_ext/big_decimal/conversions'
6
- require 'active_support/core_ext/float/rounding'
7
- require 'active_support/core_ext/object/blank'
8
4
  require 'active_support/core_ext/string/output_safety'
5
+ require 'active_support/number_helper'
9
6
 
10
7
  module ActionView
11
8
  # = Action View Number Helpers
@@ -19,9 +16,6 @@ module ActionView
19
16
  # unchanged if can't be converted into a valid number.
20
17
  module NumberHelper
21
18
 
22
- DEFAULT_CURRENCY_VALUES = { :format => "%u%n", :negative_format => "-%u%n", :unit => "$", :separator => ".", :delimiter => ",",
23
- :precision => 2, :significant => false, :strip_insignificant_zeros => false }
24
-
25
19
  # Raised when argument +number+ param given to the helpers is invalid and
26
20
  # the option :raise is set to +true+.
27
21
  class InvalidNumberError < StandardError
@@ -34,8 +28,6 @@ module ActionView
34
28
  # Formats a +number+ into a US phone number (e.g., (555)
35
29
  # 123-9876). You can customize the format in the +options+ hash.
36
30
  #
37
- # ==== Options
38
- #
39
31
  # * <tt>:area_code</tt> - Adds parentheses around the area code.
40
32
  # * <tt>:delimiter</tt> - Specifies the delimiter to use
41
33
  # (defaults to "-").
@@ -46,56 +38,29 @@ module ActionView
46
38
  # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
47
39
  # the argument is invalid.
48
40
  #
49
- # ==== Examples
50
- #
51
- # number_to_phone(5551234) # => 555-1234
52
- # number_to_phone("5551234") # => 555-1234
53
- # number_to_phone(1235551234) # => 123-555-1234
54
- # number_to_phone(1235551234, :area_code => true) # => (123) 555-1234
55
- # number_to_phone(1235551234, :delimiter => " ") # => 123 555 1234
56
- # number_to_phone(1235551234, :area_code => true, :extension => 555) # => (123) 555-1234 x 555
57
- # number_to_phone(1235551234, :country_code => 1) # => +1-123-555-1234
58
- # number_to_phone("123a456") # => 123a456
59
- #
60
- # number_to_phone("1234a567", :raise => true) # => InvalidNumberError
61
- #
62
- # number_to_phone(1235551234, :country_code => 1, :extension => 1343, :delimiter => ".")
63
- # # => +1.123.555.1234 x 1343
41
+ # number_to_phone(5551234) # => 555-1234
42
+ # number_to_phone("5551234") # => 555-1234
43
+ # number_to_phone(1235551234) # => 123-555-1234
44
+ # number_to_phone(1235551234, area_code: true) # => (123) 555-1234
45
+ # number_to_phone(1235551234, delimiter: " ") # => 123 555 1234
46
+ # number_to_phone(1235551234, area_code: true, extension: 555) # => (123) 555-1234 x 555
47
+ # number_to_phone(1235551234, country_code: 1) # => +1-123-555-1234
48
+ # number_to_phone("123a456") # => 123a456
49
+ # number_to_phone("1234a567", raise: true) # => InvalidNumberError
50
+ #
51
+ # number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: ".")
52
+ # # => +1.123.555.1234 x 1343
64
53
  def number_to_phone(number, options = {})
65
54
  return unless number
55
+ options = options.symbolize_keys
66
56
 
67
- begin
68
- Float(number)
69
- rescue ArgumentError, TypeError
70
- raise InvalidNumberError, number
71
- end if options[:raise]
72
-
73
- number = number.to_s.strip
74
- options = options.symbolize_keys
75
- area_code = options[:area_code]
76
- delimiter = options[:delimiter] || "-"
77
- extension = options[:extension]
78
- country_code = options[:country_code]
79
-
80
- if area_code
81
- number.gsub!(/(\d{1,3})(\d{3})(\d{4}$)/,"(\\1) \\2#{delimiter}\\3")
82
- else
83
- number.gsub!(/(\d{0,3})(\d{3})(\d{4})$/,"\\1#{delimiter}\\2#{delimiter}\\3")
84
- number.slice!(0, 1) if number.starts_with?(delimiter) && !delimiter.blank?
85
- end
86
-
87
- str = []
88
- str << "+#{country_code}#{delimiter}" unless country_code.blank?
89
- str << number
90
- str << " x #{extension}" unless extension.blank?
91
- ERB::Util.html_escape(str.join)
57
+ parse_float(number, true) if options.delete(:raise)
58
+ ERB::Util.html_escape(ActiveSupport::NumberHelper.number_to_phone(number, options))
92
59
  end
93
60
 
94
61
  # Formats a +number+ into a currency string (e.g., $13.65). You
95
62
  # can customize the format in the +options+ hash.
96
63
  #
97
- # ==== Options
98
- #
99
64
  # * <tt>:locale</tt> - Sets the locale to be used for formatting
100
65
  # (defaults to current locale).
101
66
  # * <tt>:precision</tt> - Sets the level of precision (defaults
@@ -117,67 +82,32 @@ module ActionView
117
82
  # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
118
83
  # the argument is invalid.
119
84
  #
120
- # ==== Examples
85
+ # number_to_currency(1234567890.50) # => $1,234,567,890.50
86
+ # number_to_currency(1234567890.506) # => $1,234,567,890.51
87
+ # number_to_currency(1234567890.506, precision: 3) # => $1,234,567,890.506
88
+ # number_to_currency(1234567890.506, locale: :fr) # => 1 234 567 890,51 €
89
+ # number_to_currency("123a456") # => $123a456
121
90
  #
122
- # number_to_currency(1234567890.50) # => $1,234,567,890.50
123
- # number_to_currency(1234567890.506) # => $1,234,567,890.51
124
- # number_to_currency(1234567890.506, :precision => 3) # => $1,234,567,890.506
125
- # number_to_currency(1234567890.506, :locale => :fr) # => 1 234 567 890,51 €
126
- # number_to_currency("123a456") # => $123a456
91
+ # number_to_currency("123a456", raise: true) # => InvalidNumberError
127
92
  #
128
- # number_to_currency("123a456", :raise => true) # => InvalidNumberError
129
- #
130
- # number_to_currency(-1234567890.50, :negative_format => "(%u%n)")
131
- # # => ($1,234,567,890.50)
132
- # number_to_currency(1234567890.50, :unit => "R$", :separator => ",", :delimiter => "")
133
- # # => R$1234567890,50
134
- # number_to_currency(1234567890.50, :unit => "R$", :separator => ",", :delimiter => "", :format => "%n %u")
135
- # # => 1234567890,50 R$
93
+ # number_to_currency(-1234567890.50, negative_format: "(%u%n)")
94
+ # # => ($1,234,567,890.50)
95
+ # number_to_currency(1234567890.50, unit: "&pound;", separator: ",", delimiter: "")
96
+ # # => &pound;1234567890,50
97
+ # number_to_currency(1234567890.50, unit: "&pound;", separator: ",", delimiter: "", format: "%n %u")
98
+ # # => 1234567890,50 &pound;
136
99
  def number_to_currency(number, options = {})
137
100
  return unless number
101
+ options = escape_unsafe_delimiters_and_separators(options.symbolize_keys)
138
102
 
139
- options.symbolize_keys!
140
-
141
- options[:delimiter] = ERB::Util.html_escape(options[:delimiter]) if options[:delimiter]
142
- options[:separator] = ERB::Util.html_escape(options[:separator]) if options[:separator]
143
- options[:format] = ERB::Util.html_escape(options[:format]) if options[:format]
144
- options[:negative_format] = ERB::Util.html_escape(options[:negative_format]) if options[:negative_format]
145
-
146
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
147
- currency = I18n.translate(:'number.currency.format', :locale => options[:locale], :default => {})
148
- currency[:negative_format] ||= "-" + currency[:format] if currency[:format]
149
-
150
- defaults = DEFAULT_CURRENCY_VALUES.merge(defaults).merge!(currency)
151
- defaults[:negative_format] = "-" + options[:format] if options[:format]
152
-
153
- options = defaults.merge!(options)
154
-
155
- unit = options.delete(:unit)
156
- format = options.delete(:format)
157
-
158
- if number.to_f < 0
159
- format = options.delete(:negative_format)
160
- number = number.respond_to?("abs") ? number.abs : number.sub(/^-/, '')
161
- end
162
-
163
- begin
164
- value = number_with_precision(number, options.merge(:raise => true))
165
- format.gsub(/%n/, ERB::Util.html_escape(value)).gsub(/%u/, ERB::Util.html_escape(unit)).html_safe
166
- rescue InvalidNumberError => e
167
- if options[:raise]
168
- raise
169
- else
170
- formatted_number = format.gsub(/%n/, e.number).gsub(/%u/, unit)
171
- e.number.to_s.html_safe? ? formatted_number.html_safe : formatted_number
172
- end
173
- end
174
-
103
+ wrap_with_output_safety_handling(number, options.delete(:raise)) {
104
+ ActiveSupport::NumberHelper.number_to_currency(number, options)
105
+ }
175
106
  end
176
107
 
177
108
  # Formats a +number+ as a percentage string (e.g., 65%). You can
178
109
  # customize the format in the +options+ hash.
179
110
  #
180
- # ==== Options
181
111
  #
182
112
  # * <tt>:locale</tt> - Sets the locale to be used for formatting
183
113
  # (defaults to current locale).
@@ -193,51 +123,34 @@ module ActionView
193
123
  # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
194
124
  # insignificant zeros after the decimal separator (defaults to
195
125
  # +false+).
126
+ # * <tt>:format</tt> - Specifies the format of the percentage
127
+ # string The number field is <tt>%n</tt> (defaults to "%n%").
196
128
  # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
197
129
  # the argument is invalid.
198
130
  #
199
- # ==== Examples
131
+ # number_to_percentage(100) # => 100.000%
132
+ # number_to_percentage("98") # => 98.000%
133
+ # number_to_percentage(100, precision: 0) # => 100%
134
+ # number_to_percentage(1000, delimiter: '.', separator: ',') # => 1.000,000%
135
+ # number_to_percentage(302.24398923423, precision: 5) # => 302.24399%
136
+ # number_to_percentage(1000, locale: :fr) # => 1 000,000%
137
+ # number_to_percentage("98a") # => 98a%
138
+ # number_to_percentage(100, format: "%n %") # => 100 %
200
139
  #
201
- # number_to_percentage(100) # => 100.000%
202
- # number_to_percentage("98") # => 98.000%
203
- # number_to_percentage(100, :precision => 0) # => 100%
204
- # number_to_percentage(1000, :delimiter => '.', :separator => ',') # => 1.000,000%
205
- # number_to_percentage(302.24398923423, :precision => 5) # => 302.24399%
206
- # number_to_percentage(1000, :locale => :fr) # => 1 000,000%
207
- # number_to_percentage("98a") # => 98a%
208
- #
209
- # number_to_percentage("98a", :raise => true) # => InvalidNumberError
140
+ # number_to_percentage("98a", raise: true) # => InvalidNumberError
210
141
  def number_to_percentage(number, options = {})
211
142
  return unless number
143
+ options = escape_unsafe_delimiters_and_separators(options.symbolize_keys)
212
144
 
213
- options.symbolize_keys!
214
-
215
- options[:delimiter] = ERB::Util.html_escape(options[:delimiter]) if options[:delimiter]
216
- options[:separator] = ERB::Util.html_escape(options[:separator]) if options[:separator]
217
-
218
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
219
- percentage = I18n.translate(:'number.percentage.format', :locale => options[:locale], :default => {})
220
- defaults = defaults.merge(percentage)
221
-
222
- options = options.reverse_merge(defaults)
223
-
224
- begin
225
- "#{number_with_precision(number, options.merge(:raise => true))}%".html_safe
226
- rescue InvalidNumberError => e
227
- if options[:raise]
228
- raise
229
- else
230
- e.number.to_s.html_safe? ? "#{e.number}%".html_safe : "#{e.number}%"
231
- end
232
- end
145
+ wrap_with_output_safety_handling(number, options.delete(:raise)) {
146
+ ActiveSupport::NumberHelper.number_to_percentage(number, options)
147
+ }
233
148
  end
234
149
 
235
150
  # Formats a +number+ with grouped thousands using +delimiter+
236
151
  # (e.g., 12,324). You can customize the format in the +options+
237
152
  # hash.
238
153
  #
239
- # ==== Options
240
- #
241
154
  # * <tt>:locale</tt> - Sets the locale to be used for formatting
242
155
  # (defaults to current locale).
243
156
  # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
@@ -247,43 +160,24 @@ module ActionView
247
160
  # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
248
161
  # the argument is invalid.
249
162
  #
250
- # ==== Examples
251
- #
252
- # number_with_delimiter(12345678) # => 12,345,678
253
- # number_with_delimiter("123456") # => 123,456
254
- # number_with_delimiter(12345678.05) # => 12,345,678.05
255
- # number_with_delimiter(12345678, :delimiter => ".") # => 12.345.678
256
- # number_with_delimiter(12345678, :delimiter => ",") # => 12,345,678
257
- # number_with_delimiter(12345678.05, :separator => " ") # => 12,345,678 05
258
- # number_with_delimiter(12345678.05, :locale => :fr) # => 12 345 678,05
259
- # number_with_delimiter("112a") # => 112a
260
- # number_with_delimiter(98765432.98, :delimiter => " ", :separator => ",")
261
- # # => 98 765 432,98
262
- #
263
- # number_with_delimiter("112a", :raise => true) # => raise InvalidNumberError
163
+ # number_with_delimiter(12345678) # => 12,345,678
164
+ # number_with_delimiter("123456") # => 123,456
165
+ # number_with_delimiter(12345678.05) # => 12,345,678.05
166
+ # number_with_delimiter(12345678, delimiter: ".") # => 12.345.678
167
+ # number_with_delimiter(12345678, delimiter: ",") # => 12,345,678
168
+ # number_with_delimiter(12345678.05, separator: " ") # => 12,345,678 05
169
+ # number_with_delimiter(12345678.05, locale: :fr) # => 12 345 678,05
170
+ # number_with_delimiter("112a") # => 112a
171
+ # number_with_delimiter(98765432.98, delimiter: " ", separator: ",")
172
+ # # => 98 765 432,98
173
+ #
174
+ # number_with_delimiter("112a", raise: true) # => raise InvalidNumberError
264
175
  def number_with_delimiter(number, options = {})
265
- options.symbolize_keys!
266
-
267
- options[:delimiter] = ERB::Util.html_escape(options[:delimiter]) if options[:delimiter]
268
- options[:separator] = ERB::Util.html_escape(options[:separator]) if options[:separator]
269
-
270
- begin
271
- Float(number)
272
- rescue ArgumentError, TypeError
273
- if options[:raise]
274
- raise InvalidNumberError, number
275
- else
276
- return number
277
- end
278
- end
279
-
280
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
281
- options = options.reverse_merge(defaults)
282
-
283
- parts = number.to_s.to_str.split('.')
284
- parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
285
- parts.join(options[:separator]).html_safe
176
+ options = escape_unsafe_delimiters_and_separators(options.symbolize_keys)
286
177
 
178
+ wrap_with_output_safety_handling(number, options.delete(:raise)) {
179
+ ActiveSupport::NumberHelper.number_to_delimited(number, options)
180
+ }
287
181
  end
288
182
 
289
183
  # Formats a +number+ with the specified level of
@@ -291,8 +185,6 @@ module ActionView
291
185
  # +:significant+ is +false+, and 5 if +:significant+ is +true+).
292
186
  # You can customize the format in the +options+ hash.
293
187
  #
294
- # ==== Options
295
- #
296
188
  # * <tt>:locale</tt> - Sets the locale to be used for formatting
297
189
  # (defaults to current locale).
298
190
  # * <tt>:precision</tt> - Sets the precision of the number
@@ -310,70 +202,29 @@ module ActionView
310
202
  # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
311
203
  # the argument is invalid.
312
204
  #
313
- # ==== Examples
314
- #
315
- # number_with_precision(111.2345) # => 111.235
316
- # number_with_precision(111.2345, :precision => 2) # => 111.23
317
- # number_with_precision(13, :precision => 5) # => 13.00000
318
- # number_with_precision(389.32314, :precision => 0) # => 389
319
- # number_with_precision(111.2345, :significant => true) # => 111
320
- # number_with_precision(111.2345, :precision => 1, :significant => true) # => 100
321
- # number_with_precision(13, :precision => 5, :significant => true) # => 13.000
322
- # number_with_precision(111.234, :locale => :fr) # => 111,234
323
- #
324
- # number_with_precision(13, :precision => 5, :significant => true, :strip_insignificant_zeros => true)
325
- # # => 13
326
- #
327
- # number_with_precision(389.32314, :precision => 4, :significant => true) # => 389.3
328
- # number_with_precision(1111.2345, :precision => 2, :separator => ',', :delimiter => '.')
329
- # # => 1.111,23
205
+ # number_with_precision(111.2345) # => 111.235
206
+ # number_with_precision(111.2345, precision: 2) # => 111.23
207
+ # number_with_precision(13, precision: 5) # => 13.00000
208
+ # number_with_precision(389.32314, precision: 0) # => 389
209
+ # number_with_precision(111.2345, significant: true) # => 111
210
+ # number_with_precision(111.2345, precision: 1, significant: true) # => 100
211
+ # number_with_precision(13, precision: 5, significant: true) # => 13.000
212
+ # number_with_precision(111.234, locale: :fr) # => 111,234
213
+ #
214
+ # number_with_precision(13, precision: 5, significant: true, strip_insignificant_zeros: true)
215
+ # # => 13
216
+ #
217
+ # number_with_precision(389.32314, precision: 4, significant: true) # => 389.3
218
+ # number_with_precision(1111.2345, precision: 2, separator: ',', delimiter: '.')
219
+ # # => 1.111,23
330
220
  def number_with_precision(number, options = {})
331
- options.symbolize_keys!
332
-
333
- number = begin
334
- Float(number)
335
- rescue ArgumentError, TypeError
336
- if options[:raise]
337
- raise InvalidNumberError, number
338
- else
339
- return number
340
- end
341
- end
342
-
343
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
344
- precision_defaults = I18n.translate(:'number.precision.format', :locale => options[:locale], :default => {})
345
- defaults = defaults.merge(precision_defaults)
346
-
347
- options = options.reverse_merge(defaults) # Allow the user to unset default values: Eg.: :significant => false
348
- precision = options.delete :precision
349
- significant = options.delete :significant
350
- strip_insignificant_zeros = options.delete :strip_insignificant_zeros
351
-
352
- if significant and precision > 0
353
- if number == 0
354
- digits, rounded_number = 1, 0
355
- else
356
- digits = (Math.log10(number.abs) + 1).floor
357
- rounded_number = (BigDecimal.new(number.to_s) / BigDecimal.new((10 ** (digits - precision)).to_f.to_s)).round.to_f * 10 ** (digits - precision)
358
- digits = (Math.log10(rounded_number.abs) + 1).floor # After rounding, the number of digits may have changed
359
- end
360
- precision -= digits
361
- precision = precision > 0 ? precision : 0 #don't let it be negative
362
- else
363
- rounded_number = BigDecimal.new(number.to_s).round(precision).to_f
364
- end
365
- formatted_number = number_with_delimiter("%01.#{precision}f" % rounded_number, options)
366
- if strip_insignificant_zeros
367
- escaped_separator = Regexp.escape(options[:separator])
368
- formatted_number.sub(/(#{escaped_separator})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_separator}\z/, '').html_safe
369
- else
370
- formatted_number
371
- end
221
+ options = escape_unsafe_delimiters_and_separators(options.symbolize_keys)
372
222
 
223
+ wrap_with_output_safety_handling(number, options.delete(:raise)) {
224
+ ActiveSupport::NumberHelper.number_to_rounded(number, options)
225
+ }
373
226
  end
374
227
 
375
- STORAGE_UNITS = [:byte, :kb, :mb, :gb, :tb]
376
-
377
228
  # Formats the bytes in +number+ into a more understandable
378
229
  # representation (e.g., giving it 1500 yields 1.5 KB). This
379
230
  # method is useful for reporting file sizes to users. You can
@@ -382,8 +233,6 @@ module ActionView
382
233
  # See <tt>number_to_human</tt> if you want to pretty-print a
383
234
  # generic number.
384
235
  #
385
- # ==== Options
386
- #
387
236
  # * <tt>:locale</tt> - Sets the locale to be used for formatting
388
237
  # (defaults to current locale).
389
238
  # * <tt>:precision</tt> - Sets the precision of the number
@@ -403,69 +252,31 @@ module ActionView
403
252
  # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
404
253
  # the argument is invalid.
405
254
  #
406
- # ==== Examples
407
- #
408
- # number_to_human_size(123) # => 123 Bytes
409
- # number_to_human_size(1234) # => 1.21 KB
410
- # number_to_human_size(12345) # => 12.1 KB
411
- # number_to_human_size(1234567) # => 1.18 MB
412
- # number_to_human_size(1234567890) # => 1.15 GB
413
- # number_to_human_size(1234567890123) # => 1.12 TB
414
- # number_to_human_size(1234567, :precision => 2) # => 1.2 MB
415
- # number_to_human_size(483989, :precision => 2) # => 470 KB
416
- # number_to_human_size(1234567, :precision => 2, :separator => ',') # => 1,2 MB
255
+ # number_to_human_size(123) # => 123 Bytes
256
+ # number_to_human_size(1234) # => 1.21 KB
257
+ # number_to_human_size(12345) # => 12.1 KB
258
+ # number_to_human_size(1234567) # => 1.18 MB
259
+ # number_to_human_size(1234567890) # => 1.15 GB
260
+ # number_to_human_size(1234567890123) # => 1.12 TB
261
+ # number_to_human_size(1234567, precision: 2) # => 1.2 MB
262
+ # number_to_human_size(483989, precision: 2) # => 470 KB
263
+ # number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
417
264
  #
418
265
  # Non-significant zeros after the fractional separator are
419
266
  # stripped out by default (set
420
267
  # <tt>:strip_insignificant_zeros</tt> to +false+ to change
421
268
  # that):
422
- # number_to_human_size(1234567890123, :precision => 5) # => "1.1229 TB"
423
- # number_to_human_size(524288000, :precision => 5) # => "500 MB"
269
+ #
270
+ # number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB"
271
+ # number_to_human_size(524288000, precision: 5) # => "500 MB"
424
272
  def number_to_human_size(number, options = {})
425
- options.symbolize_keys!
273
+ options = escape_unsafe_delimiters_and_separators(options.symbolize_keys)
426
274
 
427
- number = begin
428
- Float(number)
429
- rescue ArgumentError, TypeError
430
- if options[:raise]
431
- raise InvalidNumberError, number
432
- else
433
- return number
434
- end
435
- end
436
-
437
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
438
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
439
- defaults = defaults.merge(human)
440
-
441
- options = options.reverse_merge(defaults)
442
- #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
443
- options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
444
-
445
- storage_units_format = I18n.translate(:'number.human.storage_units.format', :locale => options[:locale], :raise => true)
446
-
447
- base = options[:prefix] == :si ? 1000 : 1024
448
-
449
- if number.to_i < base
450
- unit = I18n.translate(:'number.human.storage_units.units.byte', :locale => options[:locale], :count => number.to_i, :raise => true)
451
- storage_units_format.gsub(/%n/, number.to_i.to_s).gsub(/%u/, unit).html_safe
452
- else
453
- max_exp = STORAGE_UNITS.size - 1
454
- exponent = (Math.log(number) / Math.log(base)).to_i # Convert to base
455
- exponent = max_exp if exponent > max_exp # we need this to avoid overflow for the highest unit
456
- number /= base ** exponent
457
-
458
- unit_key = STORAGE_UNITS[exponent]
459
- unit = I18n.translate(:"number.human.storage_units.units.#{unit_key}", :locale => options[:locale], :count => number, :raise => true)
460
-
461
- formatted_number = number_with_precision(number, options)
462
- storage_units_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).html_safe
463
- end
275
+ wrap_with_output_safety_handling(number, options.delete(:raise)) {
276
+ ActiveSupport::NumberHelper.number_to_human_size(number, options)
277
+ }
464
278
  end
465
279
 
466
- DECIMAL_UNITS = {0 => :unit, 1 => :ten, 2 => :hundred, 3 => :thousand, 6 => :million, 9 => :billion, 12 => :trillion, 15 => :quadrillion,
467
- -1 => :deci, -2 => :centi, -3 => :mili, -6 => :micro, -9 => :nano, -12 => :pico, -15 => :femto}
468
-
469
280
  # Pretty prints (formats and approximates) a number in a way it
470
281
  # is more readable by humans (eg.: 1200000000 becomes "1.2
471
282
  # Billion"). This is useful for numbers that can get very large
@@ -513,34 +324,32 @@ module ActionView
513
324
  # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
514
325
  # the argument is invalid.
515
326
  #
516
- # ==== Examples
517
- #
518
- # number_to_human(123) # => "123"
519
- # number_to_human(1234) # => "1.23 Thousand"
520
- # number_to_human(12345) # => "12.3 Thousand"
521
- # number_to_human(1234567) # => "1.23 Million"
522
- # number_to_human(1234567890) # => "1.23 Billion"
523
- # number_to_human(1234567890123) # => "1.23 Trillion"
524
- # number_to_human(1234567890123456) # => "1.23 Quadrillion"
525
- # number_to_human(1234567890123456789) # => "1230 Quadrillion"
526
- # number_to_human(489939, :precision => 2) # => "490 Thousand"
527
- # number_to_human(489939, :precision => 4) # => "489.9 Thousand"
528
- # number_to_human(1234567, :precision => 4,
529
- # :significant => false) # => "1.2346 Million"
530
- # number_to_human(1234567, :precision => 1,
531
- # :separator => ',',
532
- # :significant => false) # => "1,2 Million"
327
+ # number_to_human(123) # => "123"
328
+ # number_to_human(1234) # => "1.23 Thousand"
329
+ # number_to_human(12345) # => "12.3 Thousand"
330
+ # number_to_human(1234567) # => "1.23 Million"
331
+ # number_to_human(1234567890) # => "1.23 Billion"
332
+ # number_to_human(1234567890123) # => "1.23 Trillion"
333
+ # number_to_human(1234567890123456) # => "1.23 Quadrillion"
334
+ # number_to_human(1234567890123456789) # => "1230 Quadrillion"
335
+ # number_to_human(489939, precision: 2) # => "490 Thousand"
336
+ # number_to_human(489939, precision: 4) # => "489.9 Thousand"
337
+ # number_to_human(1234567, precision: 4,
338
+ # significant: false) # => "1.2346 Million"
339
+ # number_to_human(1234567, precision: 1,
340
+ # separator: ',',
341
+ # significant: false) # => "1,2 Million"
533
342
  #
534
343
  # Non-significant zeros after the decimal separator are stripped
535
344
  # out by default (set <tt>:strip_insignificant_zeros</tt> to
536
345
  # +false+ to change that):
537
- # number_to_human(12345012345, :significant_digits => 6) # => "12.345 Billion"
538
- # number_to_human(500000000, :precision => 5) # => "500 Million"
346
+ # number_to_human(12345012345, significant_digits: 6) # => "12.345 Billion"
347
+ # number_to_human(500000000, precision: 5) # => "500 Million"
539
348
  #
540
349
  # ==== Custom Unit Quantifiers
541
350
  #
542
351
  # You can also use your own custom unit quantifiers:
543
- # number_to_human(500000, :units => {:unit => "ml", :thousand => "lt"}) # => "500 lt"
352
+ # number_to_human(500000, units: {unit: "ml", thousand: "lt"}) # => "500 lt"
544
353
  #
545
354
  # If in your I18n locale you have:
546
355
  # distance:
@@ -557,66 +366,51 @@ module ActionView
557
366
  #
558
367
  # Then you could do:
559
368
  #
560
- # number_to_human(543934, :units => :distance) # => "544 kilometers"
561
- # number_to_human(54393498, :units => :distance) # => "54400 kilometers"
562
- # number_to_human(54393498000, :units => :distance) # => "54.4 gazillion-distance"
563
- # number_to_human(343, :units => :distance, :precision => 1) # => "300 meters"
564
- # number_to_human(1, :units => :distance) # => "1 meter"
565
- # number_to_human(0.34, :units => :distance) # => "34 centimeters"
369
+ # number_to_human(543934, units: :distance) # => "544 kilometers"
370
+ # number_to_human(54393498, units: :distance) # => "54400 kilometers"
371
+ # number_to_human(54393498000, units: :distance) # => "54.4 gazillion-distance"
372
+ # number_to_human(343, units: :distance, precision: 1) # => "300 meters"
373
+ # number_to_human(1, units: :distance) # => "1 meter"
374
+ # number_to_human(0.34, units: :distance) # => "34 centimeters"
566
375
  #
567
376
  def number_to_human(number, options = {})
568
- options.symbolize_keys!
377
+ options = escape_unsafe_delimiters_and_separators(options.symbolize_keys)
569
378
 
570
- number = begin
571
- Float(number)
572
- rescue ArgumentError, TypeError
573
- if options[:raise]
574
- raise InvalidNumberError, number
575
- else
576
- return number
577
- end
578
- end
379
+ wrap_with_output_safety_handling(number, options.delete(:raise)) {
380
+ ActiveSupport::NumberHelper.number_to_human(number, options)
381
+ }
382
+ end
579
383
 
580
- defaults = I18n.translate(:'number.format', :locale => options[:locale], :default => {})
581
- human = I18n.translate(:'number.human.format', :locale => options[:locale], :default => {})
582
- defaults = defaults.merge(human)
384
+ private
583
385
 
584
- options = options.reverse_merge(defaults)
585
- #for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
586
- options[:strip_insignificant_zeros] = true if not options.key?(:strip_insignificant_zeros)
386
+ def escape_unsafe_delimiters_and_separators(options)
387
+ options[:separator] = ERB::Util.html_escape(options[:separator]) if options[:separator] && !options[:separator].html_safe?
388
+ options[:delimiter] = ERB::Util.html_escape(options[:delimiter]) if options[:delimiter] && !options[:delimiter].html_safe?
389
+ options
390
+ end
587
391
 
588
- inverted_du = DECIMAL_UNITS.invert
392
+ def wrap_with_output_safety_handling(number, raise_on_invalid, &block)
393
+ valid_float = valid_float?(number)
394
+ raise InvalidNumberError, number if raise_on_invalid && !valid_float
589
395
 
590
- units = options.delete :units
591
- unit_exponents = case units
592
- when Hash
593
- units = Hash[units.map { |k, v| [k, ERB::Util.html_escape(v)] }]
594
- when String, Symbol
595
- I18n.translate(:"#{units}", :locale => options[:locale], :raise => true)
596
- when nil
597
- I18n.translate(:"number.human.decimal_units.units", :locale => options[:locale], :raise => true)
598
- else
599
- raise ArgumentError, ":units must be a Hash or String translation scope."
600
- end.keys.map{|e_name| inverted_du[e_name] }.sort_by{|e| -e}
396
+ formatted_number = yield
601
397
 
602
- number_exponent = number != 0 ? Math.log10(number.abs).floor : 0
603
- display_exponent = unit_exponents.find{ |e| number_exponent >= e } || 0
604
- number /= 10 ** display_exponent
605
-
606
- unit = case units
607
- when Hash
608
- units[DECIMAL_UNITS[display_exponent]] || ''
609
- when String, Symbol
610
- I18n.translate(:"#{units}.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
398
+ if valid_float || number.html_safe?
399
+ formatted_number.html_safe
611
400
  else
612
- I18n.translate(:"number.human.decimal_units.units.#{DECIMAL_UNITS[display_exponent]}", :locale => options[:locale], :count => number.to_i)
401
+ formatted_number
613
402
  end
403
+ end
614
404
 
615
- decimal_format = options[:format] || I18n.translate(:'number.human.decimal_units.format', :locale => options[:locale], :default => "%n %u")
616
- formatted_number = number_with_precision(number, options)
617
- decimal_format.gsub(/%n/, formatted_number).gsub(/%u/, unit).strip.html_safe
405
+ def valid_float?(number)
406
+ !parse_float(number, false).nil?
618
407
  end
619
408
 
409
+ def parse_float(number, raise_error)
410
+ Float(number)
411
+ rescue ArgumentError, TypeError
412
+ raise InvalidNumberError, number if raise_error
413
+ end
620
414
  end
621
415
  end
622
416
  end