activesupport 5.2.4.3 → 7.0.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +244 -459
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -3
- data/lib/active_support/actionable_error.rb +48 -0
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +31 -5
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +47 -41
- data/lib/active_support/cache/mem_cache_store.rb +151 -40
- data/lib/active_support/cache/memory_store.rb +68 -34
- data/lib/active_support/cache/null_store.rb +16 -3
- data/lib/active_support/cache/redis_cache_store.rb +103 -101
- data/lib/active_support/cache/strategy/local_cache.rb +56 -64
- data/lib/active_support/cache.rb +333 -116
- data/lib/active_support/callbacks.rb +244 -128
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +72 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -3
- data/lib/active_support/configurable.rb +15 -16
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +15 -7
- data/lib/active_support/core_ext/array/conversions.rb +18 -17
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +2 -1
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +32 -47
- data/lib/active_support/core_ext/class/subclasses.rb +9 -22
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +15 -14
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -51
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -14
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +241 -76
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +3 -4
- 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/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +2 -31
- data/lib/active_support/core_ext/hash/slice.rb +6 -27
- 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/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.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/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +32 -39
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +35 -28
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +70 -33
- data/lib/active_support/core_ext/module/introspection.rb +16 -15
- 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/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +132 -129
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -1
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +3 -4
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +14 -110
- data/lib/active_support/core_ext/object/json.rb +44 -27
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +24 -14
- data/lib/active_support/core_ext/object/with_options.rb +21 -2
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +23 -27
- data/lib/active_support/core_ext/range/conversions.rb +32 -30
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -2
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -5
- data/lib/active_support/core_ext/securerandom.rb +23 -3
- data/lib/active_support/core_ext/string/access.rb +5 -16
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +42 -1
- data/lib/active_support/core_ext/string/inflections.rb +46 -7
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +6 -5
- data/lib/active_support/core_ext/string/output_safety.rb +129 -20
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/string/strip.rb +3 -1
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +59 -10
- data/lib/active_support/core_ext/time/conversions.rb +15 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -22
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +47 -16
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +60 -715
- data/lib/active_support/deprecation/behaviors.rb +21 -5
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +18 -23
- data/lib/active_support/deprecation/proxy_wrappers.rb +31 -8
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +7 -2
- data/lib/active_support/descendants_tracker.rb +190 -34
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +5 -7
- data/lib/active_support/duration/iso8601_serializer.rb +27 -15
- data/lib/active_support/duration.rb +149 -67
- data/lib/active_support/encrypted_configuration.rb +12 -5
- data/lib/active_support/encrypted_file.rb +23 -5
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +85 -122
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +44 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +0 -1
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +5 -5
- data/lib/active_support/hash_with_indifferent_access.rb +73 -43
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +2 -0
- data/lib/active_support/i18n_railtie.rb +15 -8
- data/lib/active_support/inflector/inflections.rb +25 -14
- data/lib/active_support/inflector/methods.rb +38 -71
- data/lib/active_support/inflector/transliterate.rb +47 -18
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +25 -26
- data/lib/active_support/json/encoding.rb +14 -6
- data/lib/active_support/key_generator.rb +23 -38
- data/lib/active_support/lazy_load_hooks.rb +19 -5
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +51 -11
- data/lib/active_support/logger.rb +6 -22
- data/lib/active_support/logger_silence.rb +11 -19
- data/lib/active_support/logger_thread_safe_level.rb +45 -10
- data/lib/active_support/message_encryptor.rb +20 -19
- data/lib/active_support/message_verifier.rb +53 -21
- data/lib/active_support/messages/metadata.rb +13 -4
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +10 -9
- data/lib/active_support/multibyte/chars.rb +17 -76
- data/lib/active_support/multibyte/unicode.rb +7 -331
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +163 -37
- data/lib/active_support/notifications/instrumenter.rb +90 -11
- data/lib/active_support/notifications.rb +88 -30
- data/lib/active_support/number_helper/number_converter.rb +6 -9
- data/lib/active_support/number_helper/number_to_currency_converter.rb +12 -12
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -4
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
- data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -2
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +36 -12
- data/lib/active_support/option_merger.rb +15 -4
- data/lib/active_support/ordered_hash.rb +2 -2
- data/lib/active_support/ordered_options.rb +14 -4
- data/lib/active_support/parameter_filter.rb +138 -0
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -10
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/reloader.rb +5 -6
- data/lib/active_support/rescuable.rb +8 -8
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +2 -3
- data/lib/active_support/subscriber.rb +79 -46
- data/lib/active_support/tagged_logging.rb +58 -9
- data/lib/active_support/test_case.rb +79 -0
- data/lib/active_support/testing/assertions.rb +62 -11
- data/lib/active_support/testing/deprecation.rb +52 -2
- data/lib/active_support/testing/file_fixtures.rb +2 -0
- data/lib/active_support/testing/isolation.rb +4 -4
- data/lib/active_support/testing/method_call_assertions.rb +32 -5
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +55 -0
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +4 -7
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +60 -14
- data/lib/active_support/time_with_zone.rb +139 -64
- data/lib/active_support/values/time_zone.rb +66 -30
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +3 -4
- data/lib/active_support/xml_mini/libxml.rb +7 -7
- data/lib/active_support/xml_mini/libxmlsax.rb +5 -5
- data/lib/active_support/xml_mini/nokogiri.rb +6 -6
- data/lib/active_support/xml_mini/nokogirisax.rb +4 -4
- data/lib/active_support/xml_mini/rexml.rb +11 -4
- data/lib/active_support/xml_mini.rb +7 -14
- data/lib/active_support.rb +30 -1
- metadata +64 -35
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
- data/lib/active_support/core_ext/hash/compact.rb +0 -29
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
- data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -11
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
- data/lib/active_support/core_ext/range/include_range.rb +0 -3
- data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "erb"
|
4
|
-
require "active_support/core_ext/kernel/singleton_class"
|
5
4
|
require "active_support/core_ext/module/redefine_method"
|
6
5
|
require "active_support/multibyte/unicode"
|
7
6
|
|
@@ -12,6 +11,14 @@ class ERB
|
|
12
11
|
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
|
13
12
|
JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
|
14
13
|
|
14
|
+
# Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
|
15
|
+
TAG_NAME_START_REGEXP_SET = "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
|
16
|
+
"\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
|
17
|
+
"\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
|
18
|
+
TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}]/
|
19
|
+
TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}]/
|
20
|
+
TAG_NAME_REPLACEMENT_CHAR = "_"
|
21
|
+
|
15
22
|
# A utility method for escaping HTML tag characters.
|
16
23
|
# This method is also aliased as <tt>h</tt>.
|
17
24
|
#
|
@@ -85,7 +92,7 @@ class ERB
|
|
85
92
|
# use inside HTML attributes.
|
86
93
|
#
|
87
94
|
# If your JSON is being used downstream for insertion into the DOM, be aware of
|
88
|
-
# whether or not it is being inserted via
|
95
|
+
# whether or not it is being inserted via <tt>html()</tt>. Most jQuery plugins do this.
|
89
96
|
# If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
|
90
97
|
# content returned by your JSON.
|
91
98
|
#
|
@@ -98,7 +105,7 @@ class ERB
|
|
98
105
|
# WARNING: this helper only works with valid JSON. Using this on non-JSON values
|
99
106
|
# will open up serious XSS vulnerabilities. For example, if you replace the
|
100
107
|
# +current_user.to_json+ in the example above with user input instead, the browser
|
101
|
-
# will happily eval() that string as JavaScript.
|
108
|
+
# will happily <tt>eval()</tt> that string as JavaScript.
|
102
109
|
#
|
103
110
|
# The escaping performed in this method is identical to those performed in the
|
104
111
|
# Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
|
@@ -116,6 +123,26 @@ class ERB
|
|
116
123
|
end
|
117
124
|
|
118
125
|
module_function :json_escape
|
126
|
+
|
127
|
+
# A utility method for escaping XML names of tags and names of attributes.
|
128
|
+
#
|
129
|
+
# xml_name_escape('1 < 2 & 3')
|
130
|
+
# # => "1___2___3"
|
131
|
+
#
|
132
|
+
# It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
|
133
|
+
def xml_name_escape(name)
|
134
|
+
name = name.to_s
|
135
|
+
return "" if name.blank?
|
136
|
+
|
137
|
+
starting_char = name[0].gsub(TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
|
138
|
+
|
139
|
+
return starting_char if name.size == 1
|
140
|
+
|
141
|
+
following_chars = name[1..-1].gsub(TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
|
142
|
+
|
143
|
+
starting_char + following_chars
|
144
|
+
end
|
145
|
+
module_function :xml_name_escape
|
119
146
|
end
|
120
147
|
end
|
121
148
|
|
@@ -131,17 +158,20 @@ class Numeric
|
|
131
158
|
end
|
132
159
|
end
|
133
160
|
|
134
|
-
module ActiveSupport
|
161
|
+
module ActiveSupport # :nodoc:
|
135
162
|
class SafeBuffer < String
|
136
163
|
UNSAFE_STRING_METHODS = %w(
|
137
|
-
capitalize chomp chop delete
|
138
|
-
|
164
|
+
capitalize chomp chop delete delete_prefix delete_suffix
|
165
|
+
downcase lstrip next reverse rstrip scrub slice squeeze strip
|
166
|
+
succ swapcase tr tr_s unicode_normalize upcase
|
139
167
|
)
|
140
168
|
|
169
|
+
UNSAFE_STRING_METHODS_WITH_BACKREF = %w(gsub sub)
|
170
|
+
|
141
171
|
alias_method :original_concat, :concat
|
142
172
|
private :original_concat
|
143
173
|
|
144
|
-
# Raised when
|
174
|
+
# Raised when ActiveSupport::SafeBuffer#safe_concat is called on unsafe buffers.
|
145
175
|
class SafeConcatError < StandardError
|
146
176
|
def initialize
|
147
177
|
super "Could not concatenate to the buffer because it is not html safe."
|
@@ -149,15 +179,13 @@ module ActiveSupport #:nodoc:
|
|
149
179
|
end
|
150
180
|
|
151
181
|
def [](*args)
|
152
|
-
if
|
153
|
-
super
|
154
|
-
elsif html_safe?
|
155
|
-
new_safe_buffer = super
|
182
|
+
if html_safe?
|
183
|
+
new_string = super
|
156
184
|
|
157
|
-
|
158
|
-
new_safe_buffer.instance_variable_set :@html_safe, true
|
159
|
-
end
|
185
|
+
return unless new_string
|
160
186
|
|
187
|
+
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
188
|
+
new_safe_buffer.instance_variable_set :@html_safe, true
|
161
189
|
new_safe_buffer
|
162
190
|
else
|
163
191
|
to_str[*args]
|
@@ -184,24 +212,50 @@ module ActiveSupport #:nodoc:
|
|
184
212
|
end
|
185
213
|
|
186
214
|
def concat(value)
|
187
|
-
|
215
|
+
unless value.nil?
|
216
|
+
super(implicit_html_escape_interpolated_argument(value))
|
217
|
+
end
|
218
|
+
self
|
188
219
|
end
|
189
220
|
alias << concat
|
190
221
|
|
222
|
+
def insert(index, value)
|
223
|
+
super(index, implicit_html_escape_interpolated_argument(value))
|
224
|
+
end
|
225
|
+
|
191
226
|
def prepend(value)
|
192
|
-
super(
|
227
|
+
super(implicit_html_escape_interpolated_argument(value))
|
228
|
+
end
|
229
|
+
|
230
|
+
def replace(value)
|
231
|
+
super(implicit_html_escape_interpolated_argument(value))
|
232
|
+
end
|
233
|
+
|
234
|
+
def []=(*args)
|
235
|
+
if args.length == 3
|
236
|
+
super(args[0], args[1], implicit_html_escape_interpolated_argument(args[2]))
|
237
|
+
else
|
238
|
+
super(args[0], implicit_html_escape_interpolated_argument(args[1]))
|
239
|
+
end
|
193
240
|
end
|
194
241
|
|
195
242
|
def +(other)
|
196
243
|
dup.concat(other)
|
197
244
|
end
|
198
245
|
|
246
|
+
def *(*)
|
247
|
+
new_string = super
|
248
|
+
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
249
|
+
new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
|
250
|
+
new_safe_buffer
|
251
|
+
end
|
252
|
+
|
199
253
|
def %(args)
|
200
254
|
case args
|
201
255
|
when Hash
|
202
|
-
escaped_args =
|
256
|
+
escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
|
203
257
|
else
|
204
|
-
escaped_args = Array(args).map { |arg|
|
258
|
+
escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
|
205
259
|
end
|
206
260
|
|
207
261
|
self.class.new(super(escaped_args))
|
@@ -238,11 +292,66 @@ module ActiveSupport #:nodoc:
|
|
238
292
|
end
|
239
293
|
end
|
240
294
|
|
241
|
-
|
295
|
+
UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
|
296
|
+
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
297
|
+
def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
|
298
|
+
if block # if block
|
299
|
+
to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
|
300
|
+
set_block_back_references(block, $~) # set_block_back_references(block, $~)
|
301
|
+
block.call(*params) # block.call(*params)
|
302
|
+
} # }
|
303
|
+
else # else
|
304
|
+
to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
|
305
|
+
end # end
|
306
|
+
end # end
|
307
|
+
|
308
|
+
def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
|
309
|
+
@html_safe = false # @html_safe = false
|
310
|
+
if block # if block
|
311
|
+
super(*args) { |*params| # super(*args) { |*params|
|
312
|
+
set_block_back_references(block, $~) # set_block_back_references(block, $~)
|
313
|
+
block.call(*params) # block.call(*params)
|
314
|
+
} # }
|
315
|
+
else # else
|
316
|
+
super # super
|
317
|
+
end # end
|
318
|
+
end # end
|
319
|
+
EOT
|
320
|
+
end
|
242
321
|
|
243
|
-
|
322
|
+
private
|
323
|
+
def explicit_html_escape_interpolated_argument(arg)
|
244
324
|
(!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
|
245
325
|
end
|
326
|
+
|
327
|
+
def implicit_html_escape_interpolated_argument(arg)
|
328
|
+
if !html_safe? || arg.html_safe?
|
329
|
+
arg
|
330
|
+
else
|
331
|
+
arg_string = begin
|
332
|
+
arg.to_str
|
333
|
+
rescue NoMethodError => error
|
334
|
+
if error.name == :to_str
|
335
|
+
str = arg.to_s
|
336
|
+
ActiveSupport::Deprecation.warn <<~MSG.squish
|
337
|
+
Implicit conversion of #{arg.class} into String by ActiveSupport::SafeBuffer
|
338
|
+
is deprecated and will be removed in Rails 7.1.
|
339
|
+
You must explicitly cast it to a String.
|
340
|
+
MSG
|
341
|
+
str
|
342
|
+
else
|
343
|
+
raise
|
344
|
+
end
|
345
|
+
end
|
346
|
+
CGI.escapeHTML(arg_string)
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def set_block_back_references(block, match_data)
|
351
|
+
block.binding.eval("proc { |m| $~ = m }").call(match_data)
|
352
|
+
rescue ArgumentError
|
353
|
+
# Can't create binding from C level Proc
|
354
|
+
end
|
246
355
|
end
|
247
356
|
end
|
248
357
|
|
@@ -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
|
@@ -6,6 +6,7 @@ require "active_support/time_with_zone"
|
|
6
6
|
require "active_support/core_ext/time/zones"
|
7
7
|
require "active_support/core_ext/date_and_time/calculations"
|
8
8
|
require "active_support/core_ext/date/calculations"
|
9
|
+
require "active_support/core_ext/module/remove_method"
|
9
10
|
|
10
11
|
class Time
|
11
12
|
include DateAndTime::Calculations
|
@@ -41,13 +42,15 @@ class Time
|
|
41
42
|
|
42
43
|
# Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
|
43
44
|
# instances can be used when called with a single argument
|
44
|
-
def at_with_coercion(*args)
|
45
|
-
return at_without_coercion(*args) if args.size != 1
|
45
|
+
def at_with_coercion(*args, **kwargs)
|
46
|
+
return at_without_coercion(*args, **kwargs) if args.size != 1 || !kwargs.empty?
|
46
47
|
|
47
48
|
# Time.at can be called with a time or numerical value
|
48
49
|
time_or_number = args.first
|
49
50
|
|
50
|
-
if time_or_number.is_a?(ActiveSupport::TimeWithZone)
|
51
|
+
if time_or_number.is_a?(ActiveSupport::TimeWithZone)
|
52
|
+
at_without_coercion(time_or_number.to_r).getlocal
|
53
|
+
elsif time_or_number.is_a?(DateTime)
|
51
54
|
at_without_coercion(time_or_number.to_f).getlocal
|
52
55
|
else
|
53
56
|
at_without_coercion(time_or_number)
|
@@ -105,11 +108,26 @@ class Time
|
|
105
108
|
subsec
|
106
109
|
end
|
107
110
|
|
111
|
+
unless Time.method_defined?(:floor)
|
112
|
+
def floor(precision = 0)
|
113
|
+
change(nsec: 0) + subsec.floor(precision)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Restricted Ruby version due to a bug in `Time#ceil`
|
118
|
+
# See https://bugs.ruby-lang.org/issues/17025 for more details
|
119
|
+
if RUBY_VERSION <= "2.8"
|
120
|
+
remove_possible_method :ceil
|
121
|
+
def ceil(precision = 0)
|
122
|
+
change(nsec: 0) + subsec.ceil(precision)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
108
126
|
# Returns a new Time where one or more of the elements have been changed according
|
109
127
|
# to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
|
110
128
|
# <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
|
111
|
-
# the hour is passed, then minute, sec, usec and nsec is set to 0. If the hour
|
112
|
-
# and minute is passed, then sec, usec and nsec is set to 0. The +options+ parameter
|
129
|
+
# the hour is passed, then minute, sec, usec, and nsec is set to 0. If the hour
|
130
|
+
# and minute is passed, then sec, usec, and nsec is set to 0. The +options+ parameter
|
113
131
|
# takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
|
114
132
|
# <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
|
115
133
|
# <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
|
@@ -141,6 +159,8 @@ class Time
|
|
141
159
|
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
|
142
160
|
elsif utc?
|
143
161
|
::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
|
162
|
+
elsif zone&.respond_to?(:utc_to_local)
|
163
|
+
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
|
144
164
|
elsif zone
|
145
165
|
::Time.local(new_year, new_month, new_day, new_hour, new_min, new_sec)
|
146
166
|
else
|
@@ -170,8 +190,7 @@ class Time
|
|
170
190
|
options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
|
171
191
|
end
|
172
192
|
|
173
|
-
d = to_date.advance(options)
|
174
|
-
d = d.gregorian if d.julian?
|
193
|
+
d = to_date.gregorian.advance(options)
|
175
194
|
time_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
|
176
195
|
seconds_to_advance = \
|
177
196
|
options.fetch(:seconds, 0) +
|
@@ -258,7 +277,7 @@ class Time
|
|
258
277
|
end
|
259
278
|
alias :at_end_of_minute :end_of_minute
|
260
279
|
|
261
|
-
def plus_with_duration(other)
|
280
|
+
def plus_with_duration(other) # :nodoc:
|
262
281
|
if ActiveSupport::Duration === other
|
263
282
|
other.since(self)
|
264
283
|
else
|
@@ -268,7 +287,7 @@ class Time
|
|
268
287
|
alias_method :plus_without_duration, :+
|
269
288
|
alias_method :+, :plus_with_duration
|
270
289
|
|
271
|
-
def minus_with_duration(other)
|
290
|
+
def minus_with_duration(other) # :nodoc:
|
272
291
|
if ActiveSupport::Duration === other
|
273
292
|
other.until(self)
|
274
293
|
else
|
@@ -286,7 +305,7 @@ class Time
|
|
286
305
|
other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
|
287
306
|
end
|
288
307
|
alias_method :minus_without_coercion, :-
|
289
|
-
alias_method :-, :minus_with_coercion
|
308
|
+
alias_method :-, :minus_with_coercion # rubocop:disable Lint/DuplicateMethods
|
290
309
|
|
291
310
|
# Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
|
292
311
|
# can be chronologically compared with a Time
|
@@ -312,4 +331,34 @@ class Time
|
|
312
331
|
end
|
313
332
|
alias_method :eql_without_coercion, :eql?
|
314
333
|
alias_method :eql?, :eql_with_coercion
|
334
|
+
|
335
|
+
# Returns a new time the specified number of days ago.
|
336
|
+
def prev_day(days = 1)
|
337
|
+
advance(days: -days)
|
338
|
+
end
|
339
|
+
|
340
|
+
# Returns a new time the specified number of days in the future.
|
341
|
+
def next_day(days = 1)
|
342
|
+
advance(days: days)
|
343
|
+
end
|
344
|
+
|
345
|
+
# Returns a new time the specified number of months ago.
|
346
|
+
def prev_month(months = 1)
|
347
|
+
advance(months: -months)
|
348
|
+
end
|
349
|
+
|
350
|
+
# Returns a new time the specified number of months in the future.
|
351
|
+
def next_month(months = 1)
|
352
|
+
advance(months: months)
|
353
|
+
end
|
354
|
+
|
355
|
+
# Returns a new time the specified number of years ago.
|
356
|
+
def prev_year(years = 1)
|
357
|
+
advance(years: -years)
|
358
|
+
end
|
359
|
+
|
360
|
+
# Returns a new time the specified number of years in the future.
|
361
|
+
def next_year(years = 1)
|
362
|
+
advance(years: years)
|
363
|
+
end
|
315
364
|
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "time"
|
3
4
|
require "active_support/inflector/methods"
|
4
5
|
require "active_support/values/time_zone"
|
5
6
|
|
6
7
|
class Time
|
7
8
|
DATE_FORMATS = {
|
8
9
|
db: "%Y-%m-%d %H:%M:%S",
|
10
|
+
inspect: "%Y-%m-%d %H:%M:%S.%9N %z",
|
9
11
|
number: "%Y%m%d%H%M%S",
|
10
12
|
nsec: "%Y%m%d%H%M%S%9N",
|
11
13
|
usec: "%Y%m%d%H%M%S%6N",
|
@@ -25,22 +27,22 @@ class Time
|
|
25
27
|
|
26
28
|
# Converts to a formatted string. See DATE_FORMATS for built-in formats.
|
27
29
|
#
|
28
|
-
# This method is aliased to <tt>
|
30
|
+
# This method is aliased to <tt>to_formatted_s</tt>.
|
29
31
|
#
|
30
32
|
# time = Time.now # => 2007-01-18 06:10:17 -06:00
|
31
33
|
#
|
34
|
+
# time.to_fs(:time) # => "06:10"
|
32
35
|
# time.to_formatted_s(:time) # => "06:10"
|
33
|
-
# time.to_s(:time) # => "06:10"
|
34
36
|
#
|
35
|
-
# time.
|
36
|
-
# time.
|
37
|
-
# time.
|
38
|
-
# time.
|
39
|
-
# time.
|
40
|
-
# time.
|
41
|
-
# time.
|
37
|
+
# time.to_fs(:db) # => "2007-01-18 06:10:17"
|
38
|
+
# time.to_fs(:number) # => "20070118061017"
|
39
|
+
# time.to_fs(:short) # => "18 Jan 06:10"
|
40
|
+
# time.to_fs(:long) # => "January 18, 2007 06:10"
|
41
|
+
# time.to_fs(:long_ordinal) # => "January 18th, 2007 06:10"
|
42
|
+
# time.to_fs(:rfc822) # => "Thu, 18 Jan 2007 06:10:17 -0600"
|
43
|
+
# time.to_fs(:iso8601) # => "2007-01-18T06:10:17-06:00"
|
42
44
|
#
|
43
|
-
# == Adding your own time formats to +
|
45
|
+
# == Adding your own time formats to +to_fs+
|
44
46
|
# You can add your own formats to the Time::DATE_FORMATS hash.
|
45
47
|
# Use the format name as the hash key and either a strftime string
|
46
48
|
# or Proc instance that takes a time argument as the value.
|
@@ -48,15 +50,16 @@ class Time
|
|
48
50
|
# # config/initializers/time_formats.rb
|
49
51
|
# Time::DATE_FORMATS[:month_and_year] = '%B %Y'
|
50
52
|
# Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
|
51
|
-
def
|
53
|
+
def to_fs(format = :default)
|
52
54
|
if formatter = DATE_FORMATS[format]
|
53
55
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
54
56
|
else
|
57
|
+
# Change to `to_s` when deprecation is gone. Also deprecate `to_default_s`.
|
55
58
|
to_default_s
|
56
59
|
end
|
57
60
|
end
|
61
|
+
alias_method :to_formatted_s, :to_fs
|
58
62
|
alias_method :to_default_s, :to_s
|
59
|
-
alias_method :to_s, :to_formatted_s
|
60
63
|
|
61
64
|
# Returns a formatted string of the offset from UTC, or an alternative
|
62
65
|
# string if the time zone is already UTC.
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "time"
|
4
|
+
|
5
|
+
class Time
|
6
|
+
NOT_SET = Object.new # :nodoc:
|
7
|
+
def to_s(format = NOT_SET) # :nodoc:
|
8
|
+
if formatter = DATE_FORMATS[format]
|
9
|
+
ActiveSupport::Deprecation.warn(
|
10
|
+
"Time#to_s(#{format.inspect}) is deprecated. Please use Time#to_fs(#{format.inspect}) instead."
|
11
|
+
)
|
12
|
+
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
13
|
+
elsif format == NOT_SET
|
14
|
+
to_default_s
|
15
|
+
else
|
16
|
+
ActiveSupport::Deprecation.warn(
|
17
|
+
"Time#to_s(#{format.inspect}) is deprecated. Please use Time#to_fs(#{format.inspect}) instead."
|
18
|
+
)
|
19
|
+
to_default_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -12,7 +12,7 @@ class Time
|
|
12
12
|
# Returns the TimeZone for the current request, if this has been set (via Time.zone=).
|
13
13
|
# If <tt>Time.zone</tt> has not been set for the current request, returns the TimeZone specified in <tt>config.time_zone</tt>.
|
14
14
|
def zone
|
15
|
-
|
15
|
+
::ActiveSupport::IsolatedExecutionState[:time_zone] || zone_default
|
16
16
|
end
|
17
17
|
|
18
18
|
# Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
|
@@ -21,8 +21,8 @@ class Time
|
|
21
21
|
#
|
22
22
|
# * A Rails TimeZone object.
|
23
23
|
# * An identifier for a Rails TimeZone object (e.g., "Eastern Time (US & Canada)", <tt>-5.hours</tt>).
|
24
|
-
# * A TZInfo::Timezone object.
|
25
|
-
# * An identifier for a TZInfo::Timezone object (e.g., "America/New_York").
|
24
|
+
# * A <tt>TZInfo::Timezone</tt> object.
|
25
|
+
# * An identifier for a <tt>TZInfo::Timezone</tt> object (e.g., "America/New_York").
|
26
26
|
#
|
27
27
|
# Here's an example of how you might set <tt>Time.zone</tt> on a per request basis and reset it when the request is done.
|
28
28
|
# <tt>current_user.time_zone</tt> just needs to return a string identifying the user's preferred time zone:
|
@@ -39,7 +39,7 @@ class Time
|
|
39
39
|
# end
|
40
40
|
# end
|
41
41
|
def zone=(time_zone)
|
42
|
-
|
42
|
+
::ActiveSupport::IsolatedExecutionState[:time_zone] = find_zone!(time_zone)
|
43
43
|
end
|
44
44
|
|
45
45
|
# Allows override of <tt>Time.zone</tt> locally inside supplied block;
|
@@ -55,7 +55,7 @@ class Time
|
|
55
55
|
# end
|
56
56
|
# end
|
57
57
|
#
|
58
|
-
# NOTE: This won't affect any
|
58
|
+
# NOTE: This won't affect any ActiveSupport::TimeWithZone
|
59
59
|
# objects that have already been created, e.g. any model timestamp
|
60
60
|
# attributes that have been read before the block will remain in
|
61
61
|
# the application's default timezone.
|
@@ -80,24 +80,9 @@ class Time
|
|
80
80
|
# Time.find_zone! false # => false
|
81
81
|
# Time.find_zone! "NOT-A-TIMEZONE" # => ArgumentError: Invalid Timezone: NOT-A-TIMEZONE
|
82
82
|
def find_zone!(time_zone)
|
83
|
-
|
84
|
-
time_zone
|
85
|
-
else
|
86
|
-
# Look up the timezone based on the identifier (unless we've been
|
87
|
-
# passed a TZInfo::Timezone)
|
88
|
-
unless time_zone.respond_to?(:period_for_local)
|
89
|
-
time_zone = ActiveSupport::TimeZone[time_zone] || TZInfo::Timezone.get(time_zone)
|
90
|
-
end
|
83
|
+
return time_zone unless time_zone
|
91
84
|
|
92
|
-
|
93
|
-
if time_zone.is_a?(ActiveSupport::TimeZone)
|
94
|
-
time_zone
|
95
|
-
else
|
96
|
-
ActiveSupport::TimeZone.create(time_zone.name, nil, time_zone)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
rescue TZInfo::InvalidTimezoneIdentifier
|
100
|
-
raise ArgumentError, "Invalid Timezone: #{time_zone}"
|
85
|
+
ActiveSupport::TimeZone[time_zone] || raise(ArgumentError, "Invalid Timezone: #{time_zone}")
|
101
86
|
end
|
102
87
|
|
103
88
|
# Returns a TimeZone instance matching the time zone provided.
|
@@ -4,4 +4,5 @@ require "active_support/core_ext/time/acts_like"
|
|
4
4
|
require "active_support/core_ext/time/calculations"
|
5
5
|
require "active_support/core_ext/time/compatibility"
|
6
6
|
require "active_support/core_ext/time/conversions"
|
7
|
+
require "active_support/core_ext/time/deprecated_conversions" unless ENV["RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION"]
|
7
8
|
require "active_support/core_ext/time/zones"
|
@@ -1,24 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
URI::Parser.class_eval do
|
7
|
-
silence_redefinition_of_method :unescape
|
8
|
-
def unescape(str, escaped = /%[a-fA-F\d]{2}/)
|
9
|
-
# TODO: Are we actually sure that ASCII == UTF-8?
|
10
|
-
# YK: My initial experiments say yes, but let's be sure please
|
11
|
-
enc = str.encoding
|
12
|
-
enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
|
13
|
-
str.dup.force_encoding(Encoding::ASCII_8BIT).gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
module URI
|
19
|
-
class << self
|
20
|
-
def parser
|
21
|
-
@parser ||= URI::Parser.new
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
3
|
+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
4
|
+
`active_support/core_ext/uri` is deprecated and will be removed in Rails 7.1.
|
5
|
+
MSG
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveSupport::CurrentAttributes::TestHelper # :nodoc:
|
4
|
+
def before_setup
|
5
|
+
ActiveSupport::CurrentAttributes.reset_all
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def after_teardown
|
10
|
+
super
|
11
|
+
ActiveSupport::CurrentAttributes.reset_all
|
12
|
+
end
|
13
|
+
end
|