activesupport 7.0.4.3 → 7.0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +77 -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/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/encrypted_file.rb +8 -9
- 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: 04536a88c7cef8a70a74892d515e186b52035d5173af41840637b2ed9bad4d47
|
4
|
+
data.tar.gz: 68814229938ebce3a9500a6dac0d5db7ad70ba1b9ff75bf784c1006a72f66fb3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6817bb1e03d8ff97bcfbc6dd933e622a1bb8c220de50c30d435e9e53f7f2dbb26f4bfa289fc3da8384d13d5bf7528539eff53299d28e0da83ce96500e2385e10
|
7
|
+
data.tar.gz: 90a083d63440b72339b96cbd0aeade50b73907fc41157666fccf1b4bd02b86865972d98388f591c749f371c2d4a353c7e8d489cbefdc2f548a4da3030ace8b4e
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,67 @@
|
|
1
|
+
## Rails 7.0.7.2 (August 22, 2023) ##
|
2
|
+
|
3
|
+
* No changes.
|
4
|
+
|
5
|
+
|
6
|
+
## Rails 7.0.7.1 (August 22, 2023) ##
|
7
|
+
|
8
|
+
* Use a temporary file for storing unencrypted files while editing
|
9
|
+
|
10
|
+
[CVE-2023-38037]
|
11
|
+
|
12
|
+
|
13
|
+
## Rails 7.0.7 (August 09, 2023) ##
|
14
|
+
|
15
|
+
* Fix `Cache::NullStore` with local caching for repeated reads.
|
16
|
+
|
17
|
+
*fatkodima*
|
18
|
+
|
19
|
+
* Fix `to_s` with no arguments not respecting custom `:default` formats
|
20
|
+
|
21
|
+
*Hartley McGuire*
|
22
|
+
|
23
|
+
* Fix `ActiveSupport::Inflector.humanize(nil)` raising ``NoMethodError: undefined method `end_with?' for nil:NilClass``.
|
24
|
+
|
25
|
+
*James Robinson*
|
26
|
+
|
27
|
+
* Fix `Enumerable#sum` for `Enumerator#lazy`.
|
28
|
+
|
29
|
+
*fatkodima*, *Matthew Draper*, *Jonathan Hefner*
|
30
|
+
|
31
|
+
* Improve error message when EventedFileUpdateChecker is used without a
|
32
|
+
compatible version of the Listen gem
|
33
|
+
|
34
|
+
*Hartley McGuire*
|
35
|
+
|
36
|
+
|
37
|
+
## Rails 7.0.6 (June 29, 2023) ##
|
38
|
+
|
39
|
+
* Fix `EncryptedConfiguration` returning incorrect values for some `Hash`
|
40
|
+
methods
|
41
|
+
|
42
|
+
*Hartley McGuire*
|
43
|
+
|
44
|
+
* Fix arguments being destructed `Enumerable#many?` with block.
|
45
|
+
|
46
|
+
*Andrew Novoselac*
|
47
|
+
|
48
|
+
* Fix humanize for strings ending with id.
|
49
|
+
|
50
|
+
*fatkodima*
|
51
|
+
|
52
|
+
|
53
|
+
## Rails 7.0.5.1 (June 26, 2023) ##
|
54
|
+
|
55
|
+
* No changes.
|
56
|
+
|
57
|
+
|
58
|
+
## Rails 7.0.5 (May 24, 2023) ##
|
59
|
+
|
60
|
+
* Fixes TimeWithZone ArgumentError.
|
61
|
+
|
62
|
+
*Niklas Häusele*
|
63
|
+
|
64
|
+
|
1
65
|
## Rails 7.0.4.3 (March 13, 2023) ##
|
2
66
|
|
3
67
|
* Implement SafeBuffer#bytesplice
|
@@ -19,6 +83,19 @@
|
|
19
83
|
|
20
84
|
## Rails 7.0.4 (September 09, 2022) ##
|
21
85
|
|
86
|
+
* Ensure `ActiveSupport::Testing::Isolation::Forking` closes pipes
|
87
|
+
|
88
|
+
Previously, `Forking.run_in_isolation` opened two ends of a pipe. The fork
|
89
|
+
process closed the read end, wrote to it, and then terminated (which
|
90
|
+
presumably closed the file descriptors on its end). The parent process
|
91
|
+
closed the write end, read from it, and returned, never closing the read
|
92
|
+
end.
|
93
|
+
|
94
|
+
This resulted in an accumulation of open file descriptors, which could
|
95
|
+
cause errors if the limit is reached.
|
96
|
+
|
97
|
+
*Sam Bostock*
|
98
|
+
|
22
99
|
* Redis cache store is now compatible with redis-rb 5.0.
|
23
100
|
|
24
101
|
*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)
|
@@ -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,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "pathname"
|
4
|
-
require "
|
4
|
+
require "tempfile"
|
5
5
|
require "active_support/message_encryptor"
|
6
6
|
|
7
7
|
module ActiveSupport
|
@@ -81,17 +81,16 @@ module ActiveSupport
|
|
81
81
|
|
82
82
|
private
|
83
83
|
def writing(contents)
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
Tempfile.create(["", "-" + content_path.basename.to_s.chomp(".enc")]) do |tmp_file|
|
85
|
+
tmp_path = Pathname.new(tmp_file)
|
86
|
+
tmp_path.binwrite contents
|
87
87
|
|
88
|
-
|
88
|
+
yield tmp_path
|
89
89
|
|
90
|
-
|
90
|
+
updated_contents = tmp_path.binread
|
91
91
|
|
92
|
-
|
93
|
-
|
94
|
-
FileUtils.rm(tmp_path) if tmp_path&.exist?
|
92
|
+
write(updated_contents) if updated_contents != contents
|
93
|
+
end
|
95
94
|
end
|
96
95
|
|
97
96
|
|
@@ -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.2
|
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-22 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.2/activesupport/CHANGELOG.md
|
363
|
+
documentation_uri: https://api.rubyonrails.org/v7.0.7.2/
|
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.2/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.
|
384
|
+
rubygems_version: 3.3.3
|
385
385
|
signing_key:
|
386
386
|
specification_version: 4
|
387
387
|
summary: A toolkit of support libraries and Ruby core extensions extracted from the
|