activesupport 5.2.4.4 → 6.0.0

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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +327 -408
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -2
  5. data/lib/active_support.rb +2 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +28 -1
  8. data/lib/active_support/cache.rb +45 -23
  9. data/lib/active_support/cache/file_store.rb +22 -22
  10. data/lib/active_support/cache/mem_cache_store.rb +17 -2
  11. data/lib/active_support/cache/memory_store.rb +7 -2
  12. data/lib/active_support/cache/null_store.rb +5 -0
  13. data/lib/active_support/cache/redis_cache_store.rb +47 -25
  14. data/lib/active_support/callbacks.rb +16 -5
  15. data/lib/active_support/concern.rb +24 -1
  16. data/lib/active_support/configurable.rb +7 -11
  17. data/lib/active_support/core_ext/array.rb +1 -1
  18. data/lib/active_support/core_ext/array/access.rb +18 -6
  19. data/lib/active_support/core_ext/array/extract.rb +21 -0
  20. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  21. data/lib/active_support/core_ext/class/attribute.rb +11 -16
  22. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  23. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  24. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
  25. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  26. data/lib/active_support/core_ext/enumerable.rb +97 -73
  27. data/lib/active_support/core_ext/hash.rb +1 -2
  28. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  29. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  30. data/lib/active_support/core_ext/hash/except.rb +1 -1
  31. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  32. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  33. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  34. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  35. data/lib/active_support/core_ext/kernel.rb +0 -1
  36. data/lib/active_support/core_ext/load_error.rb +1 -1
  37. data/lib/active_support/core_ext/module.rb +0 -1
  38. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
  39. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
  40. data/lib/active_support/core_ext/module/delegation.rb +33 -7
  41. data/lib/active_support/core_ext/module/introspection.rb +37 -13
  42. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  43. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  44. data/lib/active_support/core_ext/numeric.rb +0 -1
  45. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  46. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  47. data/lib/active_support/core_ext/object/blank.rb +1 -2
  48. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  49. data/lib/active_support/core_ext/object/json.rb +1 -0
  50. data/lib/active_support/core_ext/object/try.rb +15 -7
  51. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  52. data/lib/active_support/core_ext/range/compare_range.rb +22 -13
  53. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  54. data/lib/active_support/core_ext/range/include_range.rb +6 -0
  55. data/lib/active_support/core_ext/regexp.rb +0 -4
  56. data/lib/active_support/core_ext/securerandom.rb +23 -3
  57. data/lib/active_support/core_ext/string/access.rb +8 -0
  58. data/lib/active_support/core_ext/string/filters.rb +42 -1
  59. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  60. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  61. data/lib/active_support/core_ext/string/output_safety.rb +61 -5
  62. data/lib/active_support/core_ext/string/strip.rb +3 -1
  63. data/lib/active_support/core_ext/time/calculations.rb +31 -2
  64. data/lib/active_support/core_ext/uri.rb +1 -0
  65. data/lib/active_support/current_attributes.rb +8 -0
  66. data/lib/active_support/dependencies.rb +69 -16
  67. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  68. data/lib/active_support/deprecation.rb +1 -1
  69. data/lib/active_support/deprecation/behaviors.rb +1 -1
  70. data/lib/active_support/deprecation/method_wrappers.rb +8 -20
  71. data/lib/active_support/deprecation/proxy_wrappers.rb +24 -5
  72. data/lib/active_support/descendants_tracker.rb +56 -9
  73. data/lib/active_support/duration.rb +4 -3
  74. data/lib/active_support/duration/iso8601_parser.rb +2 -3
  75. data/lib/active_support/duration/iso8601_serializer.rb +3 -4
  76. data/lib/active_support/encrypted_configuration.rb +0 -4
  77. data/lib/active_support/encrypted_file.rb +2 -1
  78. data/lib/active_support/evented_file_update_checker.rb +39 -9
  79. data/lib/active_support/execution_wrapper.rb +1 -0
  80. data/lib/active_support/gem_version.rb +4 -4
  81. data/lib/active_support/hash_with_indifferent_access.rb +22 -18
  82. data/lib/active_support/i18n.rb +1 -0
  83. data/lib/active_support/i18n_railtie.rb +9 -1
  84. data/lib/active_support/inflector/inflections.rb +1 -4
  85. data/lib/active_support/inflector/methods.rb +15 -27
  86. data/lib/active_support/inflector/transliterate.rb +47 -18
  87. data/lib/active_support/json/decoding.rb +23 -23
  88. data/lib/active_support/json/encoding.rb +6 -2
  89. data/lib/active_support/key_generator.rb +0 -32
  90. data/lib/active_support/lazy_load_hooks.rb +5 -1
  91. data/lib/active_support/locale/en.rb +31 -0
  92. data/lib/active_support/log_subscriber.rb +31 -8
  93. data/lib/active_support/logger.rb +0 -15
  94. data/lib/active_support/logger_silence.rb +28 -12
  95. data/lib/active_support/logger_thread_safe_level.rb +26 -4
  96. data/lib/active_support/message_encryptor.rb +3 -5
  97. data/lib/active_support/message_verifier.rb +3 -3
  98. data/lib/active_support/multibyte/chars.rb +29 -48
  99. data/lib/active_support/multibyte/unicode.rb +44 -281
  100. data/lib/active_support/notifications.rb +41 -4
  101. data/lib/active_support/notifications/fanout.rb +98 -13
  102. data/lib/active_support/notifications/instrumenter.rb +79 -8
  103. data/lib/active_support/number_helper.rb +7 -0
  104. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -2
  105. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -1
  106. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -1
  107. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -1
  108. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  109. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -0
  110. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -3
  111. data/lib/active_support/ordered_options.rb +1 -1
  112. data/lib/active_support/parameter_filter.rb +129 -0
  113. data/lib/active_support/rails.rb +0 -6
  114. data/lib/active_support/reloader.rb +4 -5
  115. data/lib/active_support/security_utils.rb +1 -1
  116. data/lib/active_support/subscriber.rb +65 -26
  117. data/lib/active_support/tagged_logging.rb +13 -4
  118. data/lib/active_support/test_case.rb +91 -0
  119. data/lib/active_support/testing/assertions.rb +15 -1
  120. data/lib/active_support/testing/deprecation.rb +0 -1
  121. data/lib/active_support/testing/file_fixtures.rb +2 -0
  122. data/lib/active_support/testing/isolation.rb +2 -2
  123. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  124. data/lib/active_support/testing/parallelization.rb +128 -0
  125. data/lib/active_support/testing/stream.rb +1 -1
  126. data/lib/active_support/testing/time_helpers.rb +7 -7
  127. data/lib/active_support/time_with_zone.rb +15 -5
  128. data/lib/active_support/values/time_zone.rb +12 -7
  129. data/lib/active_support/xml_mini.rb +2 -9
  130. data/lib/active_support/xml_mini/jdom.rb +2 -2
  131. data/lib/active_support/xml_mini/libxml.rb +2 -2
  132. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  133. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  134. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  135. data/lib/active_support/xml_mini/rexml.rb +2 -2
  136. metadata +34 -9
  137. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  138. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -30,6 +30,11 @@ module ActiveSupport
30
30
  @pruning = false
31
31
  end
32
32
 
33
+ # Advertise cache versioning support.
34
+ def self.supports_cache_versioning?
35
+ true
36
+ end
37
+
33
38
  # Delete all data stored in a given cache store.
34
39
  def clear(options = nil)
35
40
  synchronize do
@@ -57,13 +62,13 @@ module ActiveSupport
57
62
  return if pruning?
58
63
  @pruning = true
59
64
  begin
60
- start_time = Time.now
65
+ start_time = Concurrent.monotonic_time
61
66
  cleanup
62
67
  instrument(:prune, target_size, from: @cache_size) do
63
68
  keys = synchronize { @key_access.keys.sort { |a, b| @key_access[a].to_f <=> @key_access[b].to_f } }
64
69
  keys.each do |key|
65
70
  delete_entry(key, options)
66
- return if @cache_size <= target_size || (max_time && Time.now - start_time > max_time)
71
+ return if @cache_size <= target_size || (max_time && Concurrent.monotonic_time - start_time > max_time)
67
72
  end
68
73
  end
69
74
  ensure
@@ -12,6 +12,11 @@ module ActiveSupport
12
12
  class NullStore < Store
13
13
  prepend Strategy::LocalCache
14
14
 
15
+ # Advertise cache versioning support.
16
+ def self.supports_cache_versioning?
17
+ true
18
+ end
19
+
15
20
  def clear(options = nil)
16
21
  end
17
22
 
@@ -17,7 +17,6 @@ end
17
17
 
18
18
  require "digest/sha2"
19
19
  require "active_support/core_ext/marshal"
20
- require "active_support/core_ext/hash/transform_values"
21
20
 
22
21
  module ActiveSupport
23
22
  module Cache
@@ -67,9 +66,22 @@ module ActiveSupport
67
66
  SCAN_BATCH_SIZE = 1000
68
67
  private_constant :SCAN_BATCH_SIZE
69
68
 
69
+ # Advertise cache versioning support.
70
+ def self.supports_cache_versioning?
71
+ true
72
+ end
73
+
70
74
  # Support raw values in the local cache strategy.
71
75
  module LocalCacheWithRaw # :nodoc:
72
76
  private
77
+ def read_entry(key, options)
78
+ entry = super
79
+ if options[:raw] && local_cache && entry
80
+ entry = deserialize_entry(entry.value)
81
+ end
82
+ entry
83
+ end
84
+
73
85
  def write_entry(key, entry, options)
74
86
  if options[:raw] && local_cache
75
87
  raw_entry = Entry.new(serialize_entry(entry, raw: true))
@@ -140,15 +152,17 @@ module ActiveSupport
140
152
 
141
153
  # Creates a new Redis cache store.
142
154
  #
143
- # Handles three options: block provided to instantiate, single URL
144
- # provided, and multiple URLs provided.
155
+ # Handles four options: :redis block, :redis instance, single :url
156
+ # string, and multiple :url strings.
145
157
  #
146
- # :redis Proc -> options[:redis].call
147
- # :url String -> Redis.new(url: …)
148
- # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
158
+ # Option Class Result
159
+ # :redis Proc -> options[:redis].call
160
+ # :redis Object -> options[:redis]
161
+ # :url String -> Redis.new(url: …)
162
+ # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
149
163
  #
150
164
  # No namespace is set by default. Provide one if the Redis cache
151
- # server is shared with other apps: <tt>namespace: 'myapp-cache'<tt>.
165
+ # server is shared with other apps: <tt>namespace: 'myapp-cache'</tt>.
152
166
  #
153
167
  # Compression is enabled by default with a 1kB threshold, so cached
154
168
  # values larger than 1kB are automatically compressed. Disable by
@@ -251,7 +265,14 @@ module ActiveSupport
251
265
  def increment(name, amount = 1, options = nil)
252
266
  instrument :increment, name, amount: amount do
253
267
  failsafe :increment do
254
- redis.with { |c| c.incrby normalize_key(name, options), amount }
268
+ options = merged_options(options)
269
+ key = normalize_key(name, options)
270
+
271
+ redis.with do |c|
272
+ c.incrby(key, amount).tap do
273
+ write_key_expiry(c, key, options)
274
+ end
275
+ end
255
276
  end
256
277
  end
257
278
  end
@@ -267,7 +288,14 @@ module ActiveSupport
267
288
  def decrement(name, amount = 1, options = nil)
268
289
  instrument :decrement, name, amount: amount do
269
290
  failsafe :decrement do
270
- redis.with { |c| c.decrby normalize_key(name, options), amount }
291
+ options = merged_options(options)
292
+ key = normalize_key(name, options)
293
+
294
+ redis.with do |c|
295
+ c.decrby(key, amount).tap do
296
+ write_key_expiry(c, key, options)
297
+ end
298
+ end
271
299
  end
272
300
  end
273
301
  end
@@ -320,8 +348,7 @@ module ActiveSupport
320
348
  # Read an entry from the cache.
321
349
  def read_entry(key, options = nil)
322
350
  failsafe :read_entry do
323
- raw = options&.fetch(:raw, false)
324
- deserialize_entry(redis.with { |c| c.get(key) }, raw: raw)
351
+ deserialize_entry redis.with { |c| c.get(key) }
325
352
  end
326
353
  end
327
354
 
@@ -336,7 +363,7 @@ module ActiveSupport
336
363
  def read_multi_mget(*names)
337
364
  options = names.extract_options!
338
365
  options = merged_options(options)
339
- raw = options&.fetch(:raw, false)
366
+ return {} if names == []
340
367
 
341
368
  keys = names.map { |name| normalize_key(name, options) }
342
369
 
@@ -346,7 +373,7 @@ module ActiveSupport
346
373
 
347
374
  names.zip(values).each_with_object({}) do |(name, value), results|
348
375
  if value
349
- entry = deserialize_entry(value, raw: raw)
376
+ entry = deserialize_entry(value)
350
377
  unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(name, options))
351
378
  results[name] = entry.value
352
379
  end
@@ -380,6 +407,12 @@ module ActiveSupport
380
407
  end
381
408
  end
382
409
 
410
+ def write_key_expiry(client, key, options)
411
+ if options[:expires_in] && client.ttl(key).negative?
412
+ client.expire key, options[:expires_in].to_i
413
+ end
414
+ end
415
+
383
416
  # Delete an entry from the cache.
384
417
  def delete_entry(key, options)
385
418
  failsafe :delete_entry, returning: false do
@@ -415,20 +448,9 @@ module ActiveSupport
415
448
  end
416
449
  end
417
450
 
418
- def deserialize_entry(serialized_entry, raw:)
451
+ def deserialize_entry(serialized_entry)
419
452
  if serialized_entry
420
453
  entry = Marshal.load(serialized_entry) rescue serialized_entry
421
-
422
- written_raw = serialized_entry.equal?(entry)
423
- if raw != written_raw
424
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
425
- Using a different value for the raw option when reading and writing
426
- to a cache key is deprecated for :redis_cache_store and Rails 6.0
427
- will stop automatically detecting the format when reading to avoid
428
- marshal loading untrusted raw strings.
429
- MSG
430
- end
431
-
432
454
  entry.is_a?(Entry) ? entry : Entry.new(entry)
433
455
  end
434
456
  end
@@ -23,6 +23,9 @@ module ActiveSupport
23
23
  # +ClassMethods.set_callback+), and run the installed callbacks at the
24
24
  # appropriate times (via +run_callbacks+).
25
25
  #
26
+ # By default callbacks are halted by throwing +:abort+.
27
+ # See +ClassMethods.define_callbacks+ for details.
28
+ #
26
29
  # Three kinds of callbacks are supported: before callbacks, run before a
27
30
  # certain event; after callbacks, run after the event; and around callbacks,
28
31
  # blocks that surround the event, triggering it when they yield. Callback code
@@ -497,9 +500,7 @@ module ActiveSupport
497
500
  arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) }
498
501
  end
499
502
 
500
- def nested
501
- @nested
502
- end
503
+ attr_reader :nested
503
504
 
504
505
  def final?
505
506
  !@call_template
@@ -578,7 +579,7 @@ module ActiveSupport
578
579
  end
579
580
 
580
581
  protected
581
- def chain; @chain; end
582
+ attr_reader :chain
582
583
 
583
584
  private
584
585
 
@@ -659,9 +660,17 @@ module ActiveSupport
659
660
  # * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance
660
661
  # method or a proc; the callback will be called only when they all return
661
662
  # a true value.
663
+ #
664
+ # If a proc is given, its body is evaluated in the context of the
665
+ # current object. It can also optionally accept the current object as
666
+ # an argument.
662
667
  # * <tt>:unless</tt> - A symbol or an array of symbols, each naming an
663
668
  # instance method or a proc; the callback will be called only when they
664
669
  # all return a false value.
670
+ #
671
+ # If a proc is given, its body is evaluated in the context of the
672
+ # current object. It can also optionally accept the current object as
673
+ # an argument.
665
674
  # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
666
675
  # existing chain rather than appended.
667
676
  def set_callback(name, *filter_list, &block)
@@ -809,7 +818,9 @@ module ActiveSupport
809
818
  names.each do |name|
810
819
  name = name.to_sym
811
820
 
812
- set_callbacks name, CallbackChain.new(name, options)
821
+ ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
822
+ target.set_callbacks name, CallbackChain.new(name, options)
823
+ end
813
824
 
814
825
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
815
826
  def _run_#{name}_callbacks(&block)
@@ -110,7 +110,7 @@ module ActiveSupport
110
110
  base.instance_variable_set(:@_dependencies, [])
111
111
  end
112
112
 
113
- def append_features(base)
113
+ def append_features(base) #:nodoc:
114
114
  if base.instance_variable_defined?(:@_dependencies)
115
115
  base.instance_variable_get(:@_dependencies) << self
116
116
  false
@@ -123,6 +123,9 @@ module ActiveSupport
123
123
  end
124
124
  end
125
125
 
126
+ # Evaluate given block in context of base class,
127
+ # so that you can write class macros here.
128
+ # When you define more than one +included+ block, it raises an exception.
126
129
  def included(base = nil, &block)
127
130
  if base.nil?
128
131
  if instance_variable_defined?(:@_included_block)
@@ -137,6 +140,26 @@ module ActiveSupport
137
140
  end
138
141
  end
139
142
 
143
+ # Define class methods from given block.
144
+ # You can define private class methods as well.
145
+ #
146
+ # module Example
147
+ # extend ActiveSupport::Concern
148
+ #
149
+ # class_methods do
150
+ # def foo; puts 'foo'; end
151
+ #
152
+ # private
153
+ # def bar; puts 'bar'; end
154
+ # end
155
+ # end
156
+ #
157
+ # class Buzz
158
+ # include Example
159
+ # end
160
+ #
161
+ # Buzz.foo # => "foo"
162
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
140
163
  def class_methods(&class_methods_module_definition)
141
164
  mod = const_defined?(:ClassMethods, false) ?
142
165
  const_get(:ClassMethods) :
@@ -2,8 +2,6 @@
2
2
 
3
3
  require "active_support/concern"
4
4
  require "active_support/ordered_options"
5
- require "active_support/core_ext/array/extract_options"
6
- require "active_support/core_ext/regexp"
7
5
 
8
6
  module ActiveSupport
9
7
  # Configurable provides a <tt>config</tt> method to store and retrieve
@@ -69,8 +67,8 @@ module ActiveSupport
69
67
  # end
70
68
  # # => NameError: invalid config attribute name
71
69
  #
72
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
73
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
70
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
71
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
74
72
  #
75
73
  # class User
76
74
  # include ActiveSupport::Configurable
@@ -83,7 +81,7 @@ module ActiveSupport
83
81
  # User.new.allowed_access = true # => NoMethodError
84
82
  # User.new.allowed_access # => NoMethodError
85
83
  #
86
- # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
84
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
87
85
  #
88
86
  # class User
89
87
  # include ActiveSupport::Configurable
@@ -106,9 +104,7 @@ module ActiveSupport
106
104
  # end
107
105
  #
108
106
  # User.hair_colors # => [:brown, :black, :blonde, :red]
109
- def config_accessor(*names)
110
- options = names.extract_options!
111
-
107
+ def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true) # :doc:
112
108
  names.each do |name|
113
109
  raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
114
110
 
@@ -118,9 +114,9 @@ module ActiveSupport
118
114
  singleton_class.class_eval reader, __FILE__, reader_line
119
115
  singleton_class.class_eval writer, __FILE__, writer_line
120
116
 
121
- unless options[:instance_accessor] == false
122
- class_eval reader, __FILE__, reader_line unless options[:instance_reader] == false
123
- class_eval writer, __FILE__, writer_line unless options[:instance_writer] == false
117
+ if instance_accessor
118
+ class_eval reader, __FILE__, reader_line if instance_reader
119
+ class_eval writer, __FILE__, writer_line if instance_writer
124
120
  end
125
121
  send("#{name}=", yield) if block_given?
126
122
  end
@@ -3,7 +3,7 @@
3
3
  require "active_support/core_ext/array/wrap"
4
4
  require "active_support/core_ext/array/access"
5
5
  require "active_support/core_ext/array/conversions"
6
+ require "active_support/core_ext/array/extract"
6
7
  require "active_support/core_ext/array/extract_options"
7
8
  require "active_support/core_ext/array/grouping"
8
- require "active_support/core_ext/array/prepend_and_append"
9
9
  require "active_support/core_ext/array/inquiry"
@@ -29,16 +29,28 @@ class Array
29
29
  end
30
30
  end
31
31
 
32
- # Returns a copy of the Array without the specified elements.
32
+ # Returns a new array that includes the passed elements.
33
33
  #
34
- # people = ["David", "Rafael", "Aaron", "Todd"]
35
- # people.without "Aaron", "Todd"
36
- # # => ["David", "Rafael"]
34
+ # [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
35
+ # [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
36
+ def including(*elements)
37
+ self + elements.flatten(1)
38
+ end
39
+
40
+ # Returns a copy of the Array excluding the specified elements.
41
+ #
42
+ # ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
43
+ # [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
37
44
  #
38
- # Note: This is an optimization of <tt>Enumerable#without</tt> that uses <tt>Array#-</tt>
45
+ # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
39
46
  # instead of <tt>Array#reject</tt> for performance reasons.
47
+ def excluding(*elements)
48
+ self - elements.flatten(1)
49
+ end
50
+
51
+ # Alias for #excluding.
40
52
  def without(*elements)
41
- self - elements
53
+ excluding(*elements)
42
54
  end
43
55
 
44
56
  # Equal to <tt>self[1]</tt>.
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Removes and returns the elements for which the block returns a true value.
5
+ # If no block is given, an Enumerator is returned instead.
6
+ #
7
+ # numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8
+ # odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
9
+ # numbers # => [0, 2, 4, 6, 8]
10
+ def extract!
11
+ return to_enum(:extract!) { size } unless block_given?
12
+
13
+ extracted_elements = []
14
+
15
+ reject! do |element|
16
+ extracted_elements << element if yield(element)
17
+ end
18
+
19
+ extracted_elements
20
+ end
21
+ end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Array
4
- # The human way of thinking about adding stuff to the end of a list is with append.
5
- alias_method :append, :push unless [].respond_to?(:append)
3
+ require "active_support/deprecation"
6
4
 
7
- # The human way of thinking about adding stuff to the beginning of a list is with prepend.
8
- alias_method :prepend, :unshift unless [].respond_to?(:prepend)
9
- end
5
+ ActiveSupport::Deprecation.warn "Ruby 2.5+ (required by Rails 6) provides Array#append and Array#prepend natively, so requiring active_support/core_ext/array/prepend_and_append is no longer necessary. Requiring it will raise LoadError in Rails 6.1."
@@ -84,27 +84,26 @@ class Class
84
84
  # To set a default value for the attribute, pass <tt>default:</tt>, like so:
85
85
  #
86
86
  # class_attribute :settings, default: {}
87
- def class_attribute(*attrs)
88
- options = attrs.extract_options!
89
- instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
90
- instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
91
- instance_predicate = options.fetch(:instance_predicate, true)
92
- default_value = options.fetch(:default, nil)
93
-
87
+ def class_attribute(
88
+ *attrs,
89
+ instance_accessor: true,
90
+ instance_reader: instance_accessor,
91
+ instance_writer: instance_accessor,
92
+ instance_predicate: true,
93
+ default: nil
94
+ )
94
95
  attrs.each do |name|
95
96
  singleton_class.silence_redefinition_of_method(name)
96
- define_singleton_method(name) { nil }
97
+ define_singleton_method(name) { default }
97
98
 
98
99
  singleton_class.silence_redefinition_of_method("#{name}?")
99
100
  define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
100
101
 
101
- ivar = "@#{name}"
102
+ ivar = "@#{name}".to_sym
102
103
 
103
104
  singleton_class.silence_redefinition_of_method("#{name}=")
104
105
  define_singleton_method("#{name}=") do |val|
105
- singleton_class.class_eval do
106
- redefine_method(name) { val }
107
- end
106
+ redefine_singleton_method(name) { val }
108
107
 
109
108
  if singleton_class?
110
109
  class_eval do
@@ -137,10 +136,6 @@ class Class
137
136
  instance_variable_set ivar, val
138
137
  end
139
138
  end
140
-
141
- unless default_value.nil?
142
- self.send("#{name}=", default_value)
143
- end
144
139
  end
145
140
  end
146
141
  end