activesupport 5.2.5 → 6.0.4.1

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +452 -398
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/backtrace_cleaner.rb +27 -1
  7. data/lib/active_support/cache/file_store.rb +32 -32
  8. data/lib/active_support/cache/mem_cache_store.rb +12 -7
  9. data/lib/active_support/cache/memory_store.rb +15 -9
  10. data/lib/active_support/cache/null_store.rb +8 -3
  11. data/lib/active_support/cache/redis_cache_store.rb +47 -20
  12. data/lib/active_support/cache/strategy/local_cache.rb +22 -22
  13. data/lib/active_support/cache.rb +71 -48
  14. data/lib/active_support/callbacks.rb +16 -8
  15. data/lib/active_support/concern.rb +24 -1
  16. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  17. data/lib/active_support/concurrency/share_lock.rb +0 -1
  18. data/lib/active_support/configurable.rb +7 -11
  19. data/lib/active_support/core_ext/array/access.rb +18 -6
  20. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  21. data/lib/active_support/core_ext/array/extract.rb +21 -0
  22. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  23. data/lib/active_support/core_ext/array.rb +1 -1
  24. data/lib/active_support/core_ext/class/attribute.rb +11 -16
  25. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  26. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  27. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
  28. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  29. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  30. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  31. data/lib/active_support/core_ext/enumerable.rb +97 -73
  32. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  33. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  34. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  35. data/lib/active_support/core_ext/hash/except.rb +2 -2
  36. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  37. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  38. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  39. data/lib/active_support/core_ext/hash.rb +1 -2
  40. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  41. data/lib/active_support/core_ext/kernel.rb +0 -1
  42. data/lib/active_support/core_ext/load_error.rb +1 -1
  43. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
  44. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
  45. data/lib/active_support/core_ext/module/delegation.rb +41 -8
  46. data/lib/active_support/core_ext/module/introspection.rb +38 -13
  47. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  48. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  49. data/lib/active_support/core_ext/module.rb +0 -1
  50. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  51. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  52. data/lib/active_support/core_ext/numeric.rb +0 -1
  53. data/lib/active_support/core_ext/object/blank.rb +1 -2
  54. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  55. data/lib/active_support/core_ext/object/json.rb +2 -1
  56. data/lib/active_support/core_ext/object/try.rb +17 -7
  57. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  58. data/lib/active_support/core_ext/range/compare_range.rb +28 -13
  59. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  60. data/lib/active_support/core_ext/range/each.rb +0 -1
  61. data/lib/active_support/core_ext/range/include_range.rb +6 -0
  62. data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
  63. data/lib/active_support/core_ext/regexp.rb +0 -4
  64. data/lib/active_support/core_ext/securerandom.rb +23 -3
  65. data/lib/active_support/core_ext/string/access.rb +8 -0
  66. data/lib/active_support/core_ext/string/filters.rb +42 -1
  67. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  68. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  69. data/lib/active_support/core_ext/string/output_safety.rb +68 -10
  70. data/lib/active_support/core_ext/string/strip.rb +3 -1
  71. data/lib/active_support/core_ext/time/calculations.rb +34 -3
  72. data/lib/active_support/core_ext/uri.rb +1 -0
  73. data/lib/active_support/current_attributes.rb +8 -0
  74. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  75. data/lib/active_support/dependencies.rb +74 -18
  76. data/lib/active_support/deprecation/behaviors.rb +1 -1
  77. data/lib/active_support/deprecation/method_wrappers.rb +17 -23
  78. data/lib/active_support/deprecation/proxy_wrappers.rb +28 -5
  79. data/lib/active_support/deprecation.rb +1 -1
  80. data/lib/active_support/descendants_tracker.rb +55 -9
  81. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  82. data/lib/active_support/duration/iso8601_serializer.rb +3 -5
  83. data/lib/active_support/duration.rb +7 -8
  84. data/lib/active_support/encrypted_configuration.rb +0 -4
  85. data/lib/active_support/encrypted_file.rb +3 -2
  86. data/lib/active_support/evented_file_update_checker.rb +39 -10
  87. data/lib/active_support/execution_wrapper.rb +1 -0
  88. data/lib/active_support/file_update_checker.rb +0 -1
  89. data/lib/active_support/gem_version.rb +4 -4
  90. data/lib/active_support/hash_with_indifferent_access.rb +22 -18
  91. data/lib/active_support/i18n.rb +1 -0
  92. data/lib/active_support/i18n_railtie.rb +13 -1
  93. data/lib/active_support/inflector/inflections.rb +1 -5
  94. data/lib/active_support/inflector/methods.rb +16 -29
  95. data/lib/active_support/inflector/transliterate.rb +47 -18
  96. data/lib/active_support/json/decoding.rb +23 -24
  97. data/lib/active_support/json/encoding.rb +6 -2
  98. data/lib/active_support/key_generator.rb +0 -32
  99. data/lib/active_support/lazy_load_hooks.rb +5 -2
  100. data/lib/active_support/locale/en.rb +33 -0
  101. data/lib/active_support/log_subscriber.rb +31 -9
  102. data/lib/active_support/logger.rb +1 -16
  103. data/lib/active_support/logger_silence.rb +28 -12
  104. data/lib/active_support/logger_thread_safe_level.rb +26 -4
  105. data/lib/active_support/message_encryptor.rb +4 -6
  106. data/lib/active_support/message_verifier.rb +5 -5
  107. data/lib/active_support/messages/metadata.rb +11 -2
  108. data/lib/active_support/messages/rotator.rb +4 -4
  109. data/lib/active_support/multibyte/chars.rb +29 -49
  110. data/lib/active_support/multibyte/unicode.rb +44 -282
  111. data/lib/active_support/notifications/fanout.rb +98 -13
  112. data/lib/active_support/notifications/instrumenter.rb +80 -9
  113. data/lib/active_support/notifications.rb +41 -4
  114. data/lib/active_support/number_helper/number_converter.rb +4 -5
  115. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  116. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  117. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -2
  118. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -2
  119. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  120. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  121. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -4
  122. data/lib/active_support/number_helper/rounding_helper.rb +1 -1
  123. data/lib/active_support/number_helper.rb +11 -0
  124. data/lib/active_support/option_merger.rb +21 -3
  125. data/lib/active_support/ordered_hash.rb +1 -1
  126. data/lib/active_support/ordered_options.rb +5 -1
  127. data/lib/active_support/parameter_filter.rb +128 -0
  128. data/lib/active_support/rails.rb +0 -6
  129. data/lib/active_support/reloader.rb +4 -5
  130. data/lib/active_support/security_utils.rb +1 -1
  131. data/lib/active_support/string_inquirer.rb +0 -1
  132. data/lib/active_support/subscriber.rb +65 -26
  133. data/lib/active_support/tagged_logging.rb +13 -4
  134. data/lib/active_support/test_case.rb +91 -0
  135. data/lib/active_support/testing/assertions.rb +15 -1
  136. data/lib/active_support/testing/deprecation.rb +0 -1
  137. data/lib/active_support/testing/file_fixtures.rb +2 -0
  138. data/lib/active_support/testing/isolation.rb +2 -2
  139. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  140. data/lib/active_support/testing/parallelization.rb +134 -0
  141. data/lib/active_support/testing/stream.rb +1 -2
  142. data/lib/active_support/testing/time_helpers.rb +7 -9
  143. data/lib/active_support/time_with_zone.rb +15 -5
  144. data/lib/active_support/values/time_zone.rb +12 -7
  145. data/lib/active_support/xml_mini/jdom.rb +2 -3
  146. data/lib/active_support/xml_mini/libxml.rb +2 -2
  147. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  148. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  149. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  150. data/lib/active_support/xml_mini/rexml.rb +2 -2
  151. data/lib/active_support/xml_mini.rb +2 -10
  152. data/lib/active_support.rb +2 -1
  153. metadata +40 -12
  154. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  155. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -5,8 +5,8 @@ require "active_support/core_ext/class/attribute"
5
5
  require "active_support/subscriber"
6
6
 
7
7
  module ActiveSupport
8
- # ActiveSupport::LogSubscriber is an object set to consume
9
- # ActiveSupport::Notifications with the sole purpose of logging them.
8
+ # <tt>ActiveSupport::LogSubscriber</tt> is an object set to consume
9
+ # <tt>ActiveSupport::Notifications</tt> with the sole purpose of logging them.
10
10
  # The log subscriber dispatches notifications to a registered object based
11
11
  # on its given namespace.
12
12
  #
@@ -16,7 +16,7 @@ module ActiveSupport
16
16
  # module ActiveRecord
17
17
  # class LogSubscriber < ActiveSupport::LogSubscriber
18
18
  # def sql(event)
19
- # "#{event.payload[:name]} (#{event.duration}) #{event.payload[:sql]}"
19
+ # info "#{event.payload[:name]} (#{event.duration}) #{event.payload[:sql]}"
20
20
  # end
21
21
  # end
22
22
  # end
@@ -29,13 +29,36 @@ module ActiveSupport
29
29
  # subscriber, the line above should be called after your
30
30
  # <tt>ActiveRecord::LogSubscriber</tt> definition.
31
31
  #
32
- # After configured, whenever a "sql.active_record" notification is published,
33
- # it will properly dispatch the event (ActiveSupport::Notifications::Event) to
34
- # the sql method.
32
+ # After configured, whenever a <tt>"sql.active_record"</tt> notification is published,
33
+ # it will properly dispatch the event
34
+ # (<tt>ActiveSupport::Notifications::Event</tt>) to the sql method.
35
+ #
36
+ # Being an <tt>ActiveSupport::Notifications</tt> consumer,
37
+ # <tt>ActiveSupport::LogSubscriber</tt> exposes a simple interface to check if
38
+ # instrumented code raises an exception. It is common to log a different
39
+ # message in case of an error, and this can be achieved by extending
40
+ # the previous example:
41
+ #
42
+ # module ActiveRecord
43
+ # class LogSubscriber < ActiveSupport::LogSubscriber
44
+ # def sql(event)
45
+ # exception = event.payload[:exception]
46
+ #
47
+ # if exception
48
+ # exception_object = event.payload[:exception_object]
49
+ #
50
+ # error "[ERROR] #{event.payload[:name]}: #{exception.join(', ')} " \
51
+ # "(#{exception_object.backtrace.first})"
52
+ # else
53
+ # # standard logger code
54
+ # end
55
+ # end
56
+ # end
57
+ # end
35
58
  #
36
59
  # Log subscriber also has some helpers to deal with logging and automatically
37
- # flushes all logs when the request finishes (via action_dispatch.callback
38
- # notification) in a Rails environment.
60
+ # flushes all logs when the request finishes
61
+ # (via <tt>action_dispatch.callback</tt> notification) in a Rails environment.
39
62
  class LogSubscriber < Subscriber
40
63
  # Embed in a String to clear all previous ANSI sequences.
41
64
  CLEAR = "\e[0m"
@@ -89,7 +112,6 @@ module ActiveSupport
89
112
  end
90
113
 
91
114
  private
92
-
93
115
  %w(info debug warn error fatal unknown).each do |level|
94
116
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
95
117
  def #{level}(progname = nil, &block)
@@ -6,7 +6,6 @@ require "logger"
6
6
 
7
7
  module ActiveSupport
8
8
  class Logger < ::Logger
9
- include ActiveSupport::LoggerThreadSafeLevel
10
9
  include LoggerSilence
11
10
 
12
11
  # Returns true if the logger destination matches one of the sources
@@ -78,23 +77,9 @@ module ActiveSupport
78
77
  end
79
78
  end
80
79
 
81
- def initialize(*args)
80
+ def initialize(*args, **kwargs)
82
81
  super
83
82
  @formatter = SimpleFormatter.new
84
- after_initialize if respond_to? :after_initialize
85
- end
86
-
87
- def add(severity, message = nil, progname = nil, &block)
88
- return true if @logdev.nil? || (severity || UNKNOWN) < level
89
- super
90
- end
91
-
92
- Logger::Severity.constants.each do |severity|
93
- class_eval(<<-EOT, __FILE__, __LINE__ + 1)
94
- def #{severity.downcase}? # def debug?
95
- Logger::#{severity} >= level # DEBUG >= level
96
- end # end
97
- EOT
98
83
  end
99
84
 
100
85
  # Simple formatter which only displays the message.
@@ -2,28 +2,44 @@
2
2
 
3
3
  require "active_support/concern"
4
4
  require "active_support/core_ext/module/attribute_accessors"
5
- require "concurrent"
5
+ require "active_support/logger_thread_safe_level"
6
6
 
7
7
  module LoggerSilence
8
8
  extend ActiveSupport::Concern
9
9
 
10
10
  included do
11
- cattr_accessor :silencer, default: true
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
12
17
  end
18
+ end
19
+
20
+ module ActiveSupport
21
+ module LoggerSilence
22
+ extend ActiveSupport::Concern
23
+
24
+ included do
25
+ cattr_accessor :silencer, default: true
26
+ include ActiveSupport::LoggerThreadSafeLevel
27
+ end
13
28
 
14
- # Silences the logger for the duration of the block.
15
- def silence(temporary_level = Logger::ERROR)
16
- if silencer
17
- begin
18
- old_local_level = local_level
19
- self.local_level = temporary_level
29
+ # 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
20
35
 
36
+ yield self
37
+ ensure
38
+ self.local_level = old_local_level
39
+ end
40
+ else
21
41
  yield self
22
- ensure
23
- self.local_level = old_local_level
24
42
  end
25
- else
26
- yield self
27
43
  end
28
44
  end
29
45
  end
@@ -1,14 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/concern"
4
+ require "active_support/core_ext/module/attribute_accessors"
5
+ require "concurrent"
4
6
  require "fiber"
5
7
 
6
8
  module ActiveSupport
7
9
  module LoggerThreadSafeLevel # :nodoc:
8
10
  extend ActiveSupport::Concern
9
11
 
12
+ included do
13
+ cattr_accessor :local_levels, default: Concurrent::Map.new(initial_capacity: 2), instance_accessor: false
14
+ end
15
+
16
+ Logger::Severity.constants.each do |severity|
17
+ class_eval(<<-EOT, __FILE__, __LINE__ + 1)
18
+ def #{severity.downcase}? # def debug?
19
+ Logger::#{severity} >= level # DEBUG >= level
20
+ end # end
21
+ EOT
22
+ end
23
+
10
24
  def after_initialize
11
- @local_levels = Concurrent::Map.new(initial_capacity: 2)
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
+ )
12
29
  end
13
30
 
14
31
  def local_log_id
@@ -16,19 +33,24 @@ module ActiveSupport
16
33
  end
17
34
 
18
35
  def local_level
19
- @local_levels[local_log_id]
36
+ self.class.local_levels[local_log_id]
20
37
  end
21
38
 
22
39
  def local_level=(level)
23
40
  if level
24
- @local_levels[local_log_id] = level
41
+ self.class.local_levels[local_log_id] = level
25
42
  else
26
- @local_levels.delete(local_log_id)
43
+ self.class.local_levels.delete(local_log_id)
27
44
  end
28
45
  end
29
46
 
30
47
  def level
31
48
  local_level || super
32
49
  end
50
+
51
+ def add(severity, message = nil, progname = nil, &block) # :nodoc:
52
+ return true if @logdev.nil? || (severity || UNKNOWN) < level
53
+ super
54
+ end
33
55
  end
34
56
  end
@@ -53,7 +53,7 @@ module ActiveSupport
53
53
  # crypt.encrypt_and_sign(parcel, expires_in: 1.month)
54
54
  # crypt.encrypt_and_sign(doowad, expires_at: Time.now.end_of_year)
55
55
  #
56
- # Then the messages can be verified and returned upto the expire time.
56
+ # Then the messages can be verified and returned up to the expire time.
57
57
  # Thereafter, verifying returns +nil+.
58
58
  #
59
59
  # === Rotating keys
@@ -172,7 +172,7 @@ module ActiveSupport
172
172
  iv = cipher.random_iv
173
173
  cipher.auth_data = "" if aead_mode?
174
174
 
175
- encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), metadata_options))
175
+ encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), **metadata_options))
176
176
  encrypted_data << cipher.final
177
177
 
178
178
  blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
@@ -182,7 +182,7 @@ module ActiveSupport
182
182
 
183
183
  def _decrypt(encrypted_message, purpose)
184
184
  cipher = new_cipher
185
- encrypted_data, iv, auth_tag = encrypted_message.split("--".freeze).map { |v| ::Base64.strict_decode64(v) }
185
+ encrypted_data, iv, auth_tag = encrypted_message.split("--").map { |v| ::Base64.strict_decode64(v) }
186
186
 
187
187
  # Currently the OpenSSL bindings do not raise an error if auth_tag is
188
188
  # truncated, which would allow an attacker to easily forge it. See
@@ -210,9 +210,7 @@ module ActiveSupport
210
210
  OpenSSL::Cipher.new(@cipher)
211
211
  end
212
212
 
213
- def verifier
214
- @verifier
215
- end
213
+ attr_reader :verifier
216
214
 
217
215
  def aead_mode?
218
216
  @aead_mode ||= new_cipher.authenticated?
@@ -71,7 +71,7 @@ module ActiveSupport
71
71
  # @verifier.generate(parcel, expires_in: 1.month)
72
72
  # @verifier.generate(doowad, expires_at: Time.now.end_of_year)
73
73
  #
74
- # Then the messages can be verified and returned upto the expire time.
74
+ # Then the messages can be verified and returned up to the expire time.
75
75
  # Thereafter, the +verified+ method returns +nil+ while +verify+ raises
76
76
  # <tt>ActiveSupport::MessageVerifier::InvalidSignature</tt>.
77
77
  #
@@ -122,7 +122,7 @@ module ActiveSupport
122
122
  def valid_message?(signed_message)
123
123
  return if signed_message.nil? || !signed_message.valid_encoding? || signed_message.blank?
124
124
 
125
- data, digest = signed_message.split("--".freeze)
125
+ data, digest = signed_message.split("--")
126
126
  data.present? && digest.present? && ActiveSupport::SecurityUtils.secure_compare(digest, generate_digest(data))
127
127
  end
128
128
 
@@ -150,7 +150,7 @@ module ActiveSupport
150
150
  def verified(signed_message, purpose: nil, **)
151
151
  if valid_message?(signed_message)
152
152
  begin
153
- data = signed_message.split("--".freeze)[0]
153
+ data = signed_message.split("--")[0]
154
154
  message = Messages::Metadata.verify(decode(data), purpose)
155
155
  @serializer.load(message) if message
156
156
  rescue ArgumentError => argument_error
@@ -172,8 +172,8 @@ module ActiveSupport
172
172
  #
173
173
  # other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit'
174
174
  # other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature
175
- def verify(*args)
176
- verified(*args) || raise(InvalidSignature)
175
+ def verify(*args, **options)
176
+ verified(*args, **options) || raise(InvalidSignature)
177
177
  end
178
178
 
179
179
  # Generates a signed message for the provided value.
@@ -6,7 +6,8 @@ module ActiveSupport
6
6
  module Messages #:nodoc:
7
7
  class Metadata #:nodoc:
8
8
  def initialize(message, expires_at = nil, purpose = nil)
9
- @message, @expires_at, @purpose = message, expires_at, purpose
9
+ @message, @purpose = message, purpose
10
+ @expires_at = expires_at.is_a?(String) ? parse_expires_at(expires_at) : expires_at
10
11
  end
11
12
 
12
13
  def as_json(options = {})
@@ -64,7 +65,15 @@ module ActiveSupport
64
65
  end
65
66
 
66
67
  def fresh?
67
- @expires_at.nil? || Time.now.utc < Time.iso8601(@expires_at)
68
+ @expires_at.nil? || Time.now.utc < @expires_at
69
+ end
70
+
71
+ def parse_expires_at(expires_at)
72
+ if ActiveSupport.use_standard_json_time_format
73
+ Time.iso8601(expires_at)
74
+ else
75
+ Time.parse(expires_at)
76
+ end
68
77
  end
69
78
  end
70
79
  end
@@ -20,12 +20,12 @@ module ActiveSupport
20
20
  def decrypt_and_verify(*args, on_rotation: nil, **options)
21
21
  super
22
22
  rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature
23
- run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, options) } || raise
23
+ run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, **options) } || raise
24
24
  end
25
25
 
26
26
  private
27
27
  def build_rotation(secret = @secret, sign_secret = @sign_secret, options)
28
- self.class.new(secret, sign_secret, options)
28
+ self.class.new(secret, sign_secret, **options)
29
29
  end
30
30
  end
31
31
 
@@ -33,12 +33,12 @@ module ActiveSupport
33
33
  include Rotator
34
34
 
35
35
  def verified(*args, on_rotation: nil, **options)
36
- super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, options) }
36
+ super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, **options) }
37
37
  end
38
38
 
39
39
  private
40
40
  def build_rotation(secret = @secret, options)
41
- self.class.new(secret, options)
41
+ self.class.new(secret, **options)
42
42
  end
43
43
  end
44
44
 
@@ -4,7 +4,6 @@ require "active_support/json"
4
4
  require "active_support/core_ext/string/access"
5
5
  require "active_support/core_ext/string/behavior"
6
6
  require "active_support/core_ext/module/delegation"
7
- require "active_support/core_ext/regexp"
8
7
 
9
8
  module ActiveSupport #:nodoc:
10
9
  module Multibyte #:nodoc:
@@ -18,7 +17,7 @@ module ActiveSupport #:nodoc:
18
17
  # through the +mb_chars+ method. Methods which would normally return a
19
18
  # String object now return a Chars object so methods can be chained.
20
19
  #
21
- # 'The Perfect String '.mb_chars.downcase.strip.normalize
20
+ # 'The Perfect String '.mb_chars.downcase.strip
22
21
  # # => #<ActiveSupport::Multibyte::Chars:0x007fdc434ccc10 @wrapped_string="the perfect string">
23
22
  #
24
23
  # Chars objects are perfectly interchangeable with String objects as long as
@@ -77,6 +76,11 @@ module ActiveSupport #:nodoc:
77
76
  # Returns +true+ when the proxy class can handle the string. Returns
78
77
  # +false+ otherwise.
79
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
+
80
84
  string.encoding == Encoding::UTF_8
81
85
  end
82
86
 
@@ -109,7 +113,7 @@ module ActiveSupport #:nodoc:
109
113
  #
110
114
  # 'Café'.mb_chars.reverse.to_s # => 'éfaC'
111
115
  def reverse
112
- chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack("U*"))
116
+ chars(@wrapped_string.scan(/\X/).reverse.join)
113
117
  end
114
118
 
115
119
  # Limits the byte size of the string to a number of bytes without breaking
@@ -118,35 +122,7 @@ module ActiveSupport #:nodoc:
118
122
  #
119
123
  # 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
120
124
  def limit(limit)
121
- slice(0...translate_offset(limit))
122
- end
123
-
124
- # Converts characters in the string to uppercase.
125
- #
126
- # 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
127
- def upcase
128
- chars Unicode.upcase(@wrapped_string)
129
- end
130
-
131
- # Converts characters in the string to lowercase.
132
- #
133
- # 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
134
- def downcase
135
- chars Unicode.downcase(@wrapped_string)
136
- end
137
-
138
- # Converts characters in the string to the opposite case.
139
- #
140
- # 'El Cañón'.mb_chars.swapcase.to_s # => "eL cAÑÓN"
141
- def swapcase
142
- chars Unicode.swapcase(@wrapped_string)
143
- end
144
-
145
- # Converts the first character to uppercase and the remainder to lowercase.
146
- #
147
- # 'über'.mb_chars.capitalize.to_s # => "Über"
148
- def capitalize
149
- (slice(0) || chars("")).upcase + (slice(1..-1) || chars("")).downcase
125
+ chars(@wrapped_string.truncate_bytes(limit, omission: nil))
150
126
  end
151
127
 
152
128
  # Capitalizes the first letter of every word, when possible.
@@ -154,7 +130,7 @@ module ActiveSupport #:nodoc:
154
130
  # "ÉL QUE SE ENTERÓ".mb_chars.titleize.to_s # => "Él Que Se Enteró"
155
131
  # "日本語".mb_chars.titleize.to_s # => "日本語"
156
132
  def titleize
157
- chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1) })
133
+ chars(downcase.to_s.gsub(/\b('?\S)/u) { $1.upcase })
158
134
  end
159
135
  alias_method :titlecase, :titleize
160
136
 
@@ -166,7 +142,24 @@ module ActiveSupport #:nodoc:
166
142
  # <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
167
143
  # ActiveSupport::Multibyte::Unicode.default_normalization_form
168
144
  def normalize(form = nil)
169
- chars(Unicode.normalize(@wrapped_string, form))
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
170
163
  end
171
164
 
172
165
  # Performs canonical decomposition on all the characters.
@@ -190,7 +183,7 @@ module ActiveSupport #:nodoc:
190
183
  # 'क्षि'.mb_chars.length # => 4
191
184
  # 'क्षि'.mb_chars.grapheme_length # => 3
192
185
  def grapheme_length
193
- Unicode.unpack_graphemes(@wrapped_string).length
186
+ @wrapped_string.scan(/\X/).length
194
187
  end
195
188
 
196
189
  # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
@@ -206,7 +199,7 @@ module ActiveSupport #:nodoc:
206
199
  to_s.as_json(options)
207
200
  end
208
201
 
209
- %w(capitalize downcase reverse tidy_bytes upcase).each do |method|
202
+ %w(reverse tidy_bytes).each do |method|
210
203
  define_method("#{method}!") do |*args|
211
204
  @wrapped_string = send(method, *args).to_s
212
205
  self
@@ -214,19 +207,6 @@ module ActiveSupport #:nodoc:
214
207
  end
215
208
 
216
209
  private
217
-
218
- def translate_offset(byte_offset)
219
- return nil if byte_offset.nil?
220
- return 0 if @wrapped_string == ""
221
-
222
- begin
223
- @wrapped_string.byteslice(0...byte_offset).unpack("U*").length
224
- rescue ArgumentError
225
- byte_offset -= 1
226
- retry
227
- end
228
- end
229
-
230
210
  def chars(string)
231
211
  self.class.new(string)
232
212
  end