activesupport 6.1.0 → 7.1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1075 -325
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -7
- data/lib/active_support/actionable_error.rb +4 -2
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +32 -7
- data/lib/active_support/benchmarkable.rb +3 -2
- data/lib/active_support/broadcast_logger.rb +251 -0
- data/lib/active_support/builder.rb +1 -1
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +53 -20
- data/lib/active_support/cache/mem_cache_store.rb +201 -62
- data/lib/active_support/cache/memory_store.rb +86 -24
- data/lib/active_support/cache/null_store.rb +16 -2
- data/lib/active_support/cache/redis_cache_store.rb +186 -193
- data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
- data/lib/active_support/cache/strategy/local_cache.rb +63 -71
- data/lib/active_support/cache.rb +487 -249
- data/lib/active_support/callbacks.rb +227 -105
- data/lib/active_support/code_generator.rb +70 -0
- data/lib/active_support/concern.rb +9 -7
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +18 -5
- data/lib/active_support/configuration_file.rb +7 -2
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +15 -13
- 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/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/subclasses.rb +37 -26
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +24 -9
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
- data/lib/active_support/core_ext/digest/uuid.rb +30 -13
- data/lib/active_support/core_ext/enumerable.rb +85 -83
- data/lib/active_support/core_ext/erb/util.rb +196 -0
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +1 -2
- data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +4 -4
- data/lib/active_support/core_ext/integer/inflections.rb +12 -12
- 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/module/attribute_accessors.rb +8 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +49 -22
- data/lib/active_support/core_ext/module/concerning.rb +6 -6
- data/lib/active_support/core_ext/module/delegation.rb +81 -43
- data/lib/active_support/core_ext/module/deprecation.rb +15 -12
- data/lib/active_support/core_ext/module/introspection.rb +0 -1
- data/lib/active_support/core_ext/name_error.rb +2 -8
- data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
- data/lib/active_support/core_ext/numeric/conversions.rb +82 -77
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
- data/lib/active_support/core_ext/object/duplicable.rb +31 -11
- data/lib/active_support/core_ext/object/inclusion.rb +13 -5
- data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
- data/lib/active_support/core_ext/object/json.rb +49 -27
- data/lib/active_support/core_ext/object/to_query.rb +2 -4
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with.rb +44 -0
- data/lib/active_support/core_ext/object/with_options.rb +25 -6
- data/lib/active_support/core_ext/object.rb +1 -0
- data/lib/active_support/core_ext/pathname/blank.rb +16 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +0 -25
- data/lib/active_support/core_ext/range/conversions.rb +34 -13
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range.rb +1 -2
- data/lib/active_support/core_ext/securerandom.rb +25 -13
- data/lib/active_support/core_ext/string/conversions.rb +2 -2
- data/lib/active_support/core_ext/string/filters.rb +21 -15
- data/lib/active_support/core_ext/string/indent.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +17 -10
- data/lib/active_support/core_ext/string/inquiry.rb +1 -1
- data/lib/active_support/core_ext/string/output_safety.rb +85 -165
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
- data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
- data/lib/active_support/core_ext/time/calculations.rb +30 -8
- data/lib/active_support/core_ext/time/conversions.rb +15 -13
- data/lib/active_support/core_ext/time/zones.rb +12 -28
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes.rb +47 -20
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/dependencies/autoload.rb +17 -12
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -788
- data/lib/active_support/deprecation/behaviors.rb +66 -40
- data/lib/active_support/deprecation/constant_accessor.rb +5 -4
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +6 -8
- data/lib/active_support/deprecation/instance_delegator.rb +31 -4
- data/lib/active_support/deprecation/method_wrappers.rb +9 -26
- data/lib/active_support/deprecation/proxy_wrappers.rb +38 -23
- data/lib/active_support/deprecation/reporting.rb +43 -26
- data/lib/active_support/deprecation.rb +32 -5
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +150 -72
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +9 -3
- data/lib/active_support/duration.rb +83 -52
- data/lib/active_support/encrypted_configuration.rb +72 -9
- data/lib/active_support/encrypted_file.rb +29 -13
- data/lib/active_support/environment_inquirer.rb +23 -3
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +203 -0
- data/lib/active_support/evented_file_update_checker.rb +20 -7
- 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 -22
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/file_update_checker.rb +4 -2
- data/lib/active_support/fork_tracker.rb +28 -11
- data/lib/active_support/gem_version.rb +4 -4
- data/lib/active_support/gzip.rb +2 -0
- data/lib/active_support/hash_with_indifferent_access.rb +44 -19
- data/lib/active_support/html_safe_translation.rb +53 -0
- data/lib/active_support/i18n.rb +2 -1
- data/lib/active_support/i18n_railtie.rb +21 -14
- data/lib/active_support/inflector/inflections.rb +25 -7
- data/lib/active_support/inflector/methods.rb +50 -64
- data/lib/active_support/inflector/transliterate.rb +4 -2
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +2 -1
- data/lib/active_support/json/encoding.rb +27 -45
- data/lib/active_support/key_generator.rb +31 -6
- data/lib/active_support/lazy_load_hooks.rb +33 -7
- data/lib/active_support/locale/en.yml +4 -2
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +97 -35
- data/lib/active_support/logger.rb +9 -60
- data/lib/active_support/logger_thread_safe_level.rb +11 -34
- data/lib/active_support/message_encryptor.rb +206 -56
- data/lib/active_support/message_encryptors.rb +141 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +292 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +235 -84
- data/lib/active_support/message_verifiers.rb +135 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +112 -46
- data/lib/active_support/messages/rotation_coordinator.rb +93 -0
- data/lib/active_support/messages/rotator.rb +34 -32
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +12 -11
- data/lib/active_support/multibyte/unicode.rb +9 -49
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +304 -114
- data/lib/active_support/notifications/instrumenter.rb +117 -35
- data/lib/active_support/notifications.rb +25 -25
- data/lib/active_support/number_helper/number_converter.rb +14 -7
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -4
- data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +10 -6
- data/lib/active_support/number_helper/rounding_helper.rb +2 -6
- data/lib/active_support/number_helper.rb +379 -319
- data/lib/active_support/option_merger.rb +10 -18
- data/lib/active_support/ordered_hash.rb +4 -4
- data/lib/active_support/ordered_options.rb +15 -1
- data/lib/active_support/parameter_filter.rb +105 -81
- data/lib/active_support/proxy_object.rb +2 -0
- data/lib/active_support/railtie.rb +83 -21
- data/lib/active_support/reloader.rb +13 -5
- data/lib/active_support/rescuable.rb +18 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +18 -11
- data/lib/active_support/security_utils.rb +1 -1
- data/lib/active_support/string_inquirer.rb +3 -3
- data/lib/active_support/subscriber.rb +11 -40
- data/lib/active_support/syntax_error_proxy.rb +60 -0
- data/lib/active_support/tagged_logging.rb +65 -25
- data/lib/active_support/test_case.rb +166 -27
- data/lib/active_support/testing/assertions.rb +61 -15
- data/lib/active_support/testing/autorun.rb +0 -2
- data/lib/active_support/testing/constant_stubbing.rb +32 -0
- data/lib/active_support/testing/deprecation.rb +53 -2
- data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
- data/lib/active_support/testing/isolation.rb +30 -29
- data/lib/active_support/testing/method_call_assertions.rb +24 -11
- data/lib/active_support/testing/parallelization/server.rb +4 -0
- data/lib/active_support/testing/parallelization/worker.rb +3 -0
- data/lib/active_support/testing/parallelization.rb +4 -0
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/setup_and_teardown.rb +2 -0
- data/lib/active_support/testing/stream.rb +4 -6
- data/lib/active_support/testing/strict_warnings.rb +39 -0
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +49 -16
- data/lib/active_support/time_with_zone.rb +39 -28
- data/lib/active_support/values/time_zone.rb +50 -18
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +4 -11
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +5 -5
- data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
- data/lib/active_support/xml_mini/rexml.rb +2 -2
- data/lib/active_support/xml_mini.rb +7 -6
- data/lib/active_support.rb +28 -1
- metadata +150 -18
- data/lib/active_support/core_ext/marshal.rb +0 -26
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -28
- data/lib/active_support/core_ext/range/overlaps.rb +0 -10
- data/lib/active_support/core_ext/uri.rb +0 -29
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
- data/lib/active_support/per_thread_registry.rb +0 -60
@@ -4,7 +4,7 @@ require "active_support/string_inquirer"
|
|
4
4
|
require "active_support/environment_inquirer"
|
5
5
|
|
6
6
|
class String
|
7
|
-
# Wraps the current string in the
|
7
|
+
# Wraps the current string in the ActiveSupport::StringInquirer class,
|
8
8
|
# which gives you a prettier way to test for equality.
|
9
9
|
#
|
10
10
|
# env = 'production'.inquiry
|
@@ -1,123 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "erb"
|
4
|
-
require "active_support/core_ext/module/redefine_method"
|
3
|
+
require "active_support/core_ext/erb/util"
|
5
4
|
require "active_support/multibyte/unicode"
|
6
5
|
|
7
|
-
class ERB
|
8
|
-
module Util
|
9
|
-
HTML_ESCAPE = { "&" => "&", ">" => ">", "<" => "<", '"' => """, "'" => "'" }
|
10
|
-
JSON_ESCAPE = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
|
11
|
-
HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
|
12
|
-
JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
|
13
|
-
|
14
|
-
# A utility method for escaping HTML tag characters.
|
15
|
-
# This method is also aliased as <tt>h</tt>.
|
16
|
-
#
|
17
|
-
# puts html_escape('is a > 0 & a < 10?')
|
18
|
-
# # => is a > 0 & a < 10?
|
19
|
-
def html_escape(s)
|
20
|
-
unwrapped_html_escape(s).html_safe
|
21
|
-
end
|
22
|
-
|
23
|
-
silence_redefinition_of_method :h
|
24
|
-
alias h html_escape
|
25
|
-
|
26
|
-
module_function :h
|
27
|
-
|
28
|
-
singleton_class.silence_redefinition_of_method :html_escape
|
29
|
-
module_function :html_escape
|
30
|
-
|
31
|
-
# HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer.
|
32
|
-
# This method is not for public consumption! Seriously!
|
33
|
-
def unwrapped_html_escape(s) # :nodoc:
|
34
|
-
s = s.to_s
|
35
|
-
if s.html_safe?
|
36
|
-
s
|
37
|
-
else
|
38
|
-
CGI.escapeHTML(ActiveSupport::Multibyte::Unicode.tidy_bytes(s))
|
39
|
-
end
|
40
|
-
end
|
41
|
-
module_function :unwrapped_html_escape
|
42
|
-
|
43
|
-
# A utility method for escaping HTML without affecting existing escaped entities.
|
44
|
-
#
|
45
|
-
# html_escape_once('1 < 2 & 3')
|
46
|
-
# # => "1 < 2 & 3"
|
47
|
-
#
|
48
|
-
# html_escape_once('<< Accept & Checkout')
|
49
|
-
# # => "<< Accept & Checkout"
|
50
|
-
def html_escape_once(s)
|
51
|
-
result = ActiveSupport::Multibyte::Unicode.tidy_bytes(s.to_s).gsub(HTML_ESCAPE_ONCE_REGEXP, HTML_ESCAPE)
|
52
|
-
s.html_safe? ? result.html_safe : result
|
53
|
-
end
|
54
|
-
|
55
|
-
module_function :html_escape_once
|
56
|
-
|
57
|
-
# A utility method for escaping HTML entities in JSON strings. Specifically, the
|
58
|
-
# &, > and < characters are replaced with their equivalent unicode escaped form -
|
59
|
-
# \u0026, \u003e, and \u003c. The Unicode sequences \u2028 and \u2029 are also
|
60
|
-
# escaped as they are treated as newline characters in some JavaScript engines.
|
61
|
-
# These sequences have identical meaning as the original characters inside the
|
62
|
-
# context of a JSON string, so assuming the input is a valid and well-formed
|
63
|
-
# JSON value, the output will have equivalent meaning when parsed:
|
64
|
-
#
|
65
|
-
# json = JSON.generate({ name: "</script><script>alert('PWNED!!!')</script>"})
|
66
|
-
# # => "{\"name\":\"</script><script>alert('PWNED!!!')</script>\"}"
|
67
|
-
#
|
68
|
-
# json_escape(json)
|
69
|
-
# # => "{\"name\":\"\\u003C/script\\u003E\\u003Cscript\\u003Ealert('PWNED!!!')\\u003C/script\\u003E\"}"
|
70
|
-
#
|
71
|
-
# JSON.parse(json) == JSON.parse(json_escape(json))
|
72
|
-
# # => true
|
73
|
-
#
|
74
|
-
# The intended use case for this method is to escape JSON strings before including
|
75
|
-
# them inside a script tag to avoid XSS vulnerability:
|
76
|
-
#
|
77
|
-
# <script>
|
78
|
-
# var currentUser = <%= raw json_escape(current_user.to_json) %>;
|
79
|
-
# </script>
|
80
|
-
#
|
81
|
-
# It is necessary to +raw+ the result of +json_escape+, so that quotation marks
|
82
|
-
# don't get converted to <tt>"</tt> entities. +json_escape+ doesn't
|
83
|
-
# automatically flag the result as HTML safe, since the raw value is unsafe to
|
84
|
-
# use inside HTML attributes.
|
85
|
-
#
|
86
|
-
# If your JSON is being used downstream for insertion into the DOM, be aware of
|
87
|
-
# whether or not it is being inserted via +html()+. Most jQuery plugins do this.
|
88
|
-
# If that is the case, be sure to +html_escape+ or +sanitize+ any user-generated
|
89
|
-
# content returned by your JSON.
|
90
|
-
#
|
91
|
-
# If you need to output JSON elsewhere in your HTML, you can just do something
|
92
|
-
# like this, as any unsafe characters (including quotation marks) will be
|
93
|
-
# automatically escaped for you:
|
94
|
-
#
|
95
|
-
# <div data-user-info="<%= current_user.to_json %>">...</div>
|
96
|
-
#
|
97
|
-
# WARNING: this helper only works with valid JSON. Using this on non-JSON values
|
98
|
-
# will open up serious XSS vulnerabilities. For example, if you replace the
|
99
|
-
# +current_user.to_json+ in the example above with user input instead, the browser
|
100
|
-
# will happily eval() that string as JavaScript.
|
101
|
-
#
|
102
|
-
# The escaping performed in this method is identical to those performed in the
|
103
|
-
# Active Support JSON encoder when +ActiveSupport.escape_html_entities_in_json+ is
|
104
|
-
# set to true. Because this transformation is idempotent, this helper can be
|
105
|
-
# applied even if +ActiveSupport.escape_html_entities_in_json+ is already true.
|
106
|
-
#
|
107
|
-
# Therefore, when you are unsure if +ActiveSupport.escape_html_entities_in_json+
|
108
|
-
# is enabled, or if you are unsure where your JSON string originated from, it
|
109
|
-
# is recommended that you always apply this helper (other libraries, such as the
|
110
|
-
# JSON gem, do not provide this kind of protection by default; also some gems
|
111
|
-
# might override +to_json+ to bypass Active Support's encoder).
|
112
|
-
def json_escape(s)
|
113
|
-
result = s.to_s.gsub(JSON_ESCAPE_REGEXP, JSON_ESCAPE)
|
114
|
-
s.html_safe? ? result.html_safe : result
|
115
|
-
end
|
116
|
-
|
117
|
-
module_function :json_escape
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
6
|
class Object
|
122
7
|
def html_safe?
|
123
8
|
false
|
@@ -130,11 +15,11 @@ class Numeric
|
|
130
15
|
end
|
131
16
|
end
|
132
17
|
|
133
|
-
module ActiveSupport
|
18
|
+
module ActiveSupport # :nodoc:
|
134
19
|
class SafeBuffer < String
|
135
20
|
UNSAFE_STRING_METHODS = %w(
|
136
21
|
capitalize chomp chop delete delete_prefix delete_suffix
|
137
|
-
downcase lstrip next reverse rstrip scrub
|
22
|
+
downcase lstrip next reverse rstrip scrub squeeze strip
|
138
23
|
succ swapcase tr tr_s unicode_normalize upcase
|
139
24
|
)
|
140
25
|
|
@@ -143,10 +28,10 @@ module ActiveSupport #:nodoc:
|
|
143
28
|
alias_method :original_concat, :concat
|
144
29
|
private :original_concat
|
145
30
|
|
146
|
-
# Raised when
|
31
|
+
# Raised when ActiveSupport::SafeBuffer#safe_concat is called on unsafe buffers.
|
147
32
|
class SafeConcatError < StandardError
|
148
33
|
def initialize
|
149
|
-
super "Could not concatenate to the buffer because it is not
|
34
|
+
super "Could not concatenate to the buffer because it is not HTML safe."
|
150
35
|
end
|
151
36
|
end
|
152
37
|
|
@@ -156,13 +41,26 @@ module ActiveSupport #:nodoc:
|
|
156
41
|
|
157
42
|
return unless new_string
|
158
43
|
|
159
|
-
|
160
|
-
new_safe_buffer.instance_variable_set :@html_safe, true
|
161
|
-
new_safe_buffer
|
44
|
+
string_into_safe_buffer(new_string, true)
|
162
45
|
else
|
163
46
|
to_str[*args]
|
164
47
|
end
|
165
48
|
end
|
49
|
+
alias_method :slice, :[]
|
50
|
+
|
51
|
+
def slice!(*args)
|
52
|
+
new_string = super
|
53
|
+
|
54
|
+
return new_string if !html_safe? || new_string.nil?
|
55
|
+
|
56
|
+
string_into_safe_buffer(new_string, true)
|
57
|
+
end
|
58
|
+
|
59
|
+
def chr
|
60
|
+
return super unless html_safe?
|
61
|
+
|
62
|
+
string_into_safe_buffer(super, true)
|
63
|
+
end
|
166
64
|
|
167
65
|
def safe_concat(value)
|
168
66
|
raise SafeConcatError unless html_safe?
|
@@ -179,32 +77,42 @@ module ActiveSupport #:nodoc:
|
|
179
77
|
@html_safe = other.html_safe?
|
180
78
|
end
|
181
79
|
|
182
|
-
def clone_empty
|
80
|
+
def clone_empty # :nodoc:
|
81
|
+
ActiveSupport.deprecator.warn <<~EOM
|
82
|
+
ActiveSupport::SafeBuffer#clone_empty is deprecated and will be removed in Rails 7.2.
|
83
|
+
EOM
|
183
84
|
self[0, 0]
|
184
85
|
end
|
185
86
|
|
186
87
|
def concat(value)
|
187
|
-
|
88
|
+
unless value.nil?
|
89
|
+
super(implicit_html_escape_interpolated_argument(value))
|
90
|
+
end
|
91
|
+
self
|
188
92
|
end
|
189
93
|
alias << concat
|
190
94
|
|
95
|
+
def bytesplice(*args, value)
|
96
|
+
super(*args, implicit_html_escape_interpolated_argument(value))
|
97
|
+
end
|
98
|
+
|
191
99
|
def insert(index, value)
|
192
|
-
super(index,
|
100
|
+
super(index, implicit_html_escape_interpolated_argument(value))
|
193
101
|
end
|
194
102
|
|
195
103
|
def prepend(value)
|
196
|
-
super(
|
104
|
+
super(implicit_html_escape_interpolated_argument(value))
|
197
105
|
end
|
198
106
|
|
199
107
|
def replace(value)
|
200
|
-
super(
|
108
|
+
super(implicit_html_escape_interpolated_argument(value))
|
201
109
|
end
|
202
110
|
|
203
|
-
def []=(
|
204
|
-
if
|
205
|
-
super(
|
111
|
+
def []=(arg1, arg2, arg3 = nil)
|
112
|
+
if arg3
|
113
|
+
super(arg1, arg2, implicit_html_escape_interpolated_argument(arg3))
|
206
114
|
else
|
207
|
-
super(
|
115
|
+
super(arg1, implicit_html_escape_interpolated_argument(arg2))
|
208
116
|
end
|
209
117
|
end
|
210
118
|
|
@@ -212,7 +120,7 @@ module ActiveSupport #:nodoc:
|
|
212
120
|
dup.concat(other)
|
213
121
|
end
|
214
122
|
|
215
|
-
def *(
|
123
|
+
def *(_)
|
216
124
|
new_string = super
|
217
125
|
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
218
126
|
new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
|
@@ -222,17 +130,17 @@ module ActiveSupport #:nodoc:
|
|
222
130
|
def %(args)
|
223
131
|
case args
|
224
132
|
when Hash
|
225
|
-
escaped_args = args.transform_values { |arg|
|
133
|
+
escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
|
226
134
|
else
|
227
|
-
escaped_args = Array(args).map { |arg|
|
135
|
+
escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
|
228
136
|
end
|
229
137
|
|
230
138
|
self.class.new(super(escaped_args))
|
231
139
|
end
|
232
140
|
|
233
|
-
|
234
|
-
|
235
|
-
|
141
|
+
attr_reader :html_safe
|
142
|
+
alias_method :html_safe?, :html_safe
|
143
|
+
remove_method :html_safe
|
236
144
|
|
237
145
|
def to_s
|
238
146
|
self
|
@@ -262,44 +170,56 @@ module ActiveSupport #:nodoc:
|
|
262
170
|
end
|
263
171
|
|
264
172
|
UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
EOT
|
290
|
-
end
|
173
|
+
class_eval <<-EOT, __FILE__, __LINE__ + 1
|
174
|
+
def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
|
175
|
+
if block # if block
|
176
|
+
to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
|
177
|
+
set_block_back_references(block, $~) # set_block_back_references(block, $~)
|
178
|
+
block.call(*params) # block.call(*params)
|
179
|
+
} # }
|
180
|
+
else # else
|
181
|
+
to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
|
182
|
+
end # end
|
183
|
+
end # end
|
184
|
+
|
185
|
+
def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
|
186
|
+
@html_safe = false # @html_safe = false
|
187
|
+
if block # if block
|
188
|
+
super(*args) { |*params| # super(*args) { |*params|
|
189
|
+
set_block_back_references(block, $~) # set_block_back_references(block, $~)
|
190
|
+
block.call(*params) # block.call(*params)
|
191
|
+
} # }
|
192
|
+
else # else
|
193
|
+
super # super
|
194
|
+
end # end
|
195
|
+
end # end
|
196
|
+
EOT
|
291
197
|
end
|
292
198
|
|
293
199
|
private
|
294
|
-
def
|
200
|
+
def explicit_html_escape_interpolated_argument(arg)
|
295
201
|
(!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
|
296
202
|
end
|
297
203
|
|
204
|
+
def implicit_html_escape_interpolated_argument(arg)
|
205
|
+
if !html_safe? || arg.html_safe?
|
206
|
+
arg
|
207
|
+
else
|
208
|
+
CGI.escapeHTML(arg.to_str)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
298
212
|
def set_block_back_references(block, match_data)
|
299
213
|
block.binding.eval("proc { |m| $~ = m }").call(match_data)
|
300
214
|
rescue ArgumentError
|
301
215
|
# Can't create binding from C level Proc
|
302
216
|
end
|
217
|
+
|
218
|
+
def string_into_safe_buffer(new_string, is_html_safe)
|
219
|
+
new_safe_buffer = new_string.is_a?(SafeBuffer) ? new_string : SafeBuffer.new(new_string)
|
220
|
+
new_safe_buffer.instance_variable_set :@html_safe, is_html_safe
|
221
|
+
new_safe_buffer
|
222
|
+
end
|
303
223
|
end
|
304
224
|
end
|
305
225
|
|
@@ -1,14 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Symbol
|
4
|
-
def start_with?(*prefixes)
|
5
|
-
to_s.start_with?(*prefixes)
|
6
|
-
end unless method_defined?(:start_with?)
|
7
|
-
|
8
|
-
def end_with?(*suffixes)
|
9
|
-
to_s.end_with?(*suffixes)
|
10
|
-
end unless method_defined?(:end_with?)
|
11
|
-
|
12
4
|
alias :starts_with? :start_with?
|
13
5
|
alias :ends_with? :end_with?
|
14
6
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Thread::Backtrace::Location # :nodoc:
|
4
|
+
if defined?(ErrorHighlight) && Gem::Version.new(ErrorHighlight::VERSION) >= Gem::Version.new("0.4.0")
|
5
|
+
def spot(ex)
|
6
|
+
ErrorHighlight.spot(ex, backtrace_location: self)
|
7
|
+
end
|
8
|
+
else
|
9
|
+
def spot(ex)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -42,8 +42,8 @@ class Time
|
|
42
42
|
|
43
43
|
# Layers additional behavior on Time.at so that ActiveSupport::TimeWithZone and DateTime
|
44
44
|
# instances can be used when called with a single argument
|
45
|
-
def at_with_coercion(*args)
|
46
|
-
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?
|
47
47
|
|
48
48
|
# Time.at can be called with a time or numerical value
|
49
49
|
time_or_number = args.first
|
@@ -126,8 +126,8 @@ class Time
|
|
126
126
|
# Returns a new Time where one or more of the elements have been changed according
|
127
127
|
# to the +options+ parameter. The time options (<tt>:hour</tt>, <tt>:min</tt>,
|
128
128
|
# <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly, so if only
|
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
|
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
|
131
131
|
# takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
|
132
132
|
# <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>,
|
133
133
|
# <tt>:offset</tt>. Pass either <tt>:usec</tt> or <tt>:nsec</tt>, not both.
|
@@ -159,8 +159,26 @@ class Time
|
|
159
159
|
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, new_offset)
|
160
160
|
elsif utc?
|
161
161
|
::Time.utc(new_year, new_month, new_day, new_hour, new_min, new_sec)
|
162
|
+
elsif zone&.respond_to?(:utc_to_local)
|
163
|
+
new_time = ::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, zone)
|
164
|
+
|
165
|
+
# When there are two occurrences of a nominal time due to DST ending,
|
166
|
+
# `Time.new` chooses the first chronological occurrence (the one with a
|
167
|
+
# larger UTC offset). However, for `change`, we want to choose the
|
168
|
+
# occurrence that matches this time's UTC offset.
|
169
|
+
#
|
170
|
+
# If the new time's UTC offset is larger than this time's UTC offset, the
|
171
|
+
# new time might be a first chronological occurrence. So we add the offset
|
172
|
+
# difference to fast-forward the new time, and check if the result has the
|
173
|
+
# desired UTC offset (i.e. is the second chronological occurrence).
|
174
|
+
offset_difference = new_time.utc_offset - utc_offset
|
175
|
+
if offset_difference > 0 && (new_time_2 = new_time + offset_difference).utc_offset == utc_offset
|
176
|
+
new_time_2
|
177
|
+
else
|
178
|
+
new_time
|
179
|
+
end
|
162
180
|
elsif zone
|
163
|
-
::Time.local(
|
181
|
+
::Time.local(new_sec, new_min, new_hour, new_day, new_month, new_year, nil, nil, isdst, nil)
|
164
182
|
else
|
165
183
|
::Time.new(new_year, new_month, new_day, new_hour, new_min, new_sec, utc_offset)
|
166
184
|
end
|
@@ -177,6 +195,10 @@ class Time
|
|
177
195
|
# Time.new(2015, 8, 1, 14, 35, 0).advance(hours: 1) # => 2015-08-01 15:35:00 -0700
|
178
196
|
# Time.new(2015, 8, 1, 14, 35, 0).advance(days: 1) # => 2015-08-02 14:35:00 -0700
|
179
197
|
# Time.new(2015, 8, 1, 14, 35, 0).advance(weeks: 1) # => 2015-08-08 14:35:00 -0700
|
198
|
+
#
|
199
|
+
# Just like Date#advance, increments are applied in order of time units from
|
200
|
+
# largest to smallest. This order can affect the result around the end of a
|
201
|
+
# month.
|
180
202
|
def advance(options)
|
181
203
|
unless options[:weeks].nil?
|
182
204
|
options[:weeks], partial_weeks = options[:weeks].divmod(1)
|
@@ -275,7 +297,7 @@ class Time
|
|
275
297
|
end
|
276
298
|
alias :at_end_of_minute :end_of_minute
|
277
299
|
|
278
|
-
def plus_with_duration(other)
|
300
|
+
def plus_with_duration(other) # :nodoc:
|
279
301
|
if ActiveSupport::Duration === other
|
280
302
|
other.since(self)
|
281
303
|
else
|
@@ -285,7 +307,7 @@ class Time
|
|
285
307
|
alias_method :plus_without_duration, :+
|
286
308
|
alias_method :+, :plus_with_duration
|
287
309
|
|
288
|
-
def minus_with_duration(other)
|
310
|
+
def minus_with_duration(other) # :nodoc:
|
289
311
|
if ActiveSupport::Duration === other
|
290
312
|
other.until(self)
|
291
313
|
else
|
@@ -303,7 +325,7 @@ class Time
|
|
303
325
|
other.is_a?(DateTime) ? to_f - other.to_f : minus_without_coercion(other)
|
304
326
|
end
|
305
327
|
alias_method :minus_without_coercion, :-
|
306
|
-
alias_method :-, :minus_with_coercion
|
328
|
+
alias_method :-, :minus_with_coercion # rubocop:disable Lint/DuplicateMethods
|
307
329
|
|
308
330
|
# Layers additional behavior on Time#<=> so that DateTime and ActiveSupport::TimeWithZone instances
|
309
331
|
# can be chronologically compared with a Time
|
@@ -1,5 +1,6 @@
|
|
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
|
|
@@ -26,22 +27,22 @@ class Time
|
|
26
27
|
|
27
28
|
# Converts to a formatted string. See DATE_FORMATS for built-in formats.
|
28
29
|
#
|
29
|
-
# This method is aliased to <tt>
|
30
|
+
# This method is aliased to <tt>to_formatted_s</tt>.
|
30
31
|
#
|
31
32
|
# time = Time.now # => 2007-01-18 06:10:17 -06:00
|
32
33
|
#
|
34
|
+
# time.to_fs(:time) # => "06:10"
|
33
35
|
# time.to_formatted_s(:time) # => "06:10"
|
34
|
-
# time.to_s(:time) # => "06:10"
|
35
36
|
#
|
36
|
-
# time.
|
37
|
-
# time.
|
38
|
-
# time.
|
39
|
-
# time.
|
40
|
-
# time.
|
41
|
-
# time.
|
42
|
-
# 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"
|
43
44
|
#
|
44
|
-
# == Adding your own time formats to +
|
45
|
+
# == Adding your own time formats to +to_fs+
|
45
46
|
# You can add your own formats to the Time::DATE_FORMATS hash.
|
46
47
|
# Use the format name as the hash key and either a strftime string
|
47
48
|
# or Proc instance that takes a time argument as the value.
|
@@ -49,15 +50,16 @@ class Time
|
|
49
50
|
# # config/initializers/time_formats.rb
|
50
51
|
# Time::DATE_FORMATS[:month_and_year] = '%B %Y'
|
51
52
|
# Time::DATE_FORMATS[:short_ordinal] = ->(time) { time.strftime("%B #{time.day.ordinalize}") }
|
52
|
-
def
|
53
|
+
def to_fs(format = :default)
|
53
54
|
if formatter = DATE_FORMATS[format]
|
54
55
|
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
|
55
56
|
else
|
56
|
-
|
57
|
+
to_s
|
57
58
|
end
|
58
59
|
end
|
60
|
+
alias_method :to_formatted_s, :to_fs
|
59
61
|
alias_method :to_default_s, :to_s
|
60
|
-
|
62
|
+
deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
|
61
63
|
|
62
64
|
# Returns a formatted string of the offset from UTC, or an alternative
|
63
65
|
# string if the time zone is already UTC.
|
@@ -12,17 +12,17 @@ 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.
|
19
19
|
#
|
20
20
|
# This method accepts any of the following:
|
21
21
|
#
|
22
|
-
# * A Rails TimeZone object.
|
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").
|
22
|
+
# * A \Rails TimeZone object.
|
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").
|
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;
|
@@ -49,13 +49,12 @@ 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
|
-
# NOTE: This won't affect any
|
57
|
+
# NOTE: This won't affect any ActiveSupport::TimeWithZone
|
59
58
|
# objects that have already been created, e.g. any model timestamp
|
60
59
|
# attributes that have been read before the block will remain in
|
61
60
|
# the application's default timezone.
|
@@ -80,24 +79,9 @@ class Time
|
|
80
79
|
# Time.find_zone! false # => false
|
81
80
|
# Time.find_zone! "NOT-A-TIMEZONE" # => ArgumentError: Invalid Timezone: NOT-A-TIMEZONE
|
82
81
|
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
|
82
|
+
return time_zone unless time_zone
|
91
83
|
|
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}"
|
84
|
+
ActiveSupport::TimeZone[time_zone] || raise(ArgumentError, "Invalid Timezone: #{time_zone}")
|
101
85
|
end
|
102
86
|
|
103
87
|
# Returns a TimeZone instance matching the time zone provided.
|