activesupport 5.2.5 → 6.0.4.6
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 +477 -398
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/backtrace_cleaner.rb +27 -1
- data/lib/active_support/cache/file_store.rb +32 -32
- data/lib/active_support/cache/mem_cache_store.rb +12 -7
- data/lib/active_support/cache/memory_store.rb +15 -9
- data/lib/active_support/cache/null_store.rb +8 -3
- data/lib/active_support/cache/redis_cache_store.rb +47 -20
- data/lib/active_support/cache/strategy/local_cache.rb +22 -22
- data/lib/active_support/cache.rb +71 -48
- data/lib/active_support/callbacks.rb +16 -8
- data/lib/active_support/concern.rb +24 -1
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/share_lock.rb +0 -1
- data/lib/active_support/configurable.rb +7 -11
- data/lib/active_support/core_ext/array/access.rb +18 -6
- data/lib/active_support/core_ext/array/conversions.rb +5 -5
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
- data/lib/active_support/core_ext/array.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +11 -16
- data/lib/active_support/core_ext/class/subclasses.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +6 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
- data/lib/active_support/core_ext/enumerable.rb +97 -73
- data/lib/active_support/core_ext/hash/compact.rb +2 -26
- data/lib/active_support/core_ext/hash/conversions.rb +1 -1
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +2 -2
- data/lib/active_support/core_ext/hash/keys.rb +0 -29
- data/lib/active_support/core_ext/hash/slice.rb +3 -25
- data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
- data/lib/active_support/core_ext/hash.rb +1 -2
- data/lib/active_support/core_ext/integer/multiple.rb +1 -1
- data/lib/active_support/core_ext/kernel.rb +0 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
- data/lib/active_support/core_ext/module/delegation.rb +41 -8
- data/lib/active_support/core_ext/module/introspection.rb +38 -13
- data/lib/active_support/core_ext/module/reachable.rb +1 -6
- data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
- data/lib/active_support/core_ext/module.rb +0 -1
- data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
- data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
- data/lib/active_support/core_ext/numeric.rb +0 -1
- data/lib/active_support/core_ext/object/blank.rb +1 -2
- data/lib/active_support/core_ext/object/duplicable.rb +7 -114
- data/lib/active_support/core_ext/object/json.rb +2 -1
- data/lib/active_support/core_ext/object/try.rb +17 -7
- data/lib/active_support/core_ext/object/with_options.rb +1 -1
- data/lib/active_support/core_ext/range/compare_range.rb +28 -13
- data/lib/active_support/core_ext/range/conversions.rb +31 -29
- data/lib/active_support/core_ext/range/each.rb +0 -1
- data/lib/active_support/core_ext/range/include_range.rb +6 -0
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
- data/lib/active_support/core_ext/regexp.rb +0 -4
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +8 -0
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +7 -2
- data/lib/active_support/core_ext/string/multibyte.rb +4 -3
- data/lib/active_support/core_ext/string/output_safety.rb +68 -10
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/time/calculations.rb +34 -3
- data/lib/active_support/core_ext/uri.rb +1 -0
- data/lib/active_support/current_attributes.rb +8 -0
- data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
- data/lib/active_support/dependencies.rb +74 -18
- data/lib/active_support/deprecation/behaviors.rb +1 -1
- data/lib/active_support/deprecation/method_wrappers.rb +17 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +28 -5
- data/lib/active_support/deprecation.rb +1 -1
- data/lib/active_support/descendants_tracker.rb +55 -9
- data/lib/active_support/duration/iso8601_parser.rb +2 -4
- data/lib/active_support/duration/iso8601_serializer.rb +3 -5
- data/lib/active_support/duration.rb +7 -8
- data/lib/active_support/encrypted_configuration.rb +0 -4
- data/lib/active_support/encrypted_file.rb +3 -2
- data/lib/active_support/evented_file_update_checker.rb +39 -10
- data/lib/active_support/execution_wrapper.rb +17 -13
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/hash_with_indifferent_access.rb +22 -18
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +13 -1
- data/lib/active_support/inflector/inflections.rb +1 -5
- data/lib/active_support/inflector/methods.rb +16 -29
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/json/decoding.rb +23 -24
- data/lib/active_support/json/encoding.rb +6 -2
- data/lib/active_support/key_generator.rb +0 -32
- data/lib/active_support/lazy_load_hooks.rb +5 -2
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/log_subscriber.rb +31 -9
- data/lib/active_support/logger.rb +1 -16
- data/lib/active_support/logger_silence.rb +28 -12
- data/lib/active_support/logger_thread_safe_level.rb +26 -4
- data/lib/active_support/message_encryptor.rb +4 -6
- data/lib/active_support/message_verifier.rb +5 -5
- data/lib/active_support/messages/metadata.rb +11 -2
- data/lib/active_support/messages/rotator.rb +4 -4
- data/lib/active_support/multibyte/chars.rb +29 -49
- data/lib/active_support/multibyte/unicode.rb +44 -282
- data/lib/active_support/notifications/fanout.rb +98 -13
- data/lib/active_support/notifications/instrumenter.rb +80 -9
- data/lib/active_support/notifications.rb +41 -4
- data/lib/active_support/number_helper/number_converter.rb +4 -5
- data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -4
- data/lib/active_support/number_helper/rounding_helper.rb +1 -1
- data/lib/active_support/number_helper.rb +11 -0
- data/lib/active_support/option_merger.rb +21 -3
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +5 -1
- data/lib/active_support/parameter_filter.rb +128 -0
- data/lib/active_support/rails.rb +0 -6
- data/lib/active_support/reloader.rb +5 -6
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/string_inquirer.rb +0 -1
- data/lib/active_support/subscriber.rb +65 -26
- data/lib/active_support/tagged_logging.rb +13 -4
- data/lib/active_support/test_case.rb +91 -0
- data/lib/active_support/testing/assertions.rb +15 -1
- data/lib/active_support/testing/deprecation.rb +0 -1
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +28 -1
- data/lib/active_support/testing/parallelization.rb +134 -0
- data/lib/active_support/testing/stream.rb +1 -2
- data/lib/active_support/testing/time_helpers.rb +7 -9
- data/lib/active_support/time_with_zone.rb +15 -5
- data/lib/active_support/values/time_zone.rb +12 -7
- data/lib/active_support/xml_mini/jdom.rb +2 -3
- data/lib/active_support/xml_mini/libxml.rb +2 -2
- data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
- data/lib/active_support/xml_mini/nokogiri.rb +2 -2
- data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
- data/lib/active_support/xml_mini/rexml.rb +2 -2
- data/lib/active_support/xml_mini.rb +2 -10
- data/lib/active_support.rb +2 -1
- metadata +40 -12
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,39 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module ActiveSupport
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module ActiveSupport
|
4
|
+
module RangeWithFormat
|
5
|
+
RANGE_FORMATS = {
|
6
|
+
db: -> (start, stop) do
|
7
|
+
case start
|
8
|
+
when String then "BETWEEN '#{start}' AND '#{stop}'"
|
9
|
+
else
|
10
|
+
"BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
}
|
14
|
+
|
15
|
+
# Convert range to a formatted string. See RANGE_FORMATS for predefined formats.
|
16
|
+
#
|
17
|
+
# range = (1..100) # => 1..100
|
18
|
+
#
|
19
|
+
# range.to_s # => "1..100"
|
20
|
+
# range.to_s(:db) # => "BETWEEN '1' AND '100'"
|
21
|
+
#
|
22
|
+
# == Adding your own range formats to to_s
|
23
|
+
# You can add your own formats to the Range::RANGE_FORMATS hash.
|
24
|
+
# Use the format name as the hash key and a Proc instance.
|
25
|
+
#
|
26
|
+
# # config/initializers/range_formats.rb
|
27
|
+
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
|
28
|
+
def to_s(format = :default)
|
29
|
+
if formatter = RANGE_FORMATS[format]
|
30
|
+
formatter.call(first, last)
|
8
31
|
else
|
9
|
-
|
32
|
+
super()
|
10
33
|
end
|
11
34
|
end
|
12
|
-
}
|
13
35
|
|
14
|
-
|
15
|
-
|
16
|
-
# range = (1..100) # => 1..100
|
17
|
-
#
|
18
|
-
# range.to_s # => "1..100"
|
19
|
-
# range.to_s(:db) # => "BETWEEN '1' AND '100'"
|
20
|
-
#
|
21
|
-
# == Adding your own range formats to to_s
|
22
|
-
# You can add your own formats to the Range::RANGE_FORMATS hash.
|
23
|
-
# Use the format name as the hash key and a Proc instance.
|
24
|
-
#
|
25
|
-
# # config/initializers/range_formats.rb
|
26
|
-
# Range::RANGE_FORMATS[:short] = ->(start, stop) { "Between #{start.to_s(:db)} and #{stop.to_s(:db)}" }
|
27
|
-
def to_s(format = :default)
|
28
|
-
if formatter = RANGE_FORMATS[format]
|
29
|
-
formatter.call(first, last)
|
30
|
-
else
|
31
|
-
super()
|
32
|
-
end
|
36
|
+
alias_method :to_default_s, :to_s
|
37
|
+
alias_method :to_formatted_s, :to_s
|
33
38
|
end
|
34
|
-
|
35
|
-
alias_method :to_default_s, :to_s
|
36
|
-
alias_method :to_formatted_s, :to_s
|
37
39
|
end
|
38
40
|
|
39
41
|
Range.prepend(ActiveSupport::RangeWithFormat)
|
@@ -1,3 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/deprecation"
|
4
|
+
|
5
|
+
ActiveSupport::Deprecation.warn "You have required `active_support/core_ext/range/include_range`. " \
|
6
|
+
"This file will be removed in Rails 6.1. You should require `active_support/core_ext/range/compare_range` " \
|
7
|
+
"instead."
|
8
|
+
|
3
9
|
require "active_support/core_ext/range/compare_range"
|
@@ -9,9 +9,9 @@ module ActiveSupport
|
|
9
9
|
# (1.hour.ago..1.hour.from_now).include?(Time.current) # => true
|
10
10
|
#
|
11
11
|
def include?(value)
|
12
|
-
if
|
12
|
+
if self.begin.is_a?(TimeWithZone)
|
13
13
|
cover?(value)
|
14
|
-
elsif
|
14
|
+
elsif self.end.is_a?(TimeWithZone)
|
15
15
|
cover?(value)
|
16
16
|
else
|
17
17
|
super
|
@@ -4,17 +4,18 @@ require "securerandom"
|
|
4
4
|
|
5
5
|
module SecureRandom
|
6
6
|
BASE58_ALPHABET = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a - ["0", "O", "I", "l"]
|
7
|
+
BASE36_ALPHABET = ("0".."9").to_a + ("a".."z").to_a
|
8
|
+
|
7
9
|
# SecureRandom.base58 generates a random base58 string.
|
8
10
|
#
|
9
|
-
# The argument _n_ specifies the length
|
11
|
+
# The argument _n_ specifies the length of the random string to be generated.
|
10
12
|
#
|
11
13
|
# If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
|
12
14
|
#
|
13
|
-
# The result may contain alphanumeric characters except 0, O, I and l
|
15
|
+
# The result may contain alphanumeric characters except 0, O, I and l.
|
14
16
|
#
|
15
17
|
# p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
|
16
18
|
# p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
|
17
|
-
#
|
18
19
|
def self.base58(n = 16)
|
19
20
|
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
20
21
|
idx = byte % 64
|
@@ -22,4 +23,23 @@ module SecureRandom
|
|
22
23
|
BASE58_ALPHABET[idx]
|
23
24
|
end.join
|
24
25
|
end
|
26
|
+
|
27
|
+
# SecureRandom.base36 generates a random base36 string in lowercase.
|
28
|
+
#
|
29
|
+
# The argument _n_ specifies the length of the random string to be generated.
|
30
|
+
#
|
31
|
+
# If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
|
32
|
+
# This method can be used over +base58+ if a deterministic case key is necessary.
|
33
|
+
#
|
34
|
+
# The result will contain alphanumeric characters in lowercase.
|
35
|
+
#
|
36
|
+
# p SecureRandom.base36 # => "4kugl2pdqmscqtje"
|
37
|
+
# p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
|
38
|
+
def self.base36(n = 16)
|
39
|
+
SecureRandom.random_bytes(n).unpack("C*").map do |byte|
|
40
|
+
idx = byte % 64
|
41
|
+
idx = SecureRandom.random_number(36) if idx >= 36
|
42
|
+
BASE36_ALPHABET[idx]
|
43
|
+
end.join
|
44
|
+
end
|
25
45
|
end
|
@@ -75,6 +75,10 @@ class String
|
|
75
75
|
# str.first(0) # => ""
|
76
76
|
# str.first(6) # => "hello"
|
77
77
|
def first(limit = 1)
|
78
|
+
ActiveSupport::Deprecation.warn(
|
79
|
+
"Calling String#first with a negative integer limit " \
|
80
|
+
"will raise an ArgumentError in Rails 6.1."
|
81
|
+
) if limit < 0
|
78
82
|
if limit == 0
|
79
83
|
""
|
80
84
|
elsif limit >= size
|
@@ -95,6 +99,10 @@ class String
|
|
95
99
|
# str.last(0) # => ""
|
96
100
|
# str.last(6) # => "hello"
|
97
101
|
def last(limit = 1)
|
102
|
+
ActiveSupport::Deprecation.warn(
|
103
|
+
"Calling String#last with a negative integer limit " \
|
104
|
+
"will raise an ArgumentError in Rails 6.1."
|
105
|
+
) if limit < 0
|
98
106
|
if limit == 0
|
99
107
|
""
|
100
108
|
elsif limit >= size
|
@@ -75,7 +75,48 @@ class String
|
|
75
75
|
length_with_room_for_omission
|
76
76
|
end
|
77
77
|
|
78
|
-
"#{self[0, stop]}#{omission}"
|
78
|
+
+"#{self[0, stop]}#{omission}"
|
79
|
+
end
|
80
|
+
|
81
|
+
# Truncates +text+ to at most <tt>bytesize</tt> bytes in length without
|
82
|
+
# breaking string encoding by splitting multibyte characters or breaking
|
83
|
+
# grapheme clusters ("perceptual characters") by truncating at combining
|
84
|
+
# characters.
|
85
|
+
#
|
86
|
+
# >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".size
|
87
|
+
# => 20
|
88
|
+
# >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".bytesize
|
89
|
+
# => 80
|
90
|
+
# >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".truncate_bytes(20)
|
91
|
+
# => "🔪🔪🔪🔪…"
|
92
|
+
#
|
93
|
+
# The truncated text ends with the <tt>:omission</tt> string, defaulting
|
94
|
+
# to "…", for a total length not exceeding <tt>bytesize</tt>.
|
95
|
+
def truncate_bytes(truncate_at, omission: "…")
|
96
|
+
omission ||= ""
|
97
|
+
|
98
|
+
case
|
99
|
+
when bytesize <= truncate_at
|
100
|
+
dup
|
101
|
+
when omission.bytesize > truncate_at
|
102
|
+
raise ArgumentError, "Omission #{omission.inspect} is #{omission.bytesize}, larger than the truncation length of #{truncate_at} bytes"
|
103
|
+
when omission.bytesize == truncate_at
|
104
|
+
omission.dup
|
105
|
+
else
|
106
|
+
self.class.new.tap do |cut|
|
107
|
+
cut_at = truncate_at - omission.bytesize
|
108
|
+
|
109
|
+
scan(/\X/) do |grapheme|
|
110
|
+
if cut.bytesize + grapheme.bytesize <= cut_at
|
111
|
+
cut << grapheme
|
112
|
+
else
|
113
|
+
break
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
cut << omission
|
118
|
+
end
|
119
|
+
end
|
79
120
|
end
|
80
121
|
|
81
122
|
# Truncates a given +text+ after a given number of words (<tt>words_count</tt>):
|
@@ -162,6 +162,11 @@ class String
|
|
162
162
|
|
163
163
|
# Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
|
164
164
|
#
|
165
|
+
# If the optional parameter +locale+ is specified,
|
166
|
+
# the word will be parameterized as a word of that language.
|
167
|
+
# By default, this parameter is set to <tt>nil</tt> and it will use
|
168
|
+
# the configured <tt>I18n.locale</tt>.
|
169
|
+
#
|
165
170
|
# class Person
|
166
171
|
# def to_param
|
167
172
|
# "#{id}-#{name.parameterize}"
|
@@ -187,8 +192,8 @@ class String
|
|
187
192
|
#
|
188
193
|
# <%= link_to(@person.name, person_path) %>
|
189
194
|
# # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
|
190
|
-
def parameterize(separator: "-", preserve_case: false)
|
191
|
-
ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case)
|
195
|
+
def parameterize(separator: "-", preserve_case: false, locale: nil)
|
196
|
+
ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case, locale: locale)
|
192
197
|
end
|
193
198
|
|
194
199
|
# Creates the name of a table like Rails does for models to table names. This method
|
@@ -11,12 +11,13 @@ class String
|
|
11
11
|
# encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
|
12
12
|
# class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
|
13
13
|
#
|
14
|
-
# >> "lj".upcase
|
15
|
-
# => "lj"
|
16
14
|
# >> "lj".mb_chars.upcase.to_s
|
17
15
|
# => "LJ"
|
18
16
|
#
|
19
|
-
# NOTE:
|
17
|
+
# NOTE: Ruby 2.4 and later support native Unicode case mappings:
|
18
|
+
#
|
19
|
+
# >> "lj".upcase
|
20
|
+
# => "LJ"
|
20
21
|
#
|
21
22
|
# == Method chaining
|
22
23
|
#
|
@@ -134,10 +134,13 @@ end
|
|
134
134
|
module ActiveSupport #:nodoc:
|
135
135
|
class SafeBuffer < String
|
136
136
|
UNSAFE_STRING_METHODS = %w(
|
137
|
-
capitalize chomp chop delete
|
138
|
-
|
137
|
+
capitalize chomp chop delete delete_prefix delete_suffix
|
138
|
+
downcase lstrip next reverse rstrip scrub slice squeeze strip
|
139
|
+
succ swapcase tr tr_s unicode_normalize upcase
|
139
140
|
)
|
140
141
|
|
142
|
+
UNSAFE_STRING_METHODS_WITH_BACKREF = %w(gsub sub)
|
143
|
+
|
141
144
|
alias_method :original_concat, :concat
|
142
145
|
private :original_concat
|
143
146
|
|
@@ -149,15 +152,13 @@ module ActiveSupport #:nodoc:
|
|
149
152
|
end
|
150
153
|
|
151
154
|
def [](*args)
|
152
|
-
if
|
153
|
-
super
|
154
|
-
elsif html_safe?
|
155
|
-
new_safe_buffer = super
|
155
|
+
if html_safe?
|
156
|
+
new_string = super
|
156
157
|
|
157
|
-
|
158
|
-
new_safe_buffer.instance_variable_set :@html_safe, true
|
159
|
-
end
|
158
|
+
return unless new_string
|
160
159
|
|
160
|
+
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
161
|
+
new_safe_buffer.instance_variable_set :@html_safe, true
|
161
162
|
new_safe_buffer
|
162
163
|
else
|
163
164
|
to_str[*args]
|
@@ -188,14 +189,37 @@ module ActiveSupport #:nodoc:
|
|
188
189
|
end
|
189
190
|
alias << concat
|
190
191
|
|
192
|
+
def insert(index, value)
|
193
|
+
super(index, html_escape_interpolated_argument(value))
|
194
|
+
end
|
195
|
+
|
191
196
|
def prepend(value)
|
192
197
|
super(html_escape_interpolated_argument(value))
|
193
198
|
end
|
194
199
|
|
200
|
+
def replace(value)
|
201
|
+
super(html_escape_interpolated_argument(value))
|
202
|
+
end
|
203
|
+
|
204
|
+
def []=(*args)
|
205
|
+
if args.count == 3
|
206
|
+
super(args[0], args[1], html_escape_interpolated_argument(args[2]))
|
207
|
+
else
|
208
|
+
super(args[0], html_escape_interpolated_argument(args[1]))
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
195
212
|
def +(other)
|
196
213
|
dup.concat(other)
|
197
214
|
end
|
198
215
|
|
216
|
+
def *(*)
|
217
|
+
new_string = super
|
218
|
+
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
219
|
+
new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
|
220
|
+
new_safe_buffer
|
221
|
+
end
|
222
|
+
|
199
223
|
def %(args)
|
200
224
|
case args
|
201
225
|
when Hash
|
@@ -238,11 +262,45 @@ module ActiveSupport #:nodoc:
|
|
238
262
|
end
|
239
263
|
end
|
240
264
|
|
241
|
-
|
265
|
+
UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
|
266
|
+
if unsafe_method.respond_to?(unsafe_method)
|
267
|
+
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
268
|
+
def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
|
269
|
+
if block # if block
|
270
|
+
to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
|
271
|
+
set_block_back_references(block, $~) # set_block_back_references(block, $~)
|
272
|
+
block.call(*params) # block.call(*params)
|
273
|
+
} # }
|
274
|
+
else # else
|
275
|
+
to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
|
276
|
+
end # end
|
277
|
+
end # end
|
278
|
+
|
279
|
+
def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
|
280
|
+
@html_safe = false # @html_safe = false
|
281
|
+
if block # if block
|
282
|
+
super(*args) { |*params| # super(*args) { |*params|
|
283
|
+
set_block_back_references(block, $~) # set_block_back_references(block, $~)
|
284
|
+
block.call(*params) # block.call(*params)
|
285
|
+
} # }
|
286
|
+
else # else
|
287
|
+
super # super
|
288
|
+
end # end
|
289
|
+
end # end
|
290
|
+
EOT
|
291
|
+
end
|
292
|
+
end
|
242
293
|
|
294
|
+
private
|
243
295
|
def html_escape_interpolated_argument(arg)
|
244
296
|
(!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
|
245
297
|
end
|
298
|
+
|
299
|
+
def set_block_back_references(block, match_data)
|
300
|
+
block.binding.eval("proc { |m| $~ = m }").call(match_data)
|
301
|
+
rescue ArgumentError
|
302
|
+
# Can't create binding from C level Proc
|
303
|
+
end
|
246
304
|
end
|
247
305
|
end
|
248
306
|
|
@@ -20,6 +20,8 @@ class String
|
|
20
20
|
# Technically, it looks for the least indented non-empty line
|
21
21
|
# in the whole string, and removes that amount of leading whitespace.
|
22
22
|
def strip_heredoc
|
23
|
-
gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".
|
23
|
+
gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "").tap do |stripped|
|
24
|
+
stripped.freeze if frozen?
|
25
|
+
end
|
24
26
|
end
|
25
27
|
end
|
@@ -47,7 +47,9 @@ class Time
|
|
47
47
|
# Time.at can be called with a time or numerical value
|
48
48
|
time_or_number = args.first
|
49
49
|
|
50
|
-
if time_or_number.is_a?(ActiveSupport::TimeWithZone)
|
50
|
+
if time_or_number.is_a?(ActiveSupport::TimeWithZone)
|
51
|
+
at_without_coercion(time_or_number.to_r).getlocal
|
52
|
+
elsif time_or_number.is_a?(DateTime)
|
51
53
|
at_without_coercion(time_or_number.to_f).getlocal
|
52
54
|
else
|
53
55
|
at_without_coercion(time_or_number)
|
@@ -170,8 +172,7 @@ class Time
|
|
170
172
|
options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
|
171
173
|
end
|
172
174
|
|
173
|
-
d = to_date.advance(options)
|
174
|
-
d = d.gregorian if d.julian?
|
175
|
+
d = to_date.gregorian.advance(options)
|
175
176
|
time_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
|
176
177
|
seconds_to_advance = \
|
177
178
|
options.fetch(:seconds, 0) +
|
@@ -312,4 +313,34 @@ class Time
|
|
312
313
|
end
|
313
314
|
alias_method :eql_without_coercion, :eql?
|
314
315
|
alias_method :eql?, :eql_with_coercion
|
316
|
+
|
317
|
+
# Returns a new time the specified number of days ago.
|
318
|
+
def prev_day(days = 1)
|
319
|
+
advance(days: -days)
|
320
|
+
end
|
321
|
+
|
322
|
+
# Returns a new time the specified number of days in the future.
|
323
|
+
def next_day(days = 1)
|
324
|
+
advance(days: days)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Returns a new time the specified number of months ago.
|
328
|
+
def prev_month(months = 1)
|
329
|
+
advance(months: -months)
|
330
|
+
end
|
331
|
+
|
332
|
+
# Returns a new time the specified number of months in the future.
|
333
|
+
def next_month(months = 1)
|
334
|
+
advance(months: months)
|
335
|
+
end
|
336
|
+
|
337
|
+
# Returns a new time the specified number of years ago.
|
338
|
+
def prev_year(years = 1)
|
339
|
+
advance(years: -years)
|
340
|
+
end
|
341
|
+
|
342
|
+
# Returns a new time the specified number of years in the future.
|
343
|
+
def next_year(years = 1)
|
344
|
+
advance(years: years)
|
345
|
+
end
|
315
346
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/callbacks"
|
4
|
+
|
3
5
|
module ActiveSupport
|
4
6
|
# Abstract super class that provides a thread-isolated attributes singleton, which resets automatically
|
5
7
|
# before and after each request. This allows you to keep all the per-request attributes easily
|
@@ -117,10 +119,16 @@ module ActiveSupport
|
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
122
|
+
# Calls this block before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
|
123
|
+
def before_reset(&block)
|
124
|
+
set_callback :reset, :before, &block
|
125
|
+
end
|
126
|
+
|
120
127
|
# Calls this block after #reset is called on the instance. Used for resetting external collaborators, like Time.zone.
|
121
128
|
def resets(&block)
|
122
129
|
set_callback :reset, :after, &block
|
123
130
|
end
|
131
|
+
alias_method :after_reset, :resets
|
124
132
|
|
125
133
|
delegate :set, :reset, to: :instance
|
126
134
|
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "set"
|
4
|
+
require "active_support/core_ext/string/inflections"
|
5
|
+
|
6
|
+
module ActiveSupport
|
7
|
+
module Dependencies
|
8
|
+
module ZeitwerkIntegration # :nodoc: all
|
9
|
+
module Decorations
|
10
|
+
def clear
|
11
|
+
Dependencies.unload_interlock do
|
12
|
+
Rails.autoloaders.main.reload
|
13
|
+
rescue Zeitwerk::ReloadingDisabledError
|
14
|
+
raise "reloading is disabled because config.cache_classes is true"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def constantize(cpath)
|
19
|
+
ActiveSupport::Inflector.constantize(cpath)
|
20
|
+
end
|
21
|
+
|
22
|
+
def safe_constantize(cpath)
|
23
|
+
ActiveSupport::Inflector.safe_constantize(cpath)
|
24
|
+
end
|
25
|
+
|
26
|
+
def autoloaded_constants
|
27
|
+
Rails.autoloaders.main.unloadable_cpaths
|
28
|
+
end
|
29
|
+
|
30
|
+
def autoloaded?(object)
|
31
|
+
cpath = object.is_a?(Module) ? real_mod_name(object) : object.to_s
|
32
|
+
Rails.autoloaders.main.unloadable_cpath?(cpath)
|
33
|
+
end
|
34
|
+
|
35
|
+
def verbose=(verbose)
|
36
|
+
l = verbose ? logger || Rails.logger : nil
|
37
|
+
Rails.autoloaders.each { |autoloader| autoloader.logger = l }
|
38
|
+
end
|
39
|
+
|
40
|
+
def unhook!
|
41
|
+
:no_op
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module RequireDependency
|
46
|
+
def require_dependency(filename)
|
47
|
+
filename = filename.to_path if filename.respond_to?(:to_path)
|
48
|
+
if abspath = ActiveSupport::Dependencies.search_for_file(filename)
|
49
|
+
require abspath
|
50
|
+
else
|
51
|
+
require filename
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module Inflector
|
57
|
+
# Concurrent::Map is not needed. This is a private class, and overrides
|
58
|
+
# must be defined while the application boots.
|
59
|
+
@overrides = {}
|
60
|
+
|
61
|
+
def self.camelize(basename, _abspath)
|
62
|
+
@overrides[basename] || basename.camelize
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.inflect(overrides)
|
66
|
+
@overrides.merge!(overrides)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class << self
|
71
|
+
def take_over(enable_reloading:)
|
72
|
+
setup_autoloaders(enable_reloading)
|
73
|
+
freeze_paths
|
74
|
+
decorate_dependencies
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
def setup_autoloaders(enable_reloading)
|
79
|
+
Dependencies.autoload_paths.each do |autoload_path|
|
80
|
+
# Zeitwerk only accepts existing directories in `push_dir` to
|
81
|
+
# prevent misconfigurations.
|
82
|
+
next unless File.directory?(autoload_path)
|
83
|
+
|
84
|
+
autoloader = \
|
85
|
+
autoload_once?(autoload_path) ? Rails.autoloaders.once : Rails.autoloaders.main
|
86
|
+
|
87
|
+
autoloader.push_dir(autoload_path)
|
88
|
+
autoloader.do_not_eager_load(autoload_path) unless eager_load?(autoload_path)
|
89
|
+
end
|
90
|
+
|
91
|
+
Rails.autoloaders.main.enable_reloading if enable_reloading
|
92
|
+
Rails.autoloaders.each(&:setup)
|
93
|
+
end
|
94
|
+
|
95
|
+
def autoload_once?(autoload_path)
|
96
|
+
Dependencies.autoload_once_paths.include?(autoload_path)
|
97
|
+
end
|
98
|
+
|
99
|
+
def eager_load?(autoload_path)
|
100
|
+
Dependencies._eager_load_paths.member?(autoload_path)
|
101
|
+
end
|
102
|
+
|
103
|
+
def freeze_paths
|
104
|
+
Dependencies.autoload_paths.freeze
|
105
|
+
Dependencies.autoload_once_paths.freeze
|
106
|
+
Dependencies._eager_load_paths.freeze
|
107
|
+
end
|
108
|
+
|
109
|
+
def decorate_dependencies
|
110
|
+
Dependencies.unhook!
|
111
|
+
Dependencies.singleton_class.prepend(Decorations)
|
112
|
+
Object.prepend(RequireDependency)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|