activesupport 6.0.6.1 → 6.1.7.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +441 -455
  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/digest/uuid.rb +1 -0
  24. data/lib/active_support/core_ext/enumerable.rb +76 -4
  25. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  26. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  27. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  28. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  29. data/lib/active_support/core_ext/load_error.rb +1 -1
  30. data/lib/active_support/core_ext/marshal.rb +2 -0
  31. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  32. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  33. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  34. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  35. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  36. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  37. data/lib/active_support/core_ext/name_error.rb +29 -2
  38. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  39. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  40. data/lib/active_support/core_ext/object/json.rb +12 -1
  41. data/lib/active_support/core_ext/object/try.rb +2 -2
  42. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  43. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  44. data/lib/active_support/core_ext/regexp.rb +8 -1
  45. data/lib/active_support/core_ext/string/access.rb +5 -24
  46. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  47. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  48. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  49. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  50. data/lib/active_support/core_ext/string/output_safety.rb +7 -4
  51. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  52. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  53. data/lib/active_support/core_ext/symbol.rb +3 -0
  54. data/lib/active_support/core_ext/time/calculations.rb +19 -0
  55. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  56. data/lib/active_support/core_ext/uri.rb +5 -1
  57. data/lib/active_support/core_ext.rb +1 -1
  58. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  59. data/lib/active_support/current_attributes.rb +9 -2
  60. data/lib/active_support/dependencies/zeitwerk_integration.rb +4 -1
  61. data/lib/active_support/dependencies.rb +37 -18
  62. data/lib/active_support/deprecation/behaviors.rb +15 -2
  63. data/lib/active_support/deprecation/disallowed.rb +56 -0
  64. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  65. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  66. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  67. data/lib/active_support/deprecation/reporting.rb +50 -7
  68. data/lib/active_support/deprecation.rb +6 -1
  69. data/lib/active_support/descendants_tracker.rb +6 -2
  70. data/lib/active_support/digest.rb +2 -0
  71. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  72. data/lib/active_support/duration.rb +75 -25
  73. data/lib/active_support/encrypted_file.rb +27 -11
  74. data/lib/active_support/environment_inquirer.rb +20 -0
  75. data/lib/active_support/evented_file_update_checker.rb +69 -133
  76. data/lib/active_support/fork_tracker.rb +64 -0
  77. data/lib/active_support/gem_version.rb +3 -3
  78. data/lib/active_support/hash_with_indifferent_access.rb +48 -24
  79. data/lib/active_support/i18n_railtie.rb +14 -19
  80. data/lib/active_support/inflector/inflections.rb +1 -2
  81. data/lib/active_support/inflector/methods.rb +36 -33
  82. data/lib/active_support/inflector/transliterate.rb +4 -4
  83. data/lib/active_support/json/decoding.rb +4 -4
  84. data/lib/active_support/json/encoding.rb +5 -1
  85. data/lib/active_support/key_generator.rb +1 -1
  86. data/lib/active_support/locale/en.yml +7 -3
  87. data/lib/active_support/log_subscriber.rb +8 -0
  88. data/lib/active_support/logger.rb +1 -1
  89. data/lib/active_support/logger_silence.rb +2 -26
  90. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  91. data/lib/active_support/message_encryptor.rb +4 -7
  92. data/lib/active_support/message_verifier.rb +5 -5
  93. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  94. data/lib/active_support/messages/rotator.rb +6 -5
  95. data/lib/active_support/multibyte/chars.rb +4 -42
  96. data/lib/active_support/multibyte/unicode.rb +9 -83
  97. data/lib/active_support/notifications/fanout.rb +23 -8
  98. data/lib/active_support/notifications/instrumenter.rb +6 -15
  99. data/lib/active_support/notifications.rb +32 -5
  100. data/lib/active_support/number_helper/number_converter.rb +1 -1
  101. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  102. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  103. data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
  104. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  105. data/lib/active_support/number_helper.rb +29 -14
  106. data/lib/active_support/option_merger.rb +2 -1
  107. data/lib/active_support/ordered_options.rb +8 -2
  108. data/lib/active_support/parameter_filter.rb +16 -11
  109. data/lib/active_support/per_thread_registry.rb +2 -1
  110. data/lib/active_support/rails.rb +1 -4
  111. data/lib/active_support/railtie.rb +23 -1
  112. data/lib/active_support/rescuable.rb +4 -4
  113. data/lib/active_support/secure_compare_rotator.rb +51 -0
  114. data/lib/active_support/security_utils.rb +19 -12
  115. data/lib/active_support/string_inquirer.rb +4 -2
  116. data/lib/active_support/subscriber.rb +12 -7
  117. data/lib/active_support/tagged_logging.rb +30 -5
  118. data/lib/active_support/testing/assertions.rb +18 -11
  119. data/lib/active_support/testing/parallelization/server.rb +78 -0
  120. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  121. data/lib/active_support/testing/parallelization.rb +12 -95
  122. data/lib/active_support/testing/time_helpers.rb +40 -3
  123. data/lib/active_support/time_with_zone.rb +67 -43
  124. data/lib/active_support/values/time_zone.rb +22 -10
  125. data/lib/active_support/xml_mini/rexml.rb +8 -1
  126. data/lib/active_support.rb +13 -1
  127. metadata +34 -36
  128. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  129. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  130. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  131. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  132. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  133. data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -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"
@@ -9,7 +9,8 @@ module ActiveSupport
9
9
  @signed, @encrypted = [], []
10
10
  end
11
11
 
12
- def rotate(kind, *args)
12
+ def rotate(kind, *args, **options)
13
+ args << options unless options.empty?
13
14
  case kind
14
15
  when :signed
15
16
  @signed << args
@@ -3,11 +3,12 @@
3
3
  module ActiveSupport
4
4
  module Messages
5
5
  module Rotator # :nodoc:
6
- def initialize(*, **options)
7
- super
6
+ def initialize(*secrets, on_rotation: nil, **options)
7
+ super(*secrets, **options)
8
8
 
9
9
  @options = options
10
10
  @rotations = []
11
+ @on_rotation = on_rotation
11
12
  end
12
13
 
13
14
  def rotate(*secrets, **options)
@@ -17,7 +18,7 @@ module ActiveSupport
17
18
  module Encryptor
18
19
  include Rotator
19
20
 
20
- def decrypt_and_verify(*args, on_rotation: nil, **options)
21
+ def decrypt_and_verify(*args, on_rotation: @on_rotation, **options)
21
22
  super
22
23
  rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
23
24
  run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
@@ -32,7 +33,7 @@ module ActiveSupport
32
33
  module Verifier
33
34
  include Rotator
34
35
 
35
- def verified(*args, on_rotation: nil, **options)
36
+ def verified(*args, on_rotation: @on_rotation, **options)
36
37
  super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
37
38
  end
38
39
 
@@ -46,7 +47,7 @@ module ActiveSupport
46
47
  def run_rotations(on_rotation)
47
48
  @rotations.find do |rotation|
48
49
  if message = yield(rotation) rescue next
49
- on_rotation.call if on_rotation
50
+ on_rotation&.call
50
51
  return message
51
52
  end
52
53
  end
@@ -3,6 +3,7 @@
3
3
  require "active_support/json"
4
4
  require "active_support/core_ext/string/access"
5
5
  require "active_support/core_ext/string/behavior"
6
+ require "active_support/core_ext/symbol/starts_ends_with"
6
7
  require "active_support/core_ext/module/delegation"
7
8
 
8
9
  module ActiveSupport #:nodoc:
@@ -48,7 +49,7 @@ module ActiveSupport #:nodoc:
48
49
  alias to_s wrapped_string
49
50
  alias to_str wrapped_string
50
51
 
51
- delegate :<=>, :=~, :acts_like_string?, to: :wrapped_string
52
+ delegate :<=>, :=~, :match?, :acts_like_string?, to: :wrapped_string
52
53
 
53
54
  # Creates a new Chars instance by wrapping _string_.
54
55
  def initialize(string)
@@ -59,7 +60,7 @@ module ActiveSupport #:nodoc:
59
60
  # Forward all undefined methods to the wrapped string.
60
61
  def method_missing(method, *args, &block)
61
62
  result = @wrapped_string.__send__(method, *args, &block)
62
- if /!$/.match?(method)
63
+ if method.end_with?("!")
63
64
  self if result
64
65
  else
65
66
  result.kind_of?(String) ? chars(result) : result
@@ -73,17 +74,6 @@ module ActiveSupport #:nodoc:
73
74
  @wrapped_string.respond_to?(method, include_private)
74
75
  end
75
76
 
76
- # Returns +true+ when the proxy class can handle the string. Returns
77
- # +false+ otherwise.
78
- def self.consumes?(string)
79
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
80
- ActiveSupport::Multibyte::Chars.consumes? is deprecated and will be
81
- removed from Rails 6.1. Use string.is_utf8? instead.
82
- MSG
83
-
84
- string.encoding == Encoding::UTF_8
85
- end
86
-
87
77
  # Works just like <tt>String#split</tt>, with the exception that the items
88
78
  # in the resulting list are Chars instances instead of String. This makes
89
79
  # chaining methods easier.
@@ -134,34 +124,6 @@ module ActiveSupport #:nodoc:
134
124
  end
135
125
  alias_method :titlecase, :titleize
136
126
 
137
- # Returns the KC normalization of the string by default. NFKC is
138
- # considered the best normalization form for passing strings to databases
139
- # and validations.
140
- #
141
- # * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
142
- # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
143
- # ActiveSupport::Multibyte::Unicode.default_normalization_form
144
- def normalize(form = nil)
145
- form ||= Unicode.default_normalization_form
146
-
147
- # See https://www.unicode.org/reports/tr15, Table 1
148
- if alias_form = Unicode::NORMALIZATION_FORM_ALIASES[form]
149
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
150
- ActiveSupport::Multibyte::Chars#normalize is deprecated and will be
151
- removed from Rails 6.1. Use #unicode_normalize(:#{alias_form}) instead.
152
- MSG
153
-
154
- send(:unicode_normalize, alias_form)
155
- else
156
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
157
- ActiveSupport::Multibyte::Chars#normalize is deprecated and will be
158
- removed from Rails 6.1. Use #unicode_normalize instead.
159
- MSG
160
-
161
- raise ArgumentError, "#{form} is not a valid normalization variant", caller
162
- end
163
- end
164
-
165
127
  # Performs canonical decomposition on all the characters.
166
128
  #
167
129
  # 'é'.length # => 2
@@ -201,7 +163,7 @@ module ActiveSupport #:nodoc:
201
163
 
202
164
  %w(reverse tidy_bytes).each do |method|
203
165
  define_method("#{method}!") do |*args|
204
- @wrapped_string = send(method, *args).to_s
166
+ @wrapped_string = public_send(method, *args).to_s
205
167
  self
206
168
  end
207
169
  end
@@ -5,53 +5,19 @@ module ActiveSupport
5
5
  module Unicode
6
6
  extend self
7
7
 
8
- # A list of all available normalization forms.
9
- # See https://www.unicode.org/reports/tr15/tr15-29.html for more
10
- # information about normalization.
11
- NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
12
-
13
- NORMALIZATION_FORM_ALIASES = { # :nodoc:
14
- c: :nfc,
15
- d: :nfd,
16
- kc: :nfkc,
17
- kd: :nfkd
18
- }
19
-
20
8
  # The Unicode version that is supported by the implementation
21
9
  UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
22
10
 
23
- # The default normalization used for operations that require
24
- # normalization. It can be set to any of the normalizations
25
- # in NORMALIZATION_FORMS.
26
- #
27
- # ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
28
- attr_accessor :default_normalization_form
29
- @default_normalization_form = :kc
30
-
31
- # Unpack the string at grapheme boundaries. Returns a list of character
32
- # lists.
33
- #
34
- # Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
35
- # Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
36
- def unpack_graphemes(string)
37
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
38
- ActiveSupport::Multibyte::Unicode#unpack_graphemes is deprecated and will be
39
- removed from Rails 6.1. Use string.scan(/\X/).map(&:codepoints) instead.
40
- MSG
41
-
42
- string.scan(/\X/).map(&:codepoints)
11
+ def default_normalization_form
12
+ ActiveSupport::Deprecation.warn(
13
+ "ActiveSupport::Multibyte::Unicode.default_normalization_form is deprecated and will be removed in Rails 7.0."
14
+ )
43
15
  end
44
16
 
45
- # Reverse operation of unpack_graphemes.
46
- #
47
- # Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
48
- def pack_graphemes(unpacked)
49
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
50
- ActiveSupport::Multibyte::Unicode#pack_graphemes is deprecated and will be
51
- removed from Rails 6.1. Use array.flatten.pack("U*") instead.
52
- MSG
53
-
54
- unpacked.flatten.pack("U*")
17
+ def default_normalization_form=(_)
18
+ ActiveSupport::Deprecation.warn(
19
+ "ActiveSupport::Multibyte::Unicode.default_normalization_form= is deprecated and will be removed in Rails 7.0."
20
+ )
55
21
  end
56
22
 
57
23
  # Decompose composed characters to the decomposed form.
@@ -76,7 +42,7 @@ module ActiveSupport
76
42
  # Passing +true+ will forcibly tidy all bytes, assuming that the string's
77
43
  # encoding is entirely CP1252 or ISO-8859-1.
78
44
  def tidy_bytes(string, force = false)
79
- return string if string.empty?
45
+ return string if string.empty? || string.ascii_only?
80
46
  return recode_windows1252_chars(string) if force
81
47
  string.scrub { |bad| recode_windows1252_chars(bad) }
82
48
  end
@@ -107,46 +73,6 @@ module ActiveSupport
107
73
  end
108
74
  end
109
75
 
110
- # Returns the KC normalization of the string by default. NFKC is
111
- # considered the best normalization form for passing strings to databases
112
- # and validations.
113
- #
114
- # * <tt>string</tt> - The string to perform normalization on.
115
- # * <tt>form</tt> - The form you want to normalize in. Should be one of
116
- # the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
117
- # Default is ActiveSupport::Multibyte::Unicode.default_normalization_form.
118
- def normalize(string, form = nil)
119
- form ||= @default_normalization_form
120
-
121
- # See https://www.unicode.org/reports/tr15, Table 1
122
- if alias_form = NORMALIZATION_FORM_ALIASES[form]
123
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
124
- ActiveSupport::Multibyte::Unicode#normalize is deprecated and will be
125
- removed from Rails 6.1. Use String#unicode_normalize(:#{alias_form}) instead.
126
- MSG
127
-
128
- string.unicode_normalize(alias_form)
129
- else
130
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
131
- ActiveSupport::Multibyte::Unicode#normalize is deprecated and will be
132
- removed from Rails 6.1. Use String#unicode_normalize instead.
133
- MSG
134
-
135
- raise ArgumentError, "#{form} is not a valid normalization variant", caller
136
- end
137
- end
138
-
139
- %w(downcase upcase swapcase).each do |method|
140
- define_method(method) do |string|
141
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
142
- ActiveSupport::Multibyte::Unicode##{method} is deprecated and
143
- will be removed from Rails 6.1. Use String methods directly.
144
- MSG
145
-
146
- string.send(method)
147
- end
148
- end
149
-
150
76
  private
151
77
  def recode_windows1252_chars(string)
152
78
  string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
@@ -3,6 +3,7 @@
3
3
  require "mutex_m"
4
4
  require "concurrent/map"
5
5
  require "set"
6
+ require "active_support/core_ext/object/try"
6
7
 
7
8
  module ActiveSupport
8
9
  module Notifications
@@ -20,8 +21,8 @@ module ActiveSupport
20
21
  super
21
22
  end
22
23
 
23
- def subscribe(pattern = nil, callable = nil, &block)
24
- subscriber = Subscribers.new(pattern, callable || block)
24
+ def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
25
+ subscriber = Subscribers.new(pattern, callable || block, monotonic)
25
26
  synchronize do
26
27
  if String === pattern
27
28
  @string_subscribers[pattern] << subscriber
@@ -84,8 +85,8 @@ module ActiveSupport
84
85
  end
85
86
 
86
87
  module Subscribers # :nodoc:
87
- def self.new(pattern, listener)
88
- subscriber_class = Timed
88
+ def self.new(pattern, listener, monotonic)
89
+ subscriber_class = monotonic ? MonotonicTimed : Timed
89
90
 
90
91
  if listener.respond_to?(:start) && listener.respond_to?(:finish)
91
92
  subscriber_class = Evented
@@ -103,10 +104,6 @@ module ActiveSupport
103
104
  wrap_all pattern, subscriber_class.new(pattern, listener)
104
105
  end
105
106
 
106
- def self.event_object_subscriber(pattern, block)
107
- wrap_all pattern, EventObject.new(pattern, block)
108
- end
109
-
110
107
  def self.wrap_all(pattern, subscriber)
111
108
  unless pattern
112
109
  AllMessages.new(subscriber)
@@ -190,6 +187,23 @@ module ActiveSupport
190
187
  end
191
188
  end
192
189
 
190
+ class MonotonicTimed < Evented # :nodoc:
191
+ def publish(name, *args)
192
+ @delegate.call name, *args
193
+ end
194
+
195
+ def start(name, id, payload)
196
+ timestack = Thread.current[:_timestack_monotonic] ||= []
197
+ timestack.push Concurrent.monotonic_time
198
+ end
199
+
200
+ def finish(name, id, payload)
201
+ timestack = Thread.current[:_timestack_monotonic]
202
+ started = timestack.pop
203
+ @delegate.call(name, started, Concurrent.monotonic_time, id, payload)
204
+ end
205
+ end
206
+
193
207
  class EventObject < Evented
194
208
  def start(name, id, payload)
195
209
  stack = Thread.current[:_event_stack] ||= []
@@ -201,6 +215,7 @@ module ActiveSupport
201
215
  def finish(name, id, payload)
202
216
  stack = Thread.current[:_event_stack]
203
217
  event = stack.pop
218
+ event.payload = payload
204
219
  event.finish!
205
220
  @delegate.call event
206
221
  end
@@ -52,14 +52,8 @@ module ActiveSupport
52
52
  end
53
53
 
54
54
  class Event
55
- attr_reader :name, :time, :end, :transaction_id, :payload, :children
56
-
57
- def self.clock_gettime_supported? # :nodoc:
58
- defined?(Process::CLOCK_THREAD_CPUTIME_ID) &&
59
- !Gem.win_platform? &&
60
- !RUBY_PLATFORM.match?(/solaris/i)
61
- end
62
- private_class_method :clock_gettime_supported?
55
+ attr_reader :name, :time, :end, :transaction_id, :children
56
+ attr_accessor :payload
63
57
 
64
58
  def initialize(name, start, ending, transaction_id, payload)
65
59
  @name = name
@@ -88,11 +82,6 @@ module ActiveSupport
88
82
  @allocation_count_finish = now_allocations
89
83
  end
90
84
 
91
- def end=(ending)
92
- ActiveSupport::Deprecation.deprecation_warning(:end=, :finish!)
93
- @end = ending
94
- end
95
-
96
85
  # Returns the CPU time (in milliseconds) passed since the call to
97
86
  # +start!+ and the call to +finish!+
98
87
  def cpu_time
@@ -140,11 +129,13 @@ module ActiveSupport
140
129
  Concurrent.monotonic_time
141
130
  end
142
131
 
143
- if clock_gettime_supported?
132
+ begin
133
+ Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
134
+
144
135
  def now_cpu
145
136
  Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID)
146
137
  end
147
- else
138
+ rescue
148
139
  def now_cpu
149
140
  0
150
141
  end
@@ -38,6 +38,19 @@ module ActiveSupport
38
38
  # payload # => Hash, the payload
39
39
  # end
40
40
  #
41
+ # Here, the +start+ and +finish+ values represent wall-clock time. If you are
42
+ # concerned about accuracy, you can register a monotonic subscriber.
43
+ #
44
+ # ActiveSupport::Notifications.monotonic_subscribe('render') do |name, start, finish, id, payload|
45
+ # name # => String, name of the event (such as 'render' from above)
46
+ # start # => Monotonic time, when the instrumented block started execution
47
+ # finish # => Monotonic time, when the instrumented block ended execution
48
+ # id # => String, unique ID for the instrumenter that fired the event
49
+ # payload # => Hash, the payload
50
+ # end
51
+ #
52
+ # The +start+ and +finish+ values above represent monotonic time.
53
+ #
41
54
  # For instance, let's store all "render" events in an array:
42
55
  #
43
56
  # events = []
@@ -135,6 +148,16 @@ module ActiveSupport
135
148
  # during the execution of the block. The callback is unsubscribed automatically
136
149
  # after that.
137
150
  #
151
+ # To record +started+ and +finished+ values with monotonic time,
152
+ # specify the optional <tt>:monotonic</tt> option to the
153
+ # <tt>subscribed</tt> method. The <tt>:monotonic</tt> option is set
154
+ # to +false+ by default.
155
+ #
156
+ # callback = lambda {|name, started, finished, unique_id, payload| ... }
157
+ # ActiveSupport::Notifications.subscribed(callback, "sql.active_record", monotonic: true) do
158
+ # ...
159
+ # end
160
+ #
138
161
  # === Manual Unsubscription
139
162
  #
140
163
  # The +subscribe+ method returns a subscriber object:
@@ -155,7 +178,7 @@ module ActiveSupport
155
178
  #
156
179
  # Subscribers using a regexp or other pattern-matching object will remain subscribed
157
180
  # to all events that match their original pattern, unless those events match a string
158
- # passed to `unsubscribe`:
181
+ # passed to +unsubscribe+:
159
182
  #
160
183
  # subscriber = ActiveSupport::Notifications.subscribe(/render/) { }
161
184
  # ActiveSupport::Notifications.unsubscribe('render_template.action_view')
@@ -208,12 +231,16 @@ module ActiveSupport
208
231
  # ActiveSupport::Notifications.subscribe(/render/) do |event|
209
232
  # @event = event
210
233
  # end
211
- def subscribe(*args, &block)
212
- notifier.subscribe(*args, &block)
234
+ def subscribe(pattern = nil, callback = nil, &block)
235
+ notifier.subscribe(pattern, callback, monotonic: false, &block)
236
+ end
237
+
238
+ def monotonic_subscribe(pattern = nil, callback = nil, &block)
239
+ notifier.subscribe(pattern, callback, monotonic: true, &block)
213
240
  end
214
241
 
215
- def subscribed(callback, *args, &block)
216
- subscriber = subscribe(*args, &callback)
242
+ def subscribed(callback, pattern = nil, monotonic: false, &block)
243
+ subscriber = notifier.subscribe(pattern, callback, monotonic: monotonic)
217
244
  yield
218
245
  ensure
219
246
  unsubscribe(subscriber)
@@ -30,7 +30,7 @@ module ActiveSupport
30
30
  # If set to true, precision will mean the number of significant digits instead
31
31
  # of the number of decimal digits (1234 with precision 2 becomes 1200, 1.23543 becomes 1.2)
32
32
  significant: false,
33
- # If set, the zeros after the decimal separator will always be stripped (eg.: 1.200 will be 1.2)
33
+ # If set, the zeros after the decimal separator will always be stripped (e.g.: 1.200 will be 1.2)
34
34
  strip_insignificant_zeros: false
35
35
  },
36
36
 
@@ -16,7 +16,7 @@ module ActiveSupport
16
16
  @number = RoundingHelper.new(options).round(number)
17
17
  @number = Float(number)
18
18
 
19
- # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
19
+ # For backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files.
20
20
  unless options.key?(:strip_insignificant_zeros)
21
21
  options[:strip_insignificant_zeros] = true
22
22
  end
@@ -13,7 +13,7 @@ module ActiveSupport
13
13
  def convert
14
14
  @number = Float(number)
15
15
 
16
- # for backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files
16
+ # For backwards compatibility with those that didn't add strip_insignificant_zeros to their locale files.
17
17
  unless options.key?(:strip_insignificant_zeros)
18
18
  options[:strip_insignificant_zeros] = true
19
19
  end
@@ -20,14 +20,18 @@ module ActiveSupport
20
20
  end
21
21
 
22
22
  formatted_string =
23
- if BigDecimal === rounded_number && rounded_number.finite?
23
+ if rounded_number.finite?
24
24
  s = rounded_number.to_s("F")
25
- s << "0" * precision
26
25
  a, b = s.split(".", 2)
27
- a << "."
28
- a << b[0, precision]
26
+ if precision != 0
27
+ b << "0" * precision
28
+ a << "."
29
+ a << b[0, precision]
30
+ end
31
+ a
29
32
  else
30
- "%00.#{precision}f" % rounded_number
33
+ # Infinity/NaN
34
+ "%f" % rounded_number
31
35
  end
32
36
  else
33
37
  formatted_string = rounded_number