activesupport 7.0.4.2 → 7.0.7
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 +72 -0
- data/README.rdoc +2 -2
- data/lib/active_support/cache/strategy/local_cache.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +15 -0
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +12 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +12 -1
- data/lib/active_support/core_ext/enumerable.rb +25 -20
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +3 -3
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- data/lib/active_support/core_ext/object/duplicable.rb +5 -5
- data/lib/active_support/core_ext/object/to_query.rb +0 -2
- data/lib/active_support/core_ext/object/with_options.rb +5 -5
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +8 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -2
- data/lib/active_support/core_ext/string/inflections.rb +0 -4
- data/lib/active_support/core_ext/string/output_safety.rb +4 -0
- data/lib/active_support/core_ext/time/calculations.rb +4 -0
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +12 -1
- data/lib/active_support/core_ext/time/zones.rb +3 -4
- data/lib/active_support/deprecation/disallowed.rb +3 -3
- data/lib/active_support/encrypted_configuration.rb +33 -2
- data/lib/active_support/evented_file_update_checker.rb +17 -2
- data/lib/active_support/gem_version.rb +2 -2
- data/lib/active_support/inflector/methods.rb +5 -7
- data/lib/active_support/lazy_load_hooks.rb +1 -1
- data/lib/active_support/notifications.rb +2 -2
- data/lib/active_support/number_helper.rb +4 -3
- data/lib/active_support/parameter_filter.rb +19 -15
- data/lib/active_support/testing/isolation.rb +28 -27
- data/lib/active_support/time_with_zone.rb +10 -3
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80a7bd049eb2334eb8d890f9c6e9aa59ac18ad0f389901ab2095325f975c9bf3
|
4
|
+
data.tar.gz: 6c81983a51ecab1619501c6408dd72bcda286ac4a8f10f7238d911c88a89a074
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5dc3de073888174d4cf67504cf410cd40930f91b7a6acc3e2cb070443f0001921500ec12b759dbb1889b03452b006bd9eb1df27f66a7e9453e0ee71d0e28b90
|
7
|
+
data.tar.gz: c36cc3363dd654026af0f821737b0775de90111e4d8f4e1e7b1a27f42345d110d254c308080fc0f6c7e8e62a63e0ce7e08c69978609c137fd9d0a49cd348aa09
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,62 @@
|
|
1
|
+
## Rails 7.0.7 (August 09, 2023) ##
|
2
|
+
|
3
|
+
* Fix `Cache::NullStore` with local caching for repeated reads.
|
4
|
+
|
5
|
+
*fatkodima*
|
6
|
+
|
7
|
+
* Fix `to_s` with no arguments not respecting custom `:default` formats
|
8
|
+
|
9
|
+
*Hartley McGuire*
|
10
|
+
|
11
|
+
* Fix `ActiveSupport::Inflector.humanize(nil)` raising ``NoMethodError: undefined method `end_with?' for nil:NilClass``.
|
12
|
+
|
13
|
+
*James Robinson*
|
14
|
+
|
15
|
+
* Fix `Enumerable#sum` for `Enumerator#lazy`.
|
16
|
+
|
17
|
+
*fatkodima*, *Matthew Draper*, *Jonathan Hefner*
|
18
|
+
|
19
|
+
* Improve error message when EventedFileUpdateChecker is used without a
|
20
|
+
compatible version of the Listen gem
|
21
|
+
|
22
|
+
*Hartley McGuire*
|
23
|
+
|
24
|
+
|
25
|
+
## Rails 7.0.6 (June 29, 2023) ##
|
26
|
+
|
27
|
+
* Fix `EncryptedConfiguration` returning incorrect values for some `Hash`
|
28
|
+
methods
|
29
|
+
|
30
|
+
*Hartley McGuire*
|
31
|
+
|
32
|
+
* Fix arguments being destructed `Enumerable#many?` with block.
|
33
|
+
|
34
|
+
*Andrew Novoselac*
|
35
|
+
|
36
|
+
* Fix humanize for strings ending with id.
|
37
|
+
|
38
|
+
*fatkodima*
|
39
|
+
|
40
|
+
|
41
|
+
## Rails 7.0.5.1 (June 26, 2023) ##
|
42
|
+
|
43
|
+
* No changes.
|
44
|
+
|
45
|
+
|
46
|
+
## Rails 7.0.5 (May 24, 2023) ##
|
47
|
+
|
48
|
+
* Fixes TimeWithZone ArgumentError.
|
49
|
+
|
50
|
+
*Niklas Häusele*
|
51
|
+
|
52
|
+
|
53
|
+
## Rails 7.0.4.3 (March 13, 2023) ##
|
54
|
+
|
55
|
+
* Implement SafeBuffer#bytesplice
|
56
|
+
|
57
|
+
[CVE-2023-28120]
|
58
|
+
|
59
|
+
|
1
60
|
## Rails 7.0.4.2 (January 24, 2023) ##
|
2
61
|
|
3
62
|
* No changes.
|
@@ -12,6 +71,19 @@
|
|
12
71
|
|
13
72
|
## Rails 7.0.4 (September 09, 2022) ##
|
14
73
|
|
74
|
+
* Ensure `ActiveSupport::Testing::Isolation::Forking` closes pipes
|
75
|
+
|
76
|
+
Previously, `Forking.run_in_isolation` opened two ends of a pipe. The fork
|
77
|
+
process closed the read end, wrote to it, and then terminated (which
|
78
|
+
presumably closed the file descriptors on its end). The parent process
|
79
|
+
closed the write end, read from it, and returned, never closing the read
|
80
|
+
end.
|
81
|
+
|
82
|
+
This resulted in an accumulation of open file descriptors, which could
|
83
|
+
cause errors if the limit is reached.
|
84
|
+
|
85
|
+
*Sam Bostock*
|
86
|
+
|
15
87
|
* Redis cache store is now compatible with redis-rb 5.0.
|
16
88
|
|
17
89
|
*Jean Boussier*
|
data/README.rdoc
CHANGED
@@ -13,7 +13,7 @@ The latest version of Active Support can be installed with RubyGems:
|
|
13
13
|
|
14
14
|
$ gem install activesupport
|
15
15
|
|
16
|
-
Source code can be downloaded as part of the Rails project on GitHub:
|
16
|
+
Source code can be downloaded as part of the \Rails project on GitHub:
|
17
17
|
|
18
18
|
* https://github.com/rails/rails/tree/main/activesupport
|
19
19
|
|
@@ -31,7 +31,7 @@ API documentation is at:
|
|
31
31
|
|
32
32
|
* https://api.rubyonrails.org
|
33
33
|
|
34
|
-
Bug reports for the Ruby on Rails project can be filed here:
|
34
|
+
Bug reports for the Ruby on \Rails project can be filed here:
|
35
35
|
|
36
36
|
* https://github.com/rails/rails/issues
|
37
37
|
|
@@ -124,7 +124,7 @@ module ActiveSupport
|
|
124
124
|
|
125
125
|
local_entries = local_cache.read_multi_entries(keys)
|
126
126
|
local_entries.transform_values! do |payload|
|
127
|
-
deserialize_entry(payload)
|
127
|
+
deserialize_entry(payload)&.value
|
128
128
|
end
|
129
129
|
missed_keys = keys - local_entries.keys
|
130
130
|
|
@@ -109,6 +109,21 @@ class Date
|
|
109
109
|
|
110
110
|
# Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
|
111
111
|
# any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
|
112
|
+
#
|
113
|
+
# The increments are applied in order of time units from largest to smallest.
|
114
|
+
# In other words, the date is incremented first by +:years+, then by
|
115
|
+
# +:months+, then by +:weeks+, then by +:days+. This order can affect the
|
116
|
+
# result around the end of a month. For example, incrementing first by months
|
117
|
+
# then by days:
|
118
|
+
#
|
119
|
+
# Date.new(2004, 9, 30).advance(months: 1, days: 1)
|
120
|
+
# # => Sun, 31 Oct 2004
|
121
|
+
#
|
122
|
+
# Whereas incrementing first by days then by months yields a different result:
|
123
|
+
#
|
124
|
+
# Date.new(2004, 9, 30).advance(days: 1).advance(months: 1)
|
125
|
+
# # => Mon, 01 Nov 2004
|
126
|
+
#
|
112
127
|
def advance(options)
|
113
128
|
d = self
|
114
129
|
|
@@ -15,7 +15,18 @@ class Date
|
|
15
15
|
strftime(formatter)
|
16
16
|
end
|
17
17
|
elsif format == NOT_SET
|
18
|
-
|
18
|
+
if formatter = DATE_FORMATS[:default]
|
19
|
+
ActiveSupport::Deprecation.warn(
|
20
|
+
"Using a :default format for Date#to_s is deprecated. Please use Date#to_fs instead."
|
21
|
+
)
|
22
|
+
if formatter.respond_to?(:call)
|
23
|
+
formatter.call(self).to_s
|
24
|
+
else
|
25
|
+
strftime(formatter)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
to_default_s
|
29
|
+
end
|
19
30
|
else
|
20
31
|
ActiveSupport::Deprecation.warn(
|
21
32
|
"Date#to_s(#{format.inspect}) is deprecated. Please use Date#to_fs(#{format.inspect}) instead."
|
@@ -75,6 +75,10 @@ class DateTime
|
|
75
75
|
# The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
|
76
76
|
# <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
|
77
77
|
# <tt>:minutes</tt>, <tt>:seconds</tt>.
|
78
|
+
#
|
79
|
+
# Just like Date#advance, increments are applied in order of time units from
|
80
|
+
# largest to smallest. This order can affect the result around the end of a
|
81
|
+
# month.
|
78
82
|
def advance(options)
|
79
83
|
unless options[:weeks].nil?
|
80
84
|
options[:weeks], partial_weeks = options[:weeks].divmod(1)
|
@@ -11,7 +11,18 @@ class DateTime
|
|
11
11
|
)
|
12
12
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
13
13
|
elsif format == NOT_SET
|
14
|
-
|
14
|
+
if formatter = ::Time::DATE_FORMATS[:default]
|
15
|
+
ActiveSupport::Deprecation.warn(
|
16
|
+
"Using a :default format for DateTime#to_s is deprecated. Please use DateTime#to_fs instead."
|
17
|
+
)
|
18
|
+
if formatter.respond_to?(:call)
|
19
|
+
formatter.call(self).to_s
|
20
|
+
else
|
21
|
+
strftime(formatter)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
to_default_s
|
25
|
+
end
|
15
26
|
else
|
16
27
|
ActiveSupport::Deprecation.warn(
|
17
28
|
"DateTime#to_s(#{format.inspect}) is deprecated. Please use DateTime#to_fs(#{format.inspect}) instead."
|
@@ -55,12 +55,12 @@ module Enumerable
|
|
55
55
|
|
56
56
|
# Calculates a sum from the elements.
|
57
57
|
#
|
58
|
-
#
|
59
|
-
#
|
58
|
+
# payments.sum { |p| p.price * p.tax_rate }
|
59
|
+
# payments.sum(&:price)
|
60
60
|
#
|
61
61
|
# The latter is a shortcut for:
|
62
62
|
#
|
63
|
-
#
|
63
|
+
# payments.inject(0) { |sum, p| sum + p.price }
|
64
64
|
#
|
65
65
|
# It can also calculate the sum without the use of a block.
|
66
66
|
#
|
@@ -76,19 +76,24 @@ module Enumerable
|
|
76
76
|
_original_sum_with_required_identity(identity, &block)
|
77
77
|
elsif block_given?
|
78
78
|
map(&block).sum
|
79
|
-
# we check `first(1) == []` to check if we have an
|
80
|
-
# empty Enumerable; checking `empty?` would return
|
81
|
-
# true for `[nil]`, which we want to deprecate to
|
82
|
-
# keep consistent with Ruby
|
83
|
-
elsif first.is_a?(Numeric) || first(1) == []
|
84
|
-
identity ||= 0
|
85
|
-
_original_sum_with_required_identity(identity, &block)
|
86
79
|
else
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
80
|
+
first = true
|
81
|
+
|
82
|
+
reduce(nil) do |sum, value|
|
83
|
+
if first
|
84
|
+
first = false
|
85
|
+
|
86
|
+
unless value.is_a?(Numeric) || value.respond_to?(:coerce)
|
87
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
88
|
+
Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4.
|
89
|
+
Sum of non-numeric elements requires an initial argument.
|
90
|
+
MSG
|
91
|
+
end
|
92
|
+
value
|
93
|
+
else
|
94
|
+
sum + value
|
95
|
+
end
|
96
|
+
end || 0
|
92
97
|
end
|
93
98
|
end
|
94
99
|
|
@@ -144,8 +149,8 @@ module Enumerable
|
|
144
149
|
def many?
|
145
150
|
cnt = 0
|
146
151
|
if block_given?
|
147
|
-
any? do |
|
148
|
-
cnt += 1 if yield
|
152
|
+
any? do |*args|
|
153
|
+
cnt += 1 if yield(*args)
|
149
154
|
cnt > 1
|
150
155
|
end
|
151
156
|
else
|
@@ -225,8 +230,8 @@ module Enumerable
|
|
225
230
|
# [1, "", nil, 2, " ", [], {}, false, true].compact_blank
|
226
231
|
# # => [1, 2, true]
|
227
232
|
#
|
228
|
-
# Set.new([nil, "", 1,
|
229
|
-
# # => [
|
233
|
+
# Set.new([nil, "", 1, false]).compact_blank
|
234
|
+
# # => [1]
|
230
235
|
#
|
231
236
|
# When called on a +Hash+, returns a new +Hash+ without the blank values.
|
232
237
|
#
|
@@ -245,7 +250,7 @@ module Enumerable
|
|
245
250
|
# If the +series+ include keys that have no corresponding element in the Enumerable, these are ignored.
|
246
251
|
# If the Enumerable has additional elements that aren't named in the +series+, these are not included in the result.
|
247
252
|
def in_order_of(key, series)
|
248
|
-
|
253
|
+
group_by(&key).values_at(*series).flatten(1).compact
|
249
254
|
end
|
250
255
|
|
251
256
|
# Returns the sole item in the enumerable. If there are no items, or more
|
@@ -5,10 +5,10 @@ class Hash
|
|
5
5
|
# This includes the values from the root hash and from all
|
6
6
|
# nested hashes and arrays.
|
7
7
|
#
|
8
|
-
#
|
8
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
10
|
+
# hash.deep_transform_values{ |value| value.to_s.upcase }
|
11
|
+
# # => {person: {name: "ROB", age: "28"}}
|
12
12
|
def deep_transform_values(&block)
|
13
13
|
_deep_transform_values_in_object(self, &block)
|
14
14
|
end
|
@@ -58,10 +58,10 @@ class Hash
|
|
58
58
|
# This includes the keys from the root hash and from all
|
59
59
|
# nested hashes and arrays.
|
60
60
|
#
|
61
|
-
#
|
61
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
62
62
|
#
|
63
|
-
#
|
64
|
-
#
|
63
|
+
# hash.deep_transform_keys{ |key| key.to_s.upcase }
|
64
|
+
# # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
|
65
65
|
def deep_transform_keys(&block)
|
66
66
|
_deep_transform_keys_in_object(self, &block)
|
67
67
|
end
|
@@ -6,12 +6,12 @@ class Integer
|
|
6
6
|
# Ordinalize turns a number into an ordinal string used to denote the
|
7
7
|
# position in an ordered sequence such as 1st, 2nd, 3rd, 4th.
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
9
|
+
# 1.ordinalize # => "1st"
|
10
|
+
# 2.ordinalize # => "2nd"
|
11
|
+
# 1002.ordinalize # => "1002nd"
|
12
|
+
# 1003.ordinalize # => "1003rd"
|
13
|
+
# -11.ordinalize # => "-11th"
|
14
|
+
# -1001.ordinalize # => "-1001st"
|
15
15
|
def ordinalize
|
16
16
|
ActiveSupport::Inflector.ordinalize(self)
|
17
17
|
end
|
@@ -19,12 +19,12 @@ class Integer
|
|
19
19
|
# Ordinal returns the suffix used to denote the position
|
20
20
|
# in an ordered sequence such as 1st, 2nd, 3rd, 4th.
|
21
21
|
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
22
|
+
# 1.ordinal # => "st"
|
23
|
+
# 2.ordinal # => "nd"
|
24
|
+
# 1002.ordinal # => "nd"
|
25
|
+
# 1003.ordinal # => "rd"
|
26
|
+
# -11.ordinal # => "th"
|
27
|
+
# -1001.ordinal # => "st"
|
28
28
|
def ordinal
|
29
29
|
ActiveSupport::Inflector.ordinal(self)
|
30
30
|
end
|
@@ -31,8 +31,8 @@ end
|
|
31
31
|
class Method
|
32
32
|
# Methods are not duplicable:
|
33
33
|
#
|
34
|
-
#
|
35
|
-
#
|
34
|
+
# method(:puts).duplicable? # => false
|
35
|
+
# method(:puts).dup # => TypeError: allocator undefined for Method
|
36
36
|
def duplicable?
|
37
37
|
false
|
38
38
|
end
|
@@ -41,8 +41,8 @@ end
|
|
41
41
|
class UnboundMethod
|
42
42
|
# Unbound methods are not duplicable:
|
43
43
|
#
|
44
|
-
#
|
45
|
-
#
|
44
|
+
# method(:puts).unbind.duplicable? # => false
|
45
|
+
# method(:puts).unbind.dup # => TypeError: allocator undefined for UnboundMethod
|
46
46
|
def duplicable?
|
47
47
|
false
|
48
48
|
end
|
@@ -53,7 +53,7 @@ require "singleton"
|
|
53
53
|
module Singleton
|
54
54
|
# Singleton instances are not duplicable:
|
55
55
|
#
|
56
|
-
#
|
56
|
+
# Class.new.include(Singleton).instance.dup # TypeError (can't dup instance of singleton
|
57
57
|
def duplicable?
|
58
58
|
false
|
59
59
|
end
|
@@ -72,8 +72,6 @@ class Hash
|
|
72
72
|
#
|
73
73
|
# The string pairs "key=value" that conform the query string
|
74
74
|
# are sorted lexicographically in ascending order.
|
75
|
-
#
|
76
|
-
# This method is also aliased as +to_param+.
|
77
75
|
def to_query(namespace = nil)
|
78
76
|
query = filter_map do |key, value|
|
79
77
|
unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
|
@@ -64,7 +64,7 @@ class Object
|
|
64
64
|
#
|
65
65
|
# Hence the inherited default for +if+ key is ignored.
|
66
66
|
#
|
67
|
-
# NOTE: You cannot call class methods implicitly inside of with_options
|
67
|
+
# NOTE: You cannot call class methods implicitly inside of +with_options+.
|
68
68
|
# You can access these methods using the class name instead:
|
69
69
|
#
|
70
70
|
# class Phone < ActiveRecord::Base
|
@@ -83,11 +83,11 @@ class Object
|
|
83
83
|
# end
|
84
84
|
# end
|
85
85
|
#
|
86
|
-
#
|
87
|
-
# #
|
86
|
+
# styled.link_to "I'm red", "/"
|
87
|
+
# # => <a href="/" style="color: red;">I'm red</a>
|
88
88
|
#
|
89
|
-
#
|
90
|
-
# #
|
89
|
+
# styled.button_tag "I'm red too!"
|
90
|
+
# # => <button style="color: red;">I'm red too!</button>
|
91
91
|
#
|
92
92
|
def with_options(options, &block)
|
93
93
|
option_merger = ActiveSupport::OptionMerger.new(self, options)
|
@@ -10,7 +10,14 @@ module ActiveSupport
|
|
10
10
|
)
|
11
11
|
formatter.call(first, last)
|
12
12
|
elsif format == NOT_SET
|
13
|
-
|
13
|
+
if formatter = RangeWithFormat::RANGE_FORMATS[:default]
|
14
|
+
ActiveSupport::Deprecation.warn(
|
15
|
+
"Using a :default format for Range#to_s is deprecated. Please use Range#to_fs instead."
|
16
|
+
)
|
17
|
+
formatter.call(first, last)
|
18
|
+
else
|
19
|
+
super()
|
20
|
+
end
|
14
21
|
else
|
15
22
|
ActiveSupport::Deprecation.warn(
|
16
23
|
"Range#to_s(#{format.inspect}) is deprecated. Please use Range#to_fs(#{format.inspect}) instead."
|
@@ -97,8 +97,6 @@ class String
|
|
97
97
|
# 'active_record/errors'.camelize # => "ActiveRecord::Errors"
|
98
98
|
# 'active_record/errors'.camelize(:lower) # => "activeRecord::Errors"
|
99
99
|
#
|
100
|
-
# +camelize+ is also aliased as +camelcase+.
|
101
|
-
#
|
102
100
|
# See ActiveSupport::Inflector.camelize.
|
103
101
|
def camelize(first_letter = :upper)
|
104
102
|
case first_letter
|
@@ -124,8 +122,6 @@ class String
|
|
124
122
|
# 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
|
125
123
|
# 'string_ending_with_id'.titleize(keep_id_suffix: true) # => "String Ending With Id"
|
126
124
|
#
|
127
|
-
# +titleize+ is also aliased as +titlecase+.
|
128
|
-
#
|
129
125
|
# See ActiveSupport::Inflector.titleize.
|
130
126
|
def titleize(keep_id_suffix: false)
|
131
127
|
ActiveSupport::Inflector.titleize(self, keep_id_suffix: keep_id_suffix)
|
@@ -219,6 +219,10 @@ module ActiveSupport # :nodoc:
|
|
219
219
|
end
|
220
220
|
alias << concat
|
221
221
|
|
222
|
+
def bytesplice(*args, value)
|
223
|
+
super(*args, implicit_html_escape_interpolated_argument(value))
|
224
|
+
end
|
225
|
+
|
222
226
|
def insert(index, value)
|
223
227
|
super(index, implicit_html_escape_interpolated_argument(value))
|
224
228
|
end
|
@@ -179,6 +179,10 @@ class Time
|
|
179
179
|
# Time.new(2015, 8, 1, 14, 35, 0).advance(hours: 1) # => 2015-08-01 15:35:00 -0700
|
180
180
|
# Time.new(2015, 8, 1, 14, 35, 0).advance(days: 1) # => 2015-08-02 14:35:00 -0700
|
181
181
|
# Time.new(2015, 8, 1, 14, 35, 0).advance(weeks: 1) # => 2015-08-08 14:35:00 -0700
|
182
|
+
#
|
183
|
+
# Just like Date#advance, increments are applied in order of time units from
|
184
|
+
# largest to smallest. This order can affect the result around the end of a
|
185
|
+
# month.
|
182
186
|
def advance(options)
|
183
187
|
unless options[:weeks].nil?
|
184
188
|
options[:weeks], partial_weeks = options[:weeks].divmod(1)
|
@@ -11,7 +11,18 @@ class Time
|
|
11
11
|
)
|
12
12
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
13
13
|
elsif format == NOT_SET
|
14
|
-
|
14
|
+
if formatter = ::Time::DATE_FORMATS[:default]
|
15
|
+
ActiveSupport::Deprecation.warn(
|
16
|
+
"Using a :default format for Time#to_s is deprecated. Please use Time#to_fs instead."
|
17
|
+
)
|
18
|
+
if formatter.respond_to?(:call)
|
19
|
+
formatter.call(self).to_s
|
20
|
+
else
|
21
|
+
strftime(formatter)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
to_default_s
|
25
|
+
end
|
15
26
|
else
|
16
27
|
ActiveSupport::Deprecation.warn(
|
17
28
|
"Time#to_s(#{format.inspect}) is deprecated. Please use Time#to_fs(#{format.inspect}) instead."
|
@@ -49,10 +49,9 @@ class Time
|
|
49
49
|
# around_action :set_time_zone
|
50
50
|
#
|
51
51
|
# private
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# end
|
52
|
+
# def set_time_zone
|
53
|
+
# Time.use_zone(current_user.timezone) { yield }
|
54
|
+
# end
|
56
55
|
# end
|
57
56
|
#
|
58
57
|
# NOTE: This won't affect any ActiveSupport::TimeWithZone
|
@@ -5,15 +5,15 @@ module ActiveSupport
|
|
5
5
|
module Disallowed
|
6
6
|
# Sets the criteria used to identify deprecation messages which should be
|
7
7
|
# disallowed. Can be an array containing strings, symbols, or regular
|
8
|
-
# expressions. (Symbols are treated as strings)
|
8
|
+
# expressions. (Symbols are treated as strings.) These are compared against
|
9
9
|
# the text of the generated deprecation warning.
|
10
10
|
#
|
11
11
|
# Additionally the scalar symbol +:all+ may be used to treat all
|
12
12
|
# deprecations as disallowed.
|
13
13
|
#
|
14
14
|
# Deprecations matching a substring or regular expression will be handled
|
15
|
-
# using the configured
|
16
|
-
#
|
15
|
+
# using the configured Behavior#disallowed_behavior rather than
|
16
|
+
# Behavior#behavior.
|
17
17
|
attr_writer :disallowed_warnings
|
18
18
|
|
19
19
|
# Returns the configured criteria used to identify deprecation messages
|
@@ -7,6 +7,28 @@ require "active_support/core_ext/object/inclusion"
|
|
7
7
|
require "active_support/core_ext/module/delegation"
|
8
8
|
|
9
9
|
module ActiveSupport
|
10
|
+
# Provides convenience methods on top of EncryptedFile to access values stored
|
11
|
+
# as encrypted YAML.
|
12
|
+
#
|
13
|
+
# Values can be accessed via +Hash+ methods, such as +fetch+ and +dig+, or via
|
14
|
+
# dynamic accessor methods, similar to OrderedOptions.
|
15
|
+
#
|
16
|
+
# my_config = ActiveSupport::EncryptedConfiguration.new(...)
|
17
|
+
# my_config.read # => "some_secret: 123\nsome_namespace:\n another_secret: 456"
|
18
|
+
#
|
19
|
+
# my_config[:some_secret]
|
20
|
+
# # => 123
|
21
|
+
# my_config.some_secret
|
22
|
+
# # => 123
|
23
|
+
# my_config.dig(:some_namespace, :another_secret)
|
24
|
+
# # => 456
|
25
|
+
# my_config.some_namespace.another_secret
|
26
|
+
# # => 456
|
27
|
+
# my_config.fetch(:foo)
|
28
|
+
# # => KeyError
|
29
|
+
# my_config.foo!
|
30
|
+
# # => KeyError
|
31
|
+
#
|
10
32
|
class EncryptedConfiguration < EncryptedFile
|
11
33
|
delegate :[], :fetch, to: :config
|
12
34
|
delegate_missing_to :options
|
@@ -16,10 +38,11 @@ module ActiveSupport
|
|
16
38
|
env_key: env_key, raise_if_missing_key: raise_if_missing_key
|
17
39
|
end
|
18
40
|
|
19
|
-
#
|
41
|
+
# Reads the file and returns the decrypted content. See EncryptedFile#read.
|
20
42
|
def read
|
21
43
|
super
|
22
44
|
rescue ActiveSupport::EncryptedFile::MissingContentError
|
45
|
+
# Allow a config to be started without a file present
|
23
46
|
""
|
24
47
|
end
|
25
48
|
|
@@ -29,6 +52,14 @@ module ActiveSupport
|
|
29
52
|
super
|
30
53
|
end
|
31
54
|
|
55
|
+
# Returns the decrypted content as a Hash with symbolized keys.
|
56
|
+
#
|
57
|
+
# my_config = ActiveSupport::EncryptedConfiguration.new(...)
|
58
|
+
# my_config.read # => "some_secret: 123\nsome_namespace:\n another_secret: 456"
|
59
|
+
#
|
60
|
+
# my_config.config
|
61
|
+
# # => { some_secret: 123, some_namespace: { another_secret: 789 } }
|
62
|
+
#
|
32
63
|
def config
|
33
64
|
@config ||= deserialize(read).deep_symbolize_keys
|
34
65
|
end
|
@@ -45,7 +76,7 @@ module ActiveSupport
|
|
45
76
|
end
|
46
77
|
|
47
78
|
def options
|
48
|
-
@options ||=
|
79
|
+
@options ||= deep_transform(config)
|
49
80
|
end
|
50
81
|
|
51
82
|
def deserialize(config)
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
gem "listen", "~> 3.5"
|
4
|
+
require "listen"
|
5
|
+
|
3
6
|
require "set"
|
4
7
|
require "pathname"
|
5
8
|
require "concurrent/atomic/atomic_boolean"
|
6
|
-
require "listen"
|
7
9
|
require "active_support/fork_tracker"
|
8
10
|
|
9
11
|
module ActiveSupport
|
@@ -43,6 +45,10 @@ module ActiveSupport
|
|
43
45
|
ObjectSpace.define_finalizer(self, @core.finalizer)
|
44
46
|
end
|
45
47
|
|
48
|
+
def inspect
|
49
|
+
"#<ActiveSupport::EventedFileUpdateChecker:#{object_id} @files=#{@core.files.to_a.inspect}"
|
50
|
+
end
|
51
|
+
|
46
52
|
def updated?
|
47
53
|
if @core.restart?
|
48
54
|
@core.thread_safely(&:restart)
|
@@ -66,7 +72,7 @@ module ActiveSupport
|
|
66
72
|
end
|
67
73
|
|
68
74
|
class Core
|
69
|
-
attr_reader :updated
|
75
|
+
attr_reader :updated, :files
|
70
76
|
|
71
77
|
def initialize(files, dirs)
|
72
78
|
@files = files.map { |file| Pathname(file).expand_path }.to_set
|
@@ -84,6 +90,10 @@ module ActiveSupport
|
|
84
90
|
@mutex = Mutex.new
|
85
91
|
|
86
92
|
start
|
93
|
+
# inotify / FSEvents file descriptors are inherited on fork, so
|
94
|
+
# we need to reopen them otherwise only the parent or the child
|
95
|
+
# will be notified.
|
96
|
+
# FIXME: this callback is keeping a reference on the instance
|
87
97
|
@after_fork = ActiveSupport::ForkTracker.after_fork { start }
|
88
98
|
end
|
89
99
|
|
@@ -105,6 +115,11 @@ module ActiveSupport
|
|
105
115
|
@dtw, @missing = [*@dtw, *@missing].partition(&:exist?)
|
106
116
|
@listener = @dtw.any? ? Listen.to(*@dtw, &method(:changed)) : nil
|
107
117
|
@listener&.start
|
118
|
+
|
119
|
+
# Wait for the listener to be ready to avoid race conditions
|
120
|
+
# Unfortunately this isn't quite enough on macOS because the Darwin backend
|
121
|
+
# has an extra private thread we can't wait on.
|
122
|
+
@listener&.wait_for_state(:processing_events)
|
108
123
|
end
|
109
124
|
|
110
125
|
def stop
|
@@ -136,7 +136,7 @@ module ActiveSupport
|
|
136
136
|
|
137
137
|
result.tr!("_", " ")
|
138
138
|
result.lstrip!
|
139
|
-
|
139
|
+
if !keep_id_suffix && lower_case_and_underscored_word&.end_with?("_id")
|
140
140
|
result.delete_suffix!(" id")
|
141
141
|
end
|
142
142
|
|
@@ -172,8 +172,6 @@ module ActiveSupport
|
|
172
172
|
# optional parameter +keep_id_suffix+ to true.
|
173
173
|
# By default, this parameter is false.
|
174
174
|
#
|
175
|
-
# +titleize+ is also aliased as +titlecase+.
|
176
|
-
#
|
177
175
|
# titleize('man from the boondocks') # => "Man From The Boondocks"
|
178
176
|
# titleize('x-men: the last stand') # => "X Men: The Last Stand"
|
179
177
|
# titleize('TheManWithoutAPast') # => "The Man Without A Past"
|
@@ -196,8 +194,8 @@ module ActiveSupport
|
|
196
194
|
end
|
197
195
|
|
198
196
|
# Creates a class name from a plural table name like Rails does for table
|
199
|
-
# names to models. Note that this returns a string and not a Class (To
|
200
|
-
# convert to an actual class follow +classify+ with #constantize)
|
197
|
+
# names to models. Note that this returns a string and not a Class. (To
|
198
|
+
# convert to an actual class follow +classify+ with #constantize.)
|
201
199
|
#
|
202
200
|
# classify('ham_and_eggs') # => "HamAndEgg"
|
203
201
|
# classify('posts') # => "Post"
|
@@ -361,8 +359,8 @@ module ActiveSupport
|
|
361
359
|
# If passed an optional +locale+ parameter, the uncountables will be
|
362
360
|
# found for that locale.
|
363
361
|
#
|
364
|
-
#
|
365
|
-
#
|
362
|
+
# apply_inflections('post', inflections.plurals, :en) # => "posts"
|
363
|
+
# apply_inflections('posts', inflections.singulars, :en) # => "post"
|
366
364
|
def apply_inflections(word, rules, locale = :en)
|
367
365
|
result = word.to_s.dup
|
368
366
|
|
@@ -66,7 +66,7 @@ module ActiveSupport
|
|
66
66
|
# Executes all blocks registered to +name+ via on_load, using +base+ as the
|
67
67
|
# evaluation context.
|
68
68
|
#
|
69
|
-
#
|
69
|
+
# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
|
70
70
|
#
|
71
71
|
# In the case of the above example, it will execute all hooks registered
|
72
72
|
# for +:active_record+ within the class +ActiveRecord::Base+.
|
@@ -237,8 +237,8 @@ module ActiveSupport
|
|
237
237
|
#
|
238
238
|
# Raises an error if invalid event name type is passed:
|
239
239
|
#
|
240
|
-
#
|
241
|
-
#
|
240
|
+
# ActiveSupport::Notifications.subscribe(:render) {|*args| ...}
|
241
|
+
# #=> ArgumentError (pattern must be specified as a String, Regexp or empty)
|
242
242
|
#
|
243
243
|
def subscribe(pattern = nil, callback = nil, &block)
|
244
244
|
notifier.subscribe(pattern, callback, monotonic: false, &block)
|
@@ -358,13 +358,14 @@ module ActiveSupport
|
|
358
358
|
# out by default (set <tt>:strip_insignificant_zeros</tt> to
|
359
359
|
# +false+ to change that):
|
360
360
|
#
|
361
|
-
#
|
362
|
-
#
|
361
|
+
# number_to_human(12.00001) # => "12"
|
362
|
+
# number_to_human(12.00001, strip_insignificant_zeros: false) # => "12.0"
|
363
363
|
#
|
364
364
|
# ==== Custom Unit Quantifiers
|
365
365
|
#
|
366
366
|
# You can also use your own custom unit quantifiers:
|
367
|
-
#
|
367
|
+
#
|
368
|
+
# number_to_human(500000, units: { unit: 'ml', thousand: 'lt' }) # => "500 lt"
|
368
369
|
#
|
369
370
|
# If in your I18n locale you have:
|
370
371
|
#
|
@@ -3,32 +3,36 @@
|
|
3
3
|
require "active_support/core_ext/object/duplicable"
|
4
4
|
|
5
5
|
module ActiveSupport
|
6
|
-
# +ParameterFilter+
|
7
|
-
#
|
8
|
-
# sub-keys from a hash is possible by using the dot notation:
|
9
|
-
# 'credit_card.number'. If a proc is given, each key and value of a hash and
|
10
|
-
# all sub-hashes are passed to it, where the value or the key can be replaced
|
11
|
-
# using String#replace or similar methods.
|
6
|
+
# +ParameterFilter+ replaces values in a <tt>Hash</tt>-like object if their
|
7
|
+
# keys match one of the specified filters.
|
12
8
|
#
|
9
|
+
# Matching based on nested keys is possible by using dot notation, e.g.
|
10
|
+
# <tt>"credit_card.number"</tt>.
|
11
|
+
#
|
12
|
+
# If a proc is given as a filter, each key and value of the <tt>Hash</tt>-like
|
13
|
+
# and of any nested <tt>Hash</tt>es will be passed to it. The value or key can
|
14
|
+
# then be mutated as desired using methods such as <tt>String#replace</tt>.
|
15
|
+
#
|
16
|
+
# # Replaces values with "[FILTERED]" for keys that match /password/i.
|
13
17
|
# ActiveSupport::ParameterFilter.new([:password])
|
14
|
-
# => replaces the value to all keys matching /password/i with "[FILTERED]"
|
15
18
|
#
|
19
|
+
# # Replaces values with "[FILTERED]" for keys that match /foo|bar/i.
|
16
20
|
# ActiveSupport::ParameterFilter.new([:foo, "bar"])
|
17
|
-
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
18
21
|
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
22
|
+
# # Replaces values for the exact key "pin" and for keys that begin with
|
23
|
+
# # "pin_". Does not match keys that otherwise include "pin" as a
|
24
|
+
# # substring, such as "shipping_id".
|
25
|
+
# ActiveSupport::ParameterFilter.new([/\Apin\z/, /\Apin_/])
|
23
26
|
#
|
27
|
+
# # Replaces the value for :code in `{ credit_card: { code: "xxxx" } }`.
|
28
|
+
# # Does not change `{ file: { code: "xxxx" } }`.
|
24
29
|
# ActiveSupport::ParameterFilter.new(["credit_card.code"])
|
25
|
-
# => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
|
26
|
-
# change { file: { code: "xxxx"} }
|
27
30
|
#
|
31
|
+
# # Reverses values for keys that match /secret/i.
|
28
32
|
# ActiveSupport::ParameterFilter.new([-> (k, v) do
|
29
33
|
# v.reverse! if /secret/i.match?(k)
|
30
34
|
# end])
|
31
|
-
#
|
35
|
+
#
|
32
36
|
class ParameterFilter
|
33
37
|
FILTERED = "[FILTERED]" # :nodoc:
|
34
38
|
|
@@ -25,38 +25,39 @@ module ActiveSupport
|
|
25
25
|
|
26
26
|
module Forking
|
27
27
|
def run_in_isolation(&blk)
|
28
|
-
read, write
|
29
|
-
|
30
|
-
|
28
|
+
IO.pipe do |read, write|
|
29
|
+
read.binmode
|
30
|
+
write.binmode
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
32
|
+
pid = fork do
|
33
|
+
read.close
|
34
|
+
yield
|
35
|
+
begin
|
36
|
+
if error?
|
37
|
+
failures.map! { |e|
|
38
|
+
begin
|
39
|
+
Marshal.dump e
|
40
|
+
e
|
41
|
+
rescue TypeError
|
42
|
+
ex = Exception.new e.message
|
43
|
+
ex.set_backtrace e.backtrace
|
44
|
+
Minitest::UnexpectedError.new ex
|
45
|
+
end
|
46
|
+
}
|
47
|
+
end
|
48
|
+
test_result = defined?(Minitest::Result) ? Minitest::Result.from(self) : dup
|
49
|
+
result = Marshal.dump(test_result)
|
47
50
|
end
|
48
|
-
|
49
|
-
result
|
51
|
+
|
52
|
+
write.puts [result].pack("m")
|
53
|
+
exit!
|
50
54
|
end
|
51
55
|
|
52
|
-
write.
|
53
|
-
|
56
|
+
write.close
|
57
|
+
result = read.read
|
58
|
+
Process.wait2(pid)
|
59
|
+
result.unpack1("m")
|
54
60
|
end
|
55
|
-
|
56
|
-
write.close
|
57
|
-
result = read.read
|
58
|
-
Process.wait2(pid)
|
59
|
-
result.unpack1("m")
|
60
61
|
end
|
61
62
|
end
|
62
63
|
|
@@ -221,7 +221,14 @@ module ActiveSupport
|
|
221
221
|
)
|
222
222
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
223
223
|
elsif format == NOT_SET
|
224
|
-
|
224
|
+
if formatter = ::Time::DATE_FORMATS[:default]
|
225
|
+
ActiveSupport::Deprecation.warn(
|
226
|
+
"Using a :default format for TimeWithZone#to_s is deprecated. Please use TimeWithZone#to_fs instead."
|
227
|
+
)
|
228
|
+
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
229
|
+
else
|
230
|
+
"#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
|
231
|
+
end
|
225
232
|
else
|
226
233
|
ActiveSupport::Deprecation.warn(
|
227
234
|
"TimeWithZone#to_s(#{format.inspect}) is deprecated. Please use TimeWithZone#to_fs(#{format.inspect}) instead."
|
@@ -566,8 +573,8 @@ module ActiveSupport
|
|
566
573
|
|
567
574
|
# Send the missing method to +time+ instance, and wrap result in a new
|
568
575
|
# TimeWithZone with the existing +time_zone+.
|
569
|
-
def method_missing(
|
570
|
-
wrap_with_time_zone time.__send__(
|
576
|
+
def method_missing(...)
|
577
|
+
wrap_with_time_zone time.__send__(...)
|
571
578
|
rescue NoMethodError => e
|
572
579
|
raise e, e.message.sub(time.inspect, inspect).sub("Time", "ActiveSupport::TimeWithZone"), e.backtrace
|
573
580
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activesupport
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.
|
4
|
+
version: 7.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|
@@ -359,10 +359,10 @@ licenses:
|
|
359
359
|
- MIT
|
360
360
|
metadata:
|
361
361
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
362
|
-
changelog_uri: https://github.com/rails/rails/blob/v7.0.
|
363
|
-
documentation_uri: https://api.rubyonrails.org/v7.0.
|
362
|
+
changelog_uri: https://github.com/rails/rails/blob/v7.0.7/activesupport/CHANGELOG.md
|
363
|
+
documentation_uri: https://api.rubyonrails.org/v7.0.7/
|
364
364
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
365
|
-
source_code_uri: https://github.com/rails/rails/tree/v7.0.
|
365
|
+
source_code_uri: https://github.com/rails/rails/tree/v7.0.7/activesupport
|
366
366
|
rubygems_mfa_required: 'true'
|
367
367
|
post_install_message:
|
368
368
|
rdoc_options:
|
@@ -381,7 +381,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
381
381
|
- !ruby/object:Gem::Version
|
382
382
|
version: '0'
|
383
383
|
requirements: []
|
384
|
-
rubygems_version: 3.4.
|
384
|
+
rubygems_version: 3.4.10
|
385
385
|
signing_key:
|
386
386
|
specification_version: 4
|
387
387
|
summary: A toolkit of support libraries and Ruby core extensions extracted from the
|