activesupport 6.1.4.2 → 7.0.2.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +226 -462
- 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 +127 -32
- data/lib/active_support/cache/memory_store.rb +23 -15
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +42 -67
- data/lib/active_support/cache/strategy/local_cache.rb +35 -61
- data/lib/active_support/cache.rb +189 -45
- data/lib/active_support/callbacks.rb +180 -81
- data/lib/active_support/code_generator.rb +65 -0
- 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 +13 -11
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +25 -17
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +4 -4
- data/lib/active_support/core_ext/date/conversions.rb +11 -11
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +78 -26
- data/lib/active_support/core_ext/file/atomic.rb +3 -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/attribute_accessors.rb +2 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +19 -10
- 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 +79 -76
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- 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/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -25
- data/lib/active_support/core_ext/range.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 -36
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/time/calculations.rb +7 -6
- data/lib/active_support/core_ext/time/conversions.rb +13 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +4 -19
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -27
- data/lib/active_support/core_ext.rb +1 -0
- data/lib/active_support/current_attributes.rb +31 -14
- 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 +174 -68
- data/lib/active_support/digest.rb +5 -3
- 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 +81 -51
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +1 -1
- data/lib/active_support/environment_inquirer.rb +1 -1
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +1 -1
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +43 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +19 -12
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +3 -1
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +1 -1
- data/lib/active_support/inflector/inflections.rb +23 -7
- data/lib/active_support/inflector/methods.rb +24 -48
- data/lib/active_support/isolated_execution_state.rb +64 -0
- 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 +4 -13
- data/lib/active_support/message_encryptor.rb +8 -3
- data/lib/active_support/message_verifier.rb +46 -14
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/multibyte/chars.rb +10 -11
- data/lib/active_support/multibyte/unicode.rb +0 -12
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +91 -65
- data/lib/active_support/notifications/instrumenter.rb +32 -15
- data/lib/active_support/notifications.rb +15 -21
- 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 +8 -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 +5 -0
- data/lib/active_support/railtie.rb +69 -19
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +2 -2
- data/lib/active_support/ruby_features.rb +7 -0
- 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 +7 -18
- data/lib/active_support/tagged_logging.rb +2 -2
- data/lib/active_support/test_case.rb +9 -21
- data/lib/active_support/testing/assertions.rb +35 -5
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- 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 +54 -13
- data/lib/active_support/values/time_zone.rb +30 -9
- 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 +5 -4
- data/lib/active_support.rb +17 -1
- metadata +26 -23
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -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
|
@@ -3,6 +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/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
6
7
|
require "active_support/core_ext/array/extract"
|
7
8
|
require "active_support/core_ext/array/extract_options"
|
8
9
|
require "active_support/core_ext/array/grouping"
|
@@ -1,22 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/ruby_features"
|
4
|
+
|
3
5
|
class Class
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
6
|
+
if ActiveSupport::RubyFeatures::CLASS_SUBCLASSES
|
7
|
+
# Returns an array with all classes that are < than its receiver.
|
8
|
+
#
|
9
|
+
# class C; end
|
10
|
+
# C.descendants # => []
|
11
|
+
#
|
12
|
+
# class B < C; end
|
13
|
+
# C.descendants # => [B]
|
14
|
+
#
|
15
|
+
# class A < B; end
|
16
|
+
# C.descendants # => [B, A]
|
17
|
+
#
|
18
|
+
# class D < C; end
|
19
|
+
# C.descendants # => [B, A, D]
|
20
|
+
def descendants
|
21
|
+
subclasses.concat(subclasses.flat_map(&:descendants))
|
22
|
+
end
|
23
|
+
else
|
24
|
+
def descendants
|
25
|
+
ObjectSpace.each_object(singleton_class).reject do |k|
|
26
|
+
k.singleton_class? || k == self
|
27
|
+
end
|
20
28
|
end
|
21
29
|
end
|
22
30
|
|
@@ -29,5 +37,5 @@ class Class
|
|
29
37
|
# Foo.subclasses # => [Bar]
|
30
38
|
def subclasses
|
31
39
|
descendants.select { |descendant| descendant.superclass == self }
|
32
|
-
end
|
40
|
+
end unless ActiveSupport::RubyFeatures::CLASS_SUBCLASSES
|
33
41
|
end
|
@@ -17,7 +17,7 @@ class Date
|
|
17
17
|
# If <tt>Date.beginning_of_week</tt> has not been set for the current request, returns the week start specified in <tt>config.beginning_of_week</tt>.
|
18
18
|
# If no config.beginning_of_week was specified, returns :monday.
|
19
19
|
def beginning_of_week
|
20
|
-
|
20
|
+
::ActiveSupport::IsolatedExecutionState[:beginning_of_week] || beginning_of_week_default || :monday
|
21
21
|
end
|
22
22
|
|
23
23
|
# Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. :monday) for current request/thread.
|
@@ -25,7 +25,7 @@ class Date
|
|
25
25
|
# This method accepts any of the following day symbols:
|
26
26
|
# :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
|
27
27
|
def beginning_of_week=(week_start)
|
28
|
-
|
28
|
+
::ActiveSupport::IsolatedExecutionState[:beginning_of_week] = find_beginning_of_week!(week_start)
|
29
29
|
end
|
30
30
|
|
31
31
|
# Returns week start day symbol (e.g. :monday), or raises an +ArgumentError+ for invalid day symbol.
|
@@ -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
|
@@ -22,21 +22,21 @@ class Date
|
|
22
22
|
|
23
23
|
# Convert to a formatted string. See DATE_FORMATS for predefined formats.
|
24
24
|
#
|
25
|
-
# This method is aliased to <tt>
|
25
|
+
# This method is aliased to <tt>to_formatted_s</tt>.
|
26
26
|
#
|
27
27
|
# date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
|
28
28
|
#
|
29
|
+
# date.to_fs(:db) # => "2007-11-10"
|
29
30
|
# date.to_formatted_s(:db) # => "2007-11-10"
|
30
|
-
# date.to_s(:db) # => "2007-11-10"
|
31
31
|
#
|
32
|
-
# date.
|
33
|
-
# date.
|
34
|
-
# date.
|
35
|
-
# date.
|
36
|
-
# date.
|
37
|
-
# date.
|
32
|
+
# date.to_fs(:short) # => "10 Nov"
|
33
|
+
# date.to_fs(:number) # => "20071110"
|
34
|
+
# date.to_fs(:long) # => "November 10, 2007"
|
35
|
+
# date.to_fs(:long_ordinal) # => "November 10th, 2007"
|
36
|
+
# date.to_fs(:rfc822) # => "10 Nov 2007"
|
37
|
+
# date.to_fs(:iso8601) # => "2007-11-10"
|
38
38
|
#
|
39
|
-
# == Adding your own date formats to
|
39
|
+
# == Adding your own date formats to to_fs
|
40
40
|
# You can add your own formats to the Date::DATE_FORMATS hash.
|
41
41
|
# Use the format name as the hash key and either a strftime string
|
42
42
|
# or Proc instance that takes a date argument as the value.
|
@@ -44,7 +44,7 @@ class Date
|
|
44
44
|
# # config/initializers/date_formats.rb
|
45
45
|
# Date::DATE_FORMATS[:month_and_year] = '%B %Y'
|
46
46
|
# Date::DATE_FORMATS[:short_ordinal] = ->(date) { date.strftime("%B #{date.day.ordinalize}") }
|
47
|
-
def
|
47
|
+
def to_fs(format = :default)
|
48
48
|
if formatter = DATE_FORMATS[format]
|
49
49
|
if formatter.respond_to?(:call)
|
50
50
|
formatter.call(self).to_s
|
@@ -55,8 +55,8 @@ class Date
|
|
55
55
|
to_default_s
|
56
56
|
end
|
57
57
|
end
|
58
|
+
alias_method :to_formatted_s, :to_fs
|
58
59
|
alias_method :to_default_s, :to_s
|
59
|
-
alias_method :to_s, :to_formatted_s
|
60
60
|
|
61
61
|
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
|
62
62
|
def readable_inspect
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
class Date
|
6
|
+
NOT_SET = Object.new # :nodoc:
|
7
|
+
def to_s(format = NOT_SET) # :nodoc:
|
8
|
+
if formatter = DATE_FORMATS[format]
|
9
|
+
ActiveSupport::Deprecation.warn(
|
10
|
+
"Date#to_s(#{format.inspect}) is deprecated. Please use Date#to_fs(#{format.inspect}) instead."
|
11
|
+
)
|
12
|
+
if formatter.respond_to?(:call)
|
13
|
+
formatter.call(self).to_s
|
14
|
+
else
|
15
|
+
strftime(formatter)
|
16
|
+
end
|
17
|
+
elsif format == NOT_SET
|
18
|
+
to_default_s
|
19
|
+
else
|
20
|
+
ActiveSupport::Deprecation.warn(
|
21
|
+
"Date#to_s(#{format.inspect}) is deprecated. Please use Date#to_fs(#{format.inspect}) instead."
|
22
|
+
)
|
23
|
+
to_default_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -4,4 +4,5 @@ require "active_support/core_ext/date/acts_like"
|
|
4
4
|
require "active_support/core_ext/date/blank"
|
5
5
|
require "active_support/core_ext/date/calculations"
|
6
6
|
require "active_support/core_ext/date/conversions"
|
7
|
+
require "active_support/core_ext/date/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
7
8
|
require "active_support/core_ext/date/zones"
|
@@ -15,7 +15,7 @@ module DateAndTime
|
|
15
15
|
|
16
16
|
# Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
|
17
17
|
#
|
18
|
-
# When `true`, it returns local times with
|
18
|
+
# When `true`, it returns local times with a UTC offset, with `false` local
|
19
19
|
# times are returned as UTC.
|
20
20
|
#
|
21
21
|
# # Given this zone:
|
@@ -9,21 +9,21 @@ require "active_support/values/time_zone"
|
|
9
9
|
class DateTime
|
10
10
|
# Convert to a formatted string. See Time::DATE_FORMATS for predefined formats.
|
11
11
|
#
|
12
|
-
# This method is aliased to <tt>
|
12
|
+
# This method is aliased to <tt>to_formatted_s</tt>.
|
13
13
|
#
|
14
14
|
# === Examples
|
15
15
|
# datetime = DateTime.civil(2007, 12, 4, 0, 0, 0, 0) # => Tue, 04 Dec 2007 00:00:00 +0000
|
16
16
|
#
|
17
|
-
# datetime.
|
18
|
-
# datetime.
|
19
|
-
# datetime.
|
20
|
-
# datetime.
|
21
|
-
# datetime.
|
22
|
-
# datetime.
|
23
|
-
# datetime.
|
24
|
-
# datetime.
|
17
|
+
# datetime.to_fs(:db) # => "2007-12-04 00:00:00"
|
18
|
+
# datetime.to_formatted_s(:db) # => "2007-12-04 00:00:00"
|
19
|
+
# datetime.to_fs(:number) # => "20071204000000"
|
20
|
+
# datetime.to_fs(:short) # => "04 Dec 00:00"
|
21
|
+
# datetime.to_fs(:long) # => "December 04, 2007 00:00"
|
22
|
+
# datetime.to_fs(:long_ordinal) # => "December 4th, 2007 00:00"
|
23
|
+
# datetime.to_fs(:rfc822) # => "Tue, 04 Dec 2007 00:00:00 +0000"
|
24
|
+
# datetime.to_fs(:iso8601) # => "2007-12-04T00:00:00+00:00"
|
25
25
|
#
|
26
|
-
# == Adding your own datetime formats to
|
26
|
+
# == Adding your own datetime formats to to_fs
|
27
27
|
# DateTime formats are shared with Time. You can add your own to the
|
28
28
|
# Time::DATE_FORMATS hash. Use the format name as the hash key and
|
29
29
|
# either a strftime string or Proc instance that takes a time or
|
@@ -32,15 +32,15 @@ class DateTime
|
|
32
32
|
# # config/initializers/time_formats.rb
|
33
33
|
# Time::DATE_FORMATS[:month_and_year] = '%B %Y'
|
34
34
|
# Time::DATE_FORMATS[:short_ordinal] = lambda { |time| time.strftime("%B #{time.day.ordinalize}") }
|
35
|
-
def
|
35
|
+
def to_fs(format = :default)
|
36
36
|
if formatter = ::Time::DATE_FORMATS[format]
|
37
37
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
38
38
|
else
|
39
39
|
to_default_s
|
40
40
|
end
|
41
41
|
end
|
42
|
+
alias_method :to_formatted_s, :to_fs
|
42
43
|
alias_method :to_default_s, :to_s if instance_methods(false).include?(:to_s)
|
43
|
-
alias_method :to_s, :to_formatted_s
|
44
44
|
|
45
45
|
# Returns a formatted string of the offset from UTC, or an alternative
|
46
46
|
# string if the time zone is already UTC.
|
@@ -54,7 +54,7 @@ class DateTime
|
|
54
54
|
|
55
55
|
# Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005 14:30:00 +0000".
|
56
56
|
def readable_inspect
|
57
|
-
|
57
|
+
to_fs(:rfc822)
|
58
58
|
end
|
59
59
|
alias_method :default_inspect, :inspect
|
60
60
|
alias_method :inspect, :readable_inspect
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
class DateTime
|
6
|
+
NOT_SET = Object.new # :nodoc:
|
7
|
+
def to_s(format = NOT_SET) # :nodoc:
|
8
|
+
if formatter = ::Time::DATE_FORMATS[format]
|
9
|
+
ActiveSupport::Deprecation.warn(
|
10
|
+
"DateTime#to_s(#{format.inspect}) is deprecated. Please use DateTime#to_fs(#{format.inspect}) instead."
|
11
|
+
)
|
12
|
+
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
13
|
+
elsif format == NOT_SET
|
14
|
+
to_default_s
|
15
|
+
else
|
16
|
+
ActiveSupport::Deprecation.warn(
|
17
|
+
"DateTime#to_s(#{format.inspect}) is deprecated. Please use DateTime#to_fs(#{format.inspect}) instead."
|
18
|
+
)
|
19
|
+
to_default_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -5,3 +5,4 @@ require "active_support/core_ext/date_time/blank"
|
|
5
5
|
require "active_support/core_ext/date_time/calculations"
|
6
6
|
require "active_support/core_ext/date_time/compatibility"
|
7
7
|
require "active_support/core_ext/date_time/conversions"
|
8
|
+
require "active_support/core_ext/date_time/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
@@ -1,29 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "securerandom"
|
4
|
+
require "openssl"
|
4
5
|
|
5
6
|
module Digest
|
6
7
|
module UUID
|
7
|
-
DNS_NAMESPACE = "k\xA7\xB8\x10\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8"
|
8
|
-
URL_NAMESPACE = "k\xA7\xB8\x11\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8"
|
9
|
-
OID_NAMESPACE = "k\xA7\xB8\x12\x9D\xAD\x11\xD1\x80\xB4\x00\xC0O\xD40\xC8"
|
10
|
-
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
|
+
|
13
|
+
mattr_accessor :use_rfc4122_namespaced_uuids, instance_accessor: false, default: false
|
11
14
|
|
12
15
|
# Generates a v5 non-random UUID (Universally Unique IDentifier).
|
13
16
|
#
|
14
|
-
# Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs.
|
17
|
+
# Using OpenSSL::Digest::MD5 generates version 3 UUIDs; OpenSSL::Digest::SHA1 generates version 5 UUIDs.
|
15
18
|
# uuid_from_hash always generates the same UUID for a given name and namespace combination.
|
16
19
|
#
|
17
20
|
# See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
|
18
|
-
def self.uuid_from_hash(hash_class,
|
19
|
-
if hash_class == Digest::MD5
|
21
|
+
def self.uuid_from_hash(hash_class, namespace, name)
|
22
|
+
if hash_class == Digest::MD5 || hash_class == OpenSSL::Digest::MD5
|
20
23
|
version = 3
|
21
|
-
elsif hash_class == Digest::SHA1
|
24
|
+
elsif hash_class == Digest::SHA1 || hash_class == OpenSSL::Digest::SHA1
|
22
25
|
version = 5
|
23
26
|
else
|
24
|
-
raise ArgumentError, "Expected Digest::SHA1 or Digest::MD5, got #{hash_class.name}."
|
27
|
+
raise ArgumentError, "Expected OpenSSL::Digest::SHA1 or OpenSSL::Digest::MD5, got #{hash_class.name}."
|
25
28
|
end
|
26
29
|
|
30
|
+
uuid_namespace = pack_uuid_namespace(namespace)
|
31
|
+
|
27
32
|
hash = hash_class.new
|
28
33
|
hash.update(uuid_namespace)
|
29
34
|
hash.update(name)
|
@@ -35,19 +40,40 @@ module Digest
|
|
35
40
|
"%08x-%04x-%04x-%04x-%04x%08x" % ary
|
36
41
|
end
|
37
42
|
|
38
|
-
# Convenience method for uuid_from_hash using Digest::MD5.
|
43
|
+
# Convenience method for uuid_from_hash using OpenSSL::Digest::MD5.
|
39
44
|
def self.uuid_v3(uuid_namespace, name)
|
40
|
-
uuid_from_hash(Digest::MD5, uuid_namespace, name)
|
45
|
+
uuid_from_hash(OpenSSL::Digest::MD5, uuid_namespace, name)
|
41
46
|
end
|
42
47
|
|
43
|
-
# Convenience method for uuid_from_hash using Digest::SHA1.
|
48
|
+
# Convenience method for uuid_from_hash using OpenSSL::Digest::SHA1.
|
44
49
|
def self.uuid_v5(uuid_namespace, name)
|
45
|
-
uuid_from_hash(Digest::SHA1, uuid_namespace, name)
|
50
|
+
uuid_from_hash(OpenSSL::Digest::SHA1, uuid_namespace, name)
|
46
51
|
end
|
47
52
|
|
48
53
|
# Convenience method for SecureRandom.uuid.
|
49
54
|
def self.uuid_v4
|
50
55
|
SecureRandom.uuid
|
51
56
|
end
|
57
|
+
|
58
|
+
def self.pack_uuid_namespace(namespace)
|
59
|
+
if [DNS_NAMESPACE, OID_NAMESPACE, URL_NAMESPACE, X500_NAMESPACE].include?(namespace)
|
60
|
+
namespace
|
61
|
+
elsif use_rfc4122_namespaced_uuids == true
|
62
|
+
match_data = namespace.match(/\A(\h{8})-(\h{4})-(\h{4})-(\h{4})-(\h{4})(\h{8})\z/)
|
63
|
+
|
64
|
+
raise ArgumentError, "Only UUIDs are valid namespace identifiers" unless match_data.present?
|
65
|
+
|
66
|
+
match_data.captures.map { |s| s.to_i(16) }.pack("NnnnnN")
|
67
|
+
else
|
68
|
+
ActiveSupport::Deprecation.warn <<~WARNING.squish
|
69
|
+
Providing a namespace ID that is not one of the constants defined on Digest::UUID generates an incorrect UUID value according to RFC 4122.
|
70
|
+
To enable the correct behavior, set the Rails.application.config.active_support.use_rfc4122_namespaced_uuids configuration option to true.
|
71
|
+
WARNING
|
72
|
+
|
73
|
+
namespace
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private_class_method :pack_uuid_namespace
|
52
78
|
end
|
53
79
|
end
|
@@ -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 }
|
@@ -27,19 +47,30 @@ module Enumerable
|
|
27
47
|
#
|
28
48
|
# It can also calculate the sum without the use of a block.
|
29
49
|
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
50
|
+
# [5, 15, 10].sum # => 30
|
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
|
#
|
36
|
-
#
|
56
|
+
# [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
|
37
57
|
def sum(identity = nil, &block)
|
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
|
#
|
@@ -178,40 +205,66 @@ module Enumerable
|
|
178
205
|
# Returns a new +Array+ without the blank items.
|
179
206
|
# Uses Object#blank? for determining if an item is blank.
|
180
207
|
#
|
181
|
-
#
|
182
|
-
#
|
208
|
+
# [1, "", nil, 2, " ", [], {}, false, true].compact_blank
|
209
|
+
# # => [1, 2, true]
|
183
210
|
#
|
184
|
-
#
|
185
|
-
#
|
211
|
+
# Set.new([nil, "", 1, 2])
|
212
|
+
# # => [2, 1] (or [1, 2])
|
186
213
|
#
|
187
214
|
# When called on a +Hash+, returns a new +Hash+ without the blank values.
|
188
215
|
#
|
189
|
-
#
|
190
|
-
#
|
216
|
+
# { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
|
217
|
+
# # => { b: 1, f: true }
|
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
|
|
202
255
|
# Removes all blank values from the +Hash+ in place and returns self.
|
203
256
|
# Uses Object#blank? for determining if a value is blank.
|
204
257
|
#
|
205
|
-
#
|
206
|
-
#
|
207
|
-
#
|
258
|
+
# h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
|
259
|
+
# h.compact_blank!
|
260
|
+
# # => { b: 1, f: true }
|
208
261
|
def compact_blank!
|
209
262
|
# use delete_if rather than reject! because it always returns self even if nothing changed
|
210
263
|
delete_if { |_k, v| v.blank? }
|
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
|
@@ -250,9 +302,9 @@ class Array #:nodoc:
|
|
250
302
|
# Removes all blank elements from the +Array+ in place and returns self.
|
251
303
|
# Uses Object#blank? for determining if an item is blank.
|
252
304
|
#
|
253
|
-
#
|
254
|
-
#
|
255
|
-
#
|
305
|
+
# a = [1, "", nil, 2, " ", [], {}, false, true]
|
306
|
+
# a.compact_blank!
|
307
|
+
# # => [1, 2, true]
|
256
308
|
def compact_blank!
|
257
309
|
# use delete_if rather than reject! because it always returns self even if nothing changed
|
258
310
|
delete_if(&:blank?)
|
@@ -53,7 +53,7 @@ class File
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# Private utility method.
|
56
|
-
def self.probe_stat_in(dir)
|
56
|
+
def self.probe_stat_in(dir) # :nodoc:
|
57
57
|
basename = [
|
58
58
|
".permissions_check",
|
59
59
|
Thread.current.object_id,
|
@@ -64,6 +64,8 @@ class File
|
|
64
64
|
file_name = join(dir, basename)
|
65
65
|
FileUtils.touch(file_name)
|
66
66
|
stat(file_name)
|
67
|
+
rescue Errno::ENOENT
|
68
|
+
file_name = nil
|
67
69
|
ensure
|
68
70
|
FileUtils.rm_f(file_name) if file_name
|
69
71
|
end
|
@@ -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
|