actionpack 4.0.13 → 4.1.0.beta1

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 (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +131 -1636
  3. data/README.rdoc +1 -6
  4. data/lib/abstract_controller.rb +1 -2
  5. data/lib/abstract_controller/base.rb +3 -25
  6. data/lib/abstract_controller/callbacks.rb +4 -2
  7. data/lib/abstract_controller/collector.rb +11 -1
  8. data/lib/abstract_controller/helpers.rb +18 -15
  9. data/lib/abstract_controller/rendering.rb +48 -127
  10. data/lib/action_controller.rb +1 -17
  11. data/lib/action_controller/base.rb +14 -6
  12. data/lib/action_controller/caching.rb +1 -11
  13. data/lib/action_controller/log_subscriber.rb +1 -1
  14. data/lib/action_controller/metal.rb +0 -4
  15. data/lib/action_controller/metal/flash.rb +17 -0
  16. data/lib/action_controller/metal/force_ssl.rb +1 -1
  17. data/lib/action_controller/metal/head.rb +1 -3
  18. data/lib/action_controller/metal/helpers.rb +6 -2
  19. data/lib/action_controller/metal/http_authentication.rb +7 -14
  20. data/lib/action_controller/metal/instrumentation.rb +1 -1
  21. data/lib/action_controller/metal/live.rb +74 -0
  22. data/lib/action_controller/metal/mime_responds.rb +93 -16
  23. data/lib/action_controller/metal/params_wrapper.rb +4 -11
  24. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  25. data/lib/action_controller/metal/redirecting.rb +20 -20
  26. data/lib/action_controller/metal/renderers.rb +8 -5
  27. data/lib/action_controller/metal/rendering.rb +14 -11
  28. data/lib/action_controller/metal/request_forgery_protection.rb +67 -13
  29. data/lib/action_controller/metal/responder.rb +12 -2
  30. data/lib/action_controller/metal/streaming.rb +18 -20
  31. data/lib/action_controller/metal/strong_parameters.rb +22 -34
  32. data/lib/action_controller/railtie.rb +0 -1
  33. data/lib/action_controller/test_case.rb +0 -15
  34. data/lib/action_dispatch.rb +1 -0
  35. data/lib/action_dispatch/http/headers.rb +1 -3
  36. data/lib/action_dispatch/http/mime_negotiation.rb +16 -2
  37. data/lib/action_dispatch/http/mime_type.rb +4 -22
  38. data/lib/action_dispatch/http/mime_types.rb +1 -0
  39. data/lib/action_dispatch/http/parameters.rb +18 -19
  40. data/lib/action_dispatch/http/request.rb +16 -25
  41. data/lib/action_dispatch/http/response.rb +21 -8
  42. data/lib/action_dispatch/http/upload.rb +0 -13
  43. data/lib/action_dispatch/http/url.rb +10 -18
  44. data/lib/action_dispatch/journey/formatter.rb +3 -3
  45. data/lib/action_dispatch/journey/gtg/transition_table.rb +3 -5
  46. data/lib/action_dispatch/journey/parser.rb +1 -1
  47. data/lib/action_dispatch/journey/parser.y +1 -0
  48. data/lib/action_dispatch/journey/router.rb +7 -1
  49. data/lib/action_dispatch/journey/router/utils.rb +1 -1
  50. data/lib/action_dispatch/journey/visitors.rb +26 -47
  51. data/lib/action_dispatch/middleware/callbacks.rb +6 -6
  52. data/lib/action_dispatch/middleware/cookies.rb +15 -15
  53. data/lib/action_dispatch/middleware/debug_exceptions.rb +21 -13
  54. data/lib/action_dispatch/middleware/exception_wrapper.rb +1 -1
  55. data/lib/action_dispatch/middleware/flash.rb +5 -11
  56. data/lib/action_dispatch/middleware/params_parser.rb +1 -1
  57. data/lib/action_dispatch/middleware/public_exceptions.rb +1 -5
  58. data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
  59. data/lib/action_dispatch/middleware/session/cookie_store.rb +4 -3
  60. data/lib/action_dispatch/middleware/show_exceptions.rb +5 -2
  61. data/lib/action_dispatch/middleware/ssl.rb +1 -1
  62. data/lib/action_dispatch/middleware/static.rb +5 -25
  63. data/lib/action_dispatch/middleware/templates/rescues/{_request_and_response.erb → _request_and_response.html.erb} +0 -0
  64. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  65. data/lib/action_dispatch/middleware/templates/rescues/{_trace.erb → _trace.html.erb} +0 -0
  66. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +15 -0
  67. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +1 -1
  68. data/lib/action_dispatch/middleware/templates/rescues/{missing_template.erb → missing_template.html.erb} +1 -1
  69. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  70. data/lib/action_dispatch/middleware/templates/rescues/{routing_error.erb → routing_error.html.erb} +1 -1
  71. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  72. data/lib/action_dispatch/middleware/templates/rescues/{template_error.erb → template_error.html.erb} +1 -1
  73. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +8 -0
  74. data/lib/action_dispatch/middleware/templates/rescues/{unknown_action.erb → unknown_action.html.erb} +1 -1
  75. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  76. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -3
  77. data/lib/action_dispatch/railtie.rb +1 -2
  78. data/lib/action_dispatch/request/session.rb +12 -0
  79. data/lib/action_dispatch/request/utils.rb +24 -0
  80. data/lib/action_dispatch/routing.rb +7 -6
  81. data/lib/action_dispatch/routing/inspector.rb +4 -4
  82. data/lib/action_dispatch/routing/mapper.rb +81 -138
  83. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -0
  84. data/lib/action_dispatch/routing/redirection.rb +34 -27
  85. data/lib/action_dispatch/routing/route_set.rb +43 -37
  86. data/lib/action_dispatch/routing/url_for.rb +3 -1
  87. data/lib/action_dispatch/testing/assertions/response.rb +8 -15
  88. data/lib/action_dispatch/testing/assertions/selector.rb +4 -4
  89. data/lib/action_dispatch/testing/integration.rb +1 -7
  90. data/lib/action_pack/version.rb +1 -1
  91. metadata +43 -167
  92. data/lib/abstract_controller/layouts.rb +0 -423
  93. data/lib/abstract_controller/view_paths.rb +0 -96
  94. data/lib/action_controller/deprecated.rb +0 -7
  95. data/lib/action_controller/deprecated/integration_test.rb +0 -5
  96. data/lib/action_controller/record_identifier.rb +0 -31
  97. data/lib/action_controller/vendor/html-scanner.rb +0 -5
  98. data/lib/action_view.rb +0 -93
  99. data/lib/action_view/base.rb +0 -205
  100. data/lib/action_view/buffers.rb +0 -49
  101. data/lib/action_view/context.rb +0 -36
  102. data/lib/action_view/dependency_tracker.rb +0 -93
  103. data/lib/action_view/digestor.rb +0 -113
  104. data/lib/action_view/flows.rb +0 -76
  105. data/lib/action_view/helpers.rb +0 -58
  106. data/lib/action_view/helpers/active_model_helper.rb +0 -49
  107. data/lib/action_view/helpers/asset_tag_helper.rb +0 -320
  108. data/lib/action_view/helpers/asset_url_helper.rb +0 -355
  109. data/lib/action_view/helpers/atom_feed_helper.rb +0 -203
  110. data/lib/action_view/helpers/cache_helper.rb +0 -196
  111. data/lib/action_view/helpers/capture_helper.rb +0 -216
  112. data/lib/action_view/helpers/controller_helper.rb +0 -25
  113. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  114. data/lib/action_view/helpers/date_helper.rb +0 -1087
  115. data/lib/action_view/helpers/debug_helper.rb +0 -39
  116. data/lib/action_view/helpers/form_helper.rb +0 -1882
  117. data/lib/action_view/helpers/form_options_helper.rb +0 -838
  118. data/lib/action_view/helpers/form_tag_helper.rb +0 -785
  119. data/lib/action_view/helpers/javascript_helper.rb +0 -117
  120. data/lib/action_view/helpers/number_helper.rb +0 -451
  121. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  122. data/lib/action_view/helpers/record_tag_helper.rb +0 -106
  123. data/lib/action_view/helpers/rendering_helper.rb +0 -90
  124. data/lib/action_view/helpers/sanitize_helper.rb +0 -256
  125. data/lib/action_view/helpers/tag_helper.rb +0 -173
  126. data/lib/action_view/helpers/tags.rb +0 -39
  127. data/lib/action_view/helpers/tags/base.rb +0 -148
  128. data/lib/action_view/helpers/tags/check_box.rb +0 -64
  129. data/lib/action_view/helpers/tags/checkable.rb +0 -16
  130. data/lib/action_view/helpers/tags/collection_check_boxes.rb +0 -53
  131. data/lib/action_view/helpers/tags/collection_helpers.rb +0 -84
  132. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +0 -36
  133. data/lib/action_view/helpers/tags/collection_select.rb +0 -28
  134. data/lib/action_view/helpers/tags/color_field.rb +0 -25
  135. data/lib/action_view/helpers/tags/date_field.rb +0 -13
  136. data/lib/action_view/helpers/tags/date_select.rb +0 -72
  137. data/lib/action_view/helpers/tags/datetime_field.rb +0 -22
  138. data/lib/action_view/helpers/tags/datetime_local_field.rb +0 -19
  139. data/lib/action_view/helpers/tags/datetime_select.rb +0 -8
  140. data/lib/action_view/helpers/tags/email_field.rb +0 -8
  141. data/lib/action_view/helpers/tags/file_field.rb +0 -8
  142. data/lib/action_view/helpers/tags/grouped_collection_select.rb +0 -29
  143. data/lib/action_view/helpers/tags/hidden_field.rb +0 -8
  144. data/lib/action_view/helpers/tags/label.rb +0 -65
  145. data/lib/action_view/helpers/tags/month_field.rb +0 -13
  146. data/lib/action_view/helpers/tags/number_field.rb +0 -18
  147. data/lib/action_view/helpers/tags/password_field.rb +0 -12
  148. data/lib/action_view/helpers/tags/radio_button.rb +0 -31
  149. data/lib/action_view/helpers/tags/range_field.rb +0 -8
  150. data/lib/action_view/helpers/tags/search_field.rb +0 -22
  151. data/lib/action_view/helpers/tags/select.rb +0 -40
  152. data/lib/action_view/helpers/tags/tel_field.rb +0 -8
  153. data/lib/action_view/helpers/tags/text_area.rb +0 -18
  154. data/lib/action_view/helpers/tags/text_field.rb +0 -30
  155. data/lib/action_view/helpers/tags/time_field.rb +0 -13
  156. data/lib/action_view/helpers/tags/time_select.rb +0 -8
  157. data/lib/action_view/helpers/tags/time_zone_select.rb +0 -20
  158. data/lib/action_view/helpers/tags/url_field.rb +0 -8
  159. data/lib/action_view/helpers/tags/week_field.rb +0 -13
  160. data/lib/action_view/helpers/text_helper.rb +0 -448
  161. data/lib/action_view/helpers/translation_helper.rb +0 -112
  162. data/lib/action_view/helpers/url_helper.rb +0 -635
  163. data/lib/action_view/locale/en.yml +0 -56
  164. data/lib/action_view/log_subscriber.rb +0 -30
  165. data/lib/action_view/lookup_context.rb +0 -248
  166. data/lib/action_view/model_naming.rb +0 -12
  167. data/lib/action_view/path_set.rb +0 -77
  168. data/lib/action_view/railtie.rb +0 -43
  169. data/lib/action_view/record_identifier.rb +0 -84
  170. data/lib/action_view/renderer/abstract_renderer.rb +0 -47
  171. data/lib/action_view/renderer/partial_renderer.rb +0 -500
  172. data/lib/action_view/renderer/renderer.rb +0 -50
  173. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -103
  174. data/lib/action_view/renderer/template_renderer.rb +0 -96
  175. data/lib/action_view/routing_url_for.rb +0 -107
  176. data/lib/action_view/tasks/dependencies.rake +0 -17
  177. data/lib/action_view/template.rb +0 -339
  178. data/lib/action_view/template/error.rb +0 -138
  179. data/lib/action_view/template/handlers.rb +0 -53
  180. data/lib/action_view/template/handlers/builder.rb +0 -26
  181. data/lib/action_view/template/handlers/erb.rb +0 -146
  182. data/lib/action_view/template/handlers/raw.rb +0 -11
  183. data/lib/action_view/template/resolver.rb +0 -340
  184. data/lib/action_view/template/text.rb +0 -34
  185. data/lib/action_view/template/types.rb +0 -57
  186. data/lib/action_view/test_case.rb +0 -270
  187. data/lib/action_view/testing/resolvers.rb +0 -50
  188. data/lib/action_view/vendor/html-scanner.rb +0 -20
  189. data/lib/action_view/vendor/html-scanner/html/document.rb +0 -68
  190. data/lib/action_view/vendor/html-scanner/html/node.rb +0 -532
  191. data/lib/action_view/vendor/html-scanner/html/sanitizer.rb +0 -188
  192. data/lib/action_view/vendor/html-scanner/html/selector.rb +0 -830
  193. data/lib/action_view/vendor/html-scanner/html/tokenizer.rb +0 -107
  194. data/lib/action_view/vendor/html-scanner/html/version.rb +0 -11
@@ -1,117 +0,0 @@
1
- require 'action_view/helpers/tag_helper'
2
-
3
- module ActionView
4
- module Helpers
5
- module JavaScriptHelper
6
- JS_ESCAPE_MAP = {
7
- '\\' => '\\\\',
8
- '</' => '<\/',
9
- "\r\n" => '\n',
10
- "\n" => '\n',
11
- "\r" => '\n',
12
- '"' => '\\"',
13
- "'" => "\\'"
14
- }
15
-
16
- JS_ESCAPE_MAP["\342\200\250".force_encoding(Encoding::UTF_8).encode!] = '&#x2028;'
17
- JS_ESCAPE_MAP["\342\200\251".force_encoding(Encoding::UTF_8).encode!] = '&#x2029;'
18
-
19
- # Escapes carriage returns and single and double quotes for JavaScript segments.
20
- #
21
- # Also available through the alias j(). This is particularly helpful in JavaScript
22
- # responses, like:
23
- #
24
- # $('some_element').replaceWith('<%=j render 'some/element_template' %>');
25
- def escape_javascript(javascript)
26
- if javascript
27
- result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"'])/u) {|match| JS_ESCAPE_MAP[match] }
28
- javascript.html_safe? ? result.html_safe : result
29
- else
30
- ''
31
- end
32
- end
33
-
34
- alias_method :j, :escape_javascript
35
-
36
- # Returns a JavaScript tag with the +content+ inside. Example:
37
- # javascript_tag "alert('All is good')"
38
- #
39
- # Returns:
40
- # <script>
41
- # //<![CDATA[
42
- # alert('All is good')
43
- # //]]>
44
- # </script>
45
- #
46
- # +html_options+ may be a hash of attributes for the <tt>\<script></tt>
47
- # tag.
48
- #
49
- # javascript_tag "alert('All is good')", defer: 'defer'
50
- # # => <script defer="defer">alert('All is good')</script>
51
- #
52
- # Instead of passing the content as an argument, you can also use a block
53
- # in which case, you pass your +html_options+ as the first parameter.
54
- #
55
- # <%= javascript_tag defer: 'defer' do -%>
56
- # alert('All is good')
57
- # <% end -%>
58
- def javascript_tag(content_or_options_with_block = nil, html_options = {}, &block)
59
- content =
60
- if block_given?
61
- html_options = content_or_options_with_block if content_or_options_with_block.is_a?(Hash)
62
- capture(&block)
63
- else
64
- content_or_options_with_block
65
- end
66
-
67
- content_tag(:script, javascript_cdata_section(content), html_options)
68
- end
69
-
70
- def javascript_cdata_section(content) #:nodoc:
71
- "\n//#{cdata_section("\n#{content}\n//")}\n".html_safe
72
- end
73
-
74
- # Returns a button whose +onclick+ handler triggers the passed JavaScript.
75
- #
76
- # The helper receives a name, JavaScript code, and an optional hash of HTML options. The
77
- # name is used as button label and the JavaScript code goes into its +onclick+ attribute.
78
- # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+.
79
- #
80
- # button_to_function "Greeting", "alert('Hello world!')", class: "ok"
81
- # # => <input class="ok" onclick="alert('Hello world!');" type="button" value="Greeting" />
82
- #
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 recommend using Unobtrusive JavaScript instead. " +
85
- "See http://guides.rubyonrails.org/working_with_javascript_in_rails.html#unobtrusive-javascript"
86
- ActiveSupport::Deprecation.warn message
87
-
88
- onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function};"
89
-
90
- tag(:input, html_options.merge(:type => 'button', :value => name, :onclick => onclick))
91
- end
92
-
93
- # Returns a link whose +onclick+ handler triggers the passed JavaScript.
94
- #
95
- # The helper receives a name, JavaScript code, and an optional hash of HTML options. The
96
- # name is used as the link text and the JavaScript code goes into the +onclick+ attribute.
97
- # If +html_options+ has an <tt>:onclick</tt>, that one is put before +function+. Once all
98
- # the JavaScript is set, the helper appends "; return false;".
99
- #
100
- # The +href+ attribute of the tag is set to "#" unless +html_options+ has one.
101
- #
102
- # link_to_function "Greeting", "alert('Hello world!')", class: "nav_link"
103
- # # => <a class="nav_link" href="#" onclick="alert('Hello world!'); return false;">Greeting</a>
104
- #
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 recommend using Unobtrusive JavaScript instead. " +
107
- "See http://guides.rubyonrails.org/working_with_javascript_in_rails.html#unobtrusive-javascript"
108
- ActiveSupport::Deprecation.warn message
109
-
110
- onclick = "#{"#{html_options[:onclick]}; " if html_options[:onclick]}#{function}; return false;"
111
- href = html_options[:href] || '#'
112
-
113
- content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
114
- end
115
- end
116
- end
117
- end
@@ -1,451 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'active_support/core_ext/hash/keys'
4
- require 'active_support/core_ext/string/output_safety'
5
- require 'active_support/number_helper'
6
-
7
- module ActionView
8
- # = Action View Number Helpers
9
- module Helpers #:nodoc:
10
-
11
- # Provides methods for converting numbers into formatted strings.
12
- # Methods are provided for phone numbers, currency, percentage,
13
- # precision, positional notation, file size and pretty printing.
14
- #
15
- # Most methods expect a +number+ argument, and will return it
16
- # unchanged if can't be converted into a valid number.
17
- module NumberHelper
18
-
19
- # Raised when argument +number+ param given to the helpers is invalid and
20
- # the option :raise is set to +true+.
21
- class InvalidNumberError < StandardError
22
- attr_accessor :number
23
- def initialize(number)
24
- @number = number
25
- end
26
- end
27
-
28
- # Formats a +number+ into a US phone number (e.g., (555)
29
- # 123-9876). You can customize the format in the +options+ hash.
30
- #
31
- # ==== Options
32
- #
33
- # * <tt>:area_code</tt> - Adds parentheses around the area code.
34
- # * <tt>:delimiter</tt> - Specifies the delimiter to use
35
- # (defaults to "-").
36
- # * <tt>:extension</tt> - Specifies an extension to add to the
37
- # end of the generated number.
38
- # * <tt>:country_code</tt> - Sets the country code for the phone
39
- # number.
40
- # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
41
- # the argument is invalid.
42
- #
43
- # ==== Examples
44
- #
45
- # number_to_phone(5551234) # => 555-1234
46
- # number_to_phone("5551234") # => 555-1234
47
- # number_to_phone(1235551234) # => 123-555-1234
48
- # number_to_phone(1235551234, area_code: true) # => (123) 555-1234
49
- # number_to_phone(1235551234, delimiter: " ") # => 123 555 1234
50
- # number_to_phone(1235551234, area_code: true, extension: 555) # => (123) 555-1234 x 555
51
- # number_to_phone(1235551234, country_code: 1) # => +1-123-555-1234
52
- # number_to_phone("123a456") # => 123a456
53
- # number_to_phone("1234a567", raise: true) # => InvalidNumberError
54
- #
55
- # number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: ".")
56
- # # => +1.123.555.1234 x 1343
57
- def number_to_phone(number, options = {})
58
- return unless number
59
- options = options.symbolize_keys
60
-
61
- parse_float(number, true) if options.delete(:raise)
62
- ERB::Util.html_escape(ActiveSupport::NumberHelper.number_to_phone(number, options))
63
- end
64
-
65
- # Formats a +number+ into a currency string (e.g., $13.65). You
66
- # can customize the format in the +options+ hash.
67
- #
68
- # ==== Options
69
- #
70
- # * <tt>:locale</tt> - Sets the locale to be used for formatting
71
- # (defaults to current locale).
72
- # * <tt>:precision</tt> - Sets the level of precision (defaults
73
- # to 2).
74
- # * <tt>:unit</tt> - Sets the denomination of the currency
75
- # (defaults to "$").
76
- # * <tt>:separator</tt> - Sets the separator between the units
77
- # (defaults to ".").
78
- # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
79
- # to ",").
80
- # * <tt>:format</tt> - Sets the format for non-negative numbers
81
- # (defaults to "%u%n"). Fields are <tt>%u</tt> for the
82
- # currency, and <tt>%n</tt> for the number.
83
- # * <tt>:negative_format</tt> - Sets the format for negative
84
- # numbers (defaults to prepending an hyphen to the formatted
85
- # number given by <tt>:format</tt>). Accepts the same fields
86
- # than <tt>:format</tt>, except <tt>%n</tt> is here the
87
- # absolute value of the number.
88
- # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
89
- # the argument is invalid.
90
- #
91
- # ==== Examples
92
- #
93
- # number_to_currency(1234567890.50) # => $1,234,567,890.50
94
- # number_to_currency(1234567890.506) # => $1,234,567,890.51
95
- # number_to_currency(1234567890.506, precision: 3) # => $1,234,567,890.506
96
- # number_to_currency(1234567890.506, locale: :fr) # => 1 234 567 890,51 €
97
- # number_to_currency("123a456") # => $123a456
98
- #
99
- # number_to_currency("123a456", raise: true) # => InvalidNumberError
100
- #
101
- # number_to_currency(-1234567890.50, negative_format: "(%u%n)")
102
- # # => ($1,234,567,890.50)
103
- # number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "")
104
- # # => R$1234567890,50
105
- # number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "", format: "%n %u")
106
- # # => 1234567890,50 R$
107
- def number_to_currency(number, options = {})
108
- return unless number
109
- options = escape_unsafe_options(options.symbolize_keys)
110
-
111
- wrap_with_output_safety_handling(number, options.delete(:raise)) {
112
- ActiveSupport::NumberHelper.number_to_currency(number, options)
113
- }
114
- end
115
-
116
- # Formats a +number+ as a percentage string (e.g., 65%). You can
117
- # customize the format in the +options+ hash.
118
- #
119
- # ==== Options
120
- #
121
- # * <tt>:locale</tt> - Sets the locale to be used for formatting
122
- # (defaults to current locale).
123
- # * <tt>:precision</tt> - Sets the precision of the number
124
- # (defaults to 3).
125
- # * <tt>:significant</tt> - If +true+, precision will be the #
126
- # of significant_digits. If +false+, the # of fractional
127
- # digits (defaults to +false+).
128
- # * <tt>:separator</tt> - Sets the separator between the
129
- # fractional and integer digits (defaults to ".").
130
- # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
131
- # to "").
132
- # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
133
- # insignificant zeros after the decimal separator (defaults to
134
- # +false+).
135
- # * <tt>:format</tt> - Specifies the format of the percentage
136
- # string The number field is <tt>%n</tt> (defaults to "%n%").
137
- # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
138
- # the argument is invalid.
139
- #
140
- # ==== Examples
141
- #
142
- # number_to_percentage(100) # => 100.000%
143
- # number_to_percentage("98") # => 98.000%
144
- # number_to_percentage(100, precision: 0) # => 100%
145
- # number_to_percentage(1000, delimiter: '.', separator: ',') # => 1.000,000%
146
- # number_to_percentage(302.24398923423, precision: 5) # => 302.24399%
147
- # number_to_percentage(1000, locale: :fr) # => 1 000,000%
148
- # number_to_percentage("98a") # => 98a%
149
- # number_to_percentage(100, format: "%n %") # => 100 %
150
- #
151
- # number_to_percentage("98a", raise: true) # => InvalidNumberError
152
- def number_to_percentage(number, options = {})
153
- return unless number
154
- options = escape_unsafe_options(options.symbolize_keys)
155
-
156
- wrap_with_output_safety_handling(number, options.delete(:raise)) {
157
- ActiveSupport::NumberHelper.number_to_percentage(number, options)
158
- }
159
- end
160
-
161
- # Formats a +number+ with grouped thousands using +delimiter+
162
- # (e.g., 12,324). You can customize the format in the +options+
163
- # hash.
164
- #
165
- # ==== Options
166
- #
167
- # * <tt>:locale</tt> - Sets the locale to be used for formatting
168
- # (defaults to current locale).
169
- # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
170
- # to ",").
171
- # * <tt>:separator</tt> - Sets the separator between the
172
- # fractional and integer digits (defaults to ".").
173
- # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
174
- # the argument is invalid.
175
- #
176
- # ==== Examples
177
- #
178
- # number_with_delimiter(12345678) # => 12,345,678
179
- # number_with_delimiter("123456") # => 123,456
180
- # number_with_delimiter(12345678.05) # => 12,345,678.05
181
- # number_with_delimiter(12345678, delimiter: ".") # => 12.345.678
182
- # number_with_delimiter(12345678, delimiter: ",") # => 12,345,678
183
- # number_with_delimiter(12345678.05, separator: " ") # => 12,345,678 05
184
- # number_with_delimiter(12345678.05, locale: :fr) # => 12 345 678,05
185
- # number_with_delimiter("112a") # => 112a
186
- # number_with_delimiter(98765432.98, delimiter: " ", separator: ",")
187
- # # => 98 765 432,98
188
- #
189
- # number_with_delimiter("112a", raise: true) # => raise InvalidNumberError
190
- def number_with_delimiter(number, options = {})
191
- options = escape_unsafe_options(options.symbolize_keys)
192
-
193
- wrap_with_output_safety_handling(number, options.delete(:raise)) {
194
- ActiveSupport::NumberHelper.number_to_delimited(number, options)
195
- }
196
- end
197
-
198
- # Formats a +number+ with the specified level of
199
- # <tt>:precision</tt> (e.g., 112.32 has a precision of 2 if
200
- # +:significant+ is +false+, and 5 if +:significant+ is +true+).
201
- # You can customize the format in the +options+ hash.
202
- #
203
- # ==== Options
204
- #
205
- # * <tt>:locale</tt> - Sets the locale to be used for formatting
206
- # (defaults to current locale).
207
- # * <tt>:precision</tt> - Sets the precision of the number
208
- # (defaults to 3).
209
- # * <tt>:significant</tt> - If +true+, precision will be the #
210
- # of significant_digits. If +false+, the # of fractional
211
- # digits (defaults to +false+).
212
- # * <tt>:separator</tt> - Sets the separator between the
213
- # fractional and integer digits (defaults to ".").
214
- # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
215
- # to "").
216
- # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
217
- # insignificant zeros after the decimal separator (defaults to
218
- # +false+).
219
- # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
220
- # the argument is invalid.
221
- #
222
- # ==== Examples
223
- #
224
- # number_with_precision(111.2345) # => 111.235
225
- # number_with_precision(111.2345, precision: 2) # => 111.23
226
- # number_with_precision(13, precision: 5) # => 13.00000
227
- # number_with_precision(389.32314, precision: 0) # => 389
228
- # number_with_precision(111.2345, significant: true) # => 111
229
- # number_with_precision(111.2345, precision: 1, significant: true) # => 100
230
- # number_with_precision(13, precision: 5, significant: true) # => 13.000
231
- # number_with_precision(111.234, locale: :fr) # => 111,234
232
- #
233
- # number_with_precision(13, precision: 5, significant: true, strip_insignificant_zeros: true)
234
- # # => 13
235
- #
236
- # number_with_precision(389.32314, precision: 4, significant: true) # => 389.3
237
- # number_with_precision(1111.2345, precision: 2, separator: ',', delimiter: '.')
238
- # # => 1.111,23
239
- def number_with_precision(number, options = {})
240
- options = escape_unsafe_options(options.symbolize_keys)
241
-
242
- wrap_with_output_safety_handling(number, options.delete(:raise)) {
243
- ActiveSupport::NumberHelper.number_to_rounded(number, options)
244
- }
245
- end
246
-
247
- # Formats the bytes in +number+ into a more understandable
248
- # representation (e.g., giving it 1500 yields 1.5 KB). This
249
- # method is useful for reporting file sizes to users. You can
250
- # customize the format in the +options+ hash.
251
- #
252
- # See <tt>number_to_human</tt> if you want to pretty-print a
253
- # generic number.
254
- #
255
- # ==== Options
256
- #
257
- # * <tt>:locale</tt> - Sets the locale to be used for formatting
258
- # (defaults to current locale).
259
- # * <tt>:precision</tt> - Sets the precision of the number
260
- # (defaults to 3).
261
- # * <tt>:significant</tt> - If +true+, precision will be the #
262
- # of significant_digits. If +false+, the # of fractional
263
- # digits (defaults to +true+)
264
- # * <tt>:separator</tt> - Sets the separator between the
265
- # fractional and integer digits (defaults to ".").
266
- # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
267
- # to "").
268
- # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
269
- # insignificant zeros after the decimal separator (defaults to
270
- # +true+)
271
- # * <tt>:prefix</tt> - If +:si+ formats the number using the SI
272
- # prefix (defaults to :binary)
273
- # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
274
- # the argument is invalid.
275
- #
276
- # ==== Examples
277
- #
278
- # number_to_human_size(123) # => 123 Bytes
279
- # number_to_human_size(1234) # => 1.21 KB
280
- # number_to_human_size(12345) # => 12.1 KB
281
- # number_to_human_size(1234567) # => 1.18 MB
282
- # number_to_human_size(1234567890) # => 1.15 GB
283
- # number_to_human_size(1234567890123) # => 1.12 TB
284
- # number_to_human_size(1234567, precision: 2) # => 1.2 MB
285
- # number_to_human_size(483989, precision: 2) # => 470 KB
286
- # number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
287
- #
288
- # Non-significant zeros after the fractional separator are
289
- # stripped out by default (set
290
- # <tt>:strip_insignificant_zeros</tt> to +false+ to change
291
- # that):
292
- #
293
- # number_to_human_size(1234567890123, precision: 5) # => "1.1229 TB"
294
- # number_to_human_size(524288000, precision: 5) # => "500 MB"
295
- def number_to_human_size(number, options = {})
296
- options = escape_unsafe_options(options.symbolize_keys)
297
-
298
- wrap_with_output_safety_handling(number, options.delete(:raise)) {
299
- ActiveSupport::NumberHelper.number_to_human_size(number, options)
300
- }
301
- end
302
-
303
- # Pretty prints (formats and approximates) a number in a way it
304
- # is more readable by humans (eg.: 1200000000 becomes "1.2
305
- # Billion"). This is useful for numbers that can get very large
306
- # (and too hard to read).
307
- #
308
- # See <tt>number_to_human_size</tt> if you want to print a file
309
- # size.
310
- #
311
- # You can also define you own unit-quantifier names if you want
312
- # to use other decimal units (eg.: 1500 becomes "1.5
313
- # kilometers", 0.150 becomes "150 milliliters", etc). You may
314
- # define a wide range of unit quantifiers, even fractional ones
315
- # (centi, deci, mili, etc).
316
- #
317
- # ==== Options
318
- #
319
- # * <tt>:locale</tt> - Sets the locale to be used for formatting
320
- # (defaults to current locale).
321
- # * <tt>:precision</tt> - Sets the precision of the number
322
- # (defaults to 3).
323
- # * <tt>:significant</tt> - If +true+, precision will be the #
324
- # of significant_digits. If +false+, the # of fractional
325
- # digits (defaults to +true+)
326
- # * <tt>:separator</tt> - Sets the separator between the
327
- # fractional and integer digits (defaults to ".").
328
- # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
329
- # to "").
330
- # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
331
- # insignificant zeros after the decimal separator (defaults to
332
- # +true+)
333
- # * <tt>:units</tt> - A Hash of unit quantifier names. Or a
334
- # string containing an i18n scope where to find this hash. It
335
- # might have the following keys:
336
- # * *integers*: <tt>:unit</tt>, <tt>:ten</tt>,
337
- # *<tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
338
- # *<tt>:billion</tt>, <tt>:trillion</tt>,
339
- # *<tt>:quadrillion</tt>
340
- # * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>,
341
- # *<tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
342
- # *<tt>:pico</tt>, <tt>:femto</tt>
343
- # * <tt>:format</tt> - Sets the format of the output string
344
- # (defaults to "%n %u"). The field types are:
345
- # * %u - The quantifier (ex.: 'thousand')
346
- # * %n - The number
347
- # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
348
- # the argument is invalid.
349
- #
350
- # ==== Examples
351
- #
352
- # number_to_human(123) # => "123"
353
- # number_to_human(1234) # => "1.23 Thousand"
354
- # number_to_human(12345) # => "12.3 Thousand"
355
- # number_to_human(1234567) # => "1.23 Million"
356
- # number_to_human(1234567890) # => "1.23 Billion"
357
- # number_to_human(1234567890123) # => "1.23 Trillion"
358
- # number_to_human(1234567890123456) # => "1.23 Quadrillion"
359
- # number_to_human(1234567890123456789) # => "1230 Quadrillion"
360
- # number_to_human(489939, precision: 2) # => "490 Thousand"
361
- # number_to_human(489939, precision: 4) # => "489.9 Thousand"
362
- # number_to_human(1234567, precision: 4,
363
- # significant: false) # => "1.2346 Million"
364
- # number_to_human(1234567, precision: 1,
365
- # separator: ',',
366
- # significant: false) # => "1,2 Million"
367
- #
368
- # Non-significant zeros after the decimal separator are stripped
369
- # out by default (set <tt>:strip_insignificant_zeros</tt> to
370
- # +false+ to change that):
371
- # number_to_human(12345012345, significant_digits: 6) # => "12.345 Billion"
372
- # number_to_human(500000000, precision: 5) # => "500 Million"
373
- #
374
- # ==== Custom Unit Quantifiers
375
- #
376
- # You can also use your own custom unit quantifiers:
377
- # number_to_human(500000, units: {unit: "ml", thousand: "lt"}) # => "500 lt"
378
- #
379
- # If in your I18n locale you have:
380
- # distance:
381
- # centi:
382
- # one: "centimeter"
383
- # other: "centimeters"
384
- # unit:
385
- # one: "meter"
386
- # other: "meters"
387
- # thousand:
388
- # one: "kilometer"
389
- # other: "kilometers"
390
- # billion: "gazillion-distance"
391
- #
392
- # Then you could do:
393
- #
394
- # number_to_human(543934, units: :distance) # => "544 kilometers"
395
- # number_to_human(54393498, units: :distance) # => "54400 kilometers"
396
- # number_to_human(54393498000, units: :distance) # => "54.4 gazillion-distance"
397
- # number_to_human(343, units: :distance, precision: 1) # => "300 meters"
398
- # number_to_human(1, units: :distance) # => "1 meter"
399
- # number_to_human(0.34, units: :distance) # => "34 centimeters"
400
- #
401
- def number_to_human(number, options = {})
402
- options = escape_unsafe_options(options.symbolize_keys)
403
-
404
- wrap_with_output_safety_handling(number, options.delete(:raise)) {
405
- ActiveSupport::NumberHelper.number_to_human(number, options)
406
- }
407
- end
408
-
409
- private
410
-
411
- def escape_unsafe_options(options)
412
- options[:format] = ERB::Util.html_escape(options[:format]) if options[:format]
413
- options[:negative_format] = ERB::Util.html_escape(options[:negative_format]) if options[:negative_format]
414
- options[:separator] = ERB::Util.html_escape(options[:separator]) if options[:separator]
415
- options[:delimiter] = ERB::Util.html_escape(options[:delimiter]) if options[:delimiter]
416
- options[:unit] = ERB::Util.html_escape(options[:unit]) if options[:unit] && !options[:unit].html_safe?
417
- options[:units] = escape_units(options[:units]) if options[:units] && Hash === options[:units]
418
- options
419
- end
420
-
421
- def escape_units(units)
422
- Hash[units.map do |k, v|
423
- [k, ERB::Util.html_escape(v)]
424
- end]
425
- end
426
-
427
- def wrap_with_output_safety_handling(number, raise_on_invalid, &block)
428
- valid_float = valid_float?(number)
429
- raise InvalidNumberError, number if raise_on_invalid && !valid_float
430
-
431
- formatted_number = yield
432
-
433
- if valid_float || number.html_safe?
434
- formatted_number.html_safe
435
- else
436
- formatted_number
437
- end
438
- end
439
-
440
- def valid_float?(number)
441
- !parse_float(number, false).nil?
442
- end
443
-
444
- def parse_float(number, raise_error)
445
- Float(number)
446
- rescue ArgumentError, TypeError
447
- raise InvalidNumberError, number if raise_error
448
- end
449
- end
450
- end
451
- end