activesupport 6.0.6.1 → 6.1.0.rc1

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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +337 -573
  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 +2 -2
  9. data/lib/active_support/cache/mem_cache_store.rb +20 -14
  10. data/lib/active_support/cache/memory_store.rb +38 -26
  11. data/lib/active_support/cache/redis_cache_store.rb +25 -25
  12. data/lib/active_support/cache/strategy/local_cache.rb +13 -4
  13. data/lib/active_support/cache.rb +75 -34
  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 +46 -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/enumerable.rb +76 -4
  25. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  26. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  27. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  28. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  29. data/lib/active_support/core_ext/load_error.rb +1 -1
  30. data/lib/active_support/core_ext/marshal.rb +2 -0
  31. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  32. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  33. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  34. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  35. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  36. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  37. data/lib/active_support/core_ext/name_error.rb +29 -2
  38. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  39. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  40. data/lib/active_support/core_ext/object/json.rb +5 -1
  41. data/lib/active_support/core_ext/object/try.rb +2 -2
  42. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  43. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  44. data/lib/active_support/core_ext/string/access.rb +5 -24
  45. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  46. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  47. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  48. data/lib/active_support/core_ext/string/output_safety.rb +8 -38
  49. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  50. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  51. data/lib/active_support/core_ext/symbol.rb +3 -0
  52. data/lib/active_support/core_ext/time/calculations.rb +16 -0
  53. data/lib/active_support/core_ext/time/conversions.rb +1 -0
  54. data/lib/active_support/core_ext/uri.rb +5 -1
  55. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  56. data/lib/active_support/current_attributes.rb +7 -2
  57. data/lib/active_support/dependencies.rb +38 -24
  58. data/lib/active_support/deprecation/behaviors.rb +15 -2
  59. data/lib/active_support/deprecation/disallowed.rb +56 -0
  60. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  61. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  62. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  63. data/lib/active_support/deprecation/reporting.rb +50 -7
  64. data/lib/active_support/deprecation.rb +6 -1
  65. data/lib/active_support/descendants_tracker.rb +6 -2
  66. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  67. data/lib/active_support/duration.rb +71 -22
  68. data/lib/active_support/encrypted_file.rb +19 -2
  69. data/lib/active_support/environment_inquirer.rb +20 -0
  70. data/lib/active_support/evented_file_update_checker.rb +69 -133
  71. data/lib/active_support/execution_wrapper.rb +13 -16
  72. data/lib/active_support/fork_tracker.rb +58 -0
  73. data/lib/active_support/gem_version.rb +3 -3
  74. data/lib/active_support/hash_with_indifferent_access.rb +35 -22
  75. data/lib/active_support/i18n_railtie.rb +14 -19
  76. data/lib/active_support/inflector/inflections.rb +1 -2
  77. data/lib/active_support/inflector/methods.rb +35 -31
  78. data/lib/active_support/inflector/transliterate.rb +4 -4
  79. data/lib/active_support/json/decoding.rb +4 -4
  80. data/lib/active_support/json/encoding.rb +5 -1
  81. data/lib/active_support/key_generator.rb +1 -1
  82. data/lib/active_support/locale/en.yml +7 -3
  83. data/lib/active_support/log_subscriber.rb +8 -0
  84. data/lib/active_support/logger.rb +1 -1
  85. data/lib/active_support/logger_silence.rb +2 -26
  86. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  87. data/lib/active_support/message_encryptor.rb +4 -7
  88. data/lib/active_support/message_verifier.rb +5 -5
  89. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  90. data/lib/active_support/messages/rotator.rb +6 -5
  91. data/lib/active_support/multibyte/chars.rb +4 -42
  92. data/lib/active_support/multibyte/unicode.rb +9 -83
  93. data/lib/active_support/notifications/fanout.rb +23 -8
  94. data/lib/active_support/notifications/instrumenter.rb +6 -15
  95. data/lib/active_support/notifications.rb +31 -4
  96. data/lib/active_support/number_helper/number_converter.rb +1 -1
  97. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  98. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  99. data/lib/active_support/number_helper/number_to_rounded_converter.rb +3 -3
  100. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  101. data/lib/active_support/number_helper.rb +29 -14
  102. data/lib/active_support/option_merger.rb +2 -1
  103. data/lib/active_support/ordered_options.rb +8 -2
  104. data/lib/active_support/parameter_filter.rb +15 -10
  105. data/lib/active_support/per_thread_registry.rb +1 -1
  106. data/lib/active_support/rails.rb +1 -4
  107. data/lib/active_support/railtie.rb +23 -1
  108. data/lib/active_support/reloader.rb +1 -1
  109. data/lib/active_support/secure_compare_rotator.rb +51 -0
  110. data/lib/active_support/security_utils.rb +19 -12
  111. data/lib/active_support/string_inquirer.rb +4 -2
  112. data/lib/active_support/subscriber.rb +12 -7
  113. data/lib/active_support/tagged_logging.rb +29 -4
  114. data/lib/active_support/testing/assertions.rb +18 -11
  115. data/lib/active_support/testing/parallelization/server.rb +78 -0
  116. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  117. data/lib/active_support/testing/parallelization.rb +12 -95
  118. data/lib/active_support/testing/time_helpers.rb +40 -3
  119. data/lib/active_support/time_with_zone.rb +66 -42
  120. data/lib/active_support/values/time_zone.rb +20 -10
  121. data/lib/active_support/xml_mini/rexml.rb +8 -1
  122. data/lib/active_support.rb +13 -1
  123. metadata +39 -42
  124. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  125. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  126. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  127. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  128. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  129. data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -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)
@@ -169,7 +169,11 @@ class Hash
169
169
  self
170
170
  end
171
171
 
172
- Hash[subset.map { |k, v| [k.to_s, options ? v.as_json(options.dup) : v.as_json] }]
172
+ result = {}
173
+ subset.each do |k, v|
174
+ result[k.to_s] = options ? v.as_json(options.dup) : v.as_json
175
+ end
176
+ result
173
177
  end
174
178
  end
175
179
 
@@ -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
@@ -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
@@ -30,6 +30,8 @@ class String
30
30
  # 'apple'.pluralize(2) # => "apples"
31
31
  # 'ley'.pluralize(:es) # => "leyes"
32
32
  # 'ley'.pluralize(1, :es) # => "ley"
33
+ #
34
+ # See ActiveSupport::Inflector.pluralize.
33
35
  def pluralize(count = nil, locale = :en)
34
36
  locale = count if count.is_a?(Symbol)
35
37
  if count == 1
@@ -53,28 +55,34 @@ class String
53
55
  # 'the blue mailmen'.singularize # => "the blue mailman"
54
56
  # 'CamelOctopi'.singularize # => "CamelOctopus"
55
57
  # 'leyes'.singularize(:es) # => "ley"
58
+ #
59
+ # See ActiveSupport::Inflector.singularize.
56
60
  def singularize(locale = :en)
57
61
  ActiveSupport::Inflector.singularize(self, locale)
58
62
  end
59
63
 
60
64
  # +constantize+ tries to find a declared constant with the name specified
61
65
  # in the string. It raises a NameError when the name is not in CamelCase
62
- # or is not initialized. See ActiveSupport::Inflector.constantize
66
+ # or is not initialized.
63
67
  #
64
68
  # 'Module'.constantize # => Module
65
69
  # 'Class'.constantize # => Class
66
70
  # 'blargle'.constantize # => NameError: wrong constant name blargle
71
+ #
72
+ # See ActiveSupport::Inflector.constantize.
67
73
  def constantize
68
74
  ActiveSupport::Inflector.constantize(self)
69
75
  end
70
76
 
71
77
  # +safe_constantize+ tries to find a declared constant with the name specified
72
78
  # in the string. It returns +nil+ when the name is not in CamelCase
73
- # or is not initialized. See ActiveSupport::Inflector.safe_constantize
79
+ # or is not initialized.
74
80
  #
75
81
  # 'Module'.safe_constantize # => Module
76
82
  # 'Class'.safe_constantize # => Class
77
83
  # 'blargle'.safe_constantize # => nil
84
+ #
85
+ # See ActiveSupport::Inflector.safe_constantize.
78
86
  def safe_constantize
79
87
  ActiveSupport::Inflector.safe_constantize(self)
80
88
  end
@@ -88,6 +96,10 @@ class String
88
96
  # 'active_record'.camelize(:lower) # => "activeRecord"
89
97
  # 'active_record/errors'.camelize # => "ActiveRecord::Errors"
90
98
  # 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
99
+ #
100
+ # +camelize+ is also aliased as +camelcase+.
101
+ #
102
+ # See ActiveSupport::Inflector.camelize.
91
103
  def camelize(first_letter = :upper)
92
104
  case first_letter
93
105
  when :upper
@@ -108,11 +120,13 @@ class String
108
120
  # optional parameter +keep_id_suffix+ to true.
109
121
  # By default, this parameter is false.
110
122
  #
111
- # +titleize+ is also aliased as +titlecase+.
112
- #
113
123
  # 'man from the boondocks'.titleize # => "Man From The Boondocks"
114
124
  # 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
115
125
  # 'string_ending_with_id'.titleize(keep_id_suffix: true) # => "String Ending With Id"
126
+ #
127
+ # +titleize+ is also aliased as +titlecase+.
128
+ #
129
+ # See ActiveSupport::Inflector.titleize.
116
130
  def titleize(keep_id_suffix: false)
117
131
  ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
118
132
  end
@@ -124,6 +138,8 @@ class String
124
138
  #
125
139
  # 'ActiveModel'.underscore # => "active_model"
126
140
  # 'ActiveModel::Errors'.underscore # => "active_model/errors"
141
+ #
142
+ # See ActiveSupport::Inflector.underscore.
127
143
  def underscore
128
144
  ActiveSupport::Inflector.underscore(self)
129
145
  end
@@ -131,6 +147,8 @@ class String
131
147
  # Replaces underscores with dashes in the string.
132
148
  #
133
149
  # 'puni_puni'.dasherize # => "puni-puni"
150
+ #
151
+ # See ActiveSupport::Inflector.dasherize.
134
152
  def dasherize
135
153
  ActiveSupport::Inflector.dasherize(self)
136
154
  end
@@ -142,6 +160,8 @@ class String
142
160
  # '::Inflections'.demodulize # => "Inflections"
143
161
  # ''.demodulize # => ''
144
162
  #
163
+ # See ActiveSupport::Inflector.demodulize.
164
+ #
145
165
  # See also +deconstantize+.
146
166
  def demodulize
147
167
  ActiveSupport::Inflector.demodulize(self)
@@ -155,6 +175,8 @@ class String
155
175
  # '::String'.deconstantize # => ""
156
176
  # ''.deconstantize # => ""
157
177
  #
178
+ # See ActiveSupport::Inflector.deconstantize.
179
+ #
158
180
  # See also +demodulize+.
159
181
  def deconstantize
160
182
  ActiveSupport::Inflector.deconstantize(self)
@@ -192,6 +214,8 @@ class String
192
214
  #
193
215
  # <%= link_to(@person.name, person_path) %>
194
216
  # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
217
+ #
218
+ # See ActiveSupport::Inflector.parameterize.
195
219
  def parameterize(separator: "-", preserve_case: false, locale: nil)
196
220
  ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case, locale: locale)
197
221
  end
@@ -202,6 +226,8 @@ class String
202
226
  # 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
203
227
  # 'ham_and_egg'.tableize # => "ham_and_eggs"
204
228
  # 'fancyCategory'.tableize # => "fancy_categories"
229
+ #
230
+ # See ActiveSupport::Inflector.tableize.
205
231
  def tableize
206
232
  ActiveSupport::Inflector.tableize(self)
207
233
  end
@@ -212,6 +238,8 @@ class String
212
238
  #
213
239
  # 'ham_and_eggs'.classify # => "HamAndEgg"
214
240
  # 'posts'.classify # => "Post"
241
+ #
242
+ # See ActiveSupport::Inflector.classify.
215
243
  def classify
216
244
  ActiveSupport::Inflector.classify(self)
217
245
  end
@@ -233,6 +261,8 @@ class String
233
261
  # 'author_id'.humanize(capitalize: false) # => "author"
234
262
  # '_id'.humanize # => "Id"
235
263
  # 'author_id'.humanize(keep_id_suffix: true) # => "Author Id"
264
+ #
265
+ # See ActiveSupport::Inflector.humanize.
236
266
  def humanize(capitalize: true, keep_id_suffix: false)
237
267
  ActiveSupport::Inflector.humanize(self, capitalize: capitalize, keep_id_suffix: keep_id_suffix)
238
268
  end
@@ -242,6 +272,8 @@ class String
242
272
  # 'what a Lovely Day'.upcase_first # => "What a Lovely Day"
243
273
  # 'w'.upcase_first # => "W"
244
274
  # ''.upcase_first # => ""
275
+ #
276
+ # See ActiveSupport::Inflector.upcase_first.
245
277
  def upcase_first
246
278
  ActiveSupport::Inflector.upcase_first(self)
247
279
  end
@@ -253,6 +285,8 @@ class String
253
285
  # 'Message'.foreign_key # => "message_id"
254
286
  # 'Message'.foreign_key(false) # => "messageid"
255
287
  # 'Admin::Post'.foreign_key # => "post_id"
288
+ #
289
+ # See ActiveSupport::Inflector.foreign_key.
256
290
  def foreign_key(separate_class_name_and_id_with_underscore = true)
257
291
  ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
258
292
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/string_inquirer"
4
+ require "active_support/environment_inquirer"
4
5
 
5
6
  class String
6
7
  # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class,
@@ -47,9 +47,9 @@ class String
47
47
  # iso_str.is_utf8? # => false
48
48
  def is_utf8?
49
49
  case encoding
50
- when Encoding::UTF_8
50
+ when Encoding::UTF_8, Encoding::US_ASCII
51
51
  valid_encoding?
52
- when Encoding::ASCII_8BIT, Encoding::US_ASCII
52
+ when Encoding::ASCII_8BIT
53
53
  dup.force_encoding(Encoding::UTF_8).valid_encoding?
54
54
  else
55
55
  false