actionview 7.0.10 → 7.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +235 -404
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/app/assets/javascripts/rails-ujs.esm.js +668 -0
  6. data/app/assets/javascripts/rails-ujs.js +606 -0
  7. data/lib/action_view/base.rb +28 -7
  8. data/lib/action_view/buffers.rb +106 -8
  9. data/lib/action_view/cache_expiry.rb +40 -43
  10. data/lib/action_view/context.rb +1 -1
  11. data/lib/action_view/deprecator.rb +7 -0
  12. data/lib/action_view/digestor.rb +1 -1
  13. data/lib/action_view/gem_version.rb +4 -4
  14. data/lib/action_view/helpers/active_model_helper.rb +1 -1
  15. data/lib/action_view/helpers/asset_tag_helper.rb +134 -50
  16. data/lib/action_view/helpers/asset_url_helper.rb +6 -5
  17. data/lib/action_view/helpers/atom_feed_helper.rb +5 -5
  18. data/lib/action_view/helpers/cache_helper.rb +3 -9
  19. data/lib/action_view/helpers/capture_helper.rb +24 -10
  20. data/lib/action_view/helpers/content_exfiltration_prevention_helper.rb +70 -0
  21. data/lib/action_view/helpers/controller_helper.rb +6 -0
  22. data/lib/action_view/helpers/csp_helper.rb +2 -2
  23. data/lib/action_view/helpers/csrf_helper.rb +2 -2
  24. data/lib/action_view/helpers/date_helper.rb +17 -19
  25. data/lib/action_view/helpers/debug_helper.rb +3 -3
  26. data/lib/action_view/helpers/form_helper.rb +46 -25
  27. data/lib/action_view/helpers/form_options_helper.rb +2 -1
  28. data/lib/action_view/helpers/form_tag_helper.rb +43 -9
  29. data/lib/action_view/helpers/javascript_helper.rb +1 -0
  30. data/lib/action_view/helpers/number_helper.rb +331 -36
  31. data/lib/action_view/helpers/output_safety_helper.rb +2 -2
  32. data/lib/action_view/helpers/rendering_helper.rb +1 -1
  33. data/lib/action_view/helpers/sanitize_helper.rb +40 -32
  34. data/lib/action_view/helpers/tag_helper.rb +5 -27
  35. data/lib/action_view/helpers/tags/base.rb +11 -52
  36. data/lib/action_view/helpers/tags/collection_check_boxes.rb +1 -0
  37. data/lib/action_view/helpers/tags/collection_radio_buttons.rb +1 -0
  38. data/lib/action_view/helpers/tags/collection_select.rb +3 -0
  39. data/lib/action_view/helpers/tags/date_field.rb +1 -1
  40. data/lib/action_view/helpers/tags/date_select.rb +2 -0
  41. data/lib/action_view/helpers/tags/datetime_field.rb +14 -6
  42. data/lib/action_view/helpers/tags/datetime_local_field.rb +11 -2
  43. data/lib/action_view/helpers/tags/grouped_collection_select.rb +3 -0
  44. data/lib/action_view/helpers/tags/month_field.rb +1 -1
  45. data/lib/action_view/helpers/tags/select.rb +3 -0
  46. data/lib/action_view/helpers/tags/select_renderer.rb +56 -0
  47. data/lib/action_view/helpers/tags/time_field.rb +1 -1
  48. data/lib/action_view/helpers/tags/time_zone_select.rb +3 -0
  49. data/lib/action_view/helpers/tags/week_field.rb +1 -1
  50. data/lib/action_view/helpers/tags/weekday_select.rb +3 -0
  51. data/lib/action_view/helpers/tags.rb +2 -0
  52. data/lib/action_view/helpers/text_helper.rb +100 -138
  53. data/lib/action_view/helpers/translation_helper.rb +3 -3
  54. data/lib/action_view/helpers/url_helper.rb +41 -14
  55. data/lib/action_view/helpers.rb +2 -0
  56. data/lib/action_view/layouts.rb +6 -4
  57. data/lib/action_view/log_subscriber.rb +49 -32
  58. data/lib/action_view/lookup_context.rb +29 -13
  59. data/lib/action_view/path_registry.rb +57 -0
  60. data/lib/action_view/path_set.rb +13 -14
  61. data/lib/action_view/railtie.rb +26 -3
  62. data/lib/action_view/record_identifier.rb +15 -8
  63. data/lib/action_view/renderer/abstract_renderer.rb +1 -1
  64. data/lib/action_view/renderer/collection_renderer.rb +9 -1
  65. data/lib/action_view/renderer/partial_renderer/collection_caching.rb +2 -1
  66. data/lib/action_view/renderer/partial_renderer.rb +2 -1
  67. data/lib/action_view/renderer/renderer.rb +2 -0
  68. data/lib/action_view/renderer/streaming_template_renderer.rb +3 -2
  69. data/lib/action_view/renderer/template_renderer.rb +3 -2
  70. data/lib/action_view/rendering.rb +22 -4
  71. data/lib/action_view/ripper_ast_parser.rb +6 -6
  72. data/lib/action_view/template/error.rb +14 -1
  73. data/lib/action_view/template/handlers/builder.rb +4 -4
  74. data/lib/action_view/template/handlers/erb/erubi.rb +23 -27
  75. data/lib/action_view/template/handlers/erb.rb +73 -1
  76. data/lib/action_view/template/handlers.rb +1 -1
  77. data/lib/action_view/template/html.rb +1 -1
  78. data/lib/action_view/template/raw_file.rb +1 -1
  79. data/lib/action_view/template/renderable.rb +1 -1
  80. data/lib/action_view/template/resolver.rb +10 -2
  81. data/lib/action_view/template/text.rb +1 -1
  82. data/lib/action_view/template/types.rb +25 -34
  83. data/lib/action_view/template.rb +180 -53
  84. data/lib/action_view/template_path.rb +2 -0
  85. data/lib/action_view/test_case.rb +8 -5
  86. data/lib/action_view/unbound_template.rb +15 -5
  87. data/lib/action_view/version.rb +1 -1
  88. data/lib/action_view/view_paths.rb +15 -24
  89. data/lib/action_view.rb +4 -1
  90. metadata +29 -26
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "cgi"
4
+ require "action_view/helpers/content_exfiltration_prevention_helper"
4
5
  require "action_view/helpers/url_helper"
5
6
  require "action_view/helpers/text_helper"
6
7
  require "active_support/core_ext/string/output_safety"
7
8
  require "active_support/core_ext/module/attribute_accessors"
8
9
 
9
10
  module ActionView
10
- # = Action View Form Tag Helpers
11
11
  module Helpers # :nodoc:
12
+ # = Action View Form Tag \Helpers
13
+ #
12
14
  # Provides a number of methods for creating form tags that don't rely on an Active Record object assigned to the template like
13
15
  # FormHelper does. Instead, you provide the names and values manually.
14
16
  #
@@ -19,6 +21,7 @@ module ActionView
19
21
 
20
22
  include UrlHelper
21
23
  include TextHelper
24
+ include ContentExfiltrationPreventionHelper
22
25
 
23
26
  mattr_accessor :embed_authenticity_token_in_remote_forms
24
27
  self.embed_authenticity_token_in_remote_forms = nil
@@ -420,9 +423,17 @@ module ActionView
420
423
  content_tag :textarea, content.to_s.html_safe, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
421
424
  end
422
425
 
426
+ ##
427
+ # :call-seq:
428
+ # check_box_tag(name, options = {})
429
+ # check_box_tag(name, value, options = {})
430
+ # check_box_tag(name, value, checked, options = {})
431
+ #
423
432
  # Creates a check box form input tag.
424
433
  #
425
434
  # ==== Options
435
+ # * <tt>:value</tt> - The value of the input. Defaults to <tt>"1"</tt>.
436
+ # * <tt>:checked</tt> - If set to true, the checkbox will be checked by default.
426
437
  # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
427
438
  # * Any other key creates standard HTML options for the tag.
428
439
  #
@@ -441,16 +452,27 @@ module ActionView
441
452
  #
442
453
  # check_box_tag 'eula', 'accepted', false, disabled: true
443
454
  # # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />
444
- def check_box_tag(name, value = "1", checked = false, options = {})
455
+ def check_box_tag(name, *args)
456
+ if args.length >= 4
457
+ raise ArgumentError, "wrong number of arguments (given #{args.length + 1}, expected 1..4)"
458
+ end
459
+ options = args.extract_options!
460
+ value, checked = args.empty? ? ["1", false] : [*args, false]
445
461
  html_options = { "type" => "checkbox", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
446
462
  html_options["checked"] = "checked" if checked
447
463
  tag :input, html_options
448
464
  end
449
465
 
466
+ ##
467
+ # :call-seq:
468
+ # radio_button_tag(name, value, options = {})
469
+ # radio_button_tag(name, value, checked, options = {})
470
+ #
450
471
  # Creates a radio button; use groups of radio buttons named the same to allow users to
451
472
  # select from a group of options.
452
473
  #
453
474
  # ==== Options
475
+ # * <tt>:checked</tt> - If set to true, the radio button will be selected by default.
454
476
  # * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
455
477
  # * Any other key creates standard HTML options for the tag.
456
478
  #
@@ -466,7 +488,12 @@ module ActionView
466
488
  #
467
489
  # radio_button_tag 'color', "green", true, class: "color_input"
468
490
  # # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" />
469
- def radio_button_tag(name, value, checked = false, options = {})
491
+ def radio_button_tag(name, value, *args)
492
+ if args.length >= 3
493
+ raise ArgumentError, "wrong number of arguments (given #{args.length + 2}, expected 2..4)"
494
+ end
495
+ options = args.extract_options!
496
+ checked = args.empty? ? false : args.first
470
497
  html_options = { "type" => "radio", "name" => name, "id" => "#{sanitize_to_id(name)}_#{sanitize_to_id(value)}", "value" => value }.update(options.stringify_keys)
471
498
  html_options["checked"] = "checked" if checked
472
499
  tag :input, html_options
@@ -495,9 +522,9 @@ module ActionView
495
522
  # submit_tag "Edit", class: "edit_button"
496
523
  # # => <input class="edit_button" data-disable-with="Edit" name="commit" type="submit" value="Edit" />
497
524
  #
498
- # ==== Deprecated: Rails UJS attributes
525
+ # ==== Deprecated: \Rails UJS attributes
499
526
  #
500
- # Prior to Rails 7, Rails shipped with the JavaScript library called @rails/ujs on by default. Following Rails 7,
527
+ # Prior to \Rails 7, \Rails shipped with the JavaScript library called @rails/ujs on by default. Following \Rails 7,
501
528
  # this library is no longer on by default. This library integrated with the following options:
502
529
  #
503
530
  # * <tt>confirm: 'question?'</tt> - If present the unobtrusive JavaScript
@@ -555,9 +582,9 @@ module ActionView
555
582
  # # <strong>Ask me!</strong>
556
583
  # # </button>
557
584
  #
558
- # ==== Deprecated: Rails UJS attributes
585
+ # ==== Deprecated: \Rails UJS attributes
559
586
  #
560
- # Prior to Rails 7, Rails shipped with a JavaScript library called @rails/ujs on by default. Following Rails 7,
587
+ # Prior to \Rails 7, \Rails shipped with a JavaScript library called @rails/ujs on by default. Following \Rails 7,
561
588
  # this library is no longer on by default. This library integrated with the following options:
562
589
  #
563
590
  # * <tt>confirm: 'question?'</tt> - If present, the
@@ -770,6 +797,7 @@ module ActionView
770
797
  # * <tt>:min</tt> - The minimum acceptable value.
771
798
  # * <tt>:max</tt> - The maximum acceptable value.
772
799
  # * <tt>:step</tt> - The acceptable value granularity.
800
+ # * <tt>:include_seconds</tt> - Include seconds in the output timestamp format (true by default).
773
801
  def datetime_field_tag(name, value = nil, options = {})
774
802
  text_field_tag(name, value, options.merge(type: "datetime-local"))
775
803
  end
@@ -979,7 +1007,8 @@ module ActionView
979
1007
 
980
1008
  def form_tag_html(html_options)
981
1009
  extra_tags = extra_tags_for_form(html_options)
982
- tag(:form, html_options, true) + extra_tags
1010
+ html = tag(:form, html_options, true) + extra_tags
1011
+ prevent_content_exfiltration(html)
983
1012
  end
984
1013
 
985
1014
  def form_tag_with_body(html_options, content)
@@ -1009,9 +1038,14 @@ module ActionView
1009
1038
  end
1010
1039
 
1011
1040
  def convert_direct_upload_option_to_url(options)
1012
- if options.delete(:direct_upload) && respond_to?(:rails_direct_uploads_url)
1041
+ return options unless options.delete(:direct_upload)
1042
+
1043
+ if respond_to?(:rails_direct_uploads_url)
1013
1044
  options["data-direct-upload-url"] = rails_direct_uploads_url
1045
+ elsif respond_to?(:main_app) && main_app.respond_to?(:rails_direct_uploads_url)
1046
+ options["data-direct-upload-url"] = main_app.rails_direct_uploads_url
1014
1047
  end
1048
+
1015
1049
  options
1016
1050
  end
1017
1051
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  module ActionView
4
4
  module Helpers # :nodoc:
5
+ # = Action View JavaScript \Helpers
5
6
  module JavaScriptHelper
6
7
  JS_ESCAPE_MAP = {
7
8
  "\\" => "\\\\",
@@ -5,8 +5,9 @@ require "active_support/core_ext/string/output_safety"
5
5
  require "active_support/number_helper"
6
6
 
7
7
  module ActionView
8
- # = Action View Number Helpers
9
8
  module Helpers # :nodoc:
9
+ # = Action View Number \Helpers
10
+ #
10
11
  # Provides methods for converting numbers into formatted strings.
11
12
  # Methods are provided for phone numbers, currency, percentage,
12
13
  # precision, positional notation, file size, and pretty printing.
@@ -23,14 +24,42 @@ module ActionView
23
24
  end
24
25
  end
25
26
 
26
- # Delegates to ActiveSupport::NumberHelper#number_to_phone.
27
+ # Formats a +number+ into a phone number (US by default e.g., (555)
28
+ # 123-9876). You can customize the format in the +options+ hash.
29
+ #
30
+ # ==== Options
31
+ #
32
+ # * <tt>:area_code</tt> - Adds parentheses around the area code.
33
+ # * <tt>:delimiter</tt> - Specifies the delimiter to use
34
+ # (defaults to "-").
35
+ # * <tt>:extension</tt> - Specifies an extension to add to the
36
+ # end of the generated number.
37
+ # * <tt>:country_code</tt> - Sets the country code for the phone
38
+ # number.
39
+ # * <tt>:pattern</tt> - Specifies how the number is divided into three
40
+ # groups with the custom regexp to override the default format.
41
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
42
+ # the argument is invalid.
43
+ #
44
+ # ==== Examples
27
45
  #
28
- # Additionally, supports a +:raise+ option that will cause
29
- # InvalidNumberError to be raised if +number+ is not a valid number:
46
+ # number_to_phone(5551234) # => 555-1234
47
+ # number_to_phone("5551234") # => 555-1234
48
+ # number_to_phone(1235551234) # => 123-555-1234
49
+ # number_to_phone(1235551234, area_code: true) # => (123) 555-1234
50
+ # number_to_phone(1235551234, delimiter: " ") # => 123 555 1234
51
+ # number_to_phone(1235551234, area_code: true, extension: 555) # => (123) 555-1234 x 555
52
+ # number_to_phone(1235551234, country_code: 1) # => +1-123-555-1234
53
+ # number_to_phone("123a456") # => 123a456
54
+ # number_to_phone("1234a567", raise: true) # => InvalidNumberError
30
55
  #
31
- # number_to_phone("12x34") # => "12x34"
32
- # number_to_phone("12x34", raise: true) # => InvalidNumberError
56
+ # number_to_phone(1235551234, country_code: 1, extension: 1343, delimiter: ".")
57
+ # # => +1.123.555.1234 x 1343
33
58
  #
59
+ # number_to_phone(75561234567, pattern: /(\d{1,4})(\d{4})(\d{4})$/, area_code: true)
60
+ # # => "(755) 6123-4567"
61
+ # number_to_phone(13312345678, pattern: /(\d{3})(\d{4})(\d{4})$/)
62
+ # # => "133-1234-5678"
34
63
  def number_to_phone(number, options = {})
35
64
  return unless number
36
65
  options = options.symbolize_keys
@@ -39,73 +68,339 @@ module ActionView
39
68
  ERB::Util.html_escape(ActiveSupport::NumberHelper.number_to_phone(number, options))
40
69
  end
41
70
 
42
- # Delegates to ActiveSupport::NumberHelper#number_to_currency.
71
+ # Formats a +number+ into a currency string (e.g., $13.65). You
72
+ # can customize the format in the +options+ hash.
73
+ #
74
+ # The currency unit and number formatting of the current locale will be used
75
+ # unless otherwise specified in the provided options. No currency conversion
76
+ # is performed. If the user is given a way to change their locale, they will
77
+ # also be able to change the relative value of the currency displayed with
78
+ # this helper. If your application will ever support multiple locales, you
79
+ # may want to specify a constant <tt>:locale</tt> option or consider
80
+ # using a library capable of currency conversion.
81
+ #
82
+ # ==== Options
83
+ #
84
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
85
+ # (defaults to current locale).
86
+ # * <tt>:precision</tt> - Sets the level of precision (defaults
87
+ # to 2).
88
+ # * <tt>:unit</tt> - Sets the denomination of the currency
89
+ # (defaults to "$").
90
+ # * <tt>:separator</tt> - Sets the separator between the units
91
+ # (defaults to ".").
92
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
93
+ # to ",").
94
+ # * <tt>:format</tt> - Sets the format for non-negative numbers
95
+ # (defaults to "%u%n"). Fields are <tt>%u</tt> for the
96
+ # currency, and <tt>%n</tt> for the number.
97
+ # * <tt>:negative_format</tt> - Sets the format for negative
98
+ # numbers (defaults to prepending a hyphen to the formatted
99
+ # number given by <tt>:format</tt>). Accepts the same fields
100
+ # than <tt>:format</tt>, except <tt>%n</tt> is here the
101
+ # absolute value of the number.
102
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
103
+ # the argument is invalid.
104
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
105
+ # insignificant zeros after the decimal separator (defaults to
106
+ # +false+).
107
+ #
108
+ # ==== Examples
43
109
  #
44
- # Additionally, supports a +:raise+ option that will cause
45
- # InvalidNumberError to be raised if +number+ is not a valid number:
110
+ # number_to_currency(1234567890.50) # => $1,234,567,890.50
111
+ # number_to_currency(1234567890.506) # => $1,234,567,890.51
112
+ # number_to_currency(1234567890.506, precision: 3) # => $1,234,567,890.506
113
+ # number_to_currency(1234567890.506, locale: :fr) # => 1 234 567 890,51 €
114
+ # number_to_currency("123a456") # => $123a456
46
115
  #
47
- # number_to_currency("12x34") # => "$12x34"
48
- # number_to_currency("12x34", raise: true) # => InvalidNumberError
116
+ # number_to_currency("123a456", raise: true) # => InvalidNumberError
49
117
  #
118
+ # number_to_currency(-0.456789, precision: 0)
119
+ # # => "$0"
120
+ # number_to_currency(-1234567890.50, negative_format: "(%u%n)")
121
+ # # => ($1,234,567,890.50)
122
+ # number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "")
123
+ # # => R$1234567890,50
124
+ # number_to_currency(1234567890.50, unit: "R$", separator: ",", delimiter: "", format: "%n %u")
125
+ # # => 1234567890,50 R$
126
+ # number_to_currency(1234567890.50, strip_insignificant_zeros: true)
127
+ # # => "$1,234,567,890.5"
50
128
  def number_to_currency(number, options = {})
51
129
  delegate_number_helper_method(:number_to_currency, number, options)
52
130
  end
53
131
 
54
- # Delegates to ActiveSupport::NumberHelper#number_to_percentage.
132
+ # Formats a +number+ as a percentage string (e.g., 65%). You can
133
+ # customize the format in the +options+ hash.
55
134
  #
56
- # Additionally, supports a +:raise+ option that will cause
57
- # InvalidNumberError to be raised if +number+ is not a valid number:
135
+ # ==== Options
58
136
  #
59
- # number_to_percentage("99x") # => "99x%"
60
- # number_to_percentage("99x", raise: true) # => InvalidNumberError
137
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
138
+ # (defaults to current locale).
139
+ # * <tt>:precision</tt> - Sets the precision of the number
140
+ # (defaults to 3).
141
+ # * <tt>:significant</tt> - If +true+, precision will be the number
142
+ # of significant_digits. If +false+, the number of fractional
143
+ # digits (defaults to +false+).
144
+ # * <tt>:separator</tt> - Sets the separator between the
145
+ # fractional and integer digits (defaults to ".").
146
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
147
+ # to "").
148
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
149
+ # insignificant zeros after the decimal separator (defaults to
150
+ # +false+).
151
+ # * <tt>:format</tt> - Specifies the format of the percentage
152
+ # string The number field is <tt>%n</tt> (defaults to "%n%").
153
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
154
+ # the argument is invalid.
61
155
  #
156
+ # ==== Examples
157
+ #
158
+ # number_to_percentage(100) # => 100.000%
159
+ # number_to_percentage("98") # => 98.000%
160
+ # number_to_percentage(100, precision: 0) # => 100%
161
+ # number_to_percentage(1000, delimiter: '.', separator: ',') # => 1.000,000%
162
+ # number_to_percentage(302.24398923423, precision: 5) # => 302.24399%
163
+ # number_to_percentage(1000, locale: :fr) # => 1 000,000%
164
+ # number_to_percentage("98a") # => 98a%
165
+ # number_to_percentage(100, format: "%n %") # => 100.000 %
166
+ #
167
+ # number_to_percentage("98a", raise: true) # => InvalidNumberError
62
168
  def number_to_percentage(number, options = {})
63
169
  delegate_number_helper_method(:number_to_percentage, number, options)
64
170
  end
65
171
 
66
- # Delegates to ActiveSupport::NumberHelper#number_to_delimited.
172
+ # Formats a +number+ with grouped thousands using +delimiter+
173
+ # (e.g., 12,324). You can customize the format in the +options+
174
+ # hash.
175
+ #
176
+ # ==== Options
177
+ #
178
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
179
+ # (defaults to current locale).
180
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
181
+ # to ",").
182
+ # * <tt>:separator</tt> - Sets the separator between the
183
+ # fractional and integer digits (defaults to ".").
184
+ # * <tt>:delimiter_pattern</tt> - Sets a custom regular expression used for
185
+ # deriving the placement of delimiter. Helpful when using currency formats
186
+ # like INR.
187
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
188
+ # the argument is invalid.
67
189
  #
68
- # Additionally, supports a +:raise+ option that will cause
69
- # InvalidNumberError to be raised if +number+ is not a valid number:
190
+ # ==== Examples
70
191
  #
71
- # number_with_delimiter("12x34") # => "12x34"
72
- # number_with_delimiter("12x34", raise: true) # => InvalidNumberError
192
+ # number_with_delimiter(12345678) # => 12,345,678
193
+ # number_with_delimiter("123456") # => 123,456
194
+ # number_with_delimiter(12345678.05) # => 12,345,678.05
195
+ # number_with_delimiter(12345678, delimiter: ".") # => 12.345.678
196
+ # number_with_delimiter(12345678, delimiter: ",") # => 12,345,678
197
+ # number_with_delimiter(12345678.05, separator: " ") # => 12,345,678 05
198
+ # number_with_delimiter(12345678.05, locale: :fr) # => 12 345 678,05
199
+ # number_with_delimiter("112a") # => 112a
200
+ # number_with_delimiter(98765432.98, delimiter: " ", separator: ",")
201
+ # # => 98 765 432,98
73
202
  #
203
+ # number_with_delimiter("123456.78",
204
+ # delimiter_pattern: /(\d+?)(?=(\d\d)+(\d)(?!\d))/) # => "1,23,456.78"
205
+ #
206
+ # number_with_delimiter("112a", raise: true) # => raise InvalidNumberError
74
207
  def number_with_delimiter(number, options = {})
75
208
  delegate_number_helper_method(:number_to_delimited, number, options)
76
209
  end
77
210
 
78
- # Delegates to ActiveSupport::NumberHelper#number_to_rounded.
211
+ # Formats a +number+ with the specified level of
212
+ # <tt>:precision</tt> (e.g., 112.32 has a precision of 2 if
213
+ # +:significant+ is +false+, and 5 if +:significant+ is +true+).
214
+ # You can customize the format in the +options+ hash.
215
+ #
216
+ # ==== Options
217
+ #
218
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
219
+ # (defaults to current locale).
220
+ # * <tt>:precision</tt> - Sets the precision of the number
221
+ # (defaults to 3).
222
+ # * <tt>:significant</tt> - If +true+, precision will be the number
223
+ # of significant_digits. If +false+, the number of fractional
224
+ # digits (defaults to +false+).
225
+ # * <tt>:separator</tt> - Sets the separator between the
226
+ # fractional and integer digits (defaults to ".").
227
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
228
+ # to "").
229
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
230
+ # insignificant zeros after the decimal separator (defaults to
231
+ # +false+).
232
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
233
+ # the argument is invalid.
234
+ #
235
+ # ==== Examples
79
236
  #
80
- # Additionally, supports a +:raise+ option that will cause
81
- # InvalidNumberError to be raised if +number+ is not a valid number:
237
+ # number_with_precision(111.2345) # => 111.235
238
+ # number_with_precision(111.2345, precision: 2) # => 111.23
239
+ # number_with_precision(13, precision: 5) # => 13.00000
240
+ # number_with_precision(389.32314, precision: 0) # => 389
241
+ # number_with_precision(111.2345, significant: true) # => 111
242
+ # number_with_precision(111.2345, precision: 1, significant: true) # => 100
243
+ # number_with_precision(13, precision: 5, significant: true) # => 13.000
244
+ # number_with_precision(111.234, locale: :fr) # => 111,234
82
245
  #
83
- # number_with_precision("12x34") # => "12x34"
84
- # number_with_precision("12x34", raise: true) # => InvalidNumberError
246
+ # number_with_precision(13, precision: 5, significant: true, strip_insignificant_zeros: true)
247
+ # # => 13
85
248
  #
249
+ # number_with_precision(389.32314, precision: 4, significant: true) # => 389.3
250
+ # number_with_precision(1111.2345, precision: 2, separator: ',', delimiter: '.')
251
+ # # => 1.111,23
86
252
  def number_with_precision(number, options = {})
87
253
  delegate_number_helper_method(:number_to_rounded, number, options)
88
254
  end
89
255
 
90
- # Delegates to ActiveSupport::NumberHelper#number_to_human_size.
256
+ # Formats the bytes in +number+ into a more understandable
257
+ # representation (e.g., giving it 1500 yields 1.46 KB). This
258
+ # method is useful for reporting file sizes to users. You can
259
+ # customize the format in the +options+ hash.
91
260
  #
92
- # Additionally, supports a +:raise+ option that will cause
93
- # InvalidNumberError to be raised if +number+ is not a valid number:
261
+ # See <tt>number_to_human</tt> if you want to pretty-print a
262
+ # generic number.
94
263
  #
95
- # number_to_human_size("12x34") # => "12x34"
96
- # number_to_human_size("12x34", raise: true) # => InvalidNumberError
264
+ # ==== Options
97
265
  #
266
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
267
+ # (defaults to current locale).
268
+ # * <tt>:precision</tt> - Sets the precision of the number
269
+ # (defaults to 3).
270
+ # * <tt>:significant</tt> - If +true+, precision will be the number
271
+ # of significant_digits. If +false+, the number of fractional
272
+ # digits (defaults to +true+)
273
+ # * <tt>:separator</tt> - Sets the separator between the
274
+ # fractional and integer digits (defaults to ".").
275
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
276
+ # to "").
277
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
278
+ # insignificant zeros after the decimal separator (defaults to
279
+ # +true+)
280
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
281
+ # the argument is invalid.
282
+ #
283
+ # ==== Examples
284
+ #
285
+ # number_to_human_size(123) # => 123 Bytes
286
+ # number_to_human_size(1234) # => 1.21 KB
287
+ # number_to_human_size(12345) # => 12.1 KB
288
+ # number_to_human_size(1234567) # => 1.18 MB
289
+ # number_to_human_size(1234567890) # => 1.15 GB
290
+ # number_to_human_size(1234567890123) # => 1.12 TB
291
+ # number_to_human_size(1234567890123456) # => 1.1 PB
292
+ # number_to_human_size(1234567890123456789) # => 1.07 EB
293
+ # number_to_human_size(1234567, precision: 2) # => 1.2 MB
294
+ # number_to_human_size(483989, precision: 2) # => 470 KB
295
+ # number_to_human_size(1234567, precision: 2, separator: ',') # => 1,2 MB
296
+ # number_to_human_size(1234567890123, precision: 5) # => "1.1228 TB"
297
+ # number_to_human_size(524288000, precision: 5) # => "500 MB"
98
298
  def number_to_human_size(number, options = {})
99
299
  delegate_number_helper_method(:number_to_human_size, number, options)
100
300
  end
101
301
 
102
- # Delegates to ActiveSupport::NumberHelper#number_to_human.
302
+ # Pretty prints (formats and approximates) a number in a way it
303
+ # is more readable by humans (e.g.: 1200000000 becomes "1.2
304
+ # Billion"). This is useful for numbers that can get very large
305
+ # (and too hard to read).
306
+ #
307
+ # See <tt>number_to_human_size</tt> if you want to print a file
308
+ # size.
309
+ #
310
+ # You can also define your own unit-quantifier names if you want
311
+ # to use other decimal units (e.g.: 1500 becomes "1.5
312
+ # kilometers", 0.150 becomes "150 milliliters", etc). You may
313
+ # define a wide range of unit quantifiers, even fractional ones
314
+ # (centi, deci, mili, etc).
315
+ #
316
+ # ==== Options
317
+ #
318
+ # * <tt>:locale</tt> - Sets the locale to be used for formatting
319
+ # (defaults to current locale).
320
+ # * <tt>:precision</tt> - Sets the precision of the number
321
+ # (defaults to 3).
322
+ # * <tt>:significant</tt> - If +true+, precision will be the number
323
+ # of significant_digits. If +false+, the number of fractional
324
+ # digits (defaults to +true+)
325
+ # * <tt>:separator</tt> - Sets the separator between the
326
+ # fractional and integer digits (defaults to ".").
327
+ # * <tt>:delimiter</tt> - Sets the thousands delimiter (defaults
328
+ # to "").
329
+ # * <tt>:strip_insignificant_zeros</tt> - If +true+ removes
330
+ # insignificant zeros after the decimal separator (defaults to
331
+ # +true+)
332
+ # * <tt>:units</tt> - A Hash of unit quantifier names. Or a
333
+ # string containing an i18n scope where to find this hash. It
334
+ # might have the following keys:
335
+ # * *integers*: <tt>:unit</tt>, <tt>:ten</tt>,
336
+ # <tt>:hundred</tt>, <tt>:thousand</tt>, <tt>:million</tt>,
337
+ # <tt>:billion</tt>, <tt>:trillion</tt>,
338
+ # <tt>:quadrillion</tt>
339
+ # * *fractionals*: <tt>:deci</tt>, <tt>:centi</tt>,
340
+ # <tt>:mili</tt>, <tt>:micro</tt>, <tt>:nano</tt>,
341
+ # <tt>:pico</tt>, <tt>:femto</tt>
342
+ # * <tt>:format</tt> - Sets the format of the output string
343
+ # (defaults to "%n %u"). The field types are:
344
+ # * %u - The quantifier (ex.: 'thousand')
345
+ # * %n - The number
346
+ # * <tt>:raise</tt> - If true, raises +InvalidNumberError+ when
347
+ # the argument is invalid.
348
+ #
349
+ # ==== Examples
350
+ #
351
+ # number_to_human(123) # => "123"
352
+ # number_to_human(1234) # => "1.23 Thousand"
353
+ # number_to_human(12345) # => "12.3 Thousand"
354
+ # number_to_human(1234567) # => "1.23 Million"
355
+ # number_to_human(1234567890) # => "1.23 Billion"
356
+ # number_to_human(1234567890123) # => "1.23 Trillion"
357
+ # number_to_human(1234567890123456) # => "1.23 Quadrillion"
358
+ # number_to_human(1234567890123456789) # => "1230 Quadrillion"
359
+ # number_to_human(489939, precision: 2) # => "490 Thousand"
360
+ # number_to_human(489939, precision: 4) # => "489.9 Thousand"
361
+ # number_to_human(1234567, precision: 4,
362
+ # significant: false) # => "1.2346 Million"
363
+ # number_to_human(1234567, precision: 1,
364
+ # separator: ',',
365
+ # significant: false) # => "1,2 Million"
366
+ #
367
+ # number_to_human(500000000, precision: 5) # => "500 Million"
368
+ # number_to_human(12345012345, significant: false) # => "12.345 Billion"
369
+ #
370
+ # Non-significant zeros after the decimal separator are stripped
371
+ # out by default (set <tt>:strip_insignificant_zeros</tt> to
372
+ # +false+ to change that):
373
+ #
374
+ # number_to_human(12.00001) # => "12"
375
+ # number_to_human(12.00001, strip_insignificant_zeros: false) # => "12.0"
376
+ #
377
+ # ==== Custom Unit Quantifiers
378
+ #
379
+ # You can also use your own custom unit quantifiers:
380
+ #
381
+ # number_to_human(500000, units: {unit: "ml", thousand: "lt"}) # => "500 lt"
382
+ #
383
+ # If in your I18n locale you have:
384
+ # distance:
385
+ # centi:
386
+ # one: "centimeter"
387
+ # other: "centimeters"
388
+ # unit:
389
+ # one: "meter"
390
+ # other: "meters"
391
+ # thousand:
392
+ # one: "kilometer"
393
+ # other: "kilometers"
394
+ # billion: "gazillion-distance"
103
395
  #
104
- # Additionally, supports a +:raise+ option that will cause
105
- # InvalidNumberError to be raised if +number+ is not a valid number:
396
+ # Then you could do:
106
397
  #
107
- # number_to_human("12x34") # => "12x34"
108
- # number_to_human("12x34", raise: true) # => InvalidNumberError
398
+ # number_to_human(543934, units: :distance) # => "544 kilometers"
399
+ # number_to_human(54393498, units: :distance) # => "54400 kilometers"
400
+ # number_to_human(54393498000, units: :distance) # => "54.4 gazillion-distance"
401
+ # number_to_human(343, units: :distance, precision: 1) # => "300 meters"
402
+ # number_to_human(1, units: :distance) # => "1 meter"
403
+ # number_to_human(0.34, units: :distance) # => "34 centimeters"
109
404
  #
110
405
  def number_to_human(number, options = {})
111
406
  delegate_number_helper_method(:number_to_human, number, options)
@@ -3,11 +3,11 @@
3
3
  require "active_support/core_ext/string/output_safety"
4
4
 
5
5
  module ActionView # :nodoc:
6
- # = Action View Raw Output Helper
7
6
  module Helpers # :nodoc:
7
+ # = Action View Raw Output \Helpers
8
8
  module OutputSafetyHelper
9
9
  # This method outputs without escaping a string. Since escaping tags is
10
- # now default, this can be used when you don't want Rails to automatically
10
+ # now default, this can be used when you don't want \Rails to automatically
11
11
  # escape tags. This is not recommended if the data is coming from the user's
12
12
  # input.
13
13
  #
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActionView
4
4
  module Helpers # :nodoc:
5
- # = Action View Rendering
5
+ # = Action View \Rendering \Helpers
6
6
  #
7
7
  # Implements methods that allow rendering from a view context.
8
8
  # In order to use this module, all you need is to implement