activesupport 6.0.3.4 → 6.1.7.1

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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +456 -398
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/array_inquirer.rb +4 -2
  6. data/lib/active_support/backtrace_cleaner.rb +3 -3
  7. data/lib/active_support/benchmarkable.rb +1 -1
  8. data/lib/active_support/cache/file_store.rb +5 -4
  9. data/lib/active_support/cache/mem_cache_store.rb +29 -18
  10. data/lib/active_support/cache/memory_store.rb +46 -26
  11. data/lib/active_support/cache/redis_cache_store.rb +27 -27
  12. data/lib/active_support/cache/strategy/local_cache.rb +21 -6
  13. data/lib/active_support/cache.rb +92 -45
  14. data/lib/active_support/callbacks.rb +65 -56
  15. data/lib/active_support/concern.rb +46 -2
  16. data/lib/active_support/configurable.rb +3 -3
  17. data/lib/active_support/configuration_file.rb +51 -0
  18. data/lib/active_support/core_ext/benchmark.rb +2 -2
  19. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  20. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  21. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  22. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  23. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  24. data/lib/active_support/core_ext/digest/uuid.rb +1 -0
  25. data/lib/active_support/core_ext/enumerable.rb +76 -4
  26. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  27. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  28. data/lib/active_support/core_ext/hash/except.rb +1 -1
  29. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  30. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  31. data/lib/active_support/core_ext/load_error.rb +1 -1
  32. data/lib/active_support/core_ext/marshal.rb +2 -0
  33. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  34. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  35. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  36. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  37. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  38. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  39. data/lib/active_support/core_ext/name_error.rb +29 -2
  40. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  41. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  42. data/lib/active_support/core_ext/object/json.rb +13 -2
  43. data/lib/active_support/core_ext/object/try.rb +2 -2
  44. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  45. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  46. data/lib/active_support/core_ext/regexp.rb +8 -1
  47. data/lib/active_support/core_ext/string/access.rb +5 -24
  48. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  49. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  50. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  51. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  52. data/lib/active_support/core_ext/string/output_safety.rb +38 -10
  53. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  54. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  55. data/lib/active_support/core_ext/symbol.rb +3 -0
  56. data/lib/active_support/core_ext/time/calculations.rb +22 -1
  57. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  58. data/lib/active_support/core_ext/uri.rb +5 -1
  59. data/lib/active_support/core_ext.rb +1 -1
  60. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  61. data/lib/active_support/current_attributes.rb +9 -2
  62. data/lib/active_support/dependencies/zeitwerk_integration.rb +4 -1
  63. data/lib/active_support/dependencies.rb +43 -19
  64. data/lib/active_support/deprecation/behaviors.rb +15 -2
  65. data/lib/active_support/deprecation/disallowed.rb +56 -0
  66. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  67. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  68. data/lib/active_support/deprecation/proxy_wrappers.rb +3 -3
  69. data/lib/active_support/deprecation/reporting.rb +50 -7
  70. data/lib/active_support/deprecation.rb +6 -1
  71. data/lib/active_support/descendants_tracker.rb +6 -2
  72. data/lib/active_support/digest.rb +2 -0
  73. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  74. data/lib/active_support/duration.rb +75 -25
  75. data/lib/active_support/encrypted_file.rb +19 -2
  76. data/lib/active_support/environment_inquirer.rb +20 -0
  77. data/lib/active_support/evented_file_update_checker.rb +69 -133
  78. data/lib/active_support/execution_wrapper.rb +16 -13
  79. data/lib/active_support/fork_tracker.rb +64 -0
  80. data/lib/active_support/gem_version.rb +3 -3
  81. data/lib/active_support/hash_with_indifferent_access.rb +48 -24
  82. data/lib/active_support/i18n_railtie.rb +14 -19
  83. data/lib/active_support/inflector/inflections.rb +1 -2
  84. data/lib/active_support/inflector/methods.rb +36 -33
  85. data/lib/active_support/inflector/transliterate.rb +4 -4
  86. data/lib/active_support/json/decoding.rb +4 -4
  87. data/lib/active_support/json/encoding.rb +5 -1
  88. data/lib/active_support/key_generator.rb +1 -1
  89. data/lib/active_support/locale/en.yml +7 -3
  90. data/lib/active_support/log_subscriber.rb +8 -0
  91. data/lib/active_support/logger.rb +1 -1
  92. data/lib/active_support/logger_silence.rb +2 -26
  93. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  94. data/lib/active_support/message_encryptor.rb +4 -7
  95. data/lib/active_support/message_verifier.rb +5 -5
  96. data/lib/active_support/messages/metadata.rb +9 -1
  97. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  98. data/lib/active_support/messages/rotator.rb +6 -5
  99. data/lib/active_support/multibyte/chars.rb +4 -42
  100. data/lib/active_support/multibyte/unicode.rb +9 -83
  101. data/lib/active_support/notifications/fanout.rb +23 -8
  102. data/lib/active_support/notifications/instrumenter.rb +6 -15
  103. data/lib/active_support/notifications.rb +32 -5
  104. data/lib/active_support/number_helper/number_converter.rb +1 -1
  105. data/lib/active_support/number_helper/number_to_currency_converter.rb +3 -7
  106. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  107. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  108. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  109. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  110. data/lib/active_support/number_helper.rb +29 -14
  111. data/lib/active_support/option_merger.rb +3 -2
  112. data/lib/active_support/ordered_options.rb +8 -2
  113. data/lib/active_support/parameter_filter.rb +16 -11
  114. data/lib/active_support/per_thread_registry.rb +2 -1
  115. data/lib/active_support/rails.rb +1 -4
  116. data/lib/active_support/railtie.rb +23 -1
  117. data/lib/active_support/reloader.rb +1 -1
  118. data/lib/active_support/rescuable.rb +4 -4
  119. data/lib/active_support/secure_compare_rotator.rb +51 -0
  120. data/lib/active_support/security_utils.rb +19 -12
  121. data/lib/active_support/string_inquirer.rb +4 -2
  122. data/lib/active_support/subscriber.rb +12 -7
  123. data/lib/active_support/tagged_logging.rb +30 -5
  124. data/lib/active_support/testing/assertions.rb +18 -11
  125. data/lib/active_support/testing/parallelization/server.rb +78 -0
  126. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  127. data/lib/active_support/testing/parallelization.rb +12 -95
  128. data/lib/active_support/testing/time_helpers.rb +40 -3
  129. data/lib/active_support/time_with_zone.rb +67 -43
  130. data/lib/active_support/values/time_zone.rb +22 -10
  131. data/lib/active_support/xml_mini/rexml.rb +8 -1
  132. data/lib/active_support.rb +13 -1
  133. metadata +35 -36
  134. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  135. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  136. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  137. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  138. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  139. data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -104,10 +104,16 @@ class Module
104
104
  # * grok the behavior of our class in one glance,
105
105
  # * clean up monolithic junk-drawer classes by separating their concerns, and
106
106
  # * stop leaning on protected/private for crude "this is internal stuff" modularity.
107
+ #
108
+ # === Prepending concerning
109
+ #
110
+ # <tt>concerning</tt> supports a <tt>prepend: true</tt> argument which will <tt>prepend</tt> the
111
+ # concern instead of using <tt>include</tt> for it.
107
112
  module Concerning
108
113
  # Define a new concern and mix it in.
109
- def concerning(topic, &block)
110
- include concern(topic, &block)
114
+ def concerning(topic, prepend: false, &block)
115
+ method = prepend ? :prepend : :include
116
+ __send__(method, concern(topic, &block))
111
117
  end
112
118
 
113
119
  # A low-cruft shortcut to define a concern.
@@ -170,7 +170,7 @@ class Module
170
170
  # The target method must be public, otherwise it will raise +NoMethodError+.
171
171
  def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
172
172
  unless to
173
- raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)."
173
+ raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
174
174
  end
175
175
 
176
176
  if prefix == true && /^[^a-z_]/.match?(to)
@@ -190,7 +190,13 @@ class Module
190
190
  to = to.to_s
191
191
  to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
192
192
 
193
- method_names = methods.map do |method|
193
+ method_def = []
194
+ method_names = []
195
+
196
+ methods.map do |method|
197
+ method_name = prefix ? "#{method_prefix}#{method}" : method
198
+ method_names << method_name.to_sym
199
+
194
200
  # Attribute writer methods only accept one argument. Makes sure []=
195
201
  # methods still accept two arguments.
196
202
  definition = if /[^\]]=$/.match?(method)
@@ -209,34 +215,33 @@ class Module
209
215
  # whereas conceptually, from the user point of view, the delegator should
210
216
  # be doing one call.
211
217
  if allow_nil
212
- method_def = [
213
- "def #{method_prefix}#{method}(#{definition})",
214
- "_ = #{to}",
215
- "if !_.nil? || nil.respond_to?(:#{method})",
216
- " _.#{method}(#{definition})",
217
- "end",
218
- "end"
219
- ].join ";"
218
+ method = method.to_s
219
+
220
+ method_def <<
221
+ "def #{method_name}(#{definition})" <<
222
+ " _ = #{to}" <<
223
+ " if !_.nil? || nil.respond_to?(:#{method})" <<
224
+ " _.#{method}(#{definition})" <<
225
+ " end" <<
226
+ "end"
220
227
  else
221
- exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
228
+ method = method.to_s
229
+ method_name = method_name.to_s
222
230
 
223
- method_def = [
224
- "def #{method_prefix}#{method}(#{definition})",
225
- " _ = #{to}",
226
- " _.#{method}(#{definition})",
227
- "rescue NoMethodError => e",
228
- " if _.nil? && e.name == :#{method}",
229
- " #{exception}",
230
- " else",
231
- " raise",
232
- " end",
231
+ method_def <<
232
+ "def #{method_name}(#{definition})" <<
233
+ " _ = #{to}" <<
234
+ " _.#{method}(#{definition})" <<
235
+ "rescue NoMethodError => e" <<
236
+ " if _.nil? && e.name == :#{method}" <<
237
+ %( raise DelegationError, "#{self}##{method_name} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") <<
238
+ " else" <<
239
+ " raise" <<
240
+ " end" <<
233
241
  "end"
234
- ].join ";"
235
242
  end
236
-
237
- module_eval(method_def, file, line)
238
243
  end
239
-
244
+ module_eval(method_def.join(";"), file, line)
240
245
  private(*method_names) if private
241
246
  method_names
242
247
  end
@@ -280,13 +285,14 @@ class Module
280
285
  # variables, methods, constants, etc.
281
286
  #
282
287
  # The delegated method must be public on the target, otherwise it will
283
- # raise +NoMethodError+.
288
+ # raise +DelegationError+. If you wish to instead return +nil+,
289
+ # use the <tt>:allow_nil</tt> option.
284
290
  #
285
291
  # The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
286
292
  # delegation due to possible interference when calling
287
293
  # <tt>Marshal.dump(object)</tt>, should the delegation target method
288
294
  # of <tt>object</tt> add or remove instance variables.
289
- def delegate_missing_to(target)
295
+ def delegate_missing_to(target, allow_nil: nil)
290
296
  target = target.to_s
291
297
  target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
292
298
 
@@ -307,7 +313,11 @@ class Module
307
313
  super
308
314
  rescue NoMethodError
309
315
  if #{target}.nil?
310
- raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
316
+ if #{allow_nil == true}
317
+ nil
318
+ else
319
+ raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
320
+ end
311
321
  else
312
322
  raise
313
323
  end
@@ -11,20 +11,12 @@ class Module
11
11
  if defined?(@parent_name)
12
12
  @parent_name
13
13
  else
14
- parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
14
+ parent_name = name =~ /::[^:]+\z/ ? -$` : nil
15
15
  @parent_name = parent_name unless frozen?
16
16
  parent_name
17
17
  end
18
18
  end
19
19
 
20
- def parent_name
21
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
22
- `Module#parent_name` has been renamed to `module_parent_name`.
23
- `parent_name` is deprecated and will be removed in Rails 6.1.
24
- MSG
25
- module_parent_name
26
- end
27
-
28
20
  # Returns the module which contains this one according to its name.
29
21
  #
30
22
  # module M
@@ -44,14 +36,6 @@ class Module
44
36
  module_parent_name ? ActiveSupport::Inflector.constantize(module_parent_name) : Object
45
37
  end
46
38
 
47
- def parent
48
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
49
- `Module#parent` has been renamed to `module_parent`.
50
- `parent` is deprecated and will be removed in Rails 6.1.
51
- MSG
52
- module_parent
53
- end
54
-
55
39
  # Returns all the parents of this module according to its name, ordered from
56
40
  # nested outwards. The receiver is not contained within the result.
57
41
  #
@@ -76,12 +60,4 @@ class Module
76
60
  parents << Object unless parents.include? Object
77
61
  parents
78
62
  end
79
-
80
- def parents
81
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
82
- `Module#parents` has been renamed to `module_parents`.
83
- `parents` is deprecated and will be removed in Rails 6.1.
84
- MSG
85
- module_parents
86
- end
87
63
  end
@@ -14,9 +14,22 @@ class NameError
14
14
  # It extends NameError#message with spell corrections which are SLOW.
15
15
  # We should use original_message message instead.
16
16
  message = respond_to?(:original_message) ? original_message : self.message
17
+ return unless message.start_with?("uninitialized constant ")
17
18
 
18
- if /undefined local variable or method/ !~ message
19
- $1 if /((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/ =~ message
19
+ receiver = begin
20
+ self.receiver
21
+ rescue ArgumentError
22
+ nil
23
+ end
24
+
25
+ if receiver == Object
26
+ name.to_s
27
+ elsif receiver
28
+ "#{real_mod_name(receiver)}::#{self.name}"
29
+ else
30
+ if match = message.match(/((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/)
31
+ match[1]
32
+ end
20
33
  end
21
34
  end
22
35
 
@@ -35,4 +48,18 @@ class NameError
35
48
  missing_name == name.to_s
36
49
  end
37
50
  end
51
+
52
+ private
53
+ UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
54
+ private_constant :UNBOUND_METHOD_MODULE_NAME
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
64
+ end
38
65
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "active_support/core_ext/big_decimal/conversions"
4
4
  require "active_support/number_helper"
5
- require "active_support/core_ext/module/deprecation"
6
5
 
7
6
  module ActiveSupport
8
7
  module NumericWithFormat
@@ -27,10 +26,11 @@ module ActiveSupport
27
26
  # # => "+1.123.555.1234 x 1343"
28
27
  #
29
28
  # Currency:
30
- # 1234567890.50.to_s(:currency) # => "$1,234,567,890.50"
31
- # 1234567890.506.to_s(:currency) # => "$1,234,567,890.51"
32
- # 1234567890.506.to_s(:currency, precision: 3) # => "$1,234,567,890.506"
33
- # 1234567890.506.to_s(:currency, locale: :fr) # => "1 234 567 890,51 €"
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
34
  # -1234567890.50.to_s(:currency, negative_format: '(%u%n)')
35
35
  # # => "($1,234,567,890.50)"
36
36
  # 1234567890.50.to_s(:currency, unit: '&pound;', separator: ',', delimiter: '')
@@ -43,6 +43,7 @@ module ActiveSupport
43
43
  # 100.to_s(:percentage, precision: 0) # => "100%"
44
44
  # 1000.to_s(:percentage, delimiter: '.', separator: ',') # => "1.000,000%"
45
45
  # 302.24398923423.to_s(:percentage, precision: 5) # => "302.24399%"
46
+ # 302.24398923423.to_s(:percentage, round_mode: :down) # => "302.243%"
46
47
  # 1000.to_s(:percentage, locale: :fr) # => "1 000,000%"
47
48
  # 100.to_s(:percentage, format: '%n %') # => "100.000 %"
48
49
  #
@@ -59,6 +60,7 @@ module ActiveSupport
59
60
  # Rounded:
60
61
  # 111.2345.to_s(:rounded) # => "111.235"
61
62
  # 111.2345.to_s(:rounded, precision: 2) # => "111.23"
63
+ # 111.2345.to_s(:rounded, precision: 2, round_mode: :up) # => "111.24"
62
64
  # 13.to_s(:rounded, precision: 5) # => "13.00000"
63
65
  # 389.32314.to_s(:rounded, precision: 0) # => "389"
64
66
  # 111.2345.to_s(:rounded, significant: true) # => "111"
@@ -72,19 +74,20 @@ module ActiveSupport
72
74
  # # => "1.111,23"
73
75
  #
74
76
  # Human-friendly size in Bytes:
75
- # 123.to_s(:human_size) # => "123 Bytes"
76
- # 1234.to_s(:human_size) # => "1.21 KB"
77
- # 12345.to_s(:human_size) # => "12.1 KB"
78
- # 1234567.to_s(:human_size) # => "1.18 MB"
79
- # 1234567890.to_s(:human_size) # => "1.15 GB"
80
- # 1234567890123.to_s(:human_size) # => "1.12 TB"
81
- # 1234567890123456.to_s(:human_size) # => "1.1 PB"
82
- # 1234567890123456789.to_s(:human_size) # => "1.07 EB"
83
- # 1234567.to_s(:human_size, precision: 2) # => "1.2 MB"
84
- # 483989.to_s(:human_size, precision: 2) # => "470 KB"
85
- # 1234567.to_s(:human_size, precision: 2, separator: ',') # => "1,2 MB"
86
- # 1234567890123.to_s(:human_size, precision: 5) # => "1.1228 TB"
87
- # 524288000.to_s(:human_size, precision: 5) # => "500 MB"
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"
88
91
  #
89
92
  # Human-friendly format:
90
93
  # 123.to_s(:human) # => "123"
@@ -96,6 +99,7 @@ module ActiveSupport
96
99
  # 1234567890123456.to_s(:human) # => "1.23 Quadrillion"
97
100
  # 1234567890123456789.to_s(:human) # => "1230 Quadrillion"
98
101
  # 489939.to_s(:human, precision: 2) # => "490 Thousand"
102
+ # 489939.to_s(:human, precision: 2, round_mode: :down) # => "480 Thousand"
99
103
  # 489939.to_s(:human, precision: 4) # => "489.9 Thousand"
100
104
  # 1234567.to_s(:human, precision: 4,
101
105
  # significant: false) # => "1.2346 Million"
@@ -43,7 +43,7 @@ class Hash
43
43
  def deep_dup
44
44
  hash = dup
45
45
  each_pair do |key, value|
46
- if key.frozen? && ::String === key
46
+ if (::String === key && key.frozen?) || ::Symbol === key
47
47
  hash[key] = value.deep_dup
48
48
  else
49
49
  hash.delete(key)
@@ -3,6 +3,7 @@
3
3
  # Hack to load json gem first so we can overwrite its to_json.
4
4
  require "json"
5
5
  require "bigdecimal"
6
+ require "ipaddr"
6
7
  require "uri/generic"
7
8
  require "pathname"
8
9
  require "active_support/core_ext/big_decimal/conversions" # for #to_s
@@ -45,7 +46,7 @@ module ActiveSupport
45
46
  end
46
47
  end
47
48
 
48
- [Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass, Enumerable].reverse_each do |klass|
49
+ [Enumerable, Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass].reverse_each do |klass|
49
50
  klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
50
51
  end
51
52
 
@@ -169,7 +170,11 @@ class Hash
169
170
  self
170
171
  end
171
172
 
172
- Hash[subset.map { |k, v| [k.to_s, options ? v.as_json(options.dup) : v.as_json] }]
173
+ result = {}
174
+ subset.each do |k, v|
175
+ result[k.to_s] = options ? v.as_json(options.dup) : v.as_json
176
+ end
177
+ result
173
178
  end
174
179
  end
175
180
 
@@ -215,6 +220,12 @@ class Pathname #:nodoc:
215
220
  end
216
221
  end
217
222
 
223
+ class IPAddr # :nodoc:
224
+ def as_json(options = nil)
225
+ to_s
226
+ end
227
+ end
228
+
218
229
  class Process::Status #:nodoc:
219
230
  def as_json(options = nil)
220
231
  { exitstatus: exitstatus, pid: pid }
@@ -145,14 +145,14 @@ class NilClass
145
145
  #
146
146
  # With +try+
147
147
  # @person.try(:children).try(:first).try(:name)
148
- def try(method_name = nil, *args)
148
+ def try(_method_name = nil, *)
149
149
  nil
150
150
  end
151
151
 
152
152
  # Calling +try!+ on +nil+ always returns +nil+.
153
153
  #
154
154
  # nil.try!(:name) # => nil
155
- def try!(method_name = nil, *args)
155
+ def try!(_method_name = nil, *)
156
156
  nil
157
157
  end
158
158
  end
@@ -15,11 +15,13 @@ module ActiveSupport
15
15
  # The given range must be fully bounded, with both start and end.
16
16
  def ===(value)
17
17
  if value.is_a?(::Range)
18
+ is_backwards_op = value.exclude_end? ? :>= : :>
19
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
18
20
  # 1...10 includes 1..9 but it does not include 1..10.
19
21
  # 1..10 includes 1...11 but it does not include 1...12.
20
22
  operator = exclude_end? && !value.exclude_end? ? :< : :<=
21
23
  value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
22
- super(value.first) && (self.end.nil? || value_max.send(operator, last))
24
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
23
25
  else
24
26
  super
25
27
  end
@@ -38,11 +40,13 @@ module ActiveSupport
38
40
  # The given range must be fully bounded, with both start and end.
39
41
  def include?(value)
40
42
  if value.is_a?(::Range)
43
+ is_backwards_op = value.exclude_end? ? :>= : :>
44
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
41
45
  # 1...10 includes 1..9 but it does not include 1..10.
42
46
  # 1..10 includes 1...11 but it does not include 1...12.
43
47
  operator = exclude_end? && !value.exclude_end? ? :< : :<=
44
48
  value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
45
- super(value.first) && (self.end.nil? || value_max.send(operator, last))
49
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
46
50
  else
47
51
  super
48
52
  end
@@ -61,11 +65,13 @@ module ActiveSupport
61
65
  # The given range must be fully bounded, with both start and end.
62
66
  def cover?(value)
63
67
  if value.is_a?(::Range)
68
+ is_backwards_op = value.exclude_end? ? :>= : :>
69
+ return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
64
70
  # 1...10 covers 1..9 but it does not cover 1..10.
65
71
  # 1..10 covers 1...11 but it does not cover 1...12.
66
72
  operator = exclude_end? && !value.exclude_end? ? :< : :<=
67
73
  value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
68
- super(value.first) && (self.end.nil? || value_max.send(operator, last))
74
+ super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
69
75
  else
70
76
  super
71
77
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/time_with_zone"
4
+ require "active_support/deprecation"
4
5
 
5
6
  module ActiveSupport
6
7
  module IncludeTimeWithZone #:nodoc:
@@ -9,9 +10,13 @@ module ActiveSupport
9
10
  # (1.hour.ago..1.hour.from_now).include?(Time.current) # => true
10
11
  #
11
12
  def include?(value)
12
- if self.begin.is_a?(TimeWithZone)
13
- cover?(value)
14
- elsif self.end.is_a?(TimeWithZone)
13
+ if self.begin.is_a?(TimeWithZone) || self.end.is_a?(TimeWithZone)
14
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
15
+ Using `Range#include?` to check the inclusion of a value in
16
+ a date time range is deprecated.
17
+ It is recommended to use `Range#cover?` instead of `Range#include?` to
18
+ check the inclusion of a value in a date time range.
19
+ MSG
15
20
  cover?(value)
16
21
  else
17
22
  super
@@ -1,6 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Regexp #:nodoc:
3
+ class Regexp
4
+ # Returns +true+ if the regexp has the multiline flag set.
5
+ #
6
+ # (/./).multiline? # => false
7
+ # (/./m).multiline? # => true
8
+ #
9
+ # Regexp.new(".").multiline? # => false
10
+ # Regexp.new(".", Regexp::MULTILINE).multiline? # => true
4
11
  def multiline?
5
12
  options & MULTILINE == MULTILINE
6
13
  end
@@ -44,7 +44,7 @@ class String
44
44
  # str.from(0).to(-1) # => "hello"
45
45
  # str.from(1).to(-2) # => "ell"
46
46
  def from(position)
47
- self[position..-1]
47
+ self[position, length]
48
48
  end
49
49
 
50
50
  # Returns a substring from the beginning of the string to the given position.
@@ -61,7 +61,8 @@ class String
61
61
  # str.from(0).to(-1) # => "hello"
62
62
  # str.from(1).to(-2) # => "ell"
63
63
  def to(position)
64
- self[0..position]
64
+ position += size if position < 0
65
+ self[0, position + 1] || +""
65
66
  end
66
67
 
67
68
  # Returns the first character. If a limit is supplied, returns a substring
@@ -75,17 +76,7 @@ class String
75
76
  # str.first(0) # => ""
76
77
  # str.first(6) # => "hello"
77
78
  def first(limit = 1)
78
- ActiveSupport::Deprecation.warn(
79
- "Calling String#first with a negative integer limit " \
80
- "will raise an ArgumentError in Rails 6.1."
81
- ) if limit < 0
82
- if limit == 0
83
- ""
84
- elsif limit >= size
85
- dup
86
- else
87
- to(limit - 1)
88
- end
79
+ self[0, limit] || raise(ArgumentError, "negative limit")
89
80
  end
90
81
 
91
82
  # Returns the last character of the string. If a limit is supplied, returns a substring
@@ -99,16 +90,6 @@ class String
99
90
  # str.last(0) # => ""
100
91
  # str.last(6) # => "hello"
101
92
  def last(limit = 1)
102
- ActiveSupport::Deprecation.warn(
103
- "Calling String#last with a negative integer limit " \
104
- "will raise an ArgumentError in Rails 6.1."
105
- ) if limit < 0
106
- if limit == 0
107
- ""
108
- elsif limit >= size
109
- dup
110
- else
111
- from(-limit)
112
- end
93
+ self[[length - limit, 0].max, limit] || raise(ArgumentError, "negative limit")
113
94
  end
114
95
  end
@@ -18,6 +18,7 @@ class String
18
18
  # "2012-12-13T06:12".to_time # => 2012-12-13 06:12:00 +0100
19
19
  # "2012-12-13T06:12".to_time(:utc) # => 2012-12-13 06:12:00 UTC
20
20
  # "12/13/2012".to_time # => ArgumentError: argument out of range
21
+ # "1604326192".to_time # => ArgumentError: argument out of range
21
22
  def to_time(form = :local)
22
23
  parts = Date._parse(self, false)
23
24
  used_keys = %i(year mon mday hour min sec sec_fraction offset)