activesupport 6.1.7.2 → 7.0.0.alpha1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +151 -620
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +0 -2
- data/lib/active_support/benchmarkable.rb +2 -2
- data/lib/active_support/cache/file_store.rb +15 -9
- data/lib/active_support/cache/mem_cache_store.rb +119 -28
- data/lib/active_support/cache/memory_store.rb +21 -13
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +39 -59
- data/lib/active_support/cache/strategy/local_cache.rb +29 -49
- data/lib/active_support/cache.rb +189 -45
- data/lib/active_support/callbacks.rb +35 -31
- data/lib/active_support/concern.rb +5 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +6 -3
- data/lib/active_support/configuration_file.rb +1 -1
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +6 -6
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +2 -2
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/digest/uuid.rb +13 -13
- data/lib/active_support/core_ext/enumerable.rb +64 -12
- data/lib/active_support/core_ext/file/atomic.rb +1 -1
- data/lib/active_support/core_ext/hash/keys.rb +1 -1
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/module/delegation.rb +2 -8
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/conversions.rb +2 -2
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +29 -24
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +1 -1
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +60 -64
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +4 -5
- data/lib/active_support/core_ext/time/zones.rb +2 -17
- data/lib/active_support/core_ext/uri.rb +0 -14
- data/lib/active_support/current_attributes.rb +17 -2
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +4 -1
- data/lib/active_support/deprecation/method_wrappers.rb +3 -3
- data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/descendants_tracker.rb +12 -9
- data/lib/active_support/digest.rb +4 -4
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -1
- data/lib/active_support/duration.rb +80 -52
- data/lib/active_support/encrypted_configuration.rb +11 -1
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/evented_file_update_checker.rb +1 -1
- data/lib/active_support/execution_wrapper.rb +13 -16
- data/lib/active_support/fork_tracker.rb +2 -4
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +3 -1
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/inflector/inflections.rb +11 -4
- data/lib/active_support/inflector/methods.rb +23 -46
- data/lib/active_support/json/encoding.rb +3 -3
- data/lib/active_support/key_generator.rb +18 -1
- data/lib/active_support/locale/en.yml +1 -1
- data/lib/active_support/log_subscriber.rb +13 -3
- data/lib/active_support/logger_thread_safe_level.rb +5 -13
- data/lib/active_support/message_encryptor.rb +3 -3
- data/lib/active_support/message_verifier.rb +4 -4
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +31 -11
- data/lib/active_support/notifications/instrumenter.rb +17 -0
- data/lib/active_support/notifications.rb +10 -0
- data/lib/active_support/number_helper/number_converter.rb +1 -3
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/rounding_helper.rb +1 -5
- data/lib/active_support/number_helper.rb +0 -2
- data/lib/active_support/option_merger.rb +4 -16
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/parameter_filter.rb +5 -0
- data/lib/active_support/per_thread_registry.rb +1 -1
- data/lib/active_support/railtie.rb +33 -10
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +2 -2
- data/lib/active_support/secure_compare_rotator.rb +1 -1
- data/lib/active_support/string_inquirer.rb +0 -2
- data/lib/active_support/subscriber.rb +5 -0
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +34 -4
- data/lib/active_support/testing/deprecation.rb +1 -1
- data/lib/active_support/testing/isolation.rb +1 -1
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +13 -2
- data/lib/active_support/time_with_zone.rb +19 -6
- data/lib/active_support/values/time_zone.rb +25 -11
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +1 -1
- data/lib/active_support/xml_mini.rb +2 -1
- data/lib/active_support.rb +14 -1
- metadata +14 -29
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -17,14 +17,12 @@ module ActiveSupport
|
|
17
17
|
ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
|
18
18
|
end
|
19
19
|
|
20
|
-
def synchronize
|
20
|
+
def synchronize(&block)
|
21
21
|
Thread.handle_interrupt(EXCEPTION_NEVER) do
|
22
22
|
mon_enter
|
23
23
|
|
24
24
|
begin
|
25
|
-
Thread.handle_interrupt(EXCEPTION_IMMEDIATE)
|
26
|
-
yield
|
27
|
-
end
|
25
|
+
Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
|
28
26
|
ensure
|
29
27
|
mon_exit
|
30
28
|
end
|
@@ -215,9 +215,9 @@ module ActiveSupport
|
|
215
215
|
@waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
|
216
216
|
end
|
217
217
|
|
218
|
-
def wait_for(method)
|
218
|
+
def wait_for(method, &block)
|
219
219
|
@sleeping[Thread.current] = method
|
220
|
-
@cv.wait_while
|
220
|
+
@cv.wait_while(&block)
|
221
221
|
ensure
|
222
222
|
@sleeping.delete Thread.current
|
223
223
|
end
|
@@ -94,17 +94,19 @@ module ActiveSupport
|
|
94
94
|
# User.new.allowed_access = true # => NoMethodError
|
95
95
|
# User.new.allowed_access # => NoMethodError
|
96
96
|
#
|
97
|
-
# Also you can pass a block to set up the attribute with a default value.
|
97
|
+
# Also you can pass <tt>default</tt> or a block to set up the attribute with a default value.
|
98
98
|
#
|
99
99
|
# class User
|
100
100
|
# include ActiveSupport::Configurable
|
101
|
+
# config_accessor :allowed_access, default: false
|
101
102
|
# config_accessor :hair_colors do
|
102
103
|
# [:brown, :black, :blonde, :red]
|
103
104
|
# end
|
104
105
|
# end
|
105
106
|
#
|
107
|
+
# User.allowed_access # => false
|
106
108
|
# User.hair_colors # => [:brown, :black, :blonde, :red]
|
107
|
-
def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true) # :doc:
|
109
|
+
def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil) # :doc:
|
108
110
|
names.each do |name|
|
109
111
|
raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
|
110
112
|
|
@@ -118,7 +120,8 @@ module ActiveSupport
|
|
118
120
|
class_eval reader, __FILE__, reader_line if instance_reader
|
119
121
|
class_eval writer, __FILE__, writer_line if instance_writer
|
120
122
|
end
|
121
|
-
|
123
|
+
|
124
|
+
send("#{name}=", block_given? ? yield : default)
|
122
125
|
end
|
123
126
|
end
|
124
127
|
private :config_accessor
|
@@ -38,7 +38,7 @@ module ActiveSupport
|
|
38
38
|
|
39
39
|
File.read(content_path).tap do |content|
|
40
40
|
if content.include?("\u00A0")
|
41
|
-
warn "
|
41
|
+
warn "#{content_path} contains invisible non-breaking spaces, you may want to remove those"
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
@@ -16,12 +16,12 @@ class Array
|
|
16
16
|
#
|
17
17
|
# ==== Options
|
18
18
|
#
|
19
|
-
# * <tt>:words_connector</tt> - The sign or word used to join the
|
20
|
-
# in arrays with
|
21
|
-
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements
|
22
|
-
# in arrays with two elements (default: " and ").
|
19
|
+
# * <tt>:words_connector</tt> - The sign or word used to join all but the last
|
20
|
+
# element in arrays with three or more elements (default: ", ").
|
23
21
|
# * <tt>:last_word_connector</tt> - The sign or word used to join the last element
|
24
22
|
# in arrays with three or more elements (default: ", and ").
|
23
|
+
# * <tt>:two_words_connector</tt> - The sign or word used to join the elements
|
24
|
+
# in arrays with two elements (default: " and ").
|
25
25
|
# * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
|
26
26
|
# the connector options defined on the 'support.array' namespace in the
|
27
27
|
# corresponding dictionary file.
|
@@ -66,7 +66,7 @@ class Array
|
|
66
66
|
two_words_connector: " and ",
|
67
67
|
last_word_connector: ", and "
|
68
68
|
}
|
69
|
-
if defined?(I18n)
|
69
|
+
if options[:locale] != false && defined?(I18n)
|
70
70
|
i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
|
71
71
|
default_connectors.merge!(i18n_connectors)
|
72
72
|
end
|
@@ -187,7 +187,7 @@ class Array
|
|
187
187
|
options[:indent] ||= 2
|
188
188
|
options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
|
189
189
|
options[:root] ||= \
|
190
|
-
if first.class != Hash && all?
|
190
|
+
if first.class != Hash && all?(first.class)
|
191
191
|
underscored = ActiveSupport::Inflector.underscore(first.class.name)
|
192
192
|
ActiveSupport::Inflector.pluralize(underscored).tr("/", "_")
|
193
193
|
else
|
@@ -19,7 +19,7 @@ class Array
|
|
19
19
|
# ["1", "2"]
|
20
20
|
# ["3", "4"]
|
21
21
|
# ["5"]
|
22
|
-
def in_groups_of(number, fill_with = nil)
|
22
|
+
def in_groups_of(number, fill_with = nil, &block)
|
23
23
|
if number.to_i <= 0
|
24
24
|
raise ArgumentError,
|
25
25
|
"Group size must be a positive integer, was #{number.inspect}"
|
@@ -36,7 +36,7 @@ class Array
|
|
36
36
|
end
|
37
37
|
|
38
38
|
if block_given?
|
39
|
-
collection.each_slice(number
|
39
|
+
collection.each_slice(number, &block)
|
40
40
|
else
|
41
41
|
collection.each_slice(number).to_a
|
42
42
|
end
|
@@ -59,7 +59,7 @@ class Array
|
|
59
59
|
# ["1", "2", "3"]
|
60
60
|
# ["4", "5"]
|
61
61
|
# ["6", "7"]
|
62
|
-
def in_groups(number, fill_with = nil)
|
62
|
+
def in_groups(number, fill_with = nil, &block)
|
63
63
|
# size.div number gives minor group size;
|
64
64
|
# size % number gives how many objects need extra accommodation;
|
65
65
|
# each group hold either division or division + 1 items.
|
@@ -79,7 +79,7 @@ class Array
|
|
79
79
|
end
|
80
80
|
|
81
81
|
if block_given?
|
82
|
-
groups.each
|
82
|
+
groups.each(&block)
|
83
83
|
else
|
84
84
|
groups
|
85
85
|
end
|
@@ -90,11 +90,11 @@ class Array
|
|
90
90
|
#
|
91
91
|
# [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
|
92
92
|
# (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
|
93
|
-
def split(value = nil)
|
93
|
+
def split(value = nil, &block)
|
94
94
|
arr = dup
|
95
95
|
result = []
|
96
96
|
if block_given?
|
97
|
-
while (idx = arr.index
|
97
|
+
while (idx = arr.index(&block))
|
98
98
|
result << arr.shift(idx)
|
99
99
|
arr.shift
|
100
100
|
end
|
@@ -87,7 +87,7 @@ class Date
|
|
87
87
|
end
|
88
88
|
alias :at_end_of_day :end_of_day
|
89
89
|
|
90
|
-
def plus_with_duration(other)
|
90
|
+
def plus_with_duration(other) # :nodoc:
|
91
91
|
if ActiveSupport::Duration === other
|
92
92
|
other.since(self)
|
93
93
|
else
|
@@ -97,7 +97,7 @@ class Date
|
|
97
97
|
alias_method :plus_without_duration, :+
|
98
98
|
alias_method :+, :plus_with_duration
|
99
99
|
|
100
|
-
def minus_with_duration(other)
|
100
|
+
def minus_with_duration(other) # :nodoc:
|
101
101
|
if ActiveSupport::Duration === other
|
102
102
|
plus_with_duration(-other)
|
103
103
|
else
|
@@ -1,28 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "securerandom"
|
4
|
-
require "
|
4
|
+
require "openssl"
|
5
5
|
|
6
6
|
module Digest
|
7
7
|
module UUID
|
8
|
-
DNS_NAMESPACE = "k\xA7\xB8\x10\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8"
|
9
|
-
URL_NAMESPACE = "k\xA7\xB8\x11\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8"
|
10
|
-
OID_NAMESPACE = "k\xA7\xB8\x12\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8"
|
11
|
-
X500_NAMESPACE = "k\xA7\xB8\x14\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8"
|
8
|
+
DNS_NAMESPACE = "k\xA7\xB8\x10\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
|
9
|
+
URL_NAMESPACE = "k\xA7\xB8\x11\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
|
10
|
+
OID_NAMESPACE = "k\xA7\xB8\x12\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
|
11
|
+
X500_NAMESPACE = "k\xA7\xB8\x14\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8" # :nodoc:
|
12
12
|
|
13
13
|
# Generates a v5 non-random UUID (Universally Unique IDentifier).
|
14
14
|
#
|
15
|
-
# Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs.
|
15
|
+
# Using OpenSSL::Digest::MD5 generates version 3 UUIDs; OpenSSL::Digest::SHA1 generates version 5 UUIDs.
|
16
16
|
# uuid_from_hash always generates the same UUID for a given name and namespace combination.
|
17
17
|
#
|
18
18
|
# See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
|
19
19
|
def self.uuid_from_hash(hash_class, uuid_namespace, name)
|
20
|
-
if hash_class == Digest::MD5
|
20
|
+
if hash_class == Digest::MD5 || hash_class == OpenSSL::Digest::MD5
|
21
21
|
version = 3
|
22
|
-
elsif hash_class == Digest::SHA1
|
22
|
+
elsif hash_class == Digest::SHA1 || hash_class == OpenSSL::Digest::SHA1
|
23
23
|
version = 5
|
24
24
|
else
|
25
|
-
raise ArgumentError, "Expected Digest::SHA1 or Digest::MD5, got #{hash_class.name}."
|
25
|
+
raise ArgumentError, "Expected OpenSSL::Digest::SHA1 or OpenSSL::Digest::MD5, got #{hash_class.name}."
|
26
26
|
end
|
27
27
|
|
28
28
|
hash = hash_class.new
|
@@ -36,14 +36,14 @@ module Digest
|
|
36
36
|
"%08x-%04x-%04x-%04x-%04x%08x" % ary
|
37
37
|
end
|
38
38
|
|
39
|
-
# Convenience method for uuid_from_hash using Digest::MD5.
|
39
|
+
# Convenience method for uuid_from_hash using OpenSSL::Digest::MD5.
|
40
40
|
def self.uuid_v3(uuid_namespace, name)
|
41
|
-
uuid_from_hash(Digest::MD5, uuid_namespace, name)
|
41
|
+
uuid_from_hash(OpenSSL::Digest::MD5, uuid_namespace, name)
|
42
42
|
end
|
43
43
|
|
44
|
-
# Convenience method for uuid_from_hash using Digest::SHA1.
|
44
|
+
# Convenience method for uuid_from_hash using OpenSSL::Digest::SHA1.
|
45
45
|
def self.uuid_v5(uuid_namespace, name)
|
46
|
-
uuid_from_hash(Digest::SHA1, uuid_namespace, name)
|
46
|
+
uuid_from_hash(OpenSSL::Digest::SHA1, uuid_namespace, name)
|
47
47
|
end
|
48
48
|
|
49
49
|
# Convenience method for SecureRandom.uuid.
|
@@ -4,6 +4,10 @@ module Enumerable
|
|
4
4
|
INDEX_WITH_DEFAULT = Object.new
|
5
5
|
private_constant :INDEX_WITH_DEFAULT
|
6
6
|
|
7
|
+
# Error generated by +sole+ when called on an enumerable that doesn't have
|
8
|
+
# exactly one item.
|
9
|
+
class SoleItemExpectedError < StandardError; end
|
10
|
+
|
7
11
|
# Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
|
8
12
|
# when we omit an identity.
|
9
13
|
|
@@ -16,6 +20,22 @@ module Enumerable
|
|
16
20
|
|
17
21
|
# :startdoc:
|
18
22
|
|
23
|
+
# Calculates the minimum from the extracted elements.
|
24
|
+
#
|
25
|
+
# payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
|
26
|
+
# payments.minimum(:price) # => 5
|
27
|
+
def minimum(key)
|
28
|
+
map(&key).min
|
29
|
+
end
|
30
|
+
|
31
|
+
# Calculates the maximum from the extracted elements.
|
32
|
+
#
|
33
|
+
# payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
|
34
|
+
# payments.maximum(:price) # => 15
|
35
|
+
def maximum(key)
|
36
|
+
map(&key).max
|
37
|
+
end
|
38
|
+
|
19
39
|
# Calculates a sum from the elements.
|
20
40
|
#
|
21
41
|
# payments.sum { |p| p.price * p.tax_rate }
|
@@ -28,8 +48,8 @@ module Enumerable
|
|
28
48
|
# It can also calculate the sum without the use of a block.
|
29
49
|
#
|
30
50
|
# [5, 15, 10].sum # => 30
|
31
|
-
# ['foo', 'bar'].sum # => "foobar"
|
32
|
-
# [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
|
51
|
+
# ['foo', 'bar'].sum('') # => "foobar"
|
52
|
+
# [[1, 2], [3, 1, 5]].sum([]) # => [1, 2, 3, 1, 5]
|
33
53
|
#
|
34
54
|
# The default sum of an empty list is zero. You can override this default:
|
35
55
|
#
|
@@ -38,8 +58,19 @@ module Enumerable
|
|
38
58
|
if identity
|
39
59
|
_original_sum_with_required_identity(identity, &block)
|
40
60
|
elsif block_given?
|
41
|
-
map(&block).sum
|
61
|
+
map(&block).sum
|
62
|
+
# we check `first(1) == []` to check if we have an
|
63
|
+
# empty Enumerable; checking `empty?` would return
|
64
|
+
# true for `[nil]`, which we want to deprecate to
|
65
|
+
# keep consistent with Ruby
|
66
|
+
elsif first.is_a?(Numeric) || first(1) == []
|
67
|
+
identity ||= 0
|
68
|
+
_original_sum_with_required_identity(identity, &block)
|
42
69
|
else
|
70
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
71
|
+
Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4.
|
72
|
+
Sum of non-numeric elements requires an initial argument.
|
73
|
+
MSG
|
43
74
|
inject(:+) || 0
|
44
75
|
end
|
45
76
|
end
|
@@ -136,11 +167,7 @@ module Enumerable
|
|
136
167
|
elements.flatten!(1)
|
137
168
|
reject { |element| elements.include?(element) }
|
138
169
|
end
|
139
|
-
|
140
|
-
# Alias for #excluding.
|
141
|
-
def without(*elements)
|
142
|
-
excluding(*elements)
|
143
|
-
end
|
170
|
+
alias :without :excluding
|
144
171
|
|
145
172
|
# Extract the given key from each element in the enumerable.
|
146
173
|
#
|
@@ -191,11 +218,37 @@ module Enumerable
|
|
191
218
|
def compact_blank
|
192
219
|
reject(&:blank?)
|
193
220
|
end
|
221
|
+
|
222
|
+
# Returns a new +Array+ where the order has been set to that provided in the +series+, based on the +key+ of the
|
223
|
+
# objects in the original enumerable.
|
224
|
+
#
|
225
|
+
# [ Person.find(5), Person.find(3), Person.find(1) ].in_order_of(:id, [ 1, 5, 3 ])
|
226
|
+
# => [ Person.find(1), Person.find(5), Person.find(3) ]
|
227
|
+
#
|
228
|
+
# If the +series+ include keys that have no corresponding element in the Enumerable, these are ignored.
|
229
|
+
# If the Enumerable has additional elements that aren't named in the +series+, these are not included in the result.
|
230
|
+
def in_order_of(key, series)
|
231
|
+
index_by(&key).values_at(*series).compact
|
232
|
+
end
|
233
|
+
|
234
|
+
# Returns the sole item in the enumerable. If there are no items, or more
|
235
|
+
# than one item, raises +Enumerable::SoleItemExpectedError+.
|
236
|
+
#
|
237
|
+
# ["x"].sole # => "x"
|
238
|
+
# Set.new.sole # => Enumerable::SoleItemExpectedError: no item found
|
239
|
+
# { a: 1, b: 2 }.sole # => Enumerable::SoleItemExpectedError: multiple items found
|
240
|
+
def sole
|
241
|
+
case count
|
242
|
+
when 1 then return first # rubocop:disable Style/RedundantReturn
|
243
|
+
when 0 then raise SoleItemExpectedError, "no item found"
|
244
|
+
when 2.. then raise SoleItemExpectedError, "multiple items found"
|
245
|
+
end
|
246
|
+
end
|
194
247
|
end
|
195
248
|
|
196
249
|
class Hash
|
197
250
|
# Hash#reject has its own definition, so this needs one too.
|
198
|
-
def compact_blank
|
251
|
+
def compact_blank # :nodoc:
|
199
252
|
reject { |_k, v| v.blank? }
|
200
253
|
end
|
201
254
|
|
@@ -211,7 +264,7 @@ class Hash
|
|
211
264
|
end
|
212
265
|
end
|
213
266
|
|
214
|
-
class Range
|
267
|
+
class Range # :nodoc:
|
215
268
|
# Optimize range sum to use arithmetic progression if a block is not given and
|
216
269
|
# we have a range of numeric values.
|
217
270
|
def sum(identity = nil)
|
@@ -236,8 +289,7 @@ using Module.new {
|
|
236
289
|
end
|
237
290
|
}
|
238
291
|
|
239
|
-
class Array
|
240
|
-
# Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
|
292
|
+
class Array # :nodoc:
|
241
293
|
def sum(init = nil, &block)
|
242
294
|
if init.is_a?(Numeric) || first.is_a?(Numeric)
|
243
295
|
init ||= 0
|
@@ -116,7 +116,7 @@ class Hash
|
|
116
116
|
def _deep_transform_keys_in_object(object, &block)
|
117
117
|
case object
|
118
118
|
when Hash
|
119
|
-
object.each_with_object(
|
119
|
+
object.each_with_object(self.class.new) do |(key, value), result|
|
120
120
|
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
121
121
|
end
|
122
122
|
when Array
|
@@ -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)
|
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)
|
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
|
@@ -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 =
|
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)
|
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
|
-
|
57
|
-
|
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
|
@@ -107,9 +107,9 @@ module ActiveSupport
|
|
107
107
|
# separator: ',',
|
108
108
|
# significant: false) # => "1,2 Million"
|
109
109
|
def to_s(format = nil, options = nil)
|
110
|
+
return super() if format.nil?
|
111
|
+
|
110
112
|
case format
|
111
|
-
when nil
|
112
|
-
super()
|
113
113
|
when Integer, String
|
114
114
|
super(format)
|
115
115
|
when :phone
|
@@ -131,7 +131,7 @@ class String
|
|
131
131
|
end
|
132
132
|
end
|
133
133
|
|
134
|
-
class Numeric
|
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
|
146
|
+
class Time # :nodoc:
|
147
147
|
# No Time is blank:
|
148
148
|
#
|
149
149
|
# Time.now.blank? # => false
|
@@ -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
|