activesupport 6.1.1 → 7.0.2.3

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

Potentially problematic release.


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

Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +231 -383
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/actionable_error.rb +1 -1
  6. data/lib/active_support/array_inquirer.rb +0 -2
  7. data/lib/active_support/benchmarkable.rb +2 -2
  8. data/lib/active_support/cache/file_store.rb +16 -10
  9. data/lib/active_support/cache/mem_cache_store.rb +133 -34
  10. data/lib/active_support/cache/memory_store.rb +23 -15
  11. data/lib/active_support/cache/null_store.rb +10 -2
  12. data/lib/active_support/cache/redis_cache_store.rb +42 -67
  13. data/lib/active_support/cache/strategy/local_cache.rb +35 -61
  14. data/lib/active_support/cache.rb +196 -46
  15. data/lib/active_support/callbacks.rb +180 -81
  16. data/lib/active_support/code_generator.rb +65 -0
  17. data/lib/active_support/concern.rb +5 -5
  18. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  19. data/lib/active_support/concurrency/share_lock.rb +2 -2
  20. data/lib/active_support/configurable.rb +6 -3
  21. data/lib/active_support/configuration_file.rb +7 -2
  22. data/lib/active_support/core_ext/array/access.rb +1 -5
  23. data/lib/active_support/core_ext/array/conversions.rb +13 -11
  24. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  25. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  26. data/lib/active_support/core_ext/array.rb +1 -0
  27. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  28. data/lib/active_support/core_ext/class/subclasses.rb +25 -17
  29. data/lib/active_support/core_ext/date/blank.rb +1 -1
  30. data/lib/active_support/core_ext/date/calculations.rb +4 -4
  31. data/lib/active_support/core_ext/date/conversions.rb +11 -11
  32. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  33. data/lib/active_support/core_ext/date.rb +1 -0
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  35. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  36. data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
  37. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  38. data/lib/active_support/core_ext/date_time.rb +1 -0
  39. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  40. data/lib/active_support/core_ext/enumerable.rb +78 -26
  41. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  42. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  43. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  44. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -0
  45. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
  46. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  47. data/lib/active_support/core_ext/name_error.rb +2 -8
  48. data/lib/active_support/core_ext/numeric/conversions.rb +79 -76
  49. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  50. data/lib/active_support/core_ext/numeric.rb +1 -0
  51. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  52. data/lib/active_support/core_ext/object/blank.rb +2 -2
  53. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  54. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  55. data/lib/active_support/core_ext/object/json.rb +29 -24
  56. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  57. data/lib/active_support/core_ext/object/try.rb +20 -20
  58. data/lib/active_support/core_ext/object/with_options.rb +20 -1
  59. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  60. data/lib/active_support/core_ext/pathname.rb +3 -0
  61. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  62. data/lib/active_support/core_ext/range/conversions.rb +8 -8
  63. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  64. data/lib/active_support/core_ext/range/each.rb +1 -1
  65. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
  66. data/lib/active_support/core_ext/range.rb +1 -1
  67. data/lib/active_support/core_ext/string/filters.rb +1 -1
  68. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  69. data/lib/active_support/core_ext/string/output_safety.rb +60 -36
  70. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  71. data/lib/active_support/core_ext/time/calculations.rb +7 -5
  72. data/lib/active_support/core_ext/time/conversions.rb +13 -12
  73. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  74. data/lib/active_support/core_ext/time/zones.rb +4 -19
  75. data/lib/active_support/core_ext/time.rb +1 -0
  76. data/lib/active_support/core_ext/uri.rb +3 -27
  77. data/lib/active_support/core_ext.rb +1 -0
  78. data/lib/active_support/current_attributes.rb +32 -14
  79. data/lib/active_support/dependencies/interlock.rb +10 -18
  80. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  81. data/lib/active_support/dependencies.rb +58 -788
  82. data/lib/active_support/deprecation/behaviors.rb +4 -1
  83. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  84. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  85. data/lib/active_support/deprecation.rb +1 -1
  86. data/lib/active_support/descendants_tracker.rb +174 -68
  87. data/lib/active_support/digest.rb +5 -3
  88. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  89. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  90. data/lib/active_support/duration.rb +81 -51
  91. data/lib/active_support/encrypted_configuration.rb +13 -2
  92. data/lib/active_support/encrypted_file.rb +1 -1
  93. data/lib/active_support/environment_inquirer.rb +1 -1
  94. data/lib/active_support/error_reporter.rb +117 -0
  95. data/lib/active_support/evented_file_update_checker.rb +1 -1
  96. data/lib/active_support/execution_context/test_helper.rb +13 -0
  97. data/lib/active_support/execution_context.rb +53 -0
  98. data/lib/active_support/execution_wrapper.rb +43 -21
  99. data/lib/active_support/executor/test_helper.rb +7 -0
  100. data/lib/active_support/fork_tracker.rb +19 -10
  101. data/lib/active_support/gem_version.rb +4 -4
  102. data/lib/active_support/hash_with_indifferent_access.rb +9 -2
  103. data/lib/active_support/html_safe_translation.rb +43 -0
  104. data/lib/active_support/i18n.rb +1 -0
  105. data/lib/active_support/i18n_railtie.rb +1 -1
  106. data/lib/active_support/inflector/inflections.rb +23 -7
  107. data/lib/active_support/inflector/methods.rb +24 -48
  108. data/lib/active_support/isolated_execution_state.rb +64 -0
  109. data/lib/active_support/json/encoding.rb +3 -3
  110. data/lib/active_support/key_generator.rb +18 -1
  111. data/lib/active_support/locale/en.yml +2 -2
  112. data/lib/active_support/log_subscriber.rb +13 -3
  113. data/lib/active_support/logger_thread_safe_level.rb +4 -13
  114. data/lib/active_support/message_encryptor.rb +8 -3
  115. data/lib/active_support/message_verifier.rb +46 -14
  116. data/lib/active_support/messages/metadata.rb +2 -2
  117. data/lib/active_support/multibyte/chars.rb +10 -11
  118. data/lib/active_support/multibyte/unicode.rb +0 -12
  119. data/lib/active_support/multibyte.rb +1 -1
  120. data/lib/active_support/notifications/fanout.rb +91 -65
  121. data/lib/active_support/notifications/instrumenter.rb +32 -15
  122. data/lib/active_support/notifications.rb +16 -22
  123. data/lib/active_support/number_helper/number_converter.rb +1 -3
  124. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  125. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  126. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  127. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  128. data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
  129. data/lib/active_support/number_helper/rounding_helper.rb +2 -6
  130. data/lib/active_support/number_helper.rb +0 -2
  131. data/lib/active_support/option_merger.rb +8 -16
  132. data/lib/active_support/ordered_hash.rb +1 -1
  133. data/lib/active_support/parameter_filter.rb +6 -1
  134. data/lib/active_support/per_thread_registry.rb +5 -0
  135. data/lib/active_support/railtie.rb +69 -19
  136. data/lib/active_support/reloader.rb +1 -1
  137. data/lib/active_support/rescuable.rb +2 -2
  138. data/lib/active_support/ruby_features.rb +7 -0
  139. data/lib/active_support/secure_compare_rotator.rb +1 -1
  140. data/lib/active_support/security_utils.rb +1 -1
  141. data/lib/active_support/string_inquirer.rb +0 -2
  142. data/lib/active_support/subscriber.rb +7 -18
  143. data/lib/active_support/tagged_logging.rb +2 -2
  144. data/lib/active_support/test_case.rb +9 -21
  145. data/lib/active_support/testing/assertions.rb +35 -5
  146. data/lib/active_support/testing/deprecation.rb +52 -1
  147. data/lib/active_support/testing/isolation.rb +2 -2
  148. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  149. data/lib/active_support/testing/parallelization/server.rb +4 -0
  150. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  151. data/lib/active_support/testing/parallelization.rb +4 -0
  152. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  153. data/lib/active_support/testing/stream.rb +3 -5
  154. data/lib/active_support/testing/tagged_logging.rb +1 -1
  155. data/lib/active_support/testing/time_helpers.rb +13 -2
  156. data/lib/active_support/time_with_zone.rb +55 -14
  157. data/lib/active_support/values/time_zone.rb +31 -10
  158. data/lib/active_support/xml_mini/jdom.rb +1 -1
  159. data/lib/active_support/xml_mini/libxml.rb +5 -5
  160. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  161. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  162. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  163. data/lib/active_support/xml_mini/rexml.rb +1 -1
  164. data/lib/active_support/xml_mini.rb +5 -4
  165. data/lib/active_support.rb +17 -1
  166. metadata +26 -23
  167. data/lib/active_support/core_ext/marshal.rb +0 -26
  168. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -11,14 +11,14 @@ module Kernel
11
11
  # end
12
12
  #
13
13
  # noisy_call # warning voiced
14
- def silence_warnings
15
- with_warnings(nil) { yield }
14
+ def silence_warnings(&block)
15
+ with_warnings(nil, &block)
16
16
  end
17
17
 
18
18
  # Sets $VERBOSE to +true+ for the duration of the block and back to its
19
19
  # original value afterwards.
20
- def enable_warnings
21
- with_warnings(true) { yield }
20
+ def enable_warnings(&block)
21
+ with_warnings(true, &block)
22
22
  end
23
23
 
24
24
  # Sets $VERBOSE for the duration of the block and back to its original
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # == Attribute Accessors
4
+ #
3
5
  # Extends the module object with class/module and instance accessors for
4
6
  # class/module attributes, just like the native attr* accessors for instance
5
7
  # attributes.
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # == Attribute Accessors per Thread
4
+ #
3
5
  # Extends the module object with class/module and instance accessors for
4
6
  # class/module attributes, just like the native attr* accessors for instance
5
7
  # attributes, but does so on a per-thread basis.
6
8
  #
7
9
  # So the values are scoped within the Thread.current space under the class name
8
10
  # of the module.
11
+ #
12
+ # Note that it can also be scoped per-fiber if Rails.application.config.active_support.isolation_level
13
+ # is set to `:fiber`
9
14
  class Module
10
15
  # Defines a per-thread class attribute and creates class and instance reader methods.
11
16
  # The underlying per-thread class variable is set to +nil+, if it is not previously defined.
@@ -14,9 +19,9 @@ class Module
14
19
  # thread_mattr_reader :user
15
20
  # end
16
21
  #
17
- # Current.user # => nil
18
- # Thread.current[:attr_Current_user] = "DHH"
22
+ # Current.user = "DHH"
19
23
  # Current.user # => "DHH"
24
+ # Thread.new { Current.user }.values # => nil
20
25
  #
21
26
  # The attribute name must be a valid method name in Ruby.
22
27
  #
@@ -41,7 +46,8 @@ class Module
41
46
  # to work with inheritance via polymorphism.
42
47
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
43
48
  def self.#{sym}
44
- Thread.current["attr_" + name + "_#{sym}"]
49
+ @__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
50
+ ::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}]
45
51
  end
46
52
  EOS
47
53
 
@@ -53,7 +59,7 @@ class Module
53
59
  EOS
54
60
  end
55
61
 
56
- Thread.current["attr_" + name + "_#{sym}"] = default unless default.nil?
62
+ ::ActiveSupport::IsolatedExecutionState["attr_#{name}_#{sym}"] = default unless default.nil?
57
63
  end
58
64
  end
59
65
  alias :thread_cattr_reader :thread_mattr_reader
@@ -84,7 +90,8 @@ class Module
84
90
  # to work with inheritance via polymorphism.
85
91
  class_eval(<<-EOS, __FILE__, __LINE__ + 1)
86
92
  def self.#{sym}=(obj)
87
- Thread.current["attr_" + name + "_#{sym}"] = obj
93
+ @__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
94
+ ::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}] = obj
88
95
  end
89
96
  EOS
90
97
 
@@ -111,16 +118,18 @@ class Module
111
118
  # Account.user # => "DHH"
112
119
  # Account.new.user # => "DHH"
113
120
  #
121
+ # Unlike `mattr_accessor`, values are *not* shared with subclasses or parent classes.
114
122
  # If a subclass changes the value, the parent class' value is not changed.
115
- # Similarly, if the parent class changes the value, the value of subclasses
116
- # is not changed.
123
+ # If the parent class changes the value, the value of subclasses is not changed.
117
124
  #
118
125
  # class Customer < Account
119
126
  # end
120
127
  #
121
- # Customer.user = "Rafael"
122
- # Customer.user # => "Rafael"
123
- # Account.user # => "DHH"
128
+ # Account.user # => "DHH"
129
+ # Customer.user # => nil
130
+ # Customer.user = "Rafael"
131
+ # Customer.user # => "Rafael"
132
+ # Account.user # => "DHH"
124
133
  #
125
134
  # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
126
135
  # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
@@ -199,13 +199,7 @@ class Module
199
199
 
200
200
  # Attribute writer methods only accept one argument. Makes sure []=
201
201
  # methods still accept two arguments.
202
- definition = if /[^\]]=$/.match?(method)
203
- "arg"
204
- elsif RUBY_VERSION >= "2.7"
205
- "..."
206
- else
207
- "*args, &block"
208
- end
202
+ definition = /[^\]]=\z/.match?(method) ? "arg" : "..."
209
203
 
210
204
  # The following generated method calls the target exactly once, storing
211
205
  # the returned value in a dummy variable.
@@ -324,7 +318,7 @@ class Module
324
318
  end
325
319
  end
326
320
  end
327
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
321
+ ruby2_keywords(:method_missing)
328
322
  RUBY
329
323
  end
330
324
  end
@@ -53,13 +53,7 @@ class NameError
53
53
  UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
54
54
  private_constant :UNBOUND_METHOD_MODULE_NAME
55
55
 
56
- if UnboundMethod.method_defined?(:bind_call)
57
- def real_mod_name(mod)
58
- UNBOUND_METHOD_MODULE_NAME.bind_call(mod)
59
- end
60
- else
61
- def real_mod_name(mod)
62
- UNBOUND_METHOD_MODULE_NAME.bind(mod).call
63
- end
56
+ def real_mod_name(mod)
57
+ UNBOUND_METHOD_MODULE_NAME.bind_call(mod)
64
58
  end
65
59
  end
@@ -9,6 +9,8 @@ module ActiveSupport
9
9
  # Options are provided for phone numbers, currency, percentage,
10
10
  # precision, positional notation, file size and pretty printing.
11
11
  #
12
+ # This method is aliased to <tt>to_formatted_s</tt>.
13
+ #
12
14
  # ==== Options
13
15
  #
14
16
  # For details on which formats use which options, see ActiveSupport::NumberHelper
@@ -16,102 +18,102 @@ module ActiveSupport
16
18
  # ==== Examples
17
19
  #
18
20
  # Phone Numbers:
19
- # 5551234.to_s(:phone) # => "555-1234"
20
- # 1235551234.to_s(:phone) # => "123-555-1234"
21
- # 1235551234.to_s(:phone, area_code: true) # => "(123) 555-1234"
22
- # 1235551234.to_s(:phone, delimiter: ' ') # => "123 555 1234"
23
- # 1235551234.to_s(:phone, area_code: true, extension: 555) # => "(123) 555-1234 x 555"
24
- # 1235551234.to_s(:phone, country_code: 1) # => "+1-123-555-1234"
25
- # 1235551234.to_s(:phone, country_code: 1, extension: 1343, delimiter: '.')
21
+ # 5551234.to_fs(:phone) # => "555-1234"
22
+ # 1235551234.to_fs(:phone) # => "123-555-1234"
23
+ # 1235551234.to_fs(:phone, area_code: true) # => "(123) 555-1234"
24
+ # 1235551234.to_fs(:phone, delimiter: ' ') # => "123 555 1234"
25
+ # 1235551234.to_fs(:phone, area_code: true, extension: 555) # => "(123) 555-1234 x 555"
26
+ # 1235551234.to_fs(:phone, country_code: 1) # => "+1-123-555-1234"
27
+ # 1235551234.to_fs(:phone, country_code: 1, extension: 1343, delimiter: '.')
26
28
  # # => "+1.123.555.1234 x 1343"
27
29
  #
28
30
  # Currency:
29
- # 1234567890.50.to_s(:currency) # => "$1,234,567,890.50"
30
- # 1234567890.506.to_s(:currency) # => "$1,234,567,890.51"
31
- # 1234567890.506.to_s(:currency, precision: 3) # => "$1,234,567,890.506"
32
- # 1234567890.506.to_s(:currency, round_mode: :down) # => "$1,234,567,890.50"
33
- # 1234567890.506.to_s(:currency, locale: :fr) # => "1 234 567 890,51 €"
34
- # -1234567890.50.to_s(:currency, negative_format: '(%u%n)')
31
+ # 1234567890.50.to_fs(:currency) # => "$1,234,567,890.50"
32
+ # 1234567890.506.to_fs(:currency) # => "$1,234,567,890.51"
33
+ # 1234567890.506.to_fs(:currency, precision: 3) # => "$1,234,567,890.506"
34
+ # 1234567890.506.to_fs(:currency, round_mode: :down) # => "$1,234,567,890.50"
35
+ # 1234567890.506.to_fs(:currency, locale: :fr) # => "1 234 567 890,51 €"
36
+ # -1234567890.50.to_fs(:currency, negative_format: '(%u%n)')
35
37
  # # => "($1,234,567,890.50)"
36
- # 1234567890.50.to_s(:currency, unit: '&pound;', separator: ',', delimiter: '')
38
+ # 1234567890.50.to_fs(:currency, unit: '&pound;', separator: ',', delimiter: '')
37
39
  # # => "&pound;1234567890,50"
38
- # 1234567890.50.to_s(:currency, unit: '&pound;', separator: ',', delimiter: '', format: '%n %u')
40
+ # 1234567890.50.to_fs(:currency, unit: '&pound;', separator: ',', delimiter: '', format: '%n %u')
39
41
  # # => "1234567890,50 &pound;"
40
42
  #
41
43
  # Percentage:
42
- # 100.to_s(:percentage) # => "100.000%"
43
- # 100.to_s(:percentage, precision: 0) # => "100%"
44
- # 1000.to_s(:percentage, delimiter: '.', separator: ',') # => "1.000,000%"
45
- # 302.24398923423.to_s(:percentage, precision: 5) # => "302.24399%"
46
- # 302.24398923423.to_s(:percentage, round_mode: :down) # => "302.243%"
47
- # 1000.to_s(:percentage, locale: :fr) # => "1 000,000%"
48
- # 100.to_s(:percentage, format: '%n %') # => "100.000 %"
44
+ # 100.to_fs(:percentage) # => "100.000%"
45
+ # 100.to_fs(:percentage, precision: 0) # => "100%"
46
+ # 1000.to_fs(:percentage, delimiter: '.', separator: ',') # => "1.000,000%"
47
+ # 302.24398923423.to_fs(:percentage, precision: 5) # => "302.24399%"
48
+ # 302.24398923423.to_fs(:percentage, round_mode: :down) # => "302.243%"
49
+ # 1000.to_fs(:percentage, locale: :fr) # => "1 000,000%"
50
+ # 100.to_fs(:percentage, format: '%n %') # => "100.000 %"
49
51
  #
50
52
  # Delimited:
51
- # 12345678.to_s(:delimited) # => "12,345,678"
52
- # 12345678.05.to_s(:delimited) # => "12,345,678.05"
53
- # 12345678.to_s(:delimited, delimiter: '.') # => "12.345.678"
54
- # 12345678.to_s(:delimited, delimiter: ',') # => "12,345,678"
55
- # 12345678.05.to_s(:delimited, separator: ' ') # => "12,345,678 05"
56
- # 12345678.05.to_s(:delimited, locale: :fr) # => "12 345 678,05"
57
- # 98765432.98.to_s(:delimited, delimiter: ' ', separator: ',')
53
+ # 12345678.to_fs(:delimited) # => "12,345,678"
54
+ # 12345678.05.to_fs(:delimited) # => "12,345,678.05"
55
+ # 12345678.to_fs(:delimited, delimiter: '.') # => "12.345.678"
56
+ # 12345678.to_fs(:delimited, delimiter: ',') # => "12,345,678"
57
+ # 12345678.05.to_fs(:delimited, separator: ' ') # => "12,345,678 05"
58
+ # 12345678.05.to_fs(:delimited, locale: :fr) # => "12 345 678,05"
59
+ # 98765432.98.to_fs(:delimited, delimiter: ' ', separator: ',')
58
60
  # # => "98 765 432,98"
59
61
  #
60
62
  # Rounded:
61
- # 111.2345.to_s(:rounded) # => "111.235"
62
- # 111.2345.to_s(:rounded, precision: 2) # => "111.23"
63
- # 111.2345.to_s(:rounded, precision: 2, round_mode: :up) # => "111.24"
64
- # 13.to_s(:rounded, precision: 5) # => "13.00000"
65
- # 389.32314.to_s(:rounded, precision: 0) # => "389"
66
- # 111.2345.to_s(:rounded, significant: true) # => "111"
67
- # 111.2345.to_s(:rounded, precision: 1, significant: true) # => "100"
68
- # 13.to_s(:rounded, precision: 5, significant: true) # => "13.000"
69
- # 111.234.to_s(:rounded, locale: :fr) # => "111,234"
70
- # 13.to_s(:rounded, precision: 5, significant: true, strip_insignificant_zeros: true)
63
+ # 111.2345.to_fs(:rounded) # => "111.235"
64
+ # 111.2345.to_fs(:rounded, precision: 2) # => "111.23"
65
+ # 111.2345.to_fs(:rounded, precision: 2, round_mode: :up) # => "111.24"
66
+ # 13.to_fs(:rounded, precision: 5) # => "13.00000"
67
+ # 389.32314.to_fs(:rounded, precision: 0) # => "389"
68
+ # 111.2345.to_fs(:rounded, significant: true) # => "111"
69
+ # 111.2345.to_fs(:rounded, precision: 1, significant: true) # => "100"
70
+ # 13.to_fs(:rounded, precision: 5, significant: true) # => "13.000"
71
+ # 111.234.to_fs(:rounded, locale: :fr) # => "111,234"
72
+ # 13.to_fs(:rounded, precision: 5, significant: true, strip_insignificant_zeros: true)
71
73
  # # => "13"
72
- # 389.32314.to_s(:rounded, precision: 4, significant: true) # => "389.3"
73
- # 1111.2345.to_s(:rounded, precision: 2, separator: ',', delimiter: '.')
74
+ # 389.32314.to_fs(:rounded, precision: 4, significant: true) # => "389.3"
75
+ # 1111.2345.to_fs(:rounded, precision: 2, separator: ',', delimiter: '.')
74
76
  # # => "1.111,23"
75
77
  #
76
78
  # Human-friendly size in Bytes:
77
- # 123.to_s(:human_size) # => "123 Bytes"
78
- # 1234.to_s(:human_size) # => "1.21 KB"
79
- # 12345.to_s(:human_size) # => "12.1 KB"
80
- # 1234567.to_s(:human_size) # => "1.18 MB"
81
- # 1234567890.to_s(:human_size) # => "1.15 GB"
82
- # 1234567890123.to_s(:human_size) # => "1.12 TB"
83
- # 1234567890123456.to_s(:human_size) # => "1.1 PB"
84
- # 1234567890123456789.to_s(:human_size) # => "1.07 EB"
85
- # 1234567.to_s(:human_size, precision: 2) # => "1.2 MB"
86
- # 1234567.to_s(:human_size, precision: 2, round_mode: :up) # => "1.3 MB"
87
- # 483989.to_s(:human_size, precision: 2) # => "470 KB"
88
- # 1234567.to_s(:human_size, precision: 2, separator: ',') # => "1,2 MB"
89
- # 1234567890123.to_s(:human_size, precision: 5) # => "1.1228 TB"
90
- # 524288000.to_s(:human_size, precision: 5) # => "500 MB"
79
+ # 123.to_fs(:human_size) # => "123 Bytes"
80
+ # 1234.to_fs(:human_size) # => "1.21 KB"
81
+ # 12345.to_fs(:human_size) # => "12.1 KB"
82
+ # 1234567.to_fs(:human_size) # => "1.18 MB"
83
+ # 1234567890.to_fs(:human_size) # => "1.15 GB"
84
+ # 1234567890123.to_fs(:human_size) # => "1.12 TB"
85
+ # 1234567890123456.to_fs(:human_size) # => "1.1 PB"
86
+ # 1234567890123456789.to_fs(:human_size) # => "1.07 EB"
87
+ # 1234567.to_fs(:human_size, precision: 2) # => "1.2 MB"
88
+ # 1234567.to_fs(:human_size, precision: 2, round_mode: :up) # => "1.3 MB"
89
+ # 483989.to_fs(:human_size, precision: 2) # => "470 KB"
90
+ # 1234567.to_fs(:human_size, precision: 2, separator: ',') # => "1,2 MB"
91
+ # 1234567890123.to_fs(:human_size, precision: 5) # => "1.1228 TB"
92
+ # 524288000.to_fs(:human_size, precision: 5) # => "500 MB"
91
93
  #
92
94
  # Human-friendly format:
93
- # 123.to_s(:human) # => "123"
94
- # 1234.to_s(:human) # => "1.23 Thousand"
95
- # 12345.to_s(:human) # => "12.3 Thousand"
96
- # 1234567.to_s(:human) # => "1.23 Million"
97
- # 1234567890.to_s(:human) # => "1.23 Billion"
98
- # 1234567890123.to_s(:human) # => "1.23 Trillion"
99
- # 1234567890123456.to_s(:human) # => "1.23 Quadrillion"
100
- # 1234567890123456789.to_s(:human) # => "1230 Quadrillion"
101
- # 489939.to_s(:human, precision: 2) # => "490 Thousand"
102
- # 489939.to_s(:human, precision: 2, round_mode: :down) # => "480 Thousand"
103
- # 489939.to_s(:human, precision: 4) # => "489.9 Thousand"
104
- # 1234567.to_s(:human, precision: 4,
105
- # significant: false) # => "1.2346 Million"
106
- # 1234567.to_s(:human, precision: 1,
95
+ # 123.to_fs(:human) # => "123"
96
+ # 1234.to_fs(:human) # => "1.23 Thousand"
97
+ # 12345.to_fs(:human) # => "12.3 Thousand"
98
+ # 1234567.to_fs(:human) # => "1.23 Million"
99
+ # 1234567890.to_fs(:human) # => "1.23 Billion"
100
+ # 1234567890123.to_fs(:human) # => "1.23 Trillion"
101
+ # 1234567890123456.to_fs(:human) # => "1.23 Quadrillion"
102
+ # 1234567890123456789.to_fs(:human) # => "1230 Quadrillion"
103
+ # 489939.to_fs(:human, precision: 2) # => "490 Thousand"
104
+ # 489939.to_fs(:human, precision: 2, round_mode: :down) # => "480 Thousand"
105
+ # 489939.to_fs(:human, precision: 4) # => "489.9 Thousand"
106
+ # 1234567.to_fs(:human, precision: 4,
107
+ # significant: false) # => "1.2346 Million"
108
+ # 1234567.to_fs(:human, precision: 1,
107
109
  # separator: ',',
108
- # significant: false) # => "1,2 Million"
109
- def to_s(format = nil, options = nil)
110
+ # significant: false) # => "1,2 Million"
111
+ def to_fs(format = nil, options = nil)
112
+ return to_s if format.nil?
113
+
110
114
  case format
111
- when nil
112
- super()
113
115
  when Integer, String
114
- super(format)
116
+ to_s(format)
115
117
  when :phone
116
118
  ActiveSupport::NumberHelper.number_to_phone(self, options || {})
117
119
  when :currency
@@ -127,11 +129,12 @@ module ActiveSupport
127
129
  when :human_size
128
130
  ActiveSupport::NumberHelper.number_to_human_size(self, options || {})
129
131
  when Symbol
130
- super()
132
+ to_s
131
133
  else
132
- super(format)
134
+ to_s(format)
133
135
  end
134
136
  end
137
+ alias_method :to_formatted_s, :to_fs
135
138
  end
136
139
  end
137
140
 
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module DeprecatedNumericWithFormat # :nodoc:
5
+ def to_s(format = nil, options = nil)
6
+ return super() if format.nil?
7
+
8
+ case format
9
+ when Integer, String
10
+ super(format)
11
+ when :phone
12
+ ActiveSupport::Deprecation.warn(
13
+ "#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_fs(#{format.inspect}) instead."
14
+ )
15
+ ActiveSupport::NumberHelper.number_to_phone(self, options || {})
16
+ when :currency
17
+ ActiveSupport::Deprecation.warn(
18
+ "#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_fs(#{format.inspect}) instead."
19
+ )
20
+ ActiveSupport::NumberHelper.number_to_currency(self, options || {})
21
+ when :percentage
22
+ ActiveSupport::Deprecation.warn(
23
+ "#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_fs(#{format.inspect}) instead."
24
+ )
25
+ ActiveSupport::NumberHelper.number_to_percentage(self, options || {})
26
+ when :delimited
27
+ ActiveSupport::Deprecation.warn(
28
+ "#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_fs(#{format.inspect}) instead."
29
+ )
30
+ ActiveSupport::NumberHelper.number_to_delimited(self, options || {})
31
+ when :rounded
32
+ ActiveSupport::Deprecation.warn(
33
+ "#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_fs(#{format.inspect}) instead."
34
+ )
35
+ ActiveSupport::NumberHelper.number_to_rounded(self, options || {})
36
+ when :human
37
+ ActiveSupport::Deprecation.warn(
38
+ "#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_fs(#{format.inspect}) instead."
39
+ )
40
+ ActiveSupport::NumberHelper.number_to_human(self, options || {})
41
+ when :human_size
42
+ ActiveSupport::Deprecation.warn(
43
+ "#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_fs(#{format.inspect}) instead."
44
+ )
45
+ ActiveSupport::NumberHelper.number_to_human_size(self, options || {})
46
+ when Symbol
47
+ ActiveSupport::Deprecation.warn(
48
+ "#{self.class}#to_s(#{format.inspect}) is deprecated. Please use #{self.class}#to_fs(#{format.inspect}) instead."
49
+ )
50
+ super()
51
+ else
52
+ super(format)
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ Integer.prepend ActiveSupport::DeprecatedNumericWithFormat
59
+ Float.prepend ActiveSupport::DeprecatedNumericWithFormat
60
+ BigDecimal.prepend ActiveSupport::DeprecatedNumericWithFormat
@@ -3,3 +3,4 @@
3
3
  require "active_support/core_ext/numeric/bytes"
4
4
  require "active_support/core_ext/numeric/time"
5
5
  require "active_support/core_ext/numeric/conversions"
6
+ require "active_support/core_ext/numeric/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
@@ -1,11 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Object
4
- # A duck-type assistant method. For example, Active Support extends Date
5
- # to define an <tt>acts_like_date?</tt> method, and extends Time to define
6
- # <tt>acts_like_time?</tt>. As a result, we can do <tt>x.acts_like?(:time)</tt> and
7
- # <tt>x.acts_like?(:date)</tt> to do duck-type-safe comparisons, since classes that
8
- # we want to act like Time simply need to define an <tt>acts_like_time?</tt> method.
4
+ # Provides a way to check whether some class acts like some other class based on the existence of
5
+ # an appropriately-named marker method.
6
+ #
7
+ # A class that provides the same interface as <tt>SomeClass</tt> may define a marker method named
8
+ # <tt>acts_like_some_class?</tt> to signal its compatibility to callers of
9
+ # <tt>acts_like?(:some_class)</tt>.
10
+ #
11
+ # For example, Active Support extends <tt>Date</tt> to define an <tt>acts_like_date?</tt> method,
12
+ # and extends <tt>Time</tt> to define <tt>acts_like_time?</tt>. As a result, developers can call
13
+ # <tt>x.acts_like?(:time)</tt> and <tt>x.acts_like?(:date)</tt> to test duck-type compatibility,
14
+ # and classes that are able to act like <tt>Time</tt> can also define an <tt>acts_like_time?</tt>
15
+ # method to interoperate.
16
+ #
17
+ # Note that the marker method is only expected to exist. It isn't called, so its body or return
18
+ # value are irrelevant.
19
+ #
20
+ # ==== Example: A class that provides the same interface as <tt>String</tt>
21
+ #
22
+ # This class may define:
23
+ #
24
+ # class Stringish
25
+ # def acts_like_string?
26
+ # end
27
+ # end
28
+ #
29
+ # Then client code can query for duck-type-safeness this way:
30
+ #
31
+ # Stringish.new.acts_like?(:string) # => true
32
+ #
9
33
  def acts_like?(duck)
10
34
  case duck
11
35
  when :time
@@ -131,7 +131,7 @@ class String
131
131
  end
132
132
  end
133
133
 
134
- class Numeric #:nodoc:
134
+ class Numeric # :nodoc:
135
135
  # No number is blank:
136
136
  #
137
137
  # 1.blank? # => false
@@ -143,7 +143,7 @@ class Numeric #:nodoc:
143
143
  end
144
144
  end
145
145
 
146
- class Time #:nodoc:
146
+ class Time # :nodoc:
147
147
  # No Time is blank:
148
148
  #
149
149
  # Time.now.blank? # => false
@@ -43,7 +43,7 @@ class Hash
43
43
  def deep_dup
44
44
  hash = dup
45
45
  each_pair do |key, value|
46
- if (::String === key && key.frozen?) || ::Symbol === key
46
+ if ::String === key || ::Symbol === key
47
47
  hash[key] = value.deep_dup
48
48
  else
49
49
  hash.delete(key)
@@ -47,3 +47,14 @@ class UnboundMethod
47
47
  false
48
48
  end
49
49
  end
50
+
51
+ require "singleton"
52
+
53
+ module Singleton
54
+ # Singleton instances are not duplicable:
55
+ #
56
+ # Class.new.include(Singleton).instance.dup # TypeError (can't dup instance of singleton
57
+ def duplicable?
58
+ false
59
+ end
60
+ end