activesupport 7.0.3.1 → 7.2.3.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.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +261 -246
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +3 -1
  7. data/lib/active_support/backtrace_cleaner.rb +39 -7
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +238 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +51 -19
  14. data/lib/active_support/cache/mem_cache_store.rb +114 -134
  15. data/lib/active_support/cache/memory_store.rb +85 -30
  16. data/lib/active_support/cache/null_store.rb +8 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +175 -154
  18. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +64 -13
  20. data/lib/active_support/cache.rb +455 -378
  21. data/lib/active_support/callbacks.rb +121 -136
  22. data/lib/active_support/code_generator.rb +15 -10
  23. data/lib/active_support/concern.rb +4 -2
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/configurable.rb +10 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +1 -2
  28. data/lib/active_support/core_ext/array.rb +0 -1
  29. data/lib/active_support/core_ext/benchmark.rb +1 -0
  30. data/lib/active_support/core_ext/class/attribute.rb +2 -2
  31. data/lib/active_support/core_ext/class/subclasses.rb +17 -34
  32. data/lib/active_support/core_ext/date/blank.rb +4 -0
  33. data/lib/active_support/core_ext/date/calculations.rb +15 -0
  34. data/lib/active_support/core_ext/date/conversions.rb +1 -2
  35. data/lib/active_support/core_ext/date.rb +0 -1
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  38. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  39. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  40. data/lib/active_support/core_ext/date_time/conversions.rb +6 -4
  41. data/lib/active_support/core_ext/date_time.rb +0 -1
  42. data/lib/active_support/core_ext/digest/uuid.rb +7 -10
  43. data/lib/active_support/core_ext/enumerable.rb +25 -80
  44. data/lib/active_support/core_ext/erb/util.rb +201 -0
  45. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  46. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  48. data/lib/active_support/core_ext/hash/keys.rb +7 -7
  49. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  50. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  51. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  52. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  53. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  54. data/lib/active_support/core_ext/module/delegation.rb +20 -119
  55. data/lib/active_support/core_ext/module/deprecation.rb +12 -12
  56. data/lib/active_support/core_ext/module/introspection.rb +3 -1
  57. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  58. data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
  59. data/lib/active_support/core_ext/numeric.rb +0 -1
  60. data/lib/active_support/core_ext/object/blank.rb +45 -1
  61. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  62. data/lib/active_support/core_ext/object/duplicable.rb +25 -16
  63. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  64. data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
  65. data/lib/active_support/core_ext/object/json.rb +17 -7
  66. data/lib/active_support/core_ext/object/to_query.rb +0 -2
  67. data/lib/active_support/core_ext/object/try.rb +2 -2
  68. data/lib/active_support/core_ext/object/with.rb +46 -0
  69. data/lib/active_support/core_ext/object/with_options.rb +9 -9
  70. data/lib/active_support/core_ext/object.rb +1 -0
  71. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  72. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  73. data/lib/active_support/core_ext/pathname.rb +1 -0
  74. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  75. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  76. data/lib/active_support/core_ext/range/sole.rb +17 -0
  77. data/lib/active_support/core_ext/range.rb +2 -2
  78. data/lib/active_support/core_ext/securerandom.rb +24 -12
  79. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  80. data/lib/active_support/core_ext/string/filters.rb +24 -18
  81. data/lib/active_support/core_ext/string/indent.rb +1 -1
  82. data/lib/active_support/core_ext/string/inflections.rb +16 -9
  83. data/lib/active_support/core_ext/string/multibyte.rb +3 -3
  84. data/lib/active_support/core_ext/string/output_safety.rb +41 -178
  85. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  86. data/lib/active_support/core_ext/time/calculations.rb +40 -30
  87. data/lib/active_support/core_ext/time/compatibility.rb +24 -0
  88. data/lib/active_support/core_ext/time/conversions.rb +1 -3
  89. data/lib/active_support/core_ext/time/zones.rb +7 -8
  90. data/lib/active_support/core_ext/time.rb +0 -1
  91. data/lib/active_support/core_ext.rb +0 -1
  92. data/lib/active_support/current_attributes.rb +60 -46
  93. data/lib/active_support/deep_mergeable.rb +53 -0
  94. data/lib/active_support/delegation.rb +202 -0
  95. data/lib/active_support/dependencies/autoload.rb +9 -16
  96. data/lib/active_support/deprecation/behaviors.rb +64 -41
  97. data/lib/active_support/deprecation/constant_accessor.rb +47 -25
  98. data/lib/active_support/deprecation/deprecators.rb +104 -0
  99. data/lib/active_support/deprecation/disallowed.rb +6 -8
  100. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  101. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
  102. data/lib/active_support/deprecation/reporting.rb +49 -27
  103. data/lib/active_support/deprecation.rb +39 -9
  104. data/lib/active_support/deprecator.rb +7 -0
  105. data/lib/active_support/descendants_tracker.rb +66 -172
  106. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  107. data/lib/active_support/duration/iso8601_serializer.rb +1 -4
  108. data/lib/active_support/duration.rb +13 -7
  109. data/lib/active_support/encrypted_configuration.rb +63 -11
  110. data/lib/active_support/encrypted_file.rb +29 -13
  111. data/lib/active_support/environment_inquirer.rb +22 -2
  112. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  113. data/lib/active_support/error_reporter.rb +163 -36
  114. data/lib/active_support/evented_file_update_checker.rb +17 -3
  115. data/lib/active_support/execution_wrapper.rb +5 -6
  116. data/lib/active_support/file_update_checker.rb +6 -4
  117. data/lib/active_support/fork_tracker.rb +4 -32
  118. data/lib/active_support/gem_version.rb +2 -2
  119. data/lib/active_support/gzip.rb +2 -0
  120. data/lib/active_support/hash_with_indifferent_access.rb +50 -30
  121. data/lib/active_support/html_safe_translation.rb +19 -6
  122. data/lib/active_support/i18n.rb +1 -1
  123. data/lib/active_support/i18n_railtie.rb +20 -13
  124. data/lib/active_support/inflector/inflections.rb +2 -0
  125. data/lib/active_support/inflector/methods.rb +28 -18
  126. data/lib/active_support/inflector/transliterate.rb +3 -1
  127. data/lib/active_support/isolated_execution_state.rb +26 -22
  128. data/lib/active_support/json/decoding.rb +3 -2
  129. data/lib/active_support/json/encoding.rb +48 -48
  130. data/lib/active_support/key_generator.rb +9 -1
  131. data/lib/active_support/lazy_load_hooks.rb +22 -7
  132. data/lib/active_support/locale/en.yml +2 -0
  133. data/lib/active_support/log_subscriber.rb +74 -34
  134. data/lib/active_support/logger.rb +22 -59
  135. data/lib/active_support/logger_thread_safe_level.rb +10 -32
  136. data/lib/active_support/message_encryptor.rb +197 -53
  137. data/lib/active_support/message_encryptors.rb +141 -0
  138. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  139. data/lib/active_support/message_pack/extensions.rb +305 -0
  140. data/lib/active_support/message_pack/serializer.rb +63 -0
  141. data/lib/active_support/message_pack.rb +50 -0
  142. data/lib/active_support/message_verifier.rb +229 -89
  143. data/lib/active_support/message_verifiers.rb +137 -0
  144. data/lib/active_support/messages/codec.rb +65 -0
  145. data/lib/active_support/messages/metadata.rb +111 -45
  146. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  147. data/lib/active_support/messages/rotator.rb +38 -31
  148. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  149. data/lib/active_support/multibyte/chars.rb +8 -3
  150. data/lib/active_support/multibyte/unicode.rb +9 -37
  151. data/lib/active_support/notifications/fanout.rb +248 -87
  152. data/lib/active_support/notifications/instrumenter.rb +93 -25
  153. data/lib/active_support/notifications.rb +36 -29
  154. data/lib/active_support/number_helper/number_converter.rb +16 -7
  155. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  156. data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
  157. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  158. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  159. data/lib/active_support/number_helper.rb +379 -317
  160. data/lib/active_support/option_merger.rb +4 -4
  161. data/lib/active_support/ordered_hash.rb +3 -3
  162. data/lib/active_support/ordered_options.rb +67 -15
  163. data/lib/active_support/parameter_filter.rb +103 -84
  164. data/lib/active_support/proxy_object.rb +8 -3
  165. data/lib/active_support/railtie.rb +25 -20
  166. data/lib/active_support/reloader.rb +12 -4
  167. data/lib/active_support/rescuable.rb +10 -8
  168. data/lib/active_support/secure_compare_rotator.rb +16 -9
  169. data/lib/active_support/string_inquirer.rb +4 -2
  170. data/lib/active_support/subscriber.rb +10 -27
  171. data/lib/active_support/syntax_error_proxy.rb +60 -0
  172. data/lib/active_support/tagged_logging.rb +64 -40
  173. data/lib/active_support/test_case.rb +160 -7
  174. data/lib/active_support/testing/assertions.rb +28 -12
  175. data/lib/active_support/testing/autorun.rb +0 -2
  176. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  177. data/lib/active_support/testing/deprecation.rb +20 -27
  178. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  179. data/lib/active_support/testing/isolation.rb +46 -33
  180. data/lib/active_support/testing/method_call_assertions.rb +7 -8
  181. data/lib/active_support/testing/parallelization/server.rb +18 -2
  182. data/lib/active_support/testing/parallelization/worker.rb +2 -2
  183. data/lib/active_support/testing/parallelization.rb +12 -1
  184. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  185. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  186. data/lib/active_support/testing/stream.rb +1 -1
  187. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  188. data/lib/active_support/testing/time_helpers.rb +38 -16
  189. data/lib/active_support/time_with_zone.rb +18 -44
  190. data/lib/active_support/values/time_zone.rb +25 -14
  191. data/lib/active_support/version.rb +1 -1
  192. data/lib/active_support/xml_mini/jdom.rb +3 -10
  193. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  194. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  195. data/lib/active_support/xml_mini/rexml.rb +1 -1
  196. data/lib/active_support/xml_mini.rb +14 -3
  197. data/lib/active_support.rb +15 -3
  198. metadata +148 -24
  199. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  200. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
  201. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
  202. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  203. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
  204. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
  205. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  206. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
  207. data/lib/active_support/core_ext/uri.rb +0 -5
  208. data/lib/active_support/deprecation/instance_delegator.rb +0 -38
  209. data/lib/active_support/per_thread_registry.rb +0 -65
  210. data/lib/active_support/ruby_features.rb +0 -7
@@ -2,42 +2,21 @@
2
2
 
3
3
  module ActiveSupport
4
4
  module ForkTracker # :nodoc:
5
- module ModernCoreExt
5
+ module CoreExt
6
6
  def _fork
7
7
  pid = super
8
8
  if pid == 0
9
- ForkTracker.check!
9
+ ForkTracker.after_fork_callback
10
10
  end
11
11
  pid
12
12
  end
13
13
  end
14
14
 
15
- module CoreExt
16
- def fork(...)
17
- if block_given?
18
- super do
19
- ForkTracker.check!
20
- yield
21
- end
22
- else
23
- unless pid = super
24
- ForkTracker.check!
25
- end
26
- pid
27
- end
28
- end
29
- end
30
-
31
- module CoreExtPrivate
32
- include CoreExt
33
- private :fork
34
- end
35
-
36
15
  @pid = Process.pid
37
16
  @callbacks = []
38
17
 
39
18
  class << self
40
- def check!
19
+ def after_fork_callback
41
20
  new_pid = Process.pid
42
21
  if @pid != new_pid
43
22
  @callbacks.each(&:call)
@@ -46,14 +25,7 @@ module ActiveSupport
46
25
  end
47
26
 
48
27
  def hook!
49
- if Process.respond_to?(:_fork) # Ruby 3.1+
50
- ::Process.singleton_class.prepend(ModernCoreExt)
51
- elsif Process.respond_to?(:fork)
52
- ::Object.prepend(CoreExtPrivate) if RUBY_VERSION < "3.0"
53
- ::Kernel.prepend(CoreExtPrivate)
54
- ::Kernel.singleton_class.prepend(CoreExt)
55
- ::Process.singleton_class.prepend(CoreExt)
56
- end
28
+ ::Process.singleton_class.prepend(CoreExt)
57
29
  end
58
30
 
59
31
  def after_fork(&block)
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
- # Returns the currently loaded version of Active Support as a <tt>Gem::Version</tt>.
4
+ # Returns the currently loaded version of Active Support as a +Gem::Version+.
5
5
  def self.gem_version
6
6
  Gem::Version.new VERSION::STRING
7
7
  end
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 7
11
- MINOR = 0
11
+ MINOR = 2
12
12
  TINY = 3
13
13
  PRE = "1"
14
14
 
@@ -4,6 +4,8 @@ require "zlib"
4
4
  require "stringio"
5
5
 
6
6
  module ActiveSupport
7
+ # = Active Support \Gzip
8
+ #
7
9
  # A convenient wrapper for the zlib standard library that allows
8
10
  # compression/decompression of strings with gzip.
9
11
  #
@@ -6,6 +6,8 @@ require "active_support/core_ext/hash/except"
6
6
  require "active_support/core_ext/hash/slice"
7
7
 
8
8
  module ActiveSupport
9
+ # = \Hash With Indifferent Access
10
+ #
9
11
  # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
10
12
  # to be the same.
11
13
  #
@@ -37,7 +39,7 @@ module ActiveSupport
37
39
  #
38
40
  # but this class is intended for use cases where strings or symbols are the
39
41
  # expected keys and it is convenient to understand both as the same. For
40
- # example the +params+ hash in Ruby on Rails.
42
+ # example the +params+ hash in Ruby on \Rails.
41
43
  #
42
44
  # Note that core extensions define <tt>Hash#with_indifferent_access</tt>:
43
45
  #
@@ -45,7 +47,7 @@ module ActiveSupport
45
47
  #
46
48
  # which may be handy.
47
49
  #
48
- # To access this class outside of Rails, require the core extension with:
50
+ # To access this class outside of \Rails, require the core extension with:
49
51
  #
50
52
  # require "active_support/core_ext/hash/indifferent_access"
51
53
  #
@@ -113,7 +115,7 @@ module ActiveSupport
113
115
  # hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
114
116
  #
115
117
  # The arguments can be either an
116
- # <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
118
+ # +ActiveSupport::HashWithIndifferentAccess+ or a regular +Hash+.
117
119
  # In either case the merge respects the semantics of indifferent access.
118
120
  #
119
121
  # If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
@@ -218,8 +220,12 @@ module ActiveSupport
218
220
  # hash.default # => nil
219
221
  # hash.default('foo') # => 'foo'
220
222
  # hash.default(:foo) # => 'foo'
221
- def default(*args)
222
- super(*args.map { |arg| convert_key(arg) })
223
+ def default(key = (no_key = true))
224
+ if no_key
225
+ super()
226
+ else
227
+ super(convert_key(key))
228
+ end
223
229
  end
224
230
 
225
231
  # Returns an array of the values at the specified indices:
@@ -229,7 +235,8 @@ module ActiveSupport
229
235
  # hash[:b] = 'y'
230
236
  # hash.values_at('a', 'b') # => ["x", "y"]
231
237
  def values_at(*keys)
232
- super(*keys.map { |key| convert_key(key) })
238
+ keys.map! { |key| convert_key(key) }
239
+ super
233
240
  end
234
241
 
235
242
  # Returns an array of the values at the specified indices, but also
@@ -242,7 +249,8 @@ module ActiveSupport
242
249
  # hash.fetch_values('a', 'c') { |key| 'z' } # => ["x", "z"]
243
250
  # hash.fetch_values('a', 'c') # => KeyError: key not found: "c"
244
251
  def fetch_values(*indices, &block)
245
- super(*indices.map { |key| convert_key(key) }, &block)
252
+ indices.map! { |key| convert_key(key) }
253
+ super
246
254
  end
247
255
 
248
256
  # Returns a shallow copy of the hash.
@@ -254,9 +262,7 @@ module ActiveSupport
254
262
  # hash[:a][:c] # => "c"
255
263
  # dup[:a][:c] # => "c"
256
264
  def dup
257
- self.class.new(self).tap do |new_hash|
258
- set_defaults(new_hash)
259
- end
265
+ copy_defaults(self.class.new(self))
260
266
  end
261
267
 
262
268
  # This method has the same semantics of +update+, except it does not
@@ -301,7 +307,7 @@ module ActiveSupport
301
307
  # hash.except(:a, "b") # => {c: 10}.with_indifferent_access
302
308
  # hash # => { a: "x", b: "y", c: 10 }.with_indifferent_access
303
309
  def except(*keys)
304
- slice(*self.keys - keys.map { |key| convert_key(key) })
310
+ dup.except!(*keys)
305
311
  end
306
312
  alias_method :without, :except
307
313
 
@@ -326,21 +332,36 @@ module ActiveSupport
326
332
  dup.tap { |hash| hash.reject!(*args, &block) }
327
333
  end
328
334
 
329
- def transform_values(*args, &block)
335
+ def transform_values(&block)
330
336
  return to_enum(:transform_values) unless block_given?
331
- dup.tap { |hash| hash.transform_values!(*args, &block) }
337
+ dup.tap { |hash| hash.transform_values!(&block) }
332
338
  end
333
339
 
334
- def transform_keys(*args, &block)
335
- return to_enum(:transform_keys) unless block_given?
336
- dup.tap { |hash| hash.transform_keys!(*args, &block) }
340
+ NOT_GIVEN = Object.new # :nodoc:
341
+
342
+ def transform_keys(hash = NOT_GIVEN, &block)
343
+ if NOT_GIVEN.equal?(hash)
344
+ if block_given?
345
+ self.class.new(super(&block))
346
+ else
347
+ to_enum(:transform_keys)
348
+ end
349
+ else
350
+ self.class.new(super)
351
+ end
337
352
  end
338
353
 
339
- def transform_keys!
340
- return enum_for(:transform_keys!) { size } unless block_given?
341
- keys.each do |key|
342
- self[yield(key)] = delete(key)
354
+ def transform_keys!(hash = NOT_GIVEN, &block)
355
+ if NOT_GIVEN.equal?(hash)
356
+ if block_given?
357
+ replace(copy_defaults(transform_keys(&block)))
358
+ else
359
+ return to_enum(:transform_keys!)
360
+ end
361
+ else
362
+ replace(copy_defaults(transform_keys(hash, &block)))
343
363
  end
364
+
344
365
  self
345
366
  end
346
367
 
@@ -361,7 +382,7 @@ module ActiveSupport
361
382
  # Convert to a regular hash with string keys.
362
383
  def to_hash
363
384
  _new_hash = Hash.new
364
- set_defaults(_new_hash)
385
+ copy_defaults(_new_hash)
365
386
 
366
387
  each do |key, value|
367
388
  _new_hash[key] = convert_value(value, conversion: :to_hash)
@@ -369,15 +390,13 @@ module ActiveSupport
369
390
  _new_hash
370
391
  end
371
392
 
393
+ def to_proc
394
+ proc { |key| self[key] }
395
+ end
396
+
372
397
  private
373
- if Symbol.method_defined?(:name)
374
- def convert_key(key)
375
- key.kind_of?(Symbol) ? key.name : key
376
- end
377
- else
378
- def convert_key(key)
379
- key.kind_of?(Symbol) ? key.to_s : key
380
- end
398
+ def convert_key(key)
399
+ Symbol === key ? key.name : key
381
400
  end
382
401
 
383
402
  def convert_value(value, conversion: nil)
@@ -397,12 +416,13 @@ module ActiveSupport
397
416
  end
398
417
  end
399
418
 
400
- def set_defaults(target)
419
+ def copy_defaults(target)
401
420
  if default_proc
402
421
  target.default_proc = default_proc.dup
403
422
  else
404
423
  target.default = default
405
424
  end
425
+ target
406
426
  end
407
427
 
408
428
  def update_with_single_argument(other_hash, block)
@@ -7,18 +7,31 @@ module ActiveSupport
7
7
  def translate(key, **options)
8
8
  if html_safe_translation_key?(key)
9
9
  html_safe_options = html_escape_translation_options(options)
10
- translation = I18n.translate(key, **html_safe_options)
11
- html_safe_translation(translation)
10
+
11
+ exception = false
12
+
13
+ exception_handler = ->(*args) do
14
+ exception = true
15
+ I18n.exception_handler.call(*args)
16
+ end
17
+
18
+ translation = I18n.translate(key, **html_safe_options, exception_handler: exception_handler)
19
+
20
+ if exception
21
+ translation
22
+ else
23
+ html_safe_translation(translation)
24
+ end
12
25
  else
13
26
  I18n.translate(key, **options)
14
27
  end
15
28
  end
16
29
 
17
- private
18
- def html_safe_translation_key?(key)
19
- /(?:_|\b)html\z/.match?(key)
20
- end
30
+ def html_safe_translation_key?(key)
31
+ /(?:_|\b)html\z/.match?(key)
32
+ end
21
33
 
34
+ private
22
35
  def html_escape_translation_options(options)
23
36
  options.each do |name, value|
24
37
  unless i18n_option?(name) || (name == :count && value.is_a?(Numeric))
@@ -7,7 +7,7 @@ begin
7
7
  require "i18n"
8
8
  require "i18n/backend/fallbacks"
9
9
  rescue LoadError => e
10
- $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
10
+ warn "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
11
11
  raise e
12
12
  end
13
13
  require "active_support/lazy_load_hooks"
@@ -49,7 +49,7 @@ module I18n
49
49
  when :load_path
50
50
  I18n.load_path += value
51
51
  when :raise_on_missing_translations
52
- forward_raise_on_missing_translations_config(app)
52
+ setup_raise_on_missing_translations_config(app)
53
53
  else
54
54
  I18n.public_send("#{setting}=", value)
55
55
  end
@@ -60,28 +60,35 @@ module I18n
60
60
  # Restore available locales check so it will take place from now on.
61
61
  I18n.enforce_available_locales = enforce_available_locales
62
62
 
63
- directories = watched_dirs_with_extensions(reloadable_paths)
64
- reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
65
- I18n.load_path.keep_if { |p| File.exist?(p) }
66
- I18n.load_path |= reloadable_paths.flat_map(&:existent)
67
- end
63
+ if app.config.reloading_enabled?
64
+ directories = watched_dirs_with_extensions(reloadable_paths)
65
+ reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
66
+ I18n.load_path.keep_if { |p| File.exist?(p) }
67
+ I18n.load_path |= reloadable_paths.flat_map(&:existent)
68
+ end
68
69
 
69
- app.reloaders << reloader
70
- app.reloader.to_run do
71
- reloader.execute_if_updated { require_unload_lock! }
70
+ app.reloaders << reloader
71
+ app.reloader.to_run do
72
+ reloader.execute_if_updated { require_unload_lock! }
73
+ end
74
+ reloader.execute
72
75
  end
73
- reloader.execute
74
76
 
75
77
  @i18n_inited = true
76
78
  end
77
79
 
78
- def self.forward_raise_on_missing_translations_config(app)
80
+ def self.setup_raise_on_missing_translations_config(app)
79
81
  ActiveSupport.on_load(:action_view) do
80
82
  ActionView::Helpers::TranslationHelper.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
81
83
  end
82
84
 
83
- ActiveSupport.on_load(:action_controller) do
84
- AbstractController::Translation.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
85
+ if app.config.i18n.raise_on_missing_translations &&
86
+ I18n.exception_handler.is_a?(I18n::ExceptionHandler) # Only override the i18n gem's default exception handler.
87
+
88
+ I18n.exception_handler = ->(exception, *) {
89
+ exception = exception.to_exception if exception.is_a?(I18n::MissingTranslation)
90
+ raise exception
91
+ }
85
92
  end
86
93
  end
87
94
 
@@ -7,6 +7,8 @@ module ActiveSupport
7
7
  module Inflector
8
8
  extend self
9
9
 
10
+ # = Active Support \Inflections
11
+ #
10
12
  # A singleton instance of this class is yielded by Inflector.inflections,
11
13
  # which can then be used to specify additional inflection rules. If passed
12
14
  # an optional locale, rules for other languages can be specified. The
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/inflections"
4
- require "active_support/core_ext/object/blank"
5
4
 
6
5
  module ActiveSupport
6
+ # = Active Support \Inflector
7
+ #
7
8
  # The Inflector transforms words from singular to plural, class names to table
8
9
  # names, modularized class names to ones without, and class names to foreign
9
10
  # keys. The default inflections for pluralization, singularization, and
10
11
  # uncountable words are kept in inflections.rb.
11
12
  #
12
- # The Rails core team has stated patches for the inflections library will not
13
+ # The \Rails core team has stated patches for the inflections library will not
13
14
  # be accepted in order to avoid breaking legacy applications which may be
14
15
  # relying on errant inflections. If you discover an incorrect inflection and
15
16
  # require it for your application or wish to define rules for languages other
@@ -71,6 +72,8 @@ module ActiveSupport
71
72
  # String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
72
73
  if !uppercase_first_letter || uppercase_first_letter == :lower
73
74
  string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
75
+ elsif string.match?(/\A[a-z\d]*\z/)
76
+ return inflections.acronyms[string]&.dup || string.capitalize
74
77
  else
75
78
  string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
76
79
  end
@@ -94,10 +97,10 @@ module ActiveSupport
94
97
  #
95
98
  # camelize(underscore('SSLError')) # => "SslError"
96
99
  def underscore(camel_cased_word)
97
- return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
100
+ return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word)
98
101
  word = camel_cased_word.to_s.gsub("::", "/")
99
102
  word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
100
- word.gsub!(/([A-Z]+)(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
103
+ word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
101
104
  word.tr!("-", "_")
102
105
  word.downcase!
103
106
  word
@@ -136,7 +139,7 @@ module ActiveSupport
136
139
 
137
140
  result.tr!("_", " ")
138
141
  result.lstrip!
139
- unless keep_id_suffix
142
+ if !keep_id_suffix && lower_case_and_underscored_word&.end_with?("_id")
140
143
  result.delete_suffix!(" id")
141
144
  end
142
145
 
@@ -155,25 +158,32 @@ module ActiveSupport
155
158
  result
156
159
  end
157
160
 
158
- # Converts just the first character to uppercase.
161
+ # Converts the first character in the string to uppercase.
159
162
  #
160
163
  # upcase_first('what a Lovely Day') # => "What a Lovely Day"
161
164
  # upcase_first('w') # => "W"
162
165
  # upcase_first('') # => ""
163
166
  def upcase_first(string)
164
- string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
167
+ string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +""
168
+ end
169
+
170
+ # Converts the first character in the string to lowercase.
171
+ #
172
+ # downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
173
+ # downcase_first('I') # => "i"
174
+ # downcase_first('') # => ""
175
+ def downcase_first(string)
176
+ string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +""
165
177
  end
166
178
 
167
179
  # Capitalizes all the words and replaces some characters in the string to
168
180
  # create a nicer looking title. +titleize+ is meant for creating pretty
169
- # output. It is not used in the Rails internals.
181
+ # output. It is not used in the \Rails internals.
170
182
  #
171
183
  # The trailing '_id','Id'.. can be kept and capitalized by setting the
172
184
  # optional parameter +keep_id_suffix+ to true.
173
185
  # By default, this parameter is false.
174
186
  #
175
- # +titleize+ is also aliased as +titlecase+.
176
- #
177
187
  # titleize('man from the boondocks') # => "Man From The Boondocks"
178
188
  # titleize('x-men: the last stand') # => "X Men: The Last Stand"
179
189
  # titleize('TheManWithoutAPast') # => "The Man Without A Past"
@@ -185,7 +195,7 @@ module ActiveSupport
185
195
  end
186
196
  end
187
197
 
188
- # Creates the name of a table like Rails does for models to table names.
198
+ # Creates the name of a table like \Rails does for models to table names.
189
199
  # This method uses the #pluralize method on the last word in the string.
190
200
  #
191
201
  # tableize('RawScaledScorer') # => "raw_scaled_scorers"
@@ -195,9 +205,9 @@ module ActiveSupport
195
205
  pluralize(underscore(class_name))
196
206
  end
197
207
 
198
- # Creates a class name from a plural table name like Rails does for table
199
- # names to models. Note that this returns a string and not a Class (To
200
- # convert to an actual class follow +classify+ with #constantize).
208
+ # Creates a class name from a plural table name like \Rails does for table
209
+ # names to models. Note that this returns a string and not a Class. (To
210
+ # convert to an actual class follow +classify+ with #constantize.)
201
211
  #
202
212
  # classify('ham_and_eggs') # => "HamAndEgg"
203
213
  # classify('posts') # => "Post"
@@ -228,7 +238,7 @@ module ActiveSupport
228
238
  def demodulize(path)
229
239
  path = path.to_s
230
240
  if i = path.rindex("::")
231
- path[(i + 2)..-1]
241
+ path[(i + 2), path.length]
232
242
  else
233
243
  path
234
244
  end
@@ -347,7 +357,7 @@ module ActiveSupport
347
357
  def const_regexp(camel_cased_word)
348
358
  parts = camel_cased_word.split("::")
349
359
 
350
- return Regexp.escape(camel_cased_word) if parts.blank?
360
+ return Regexp.escape(camel_cased_word) if parts.empty?
351
361
 
352
362
  last = parts.pop
353
363
 
@@ -361,8 +371,8 @@ module ActiveSupport
361
371
  # If passed an optional +locale+ parameter, the uncountables will be
362
372
  # found for that locale.
363
373
  #
364
- # apply_inflections('post', inflections.plurals, :en) # => "posts"
365
- # apply_inflections('posts', inflections.singulars, :en) # => "post"
374
+ # apply_inflections('post', inflections.plurals, :en) # => "posts"
375
+ # apply_inflections('posts', inflections.singulars, :en) # => "post"
366
376
  def apply_inflections(word, rules, locale = :en)
367
377
  result = word.to_s.dup
368
378
 
@@ -62,10 +62,12 @@ module ActiveSupport
62
62
  # Transliteration is restricted to UTF-8, US-ASCII, and GB18030 strings.
63
63
  # Other encodings will raise an ArgumentError.
64
64
  def transliterate(string, replacement = "?", locale: nil)
65
- string = string.dup if string.frozen?
66
65
  raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
67
66
  raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
68
67
 
68
+ return string.dup if string.ascii_only?
69
+ string = string.dup if string.frozen?
70
+
69
71
  input_encoding = string.encoding
70
72
 
71
73
  # US-ASCII is a subset of UTF-8 so we'll force encoding as UTF-8 if
@@ -4,25 +4,30 @@ require "fiber"
4
4
 
5
5
  module ActiveSupport
6
6
  module IsolatedExecutionState # :nodoc:
7
- @isolation_level = :thread
7
+ @isolation_level = nil
8
8
 
9
9
  Thread.attr_accessor :active_support_execution_state
10
10
  Fiber.attr_accessor :active_support_execution_state
11
11
 
12
12
  class << self
13
- attr_reader :isolation_level
13
+ attr_reader :isolation_level, :scope
14
14
 
15
15
  def isolation_level=(level)
16
+ return if level == @isolation_level
17
+
16
18
  unless %i(thread fiber).include?(level)
17
19
  raise ArgumentError, "isolation_level must be `:thread` or `:fiber`, got: `#{level.inspect}`"
18
20
  end
19
21
 
20
- if level != isolation_level
21
- clear
22
- singleton_class.alias_method(:current, "current_#{level}")
23
- singleton_class.send(:private, :current)
24
- @isolation_level = level
25
- end
22
+ clear if @isolation_level
23
+
24
+ @scope =
25
+ case level
26
+ when :thread; Thread
27
+ when :fiber; Fiber
28
+ end
29
+
30
+ @isolation_level = level
26
31
  end
27
32
 
28
33
  def unique_id
@@ -30,43 +35,42 @@ module ActiveSupport
30
35
  end
31
36
 
32
37
  def [](key)
33
- current[key]
38
+ state[key]
34
39
  end
35
40
 
36
41
  def []=(key, value)
37
- current[key] = value
42
+ state[key] = value
38
43
  end
39
44
 
40
45
  def key?(key)
41
- current.key?(key)
46
+ state.key?(key)
42
47
  end
43
48
 
44
49
  def delete(key)
45
- current.delete(key)
50
+ state.delete(key)
46
51
  end
47
52
 
48
53
  def clear
49
- current.clear
54
+ state.clear
55
+ end
56
+
57
+ def context
58
+ scope.current
50
59
  end
51
60
 
52
61
  def share_with(other)
53
62
  # Action Controller streaming spawns a new thread and copy thread locals.
54
63
  # We do the same here for backward compatibility, but this is very much a hack
55
64
  # and streaming should be rethought.
56
- context = @isolation_level == :thread ? Thread.current : Fiber.current
57
65
  context.active_support_execution_state = other.active_support_execution_state.dup
58
66
  end
59
67
 
60
68
  private
61
- def current_thread
62
- Thread.current.active_support_execution_state ||= {}
63
- end
64
-
65
- def current_fiber
66
- Fiber.current.active_support_execution_state ||= {}
69
+ def state
70
+ context.active_support_execution_state ||= {}
67
71
  end
68
-
69
- alias_method :current, :current_thread
70
72
  end
73
+
74
+ self.isolation_level = :thread
71
75
  end
72
76
  end
@@ -5,7 +5,7 @@ require "active_support/core_ext/module/delegation"
5
5
  require "json"
6
6
 
7
7
  module ActiveSupport
8
- # Look for and parse json strings that look like ISO 8601 times.
8
+ # Look for and parse JSON strings that look like ISO 8601 times.
9
9
  mattr_accessor :parse_json_times
10
10
 
11
11
  module JSON
@@ -18,7 +18,7 @@ module ActiveSupport
18
18
  # See http://www.json.org for more info.
19
19
  #
20
20
  # ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
21
- # => {"team" => "rails", "players" => "36"}
21
+ # # => {"team" => "rails", "players" => "36"}
22
22
  def decode(json)
23
23
  data = ::JSON.parse(json, quirks_mode: true)
24
24
 
@@ -28,6 +28,7 @@ module ActiveSupport
28
28
  data
29
29
  end
30
30
  end
31
+ alias_method :load, :decode
31
32
 
32
33
  # Returns the class of the error that will be raised when there is an
33
34
  # error in decoding JSON. Using this method means you won't directly