activesupport 6.0.4 → 6.1.4

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +388 -460
  3. data/MIT-LICENSE +1 -1
  4. data/lib/active_support/array_inquirer.rb +4 -2
  5. data/lib/active_support/backtrace_cleaner.rb +3 -3
  6. data/lib/active_support/benchmarkable.rb +1 -1
  7. data/lib/active_support/cache/file_store.rb +3 -3
  8. data/lib/active_support/cache/mem_cache_store.rb +28 -18
  9. data/lib/active_support/cache/memory_store.rb +46 -26
  10. data/lib/active_support/cache/redis_cache_store.rb +25 -25
  11. data/lib/active_support/cache/strategy/local_cache.rb +20 -5
  12. data/lib/active_support/cache.rb +87 -40
  13. data/lib/active_support/callbacks.rb +65 -56
  14. data/lib/active_support/concern.rb +46 -2
  15. data/lib/active_support/configurable.rb +3 -3
  16. data/lib/active_support/configuration_file.rb +51 -0
  17. data/lib/active_support/core_ext/benchmark.rb +2 -2
  18. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  19. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  20. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  21. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  22. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  23. data/lib/active_support/core_ext/enumerable.rb +76 -4
  24. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  25. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  26. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  27. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  28. data/lib/active_support/core_ext/load_error.rb +1 -1
  29. data/lib/active_support/core_ext/marshal.rb +2 -0
  30. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  31. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  32. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  33. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  34. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  35. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  36. data/lib/active_support/core_ext/name_error.rb +29 -2
  37. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  38. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  39. data/lib/active_support/core_ext/object/json.rb +12 -1
  40. data/lib/active_support/core_ext/object/try.rb +2 -2
  41. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  42. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  43. data/lib/active_support/core_ext/regexp.rb +8 -1
  44. data/lib/active_support/core_ext/string/access.rb +5 -24
  45. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  46. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  47. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  48. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  49. data/lib/active_support/core_ext/string/output_safety.rb +3 -4
  50. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  51. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  52. data/lib/active_support/core_ext/symbol.rb +3 -0
  53. data/lib/active_support/core_ext/time/calculations.rb +17 -0
  54. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  55. data/lib/active_support/core_ext/uri.rb +5 -1
  56. data/lib/active_support/core_ext.rb +1 -1
  57. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  58. data/lib/active_support/current_attributes.rb +8 -2
  59. data/lib/active_support/dependencies.rb +37 -18
  60. data/lib/active_support/deprecation/behaviors.rb +15 -2
  61. data/lib/active_support/deprecation/disallowed.rb +56 -0
  62. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  63. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  64. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  65. data/lib/active_support/deprecation/reporting.rb +50 -7
  66. data/lib/active_support/deprecation.rb +6 -1
  67. data/lib/active_support/descendants_tracker.rb +6 -2
  68. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  69. data/lib/active_support/duration.rb +71 -22
  70. data/lib/active_support/encrypted_file.rb +19 -2
  71. data/lib/active_support/environment_inquirer.rb +20 -0
  72. data/lib/active_support/evented_file_update_checker.rb +69 -133
  73. data/lib/active_support/fork_tracker.rb +64 -0
  74. data/lib/active_support/gem_version.rb +1 -1
  75. data/lib/active_support/hash_with_indifferent_access.rb +48 -24
  76. data/lib/active_support/i18n_railtie.rb +14 -19
  77. data/lib/active_support/inflector/inflections.rb +1 -2
  78. data/lib/active_support/inflector/methods.rb +35 -31
  79. data/lib/active_support/inflector/transliterate.rb +4 -4
  80. data/lib/active_support/json/decoding.rb +4 -4
  81. data/lib/active_support/json/encoding.rb +5 -1
  82. data/lib/active_support/key_generator.rb +1 -1
  83. data/lib/active_support/locale/en.yml +7 -3
  84. data/lib/active_support/log_subscriber.rb +8 -0
  85. data/lib/active_support/logger.rb +1 -1
  86. data/lib/active_support/logger_silence.rb +2 -26
  87. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  88. data/lib/active_support/message_encryptor.rb +4 -7
  89. data/lib/active_support/message_verifier.rb +5 -5
  90. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  91. data/lib/active_support/messages/rotator.rb +6 -5
  92. data/lib/active_support/multibyte/chars.rb +4 -42
  93. data/lib/active_support/multibyte/unicode.rb +9 -83
  94. data/lib/active_support/notifications/fanout.rb +23 -8
  95. data/lib/active_support/notifications/instrumenter.rb +6 -15
  96. data/lib/active_support/notifications.rb +32 -5
  97. data/lib/active_support/number_helper/number_converter.rb +1 -1
  98. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  99. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  100. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  101. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  102. data/lib/active_support/number_helper.rb +29 -14
  103. data/lib/active_support/option_merger.rb +2 -1
  104. data/lib/active_support/ordered_options.rb +8 -2
  105. data/lib/active_support/parameter_filter.rb +16 -11
  106. data/lib/active_support/per_thread_registry.rb +1 -1
  107. data/lib/active_support/rails.rb +1 -4
  108. data/lib/active_support/railtie.rb +23 -1
  109. data/lib/active_support/rescuable.rb +4 -4
  110. data/lib/active_support/secure_compare_rotator.rb +51 -0
  111. data/lib/active_support/security_utils.rb +19 -12
  112. data/lib/active_support/string_inquirer.rb +4 -2
  113. data/lib/active_support/subscriber.rb +12 -7
  114. data/lib/active_support/tagged_logging.rb +29 -4
  115. data/lib/active_support/testing/assertions.rb +18 -11
  116. data/lib/active_support/testing/parallelization/server.rb +78 -0
  117. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  118. data/lib/active_support/testing/parallelization.rb +12 -95
  119. data/lib/active_support/testing/time_helpers.rb +40 -3
  120. data/lib/active_support/time_with_zone.rb +67 -43
  121. data/lib/active_support/values/time_zone.rb +20 -10
  122. data/lib/active_support/xml_mini/rexml.rb +8 -1
  123. data/lib/active_support.rb +13 -1
  124. metadata +33 -35
  125. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  126. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  127. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  128. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  129. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  130. data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -3,6 +3,7 @@
3
3
  require "active_support/core_ext/hash/keys"
4
4
  require "active_support/core_ext/hash/reverse_merge"
5
5
  require "active_support/core_ext/hash/except"
6
+ require "active_support/core_ext/hash/slice"
6
7
 
7
8
  module ActiveSupport
8
9
  # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
@@ -69,7 +70,7 @@ module ActiveSupport
69
70
  super()
70
71
  update(constructor)
71
72
 
72
- hash = constructor.to_hash
73
+ hash = constructor.is_a?(Hash) ? constructor : constructor.to_hash
73
74
  self.default = hash.default if hash.default
74
75
  self.default_proc = hash.default_proc if hash.default_proc
75
76
  else
@@ -91,12 +92,12 @@ module ActiveSupport
91
92
  #
92
93
  # This value can be later fetched using either +:key+ or <tt>'key'</tt>.
93
94
  def []=(key, value)
94
- regular_writer(convert_key(key), convert_value(value, for: :assignment))
95
+ regular_writer(convert_key(key), convert_value(value, conversion: :assignment))
95
96
  end
96
97
 
97
98
  alias_method :store, :[]=
98
99
 
99
- # Updates the receiver in-place, merging in the hash passed as argument:
100
+ # Updates the receiver in-place, merging in the hashes passed as arguments:
100
101
  #
101
102
  # hash_1 = ActiveSupport::HashWithIndifferentAccess.new
102
103
  # hash_1[:key] = 'value'
@@ -106,11 +107,14 @@ module ActiveSupport
106
107
  #
107
108
  # hash_1.update(hash_2) # => {"key"=>"New Value!"}
108
109
  #
109
- # The argument can be either an
110
+ # hash = ActiveSupport::HashWithIndifferentAccess.new
111
+ # hash.update({ "a" => 1 }, { "b" => 2 }) # => { "a" => 1, "b" => 2 }
112
+ #
113
+ # The arguments can be either an
110
114
  # <tt>ActiveSupport::HashWithIndifferentAccess</tt> or a regular +Hash+.
111
115
  # In either case the merge respects the semantics of indifferent access.
112
116
  #
113
- # If the argument is a regular hash with keys +:key+ and +"key"+ only one
117
+ # If the argument is a regular hash with keys +:key+ and <tt>"key"</tt> only one
114
118
  # of the values end up in the receiver, but which one is unspecified.
115
119
  #
116
120
  # When given a block, the value for duplicated keys will be determined
@@ -121,18 +125,15 @@ module ActiveSupport
121
125
  # hash_1[:key] = 10
122
126
  # hash_2['key'] = 12
123
127
  # hash_1.update(hash_2) { |key, old, new| old + new } # => {"key"=>22}
124
- def update(other_hash)
125
- if other_hash.is_a? HashWithIndifferentAccess
126
- super(other_hash)
128
+ def update(*other_hashes, &block)
129
+ if other_hashes.size == 1
130
+ update_with_single_argument(other_hashes.first, block)
127
131
  else
128
- other_hash.to_hash.each_pair do |key, value|
129
- if block_given? && key?(key)
130
- value = yield(convert_key(key), self[key], value)
131
- end
132
- regular_writer(convert_key(key), convert_value(value))
132
+ other_hashes.each do |other_hash|
133
+ update_with_single_argument(other_hash, block)
133
134
  end
134
- self
135
135
  end
136
+ self
136
137
  end
137
138
 
138
139
  alias_method :merge!, :update
@@ -259,8 +260,8 @@ module ActiveSupport
259
260
  # This method has the same semantics of +update+, except it does not
260
261
  # modify the receiver but rather returns a new hash with indifferent
261
262
  # access with the result of the merge.
262
- def merge(hash, &block)
263
- dup.update(hash, &block)
263
+ def merge(*hashes, &block)
264
+ dup.update(*hashes, &block)
264
265
  end
265
266
 
266
267
  # Like +merge+ but the other way around: Merges the receiver into the
@@ -293,6 +294,10 @@ module ActiveSupport
293
294
  super(convert_key(key))
294
295
  end
295
296
 
297
+ # Returns a hash with indifferent access that includes everything except given keys.
298
+ # hash = { a: "x", b: "y", c: 10 }.with_indifferent_access
299
+ # hash.except(:a, "b") # => {c: 10}.with_indifferent_access
300
+ # hash # => { a: "x", b: "y", c: 10 }.with_indifferent_access
296
301
  def except(*keys)
297
302
  slice(*self.keys - keys.map { |key| convert_key(key) })
298
303
  end
@@ -357,40 +362,59 @@ module ActiveSupport
357
362
  set_defaults(_new_hash)
358
363
 
359
364
  each do |key, value|
360
- _new_hash[key] = convert_value(value, for: :to_hash)
365
+ _new_hash[key] = convert_value(value, conversion: :to_hash)
361
366
  end
362
367
  _new_hash
363
368
  end
364
369
 
365
370
  private
366
- def convert_key(key) # :doc:
367
- key.kind_of?(Symbol) ? key.to_s : key
371
+ if Symbol.method_defined?(:name)
372
+ def convert_key(key)
373
+ key.kind_of?(Symbol) ? key.name : key
374
+ end
375
+ else
376
+ def convert_key(key)
377
+ key.kind_of?(Symbol) ? key.to_s : key
378
+ end
368
379
  end
369
380
 
370
- def convert_value(value, options = {}) # :doc:
381
+ def convert_value(value, conversion: nil)
371
382
  if value.is_a? Hash
372
- if options[:for] == :to_hash
383
+ if conversion == :to_hash
373
384
  value.to_hash
374
385
  else
375
386
  value.nested_under_indifferent_access
376
387
  end
377
388
  elsif value.is_a?(Array)
378
- if options[:for] != :assignment || value.frozen?
389
+ if conversion != :assignment || value.frozen?
379
390
  value = value.dup
380
391
  end
381
- value.map! { |e| convert_value(e, options) }
392
+ value.map! { |e| convert_value(e, conversion: conversion) }
382
393
  else
383
394
  value
384
395
  end
385
396
  end
386
397
 
387
- def set_defaults(target) # :doc:
398
+ def set_defaults(target)
388
399
  if default_proc
389
400
  target.default_proc = default_proc.dup
390
401
  else
391
402
  target.default = default
392
403
  end
393
404
  end
405
+
406
+ def update_with_single_argument(other_hash, block)
407
+ if other_hash.is_a? HashWithIndifferentAccess
408
+ regular_update(other_hash, &block)
409
+ else
410
+ other_hash.to_hash.each_pair do |key, value|
411
+ if block && key?(key)
412
+ value = block.call(convert_key(key), self[key], value)
413
+ end
414
+ regular_writer(convert_key(key), convert_value(value))
415
+ end
416
+ end
417
+ end
394
418
  end
395
419
  end
396
420
 
@@ -12,9 +12,7 @@ module I18n
12
12
  config.i18n.load_path = []
13
13
  config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
14
14
 
15
- if I18n.respond_to?(:eager_load!)
16
- config.eager_load_namespaces << I18n
17
- end
15
+ config.eager_load_namespaces << I18n
18
16
 
19
17
  # Set the i18n configuration after initialization since a lot of
20
18
  # configuration is still usually done in application initializers.
@@ -50,8 +48,10 @@ module I18n
50
48
  app.config.i18n.load_path.unshift(*value.flat_map(&:existent))
51
49
  when :load_path
52
50
  I18n.load_path += value
51
+ when :raise_on_missing_translations
52
+ forward_raise_on_missing_translations_config(app)
53
53
  else
54
- I18n.send("#{setting}=", value)
54
+ I18n.public_send("#{setting}=", value)
55
55
  end
56
56
  end
57
57
 
@@ -64,8 +64,6 @@ module I18n
64
64
  reloader = app.config.file_watcher.new(I18n.load_path.dup, directories) do
65
65
  I18n.load_path.keep_if { |p| File.exist?(p) }
66
66
  I18n.load_path |= reloadable_paths.flat_map(&:existent)
67
-
68
- I18n.reload!
69
67
  end
70
68
 
71
69
  app.reloaders << reloader
@@ -77,6 +75,16 @@ module I18n
77
75
  @i18n_inited = true
78
76
  end
79
77
 
78
+ def self.forward_raise_on_missing_translations_config(app)
79
+ ActiveSupport.on_load(:action_view) do
80
+ self.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
81
+ end
82
+
83
+ ActiveSupport.on_load(:action_controller) do
84
+ AbstractController::Translation.raise_on_missing_translations = app.config.i18n.raise_on_missing_translations
85
+ end
86
+ end
87
+
80
88
  def self.include_fallbacks_module
81
89
  I18n.backend.class.include(I18n::Backend::Fallbacks)
82
90
  end
@@ -94,19 +102,6 @@ module I18n
94
102
  [I18n.default_locale]
95
103
  end
96
104
 
97
- if args.empty? || args.first.is_a?(Hash)
98
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
99
- Using I18n fallbacks with an empty `defaults` sets the defaults to
100
- include the `default_locale`. This behavior will change in Rails 6.1.
101
- If you desire the default locale to be included in the defaults, please
102
- explicitly configure it with `config.i18n.fallbacks.defaults =
103
- [I18n.default_locale]` or `config.i18n.fallbacks = [I18n.default_locale,
104
- {...}]`. If you want to opt-in to the new behavior, use
105
- `config.i18n.fallbacks.defaults = [nil, {...}]`.
106
- MSG
107
- args.unshift I18n.default_locale
108
- end
109
-
110
105
  I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
111
106
  end
112
107
 
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "concurrent/map"
4
4
  require "active_support/i18n"
5
- require "active_support/deprecation"
6
5
 
7
6
  module ActiveSupport
8
7
  module Inflector
@@ -77,7 +76,7 @@ module ActiveSupport
77
76
  # Private, for the test suite.
78
77
  def initialize_dup(orig) # :nodoc:
79
78
  %w(plurals singulars uncountables humans acronyms).each do |scope|
80
- instance_variable_set("@#{scope}", orig.send(scope).dup)
79
+ instance_variable_set("@#{scope}", orig.public_send(scope).dup)
81
80
  end
82
81
  define_acronym_regex_patterns
83
82
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/inflections"
4
+ require "active_support/core_ext/object/blank"
4
5
 
5
6
  module ActiveSupport
6
7
  # The Inflector transforms words from singular to plural, class names to table
@@ -132,7 +133,7 @@ module ActiveSupport
132
133
 
133
134
  result.sub!(/\A_+/, "")
134
135
  unless keep_id_suffix
135
- result.sub!(/_id\z/, "")
136
+ result.delete_suffix!("_id")
136
137
  end
137
138
  result.tr!("_", " ")
138
139
 
@@ -172,7 +173,7 @@ module ActiveSupport
172
173
  # titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
173
174
  # titleize('string_ending_with_id', keep_id_suffix: true) # => "String Ending With Id"
174
175
  def titleize(word, keep_id_suffix: false)
175
- humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`])[a-z]/) do |match|
176
+ humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w['’`()])[a-z]/) do |match|
176
177
  match.capitalize
177
178
  end
178
179
  end
@@ -269,32 +270,36 @@ module ActiveSupport
269
270
  # NameError is raised when the name is not in CamelCase or the constant is
270
271
  # unknown.
271
272
  def constantize(camel_cased_word)
272
- names = camel_cased_word.split("::")
273
-
274
- # Trigger a built-in NameError exception including the ill-formed constant in the message.
275
- Object.const_get(camel_cased_word) if names.empty?
276
-
277
- # Remove the first blank element in case of '::ClassName' notation.
278
- names.shift if names.size > 1 && names.first.empty?
279
-
280
- names.inject(Object) do |constant, name|
281
- if constant == Object
282
- constant.const_get(name)
283
- else
284
- candidate = constant.const_get(name)
285
- next candidate if constant.const_defined?(name, false)
286
- next candidate unless Object.const_defined?(name)
287
-
288
- # Go down the ancestors to check if it is owned directly. The check
289
- # stops when we reach Object or the end of ancestors tree.
290
- constant = constant.ancestors.inject(constant) do |const, ancestor|
291
- break const if ancestor == Object
292
- break ancestor if ancestor.const_defined?(name, false)
293
- const
273
+ if camel_cased_word.blank? || !camel_cased_word.include?("::")
274
+ Object.const_get(camel_cased_word)
275
+ else
276
+ names = camel_cased_word.split("::")
277
+
278
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
279
+ Object.const_get(camel_cased_word) if names.empty?
280
+
281
+ # Remove the first blank element in case of '::ClassName' notation.
282
+ names.shift if names.size > 1 && names.first.empty?
283
+
284
+ names.inject(Object) do |constant, name|
285
+ if constant == Object
286
+ constant.const_get(name)
287
+ else
288
+ candidate = constant.const_get(name)
289
+ next candidate if constant.const_defined?(name, false)
290
+ next candidate unless Object.const_defined?(name)
291
+
292
+ # Go down the ancestors to check if it is owned directly. The check
293
+ # stops when we reach Object or the end of ancestors tree.
294
+ constant = constant.ancestors.inject(constant) do |const, ancestor|
295
+ break const if ancestor == Object
296
+ break ancestor if ancestor.const_defined?(name, false)
297
+ const
298
+ end
299
+
300
+ # owner is in Object, so raise
301
+ constant.const_get(name, false)
294
302
  end
295
-
296
- # owner is in Object, so raise
297
- constant.const_get(name, false)
298
303
  end
299
304
  end
300
305
  end
@@ -326,10 +331,9 @@ module ActiveSupport
326
331
  rescue NameError => e
327
332
  raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
328
333
  e.name.to_s == camel_cased_word.to_s)
329
- rescue ArgumentError => e
330
- raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.message)
331
334
  rescue LoadError => e
332
- raise unless /Unable to autoload constant #{const_regexp(camel_cased_word)}/.match?(e.message)
335
+ message = e.respond_to?(:original_message) ? e.original_message : e.message
336
+ raise unless /Unable to autoload constant #{const_regexp(camel_cased_word)}/.match?(message)
333
337
  end
334
338
 
335
339
  # Returns the suffix that should be added to a number to denote the position
@@ -371,7 +375,7 @@ module ActiveSupport
371
375
 
372
376
  last = parts.pop
373
377
 
374
- parts.reverse.inject(last) do |acc, part|
378
+ parts.reverse!.inject(last) do |acc, part|
375
379
  part.empty? ? acc : "#{part}(::#{acc})?"
376
380
  end
377
381
  end
@@ -5,6 +5,8 @@ require "active_support/i18n"
5
5
 
6
6
  module ActiveSupport
7
7
  module Inflector
8
+ ALLOWED_ENCODINGS_FOR_TRANSLITERATE = [Encoding::UTF_8, Encoding::US_ASCII, Encoding::GB18030].freeze
9
+
8
10
  # Replaces non-ASCII characters with an ASCII approximation, or if none
9
11
  # exists, a replacement character which defaults to "?".
10
12
  #
@@ -62,9 +64,7 @@ module ActiveSupport
62
64
  def transliterate(string, replacement = "?", locale: nil)
63
65
  string = string.dup if string.frozen?
64
66
  raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
65
-
66
- allowed_encodings = [Encoding::UTF_8, Encoding::US_ASCII, Encoding::GB18030]
67
- raise ArgumentError, "Can not transliterate strings with #{string.encoding} encoding" unless allowed_encodings.include?(string.encoding)
67
+ raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
68
68
 
69
69
  input_encoding = string.encoding
70
70
 
@@ -117,7 +117,7 @@ module ActiveSupport
117
117
  # If the optional parameter +locale+ is specified,
118
118
  # the word will be parameterized as a word of that language.
119
119
  # By default, this parameter is set to <tt>nil</tt> and it will use
120
- # the configured <tt>I18n.locale<tt>.
120
+ # the configured <tt>I18n.locale</tt>.
121
121
  def parameterize(string, separator: "-", preserve_case: false, locale: nil)
122
122
  # Replace accented chars with their ASCII equivalents.
123
123
  parameterized_string = transliterate(string, locale: locale)
@@ -10,8 +10,8 @@ module ActiveSupport
10
10
 
11
11
  module JSON
12
12
  # matches YAML-formatted dates
13
- DATE_REGEX = /^\d{4}-\d{2}-\d{2}$/
14
- DATETIME_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)$/
13
+ DATE_REGEX = /\A\d{4}-\d{2}-\d{2}\z/
14
+ DATETIME_REGEX = /\A(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?)?)\z/
15
15
 
16
16
  class << self
17
17
  # Parses a JSON string (JavaScript Object Notation) into a hash.
@@ -63,8 +63,8 @@ module ActiveSupport
63
63
  when Array
64
64
  data.map! { |d| convert_dates_from(d) }
65
65
  when Hash
66
- data.each do |key, value|
67
- data[key] = convert_dates_from(value)
66
+ data.transform_values! do |value|
67
+ convert_dates_from(value)
68
68
  end
69
69
  else
70
70
  data
@@ -93,7 +93,11 @@ module ActiveSupport
93
93
  when Numeric, NilClass, TrueClass, FalseClass
94
94
  value.as_json
95
95
  when Hash
96
- Hash[value.map { |k, v| [jsonify(k), jsonify(v)] }]
96
+ result = {}
97
+ value.each do |k, v|
98
+ result[jsonify(k)] = jsonify(v)
99
+ end
100
+ result
97
101
  when Array
98
102
  value.map { |v| jsonify(v) }
99
103
  else
@@ -35,7 +35,7 @@ module ActiveSupport
35
35
 
36
36
  # Returns a derived key suitable for use.
37
37
  def generate_key(*args)
38
- @cache_keys[args.join] ||= @key_generator.generate_key(*args)
38
+ @cache_keys[args.join("|")] ||= @key_generator.generate_key(*args)
39
39
  end
40
40
  end
41
41
  end
@@ -44,10 +44,12 @@ en:
44
44
  delimiter: ","
45
45
  # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
46
46
  precision: 3
47
+ # Determine how rounding is performed (see BigDecimal::mode)
48
+ round_mode: default
47
49
  # If set to true, precision will mean the number of significant digits instead
48
50
  # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
49
51
  significant: false
50
- # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2)
52
+ # If set, the zeros after the decimal separator will always be stripped (e.g.: 1.200 will be 1.2)
51
53
  strip_insignificant_zeros: false
52
54
 
53
55
  # Used in NumberHelper.number_to_currency()
@@ -56,10 +58,11 @@ en:
56
58
  # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00)
57
59
  format: "%u%n"
58
60
  unit: "$"
59
- # These five are to override number.format and are optional
61
+ # These six are to override number.format and are optional
60
62
  separator: "."
61
63
  delimiter: ","
62
64
  precision: 2
65
+ # round_mode:
63
66
  significant: false
64
67
  strip_insignificant_zeros: false
65
68
 
@@ -87,10 +90,11 @@ en:
87
90
  # Used in NumberHelper.number_to_human_size() and NumberHelper.number_to_human()
88
91
  human:
89
92
  format:
90
- # These five are to override number.format and are optional
93
+ # These six are to override number.format and are optional
91
94
  # separator:
92
95
  delimiter: ""
93
96
  precision: 3
97
+ # round_mode:
94
98
  significant: true
95
99
  strip_insignificant_zeros: true
96
100
  # Used in number_to_human_size()
@@ -29,6 +29,9 @@ module ActiveSupport
29
29
  # subscriber, the line above should be called after your
30
30
  # <tt>ActiveRecord::LogSubscriber</tt> definition.
31
31
  #
32
+ # A logger also needs to be set with <tt>ActiveRecord::LogSubscriber.logger=</tt>.
33
+ # This is assigned automatically in a Rails environment.
34
+ #
32
35
  # After configured, whenever a <tt>"sql.active_record"</tt> notification is published,
33
36
  # it will properly dispatch the event
34
37
  # (<tt>ActiveSupport::Notifications::Event</tt>) to the sql method.
@@ -93,6 +96,11 @@ module ActiveSupport
93
96
  def flush_all!
94
97
  logger.flush if logger.respond_to?(:flush)
95
98
  end
99
+
100
+ private
101
+ def fetch_public_methods(subscriber, inherit_all)
102
+ subscriber.public_methods(inherit_all) - LogSubscriber.public_instance_methods(true)
103
+ end
96
104
  end
97
105
 
98
106
  def logger
@@ -14,7 +14,7 @@ module ActiveSupport
14
14
  # ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
15
15
  # # => true
16
16
  def self.logger_outputs_to?(logger, *sources)
17
- logdev = logger.instance_variable_get("@logdev")
17
+ logdev = logger.instance_variable_get(:@logdev)
18
18
  logger_source = logdev.dev if logdev.respond_to?(:dev)
19
19
  sources.any? { |source| source == logger_source }
20
20
  end
@@ -4,19 +4,6 @@ require "active_support/concern"
4
4
  require "active_support/core_ext/module/attribute_accessors"
5
5
  require "active_support/logger_thread_safe_level"
6
6
 
7
- module LoggerSilence
8
- extend ActiveSupport::Concern
9
-
10
- included do
11
- ActiveSupport::Deprecation.warn(
12
- "Including LoggerSilence is deprecated and will be removed in Rails 6.1. " \
13
- "Please use `ActiveSupport::LoggerSilence` instead"
14
- )
15
-
16
- include ActiveSupport::LoggerSilence
17
- end
18
- end
19
-
20
7
  module ActiveSupport
21
8
  module LoggerSilence
22
9
  extend ActiveSupport::Concern
@@ -27,19 +14,8 @@ module ActiveSupport
27
14
  end
28
15
 
29
16
  # Silences the logger for the duration of the block.
30
- def silence(temporary_level = Logger::ERROR)
31
- if silencer
32
- begin
33
- old_local_level = local_level
34
- self.local_level = temporary_level
35
-
36
- yield self
37
- ensure
38
- self.local_level = old_local_level
39
- end
40
- else
41
- yield self
42
- end
17
+ def silence(severity = Logger::ERROR)
18
+ silencer ? log_at(severity) { yield self } : yield(self)
43
19
  end
44
20
  end
45
21
  end
@@ -21,13 +21,6 @@ module ActiveSupport
21
21
  EOT
22
22
  end
23
23
 
24
- def after_initialize
25
- ActiveSupport::Deprecation.warn(
26
- "Logger don't need to call #after_initialize directly anymore. It will be deprecated without replacement in " \
27
- "Rails 6.1."
28
- )
29
- end
30
-
31
24
  def local_log_id
32
25
  Fiber.current.__id__
33
26
  end
@@ -37,10 +30,15 @@ module ActiveSupport
37
30
  end
38
31
 
39
32
  def local_level=(level)
40
- if level
33
+ case level
34
+ when Integer
41
35
  self.class.local_levels[local_log_id] = level
42
- else
36
+ when Symbol
37
+ self.class.local_levels[local_log_id] = Logger::Severity.const_get(level.to_s.upcase)
38
+ when nil
43
39
  self.class.local_levels.delete(local_log_id)
40
+ else
41
+ raise ArgumentError, "Invalid log level: #{level.inspect}"
44
42
  end
45
43
  end
46
44
 
@@ -48,9 +46,33 @@ module ActiveSupport
48
46
  local_level || super
49
47
  end
50
48
 
51
- def add(severity, message = nil, progname = nil, &block) # :nodoc:
52
- return true if @logdev.nil? || (severity || UNKNOWN) < level
53
- super
49
+ # Change the thread-local level for the duration of the given block.
50
+ def log_at(level)
51
+ old_local_level, self.local_level = local_level, level
52
+ yield
53
+ ensure
54
+ self.local_level = old_local_level
55
+ end
56
+
57
+ # Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
58
+ # FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
59
+ def add(severity, message = nil, progname = nil, &block) #:nodoc:
60
+ severity ||= UNKNOWN
61
+ progname ||= @progname
62
+
63
+ return true if @logdev.nil? || severity < level
64
+
65
+ if message.nil?
66
+ if block_given?
67
+ message = yield
68
+ else
69
+ message = progname
70
+ progname = @progname
71
+ end
72
+ end
73
+
74
+ @logdev.write \
75
+ format_message(format_severity(severity), Time.now, progname, message)
54
76
  end
55
77
  end
56
78
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "openssl"
4
4
  require "base64"
5
- require "active_support/core_ext/array/extract_options"
6
5
  require "active_support/core_ext/module/attribute_accessors"
7
6
  require "active_support/message_verifier"
8
7
  require "active_support/messages/metadata"
@@ -134,15 +133,13 @@ module ActiveSupport
134
133
  # * <tt>:digest</tt> - String of digest to use for signing. Default is
135
134
  # +SHA1+. Ignored when using an AEAD cipher like 'aes-256-gcm'.
136
135
  # * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+.
137
- def initialize(secret, *signature_key_or_options)
138
- options = signature_key_or_options.extract_options!
139
- sign_secret = signature_key_or_options.first
136
+ def initialize(secret, sign_secret = nil, cipher: nil, digest: nil, serializer: nil)
140
137
  @secret = secret
141
138
  @sign_secret = sign_secret
142
- @cipher = options[:cipher] || self.class.default_cipher
143
- @digest = options[:digest] || "SHA1" unless aead_mode?
139
+ @cipher = cipher || self.class.default_cipher
140
+ @digest = digest || "SHA1" unless aead_mode?
144
141
  @verifier = resolve_verifier
145
- @serializer = options[:serializer] || Marshal
142
+ @serializer = serializer || Marshal
146
143
  end
147
144
 
148
145
  # Encrypt and sign a message. We need to sign the message in order to avoid
@@ -103,11 +103,11 @@ module ActiveSupport
103
103
 
104
104
  class InvalidSignature < StandardError; end
105
105
 
106
- def initialize(secret, options = {})
106
+ def initialize(secret, digest: nil, serializer: nil)
107
107
  raise ArgumentError, "Secret should not be nil." unless secret
108
108
  @secret = secret
109
- @digest = options[:digest] || "SHA1"
110
- @serializer = options[:serializer] || Marshal
109
+ @digest = digest || "SHA1"
110
+ @serializer = serializer || Marshal
111
111
  end
112
112
 
113
113
  # Checks if a signed message could have been generated by signing an object
@@ -178,8 +178,8 @@ module ActiveSupport
178
178
 
179
179
  # Generates a signed message for the provided value.
180
180
  #
181
- # The message is signed with the +MessageVerifier+'s secret. Without knowing
182
- # the secret, the original value cannot be extracted from the message.
181
+ # The message is signed with the +MessageVerifier+'s secret.
182
+ # Returns Base64-encoded message joined with the generated signature.
183
183
  #
184
184
  # verifier = ActiveSupport::MessageVerifier.new 's3Krit'
185
185
  # verifier.generate 'a private message' # => "BAhJIhRwcml2YXRlLW1lc3NhZ2UGOgZFVA==--e2d724331ebdee96a10fb99b089508d1c72bd772"