activesupport 6.1.7.4 → 7.0.0.alpha1

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.

Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +151 -632
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/actionable_error.rb +1 -1
  5. data/lib/active_support/array_inquirer.rb +0 -2
  6. data/lib/active_support/benchmarkable.rb +2 -2
  7. data/lib/active_support/cache/file_store.rb +15 -9
  8. data/lib/active_support/cache/mem_cache_store.rb +119 -28
  9. data/lib/active_support/cache/memory_store.rb +21 -13
  10. data/lib/active_support/cache/null_store.rb +10 -2
  11. data/lib/active_support/cache/redis_cache_store.rb +39 -59
  12. data/lib/active_support/cache/strategy/local_cache.rb +29 -49
  13. data/lib/active_support/cache.rb +189 -45
  14. data/lib/active_support/callbacks.rb +35 -31
  15. data/lib/active_support/concern.rb +5 -5
  16. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
  17. data/lib/active_support/concurrency/share_lock.rb +2 -2
  18. data/lib/active_support/configurable.rb +6 -3
  19. data/lib/active_support/configuration_file.rb +1 -1
  20. data/lib/active_support/core_ext/array/access.rb +1 -5
  21. data/lib/active_support/core_ext/array/conversions.rb +6 -6
  22. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  23. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  24. data/lib/active_support/core_ext/date/blank.rb +1 -1
  25. data/lib/active_support/core_ext/date/calculations.rb +2 -2
  26. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  27. data/lib/active_support/core_ext/digest/uuid.rb +13 -13
  28. data/lib/active_support/core_ext/enumerable.rb +64 -12
  29. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  30. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  31. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  32. data/lib/active_support/core_ext/module/delegation.rb +2 -8
  33. data/lib/active_support/core_ext/name_error.rb +2 -8
  34. data/lib/active_support/core_ext/numeric/conversions.rb +2 -2
  35. data/lib/active_support/core_ext/object/blank.rb +2 -2
  36. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  37. data/lib/active_support/core_ext/object/duplicable.rb +11 -0
  38. data/lib/active_support/core_ext/object/json.rb +29 -24
  39. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  40. data/lib/active_support/core_ext/object/try.rb +20 -20
  41. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  42. data/lib/active_support/core_ext/range/each.rb +1 -1
  43. data/lib/active_support/core_ext/range/include_time_with_zone.rb +1 -1
  44. data/lib/active_support/core_ext/string/filters.rb +1 -1
  45. data/lib/active_support/core_ext/string/inflections.rb +1 -1
  46. data/lib/active_support/core_ext/string/output_safety.rb +60 -68
  47. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  48. data/lib/active_support/core_ext/time/calculations.rb +4 -5
  49. data/lib/active_support/core_ext/time/zones.rb +2 -17
  50. data/lib/active_support/core_ext/uri.rb +0 -14
  51. data/lib/active_support/current_attributes.rb +17 -2
  52. data/lib/active_support/dependencies/interlock.rb +10 -18
  53. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  54. data/lib/active_support/dependencies.rb +58 -788
  55. data/lib/active_support/deprecation/behaviors.rb +4 -1
  56. data/lib/active_support/deprecation/method_wrappers.rb +3 -3
  57. data/lib/active_support/deprecation/proxy_wrappers.rb +1 -1
  58. data/lib/active_support/deprecation.rb +1 -1
  59. data/lib/active_support/descendants_tracker.rb +12 -9
  60. data/lib/active_support/digest.rb +4 -4
  61. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  62. data/lib/active_support/duration/iso8601_serializer.rb +9 -1
  63. data/lib/active_support/duration.rb +80 -52
  64. data/lib/active_support/encrypted_configuration.rb +11 -1
  65. data/lib/active_support/encrypted_file.rb +1 -1
  66. data/lib/active_support/environment_inquirer.rb +1 -1
  67. data/lib/active_support/evented_file_update_checker.rb +1 -1
  68. data/lib/active_support/execution_wrapper.rb +13 -16
  69. data/lib/active_support/fork_tracker.rb +2 -4
  70. data/lib/active_support/gem_version.rb +4 -4
  71. data/lib/active_support/hash_with_indifferent_access.rb +3 -1
  72. data/lib/active_support/i18n.rb +1 -0
  73. data/lib/active_support/inflector/inflections.rb +11 -4
  74. data/lib/active_support/inflector/methods.rb +23 -46
  75. data/lib/active_support/json/encoding.rb +3 -3
  76. data/lib/active_support/key_generator.rb +18 -1
  77. data/lib/active_support/locale/en.yml +1 -1
  78. data/lib/active_support/log_subscriber.rb +13 -3
  79. data/lib/active_support/logger_thread_safe_level.rb +5 -13
  80. data/lib/active_support/message_encryptor.rb +3 -3
  81. data/lib/active_support/message_verifier.rb +4 -4
  82. data/lib/active_support/messages/metadata.rb +2 -2
  83. data/lib/active_support/multibyte/chars.rb +10 -11
  84. data/lib/active_support/multibyte.rb +1 -1
  85. data/lib/active_support/notifications/fanout.rb +31 -11
  86. data/lib/active_support/notifications/instrumenter.rb +17 -0
  87. data/lib/active_support/notifications.rb +10 -0
  88. data/lib/active_support/number_helper/number_converter.rb +1 -3
  89. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  90. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  91. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  92. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
  93. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  94. data/lib/active_support/number_helper.rb +0 -2
  95. data/lib/active_support/option_merger.rb +4 -16
  96. data/lib/active_support/ordered_hash.rb +1 -1
  97. data/lib/active_support/parameter_filter.rb +5 -0
  98. data/lib/active_support/per_thread_registry.rb +1 -1
  99. data/lib/active_support/railtie.rb +33 -10
  100. data/lib/active_support/reloader.rb +1 -1
  101. data/lib/active_support/rescuable.rb +2 -2
  102. data/lib/active_support/secure_compare_rotator.rb +1 -1
  103. data/lib/active_support/string_inquirer.rb +0 -2
  104. data/lib/active_support/subscriber.rb +5 -0
  105. data/lib/active_support/test_case.rb +9 -21
  106. data/lib/active_support/testing/assertions.rb +34 -4
  107. data/lib/active_support/testing/deprecation.rb +1 -1
  108. data/lib/active_support/testing/isolation.rb +1 -1
  109. data/lib/active_support/testing/method_call_assertions.rb +5 -5
  110. data/lib/active_support/testing/parallelization/server.rb +4 -0
  111. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  112. data/lib/active_support/testing/parallelization.rb +4 -0
  113. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  114. data/lib/active_support/testing/stream.rb +3 -5
  115. data/lib/active_support/testing/tagged_logging.rb +1 -1
  116. data/lib/active_support/testing/time_helpers.rb +13 -2
  117. data/lib/active_support/time_with_zone.rb +19 -6
  118. data/lib/active_support/values/time_zone.rb +25 -11
  119. data/lib/active_support/xml_mini/jdom.rb +1 -1
  120. data/lib/active_support/xml_mini/libxml.rb +5 -5
  121. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  122. data/lib/active_support/xml_mini/nokogiri.rb +4 -4
  123. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  124. data/lib/active_support/xml_mini/rexml.rb +1 -1
  125. data/lib/active_support/xml_mini.rb +2 -1
  126. data/lib/active_support.rb +14 -1
  127. metadata +14 -29
  128. data/lib/active_support/core_ext/marshal.rb +0 -26
  129. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
@@ -19,8 +19,7 @@ require "active_support/core_ext/date/conversions"
19
19
  # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting
20
20
  # their default behavior. That said, we need to define the basic to_json method in all of them,
21
21
  # otherwise they will always use to_json gem implementation, which is backwards incompatible in
22
- # several cases (for instance, the JSON implementation for Hash does not work) with inheritance
23
- # and consequently classes as ActiveSupport::OrderedHash cannot be serialized to json.
22
+ # several cases (for instance, the JSON implementation for Hash does not work) with inheritance.
24
23
  #
25
24
  # On the other hand, we should avoid conflict with ::JSON.{generate,dump}(obj). Unfortunately, the
26
25
  # JSON gem's encoder relies on its own to_json implementation to encode objects. Since it always
@@ -50,8 +49,14 @@ end
50
49
  klass.prepend(ActiveSupport::ToJsonWithActiveSupportEncoder)
51
50
  end
52
51
 
52
+ class Module
53
+ def as_json(options = nil) # :nodoc:
54
+ name
55
+ end
56
+ end
57
+
53
58
  class Object
54
- def as_json(options = nil) #:nodoc:
59
+ def as_json(options = nil) # :nodoc:
55
60
  if respond_to?(:to_hash)
56
61
  to_hash.as_json(options)
57
62
  else
@@ -60,44 +65,44 @@ class Object
60
65
  end
61
66
  end
62
67
 
63
- class Struct #:nodoc:
68
+ class Struct # :nodoc:
64
69
  def as_json(options = nil)
65
70
  Hash[members.zip(values)].as_json(options)
66
71
  end
67
72
  end
68
73
 
69
74
  class TrueClass
70
- def as_json(options = nil) #:nodoc:
75
+ def as_json(options = nil) # :nodoc:
71
76
  self
72
77
  end
73
78
  end
74
79
 
75
80
  class FalseClass
76
- def as_json(options = nil) #:nodoc:
81
+ def as_json(options = nil) # :nodoc:
77
82
  self
78
83
  end
79
84
  end
80
85
 
81
86
  class NilClass
82
- def as_json(options = nil) #:nodoc:
87
+ def as_json(options = nil) # :nodoc:
83
88
  self
84
89
  end
85
90
  end
86
91
 
87
92
  class String
88
- def as_json(options = nil) #:nodoc:
93
+ def as_json(options = nil) # :nodoc:
89
94
  self
90
95
  end
91
96
  end
92
97
 
93
98
  class Symbol
94
- def as_json(options = nil) #:nodoc:
99
+ def as_json(options = nil) # :nodoc:
95
100
  to_s
96
101
  end
97
102
  end
98
103
 
99
104
  class Numeric
100
- def as_json(options = nil) #:nodoc:
105
+ def as_json(options = nil) # :nodoc:
101
106
  self
102
107
  end
103
108
  end
@@ -105,7 +110,7 @@ end
105
110
  class Float
106
111
  # Encoding Infinity or NaN to JSON should return "null". The default returns
107
112
  # "Infinity" or "NaN" which are not valid JSON.
108
- def as_json(options = nil) #:nodoc:
113
+ def as_json(options = nil) # :nodoc:
109
114
  finite? ? self : nil
110
115
  end
111
116
  end
@@ -120,43 +125,43 @@ class BigDecimal
120
125
  # if the other end knows by contract that the data is supposed to be a
121
126
  # BigDecimal, it still has the chance to post-process the string and get the
122
127
  # real value.
123
- def as_json(options = nil) #:nodoc:
128
+ def as_json(options = nil) # :nodoc:
124
129
  finite? ? to_s : nil
125
130
  end
126
131
  end
127
132
 
128
133
  class Regexp
129
- def as_json(options = nil) #:nodoc:
134
+ def as_json(options = nil) # :nodoc:
130
135
  to_s
131
136
  end
132
137
  end
133
138
 
134
139
  module Enumerable
135
- def as_json(options = nil) #:nodoc:
140
+ def as_json(options = nil) # :nodoc:
136
141
  to_a.as_json(options)
137
142
  end
138
143
  end
139
144
 
140
145
  class IO
141
- def as_json(options = nil) #:nodoc:
146
+ def as_json(options = nil) # :nodoc:
142
147
  to_s
143
148
  end
144
149
  end
145
150
 
146
151
  class Range
147
- def as_json(options = nil) #:nodoc:
152
+ def as_json(options = nil) # :nodoc:
148
153
  to_s
149
154
  end
150
155
  end
151
156
 
152
157
  class Array
153
- def as_json(options = nil) #:nodoc:
158
+ def as_json(options = nil) # :nodoc:
154
159
  map { |v| options ? v.as_json(options.dup) : v.as_json }
155
160
  end
156
161
  end
157
162
 
158
163
  class Hash
159
- def as_json(options = nil) #:nodoc:
164
+ def as_json(options = nil) # :nodoc:
160
165
  # create a subset of the hash by applying :only or :except
161
166
  subset = if options
162
167
  if attrs = options[:only]
@@ -179,7 +184,7 @@ class Hash
179
184
  end
180
185
 
181
186
  class Time
182
- def as_json(options = nil) #:nodoc:
187
+ def as_json(options = nil) # :nodoc:
183
188
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
184
189
  xmlschema(ActiveSupport::JSON::Encoding.time_precision)
185
190
  else
@@ -189,7 +194,7 @@ class Time
189
194
  end
190
195
 
191
196
  class Date
192
- def as_json(options = nil) #:nodoc:
197
+ def as_json(options = nil) # :nodoc:
193
198
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
194
199
  strftime("%Y-%m-%d")
195
200
  else
@@ -199,7 +204,7 @@ class Date
199
204
  end
200
205
 
201
206
  class DateTime
202
- def as_json(options = nil) #:nodoc:
207
+ def as_json(options = nil) # :nodoc:
203
208
  if ActiveSupport::JSON::Encoding.use_standard_json_time_format
204
209
  xmlschema(ActiveSupport::JSON::Encoding.time_precision)
205
210
  else
@@ -208,13 +213,13 @@ class DateTime
208
213
  end
209
214
  end
210
215
 
211
- class URI::Generic #:nodoc:
216
+ class URI::Generic # :nodoc:
212
217
  def as_json(options = nil)
213
218
  to_s
214
219
  end
215
220
  end
216
221
 
217
- class Pathname #:nodoc:
222
+ class Pathname # :nodoc:
218
223
  def as_json(options = nil)
219
224
  to_s
220
225
  end
@@ -226,7 +231,7 @@ class IPAddr # :nodoc:
226
231
  end
227
232
  end
228
233
 
229
- class Process::Status #:nodoc:
234
+ class Process::Status # :nodoc:
230
235
  def as_json(options = nil)
231
236
  { exitstatus: exitstatus, pid: pid }
232
237
  end
@@ -75,11 +75,11 @@ class Hash
75
75
  #
76
76
  # This method is also aliased as +to_param+.
77
77
  def to_query(namespace = nil)
78
- query = collect do |key, value|
78
+ query = filter_map do |key, value|
79
79
  unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
80
80
  value.to_query(namespace ? "#{namespace}[#{key}]" : key)
81
81
  end
82
- end.compact
82
+ end
83
83
 
84
84
  query.sort! unless namespace.to_s.include?("[]")
85
85
  query.join("&")
@@ -3,32 +3,32 @@
3
3
  require "delegate"
4
4
 
5
5
  module ActiveSupport
6
- module Tryable #:nodoc:
7
- def try(method_name = nil, *args, &b)
8
- if method_name.nil? && block_given?
9
- if b.arity == 0
10
- instance_eval(&b)
6
+ module Tryable # :nodoc:
7
+ def try(*args, &block)
8
+ if args.empty? && block_given?
9
+ if block.arity == 0
10
+ instance_eval(&block)
11
11
  else
12
12
  yield self
13
13
  end
14
- elsif respond_to?(method_name)
15
- public_send(method_name, *args, &b)
14
+ elsif respond_to?(args.first)
15
+ public_send(*args, &block)
16
16
  end
17
17
  end
18
- ruby2_keywords(:try) if respond_to?(:ruby2_keywords, true)
18
+ ruby2_keywords(:try)
19
19
 
20
- def try!(method_name = nil, *args, &b)
21
- if method_name.nil? && block_given?
22
- if b.arity == 0
23
- instance_eval(&b)
20
+ def try!(*args, &block)
21
+ if args.empty? && block_given?
22
+ if block.arity == 0
23
+ instance_eval(&block)
24
24
  else
25
25
  yield self
26
26
  end
27
27
  else
28
- public_send(method_name, *args, &b)
28
+ public_send(*args, &block)
29
29
  end
30
30
  end
31
- ruby2_keywords(:try!) if respond_to?(:ruby2_keywords, true)
31
+ ruby2_keywords(:try!)
32
32
  end
33
33
  end
34
34
 
@@ -39,7 +39,7 @@ class Object
39
39
  # :method: try
40
40
  #
41
41
  # :call-seq:
42
- # try(*a, &b)
42
+ # try(*args, &block)
43
43
  #
44
44
  # Invokes the public method whose name goes as first argument just like
45
45
  # +public_send+ does, except that if the receiver does not respond to it the
@@ -104,7 +104,7 @@ class Object
104
104
  # :method: try!
105
105
  #
106
106
  # :call-seq:
107
- # try!(*a, &b)
107
+ # try!(*args, &block)
108
108
  #
109
109
  # Same as #try, but raises a +NoMethodError+ exception if the receiver is
110
110
  # not +nil+ and does not implement the tried method.
@@ -121,7 +121,7 @@ class Delegator
121
121
  # :method: try
122
122
  #
123
123
  # :call-seq:
124
- # try(a*, &b)
124
+ # try(*args, &block)
125
125
  #
126
126
  # See Object#try
127
127
 
@@ -129,7 +129,7 @@ class Delegator
129
129
  # :method: try!
130
130
  #
131
131
  # :call-seq:
132
- # try!(a*, &b)
132
+ # try!(*args, &block)
133
133
  #
134
134
  # See Object#try!
135
135
  end
@@ -145,14 +145,14 @@ class NilClass
145
145
  #
146
146
  # With +try+
147
147
  # @person.try(:children).try(:first).try(:name)
148
- def try(_method_name = nil, *)
148
+ def try(*)
149
149
  nil
150
150
  end
151
151
 
152
152
  # Calling +try!+ on +nil+ always returns +nil+.
153
153
  #
154
154
  # nil.try!(:name) # => nil
155
- def try!(_method_name = nil, *)
155
+ def try!(*)
156
156
  nil
157
157
  end
158
158
  end
@@ -51,31 +51,6 @@ module ActiveSupport
51
51
  super
52
52
  end
53
53
  end
54
-
55
- # Extends the default Range#cover? to support range comparisons.
56
- # (1..5).cover?(1..5) # => true
57
- # (1..5).cover?(2..3) # => true
58
- # (1..5).cover?(1...6) # => true
59
- # (1..5).cover?(2..6) # => false
60
- #
61
- # The native Range#cover? behavior is untouched.
62
- # ('a'..'f').cover?('c') # => true
63
- # (5..9).cover?(11) # => false
64
- #
65
- # The given range must be fully bounded, with both start and end.
66
- def cover?(value)
67
- if value.is_a?(::Range)
68
- is_backwards_op = value.exclude_end? ? :>= : :>
69
- return false if value.begin && value.end && value.begin.public_send(is_backwards_op, value.end)
70
- # 1...10 covers 1..9 but it does not cover 1..10.
71
- # 1..10 covers 1...11 but it does not cover 1...12.
72
- operator = exclude_end? && !value.exclude_end? ? :< : :<=
73
- value_max = !exclude_end? && value.exclude_end? ? value.max : value.last
74
- super(value.first) && (self.end.nil? || value_max.public_send(operator, last))
75
- else
76
- super
77
- end
78
- end
79
54
  end
80
55
  end
81
56
 
@@ -3,7 +3,7 @@
3
3
  require "active_support/time_with_zone"
4
4
 
5
5
  module ActiveSupport
6
- module EachTimeWithZone #:nodoc:
6
+ module EachTimeWithZone # :nodoc:
7
7
  def each(&block)
8
8
  ensure_iteration_allowed
9
9
  super
@@ -4,7 +4,7 @@ require "active_support/time_with_zone"
4
4
  require "active_support/deprecation"
5
5
 
6
6
  module ActiveSupport
7
- module IncludeTimeWithZone #:nodoc:
7
+ module IncludeTimeWithZone # :nodoc:
8
8
  # Extends the default Range#include? to support ActiveSupport::TimeWithZone.
9
9
  #
10
10
  # (1.hour.ago..1.hour.from_now).include?(Time.current) # => true
@@ -106,7 +106,7 @@ class String
106
106
  self.class.new.tap do |cut|
107
107
  cut_at = truncate_at - omission.bytesize
108
108
 
109
- scan(/\X/) do |grapheme|
109
+ each_grapheme_cluster do |grapheme|
110
110
  if cut.bytesize + grapheme.bytesize <= cut_at
111
111
  cut << grapheme
112
112
  else
@@ -260,7 +260,7 @@ class String
260
260
  # 'author_id'.humanize # => "Author"
261
261
  # 'author_id'.humanize(capitalize: false) # => "author"
262
262
  # '_id'.humanize # => "Id"
263
- # 'author_id'.humanize(keep_id_suffix: true) # => "Author Id"
263
+ # 'author_id'.humanize(keep_id_suffix: true) # => "Author id"
264
264
  #
265
265
  # See ActiveSupport::Inflector.humanize.
266
266
  def humanize(capitalize: true, keep_id_suffix: false)
@@ -11,14 +11,6 @@ class ERB
11
11
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
12
12
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
13
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
-
22
14
  # A utility method for escaping HTML tag characters.
23
15
  # This method is also aliased as <tt>h</tt>.
24
16
  #
@@ -123,26 +115,6 @@ class ERB
123
115
  end
124
116
 
125
117
  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
146
118
  end
147
119
  end
148
120
 
@@ -158,7 +130,7 @@ class Numeric
158
130
  end
159
131
  end
160
132
 
161
- module ActiveSupport #:nodoc:
133
+ module ActiveSupport # :nodoc:
162
134
  class SafeBuffer < String
163
135
  UNSAFE_STRING_METHODS = %w(
164
136
  capitalize chomp chop delete delete_prefix delete_suffix
@@ -212,31 +184,30 @@ module ActiveSupport #:nodoc:
212
184
  end
213
185
 
214
186
  def concat(value)
215
- super(html_escape_interpolated_argument(value))
187
+ unless value.nil?
188
+ super(implicit_html_escape_interpolated_argument(value))
189
+ end
190
+ self
216
191
  end
217
192
  alias << concat
218
193
 
219
- def bytesplice(*args, value)
220
- super(*args, implicit_html_escape_interpolated_argument(value))
221
- end
222
-
223
194
  def insert(index, value)
224
- super(index, html_escape_interpolated_argument(value))
195
+ super(index, implicit_html_escape_interpolated_argument(value))
225
196
  end
226
197
 
227
198
  def prepend(value)
228
- super(html_escape_interpolated_argument(value))
199
+ super(implicit_html_escape_interpolated_argument(value))
229
200
  end
230
201
 
231
202
  def replace(value)
232
- super(html_escape_interpolated_argument(value))
203
+ super(implicit_html_escape_interpolated_argument(value))
233
204
  end
234
205
 
235
206
  def []=(*args)
236
207
  if args.length == 3
237
- super(args[0], args[1], html_escape_interpolated_argument(args[2]))
208
+ super(args[0], args[1], implicit_html_escape_interpolated_argument(args[2]))
238
209
  else
239
- super(args[0], html_escape_interpolated_argument(args[1]))
210
+ super(args[0], implicit_html_escape_interpolated_argument(args[1]))
240
211
  end
241
212
  end
242
213
 
@@ -254,9 +225,9 @@ module ActiveSupport #:nodoc:
254
225
  def %(args)
255
226
  case args
256
227
  when Hash
257
- escaped_args = args.transform_values { |arg| html_escape_interpolated_argument(arg) }
228
+ escaped_args = args.transform_values { |arg| explicit_html_escape_interpolated_argument(arg) }
258
229
  else
259
- escaped_args = Array(args).map { |arg| html_escape_interpolated_argument(arg) }
230
+ escaped_args = Array(args).map { |arg| explicit_html_escape_interpolated_argument(arg) }
260
231
  end
261
232
 
262
233
  self.class.new(super(escaped_args))
@@ -294,39 +265,60 @@ module ActiveSupport #:nodoc:
294
265
  end
295
266
 
296
267
  UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
297
- if unsafe_method.respond_to?(unsafe_method)
298
- class_eval <<-EOT, __FILE__, __LINE__ + 1
299
- def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
300
- if block # if block
301
- to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
302
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
303
- block.call(*params) # block.call(*params)
304
- } # }
305
- else # else
306
- to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
307
- end # end
308
- end # end
309
-
310
- def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
311
- @html_safe = false # @html_safe = false
312
- if block # if block
313
- super(*args) { |*params| # super(*args) { |*params|
314
- set_block_back_references(block, $~) # set_block_back_references(block, $~)
315
- block.call(*params) # block.call(*params)
316
- } # }
317
- else # else
318
- super # super
319
- end # end
320
- end # end
321
- EOT
322
- end
268
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
269
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
270
+ if block # if block
271
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
272
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
273
+ block.call(*params) # block.call(*params)
274
+ } # }
275
+ else # else
276
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
277
+ end # end
278
+ end # end
279
+
280
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
281
+ @html_safe = false # @html_safe = false
282
+ if block # if block
283
+ super(*args) { |*params| # super(*args) { |*params|
284
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
285
+ block.call(*params) # block.call(*params)
286
+ } # }
287
+ else # else
288
+ super # super
289
+ end # end
290
+ end # end
291
+ EOT
323
292
  end
324
293
 
325
294
  private
326
- def html_escape_interpolated_argument(arg)
295
+ def explicit_html_escape_interpolated_argument(arg)
327
296
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
328
297
  end
329
298
 
299
+ def implicit_html_escape_interpolated_argument(arg)
300
+ if !html_safe? || arg.html_safe?
301
+ arg
302
+ else
303
+ arg_string = begin
304
+ arg.to_str
305
+ rescue NoMethodError => error
306
+ if error.name == :to_str
307
+ str = arg.to_s
308
+ ActiveSupport::Deprecation.warn <<~MSG.squish
309
+ Implicit conversion of #{arg.class} into String by ActiveSupport::SafeBuffer
310
+ is deprecated and will be removed in Rails 7.1.
311
+ You must explicitly cast it to a String.
312
+ MSG
313
+ str
314
+ else
315
+ raise
316
+ end
317
+ end
318
+ CGI.escapeHTML(arg_string)
319
+ end
320
+ end
321
+
330
322
  def set_block_back_references(block, match_data)
331
323
  block.binding.eval("proc { |m| $~ = m }").call(match_data)
332
324
  rescue ArgumentError
@@ -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
@@ -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
@@ -56,7 +56,6 @@ class Time
56
56
  at_without_coercion(time_or_number)
57
57
  end
58
58
  end
59
- ruby2_keywords(:at_with_coercion) if respond_to?(:ruby2_keywords, true)
60
59
  alias_method :at_without_coercion, :at
61
60
  alias_method :at, :at_with_coercion
62
61
 
@@ -278,7 +277,7 @@ class Time
278
277
  end
279
278
  alias :at_end_of_minute :end_of_minute
280
279
 
281
- def plus_with_duration(other) #:nodoc:
280
+ def plus_with_duration(other) # :nodoc:
282
281
  if ActiveSupport::Duration === other
283
282
  other.since(self)
284
283
  else
@@ -288,7 +287,7 @@ class Time
288
287
  alias_method :plus_without_duration, :+
289
288
  alias_method :+, :plus_with_duration
290
289
 
291
- def minus_with_duration(other) #:nodoc:
290
+ def minus_with_duration(other) # :nodoc:
292
291
  if ActiveSupport::Duration === other
293
292
  other.until(self)
294
293
  else
@@ -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
- if !time_zone || time_zone.is_a?(ActiveSupport::TimeZone)
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
- # Return if a TimeZone instance, or wrap in a TimeZone instance if a TZInfo::Timezone
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.
@@ -2,20 +2,6 @@
2
2
 
3
3
  require "uri"
4
4
 
5
- if RUBY_VERSION < "2.6.0"
6
- require "active_support/core_ext/module/redefine_method"
7
- URI::Parser.class_eval do
8
- silence_redefinition_of_method :unescape
9
- def unescape(str, escaped = /%[a-fA-F\d]{2}/)
10
- # TODO: Are we actually sure that ASCII == UTF-8?
11
- # YK: My initial experiments say yes, but let's be sure please
12
- enc = str.encoding
13
- enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
14
- str.dup.force_encoding(Encoding::ASCII_8BIT).gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc)
15
- end
16
- end
17
- end
18
-
19
5
  module URI
20
6
  class << self
21
7
  def parser