activesupport 7.0.8 → 7.1.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +940 -286
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +2 -0
  7. data/lib/active_support/backtrace_cleaner.rb +25 -5
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +250 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +37 -10
  14. data/lib/active_support/cache/mem_cache_store.rb +100 -76
  15. data/lib/active_support/cache/memory_store.rb +78 -24
  16. data/lib/active_support/cache/null_store.rb +6 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +151 -141
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +29 -14
  20. data/lib/active_support/cache.rb +331 -252
  21. data/lib/active_support/callbacks.rb +44 -21
  22. data/lib/active_support/concern.rb +4 -2
  23. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  24. data/lib/active_support/concurrency/null_lock.rb +13 -0
  25. data/lib/active_support/configurable.rb +10 -0
  26. data/lib/active_support/core_ext/array/conversions.rb +2 -1
  27. data/lib/active_support/core_ext/array.rb +0 -1
  28. data/lib/active_support/core_ext/class/subclasses.rb +13 -10
  29. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  30. data/lib/active_support/core_ext/date.rb +0 -1
  31. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  32. data/lib/active_support/core_ext/date_time/conversions.rb +6 -2
  33. data/lib/active_support/core_ext/date_time.rb +0 -1
  34. data/lib/active_support/core_ext/digest/uuid.rb +1 -10
  35. data/lib/active_support/core_ext/enumerable.rb +3 -75
  36. data/lib/active_support/core_ext/erb/util.rb +196 -0
  37. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  38. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  39. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  40. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  41. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  42. data/lib/active_support/core_ext/module/delegation.rb +40 -11
  43. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  44. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  45. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  46. data/lib/active_support/core_ext/numeric/conversions.rb +2 -0
  47. data/lib/active_support/core_ext/numeric.rb +0 -1
  48. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  49. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  50. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  51. data/lib/active_support/core_ext/object/json.rb +11 -3
  52. data/lib/active_support/core_ext/object/with.rb +44 -0
  53. data/lib/active_support/core_ext/object/with_options.rb +4 -4
  54. data/lib/active_support/core_ext/object.rb +1 -0
  55. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  56. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  57. data/lib/active_support/core_ext/pathname.rb +1 -0
  58. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  59. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  60. data/lib/active_support/core_ext/range.rb +1 -2
  61. data/lib/active_support/core_ext/securerandom.rb +24 -12
  62. data/lib/active_support/core_ext/string/filters.rb +20 -14
  63. data/lib/active_support/core_ext/string/indent.rb +1 -1
  64. data/lib/active_support/core_ext/string/inflections.rb +16 -5
  65. data/lib/active_support/core_ext/string/output_safety.rb +38 -174
  66. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  67. data/lib/active_support/core_ext/time/calculations.rb +18 -2
  68. data/lib/active_support/core_ext/time/conversions.rb +2 -2
  69. data/lib/active_support/core_ext/time/zones.rb +4 -4
  70. data/lib/active_support/core_ext/time.rb +0 -1
  71. data/lib/active_support/current_attributes.rb +15 -6
  72. data/lib/active_support/deep_mergeable.rb +53 -0
  73. data/lib/active_support/dependencies/autoload.rb +17 -12
  74. data/lib/active_support/deprecation/behaviors.rb +65 -42
  75. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  76. data/lib/active_support/deprecation/deprecators.rb +104 -0
  77. data/lib/active_support/deprecation/disallowed.rb +3 -5
  78. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  79. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  80. data/lib/active_support/deprecation/proxy_wrappers.rb +37 -22
  81. data/lib/active_support/deprecation/reporting.rb +42 -25
  82. data/lib/active_support/deprecation.rb +32 -5
  83. data/lib/active_support/deprecator.rb +7 -0
  84. data/lib/active_support/descendants_tracker.rb +104 -132
  85. data/lib/active_support/duration/iso8601_serializer.rb +0 -2
  86. data/lib/active_support/duration.rb +2 -1
  87. data/lib/active_support/encrypted_configuration.rb +30 -9
  88. data/lib/active_support/encrypted_file.rb +8 -3
  89. data/lib/active_support/environment_inquirer.rb +22 -2
  90. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  91. data/lib/active_support/error_reporter.rb +121 -35
  92. data/lib/active_support/execution_wrapper.rb +4 -4
  93. data/lib/active_support/file_update_checker.rb +4 -2
  94. data/lib/active_support/fork_tracker.rb +10 -2
  95. data/lib/active_support/gem_version.rb +4 -4
  96. data/lib/active_support/gzip.rb +2 -0
  97. data/lib/active_support/hash_with_indifferent_access.rb +35 -17
  98. data/lib/active_support/html_safe_translation.rb +12 -2
  99. data/lib/active_support/i18n.rb +1 -1
  100. data/lib/active_support/i18n_railtie.rb +20 -13
  101. data/lib/active_support/inflector/inflections.rb +2 -0
  102. data/lib/active_support/inflector/methods.rb +23 -11
  103. data/lib/active_support/inflector/transliterate.rb +3 -1
  104. data/lib/active_support/isolated_execution_state.rb +26 -22
  105. data/lib/active_support/json/decoding.rb +2 -1
  106. data/lib/active_support/json/encoding.rb +25 -43
  107. data/lib/active_support/key_generator.rb +9 -1
  108. data/lib/active_support/lazy_load_hooks.rb +6 -4
  109. data/lib/active_support/locale/en.yml +2 -0
  110. data/lib/active_support/log_subscriber.rb +84 -33
  111. data/lib/active_support/logger.rb +9 -60
  112. data/lib/active_support/logger_thread_safe_level.rb +10 -24
  113. data/lib/active_support/message_encryptor.rb +197 -53
  114. data/lib/active_support/message_encryptors.rb +141 -0
  115. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  116. data/lib/active_support/message_pack/extensions.rb +292 -0
  117. data/lib/active_support/message_pack/serializer.rb +63 -0
  118. data/lib/active_support/message_pack.rb +50 -0
  119. data/lib/active_support/message_verifier.rb +212 -93
  120. data/lib/active_support/message_verifiers.rb +135 -0
  121. data/lib/active_support/messages/codec.rb +65 -0
  122. data/lib/active_support/messages/metadata.rb +111 -45
  123. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  124. data/lib/active_support/messages/rotator.rb +34 -32
  125. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  126. data/lib/active_support/multibyte/chars.rb +2 -0
  127. data/lib/active_support/multibyte/unicode.rb +9 -37
  128. data/lib/active_support/notifications/fanout.rb +245 -81
  129. data/lib/active_support/notifications/instrumenter.rb +77 -20
  130. data/lib/active_support/notifications.rb +1 -1
  131. data/lib/active_support/number_helper/number_converter.rb +14 -5
  132. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  133. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  134. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  135. data/lib/active_support/number_helper.rb +379 -318
  136. data/lib/active_support/ordered_hash.rb +3 -3
  137. data/lib/active_support/ordered_options.rb +14 -0
  138. data/lib/active_support/parameter_filter.rb +84 -69
  139. data/lib/active_support/proxy_object.rb +2 -0
  140. data/lib/active_support/railtie.rb +33 -21
  141. data/lib/active_support/reloader.rb +12 -4
  142. data/lib/active_support/rescuable.rb +2 -0
  143. data/lib/active_support/secure_compare_rotator.rb +16 -9
  144. data/lib/active_support/string_inquirer.rb +3 -1
  145. data/lib/active_support/subscriber.rb +9 -27
  146. data/lib/active_support/syntax_error_proxy.rb +70 -0
  147. data/lib/active_support/tagged_logging.rb +60 -24
  148. data/lib/active_support/test_case.rb +153 -6
  149. data/lib/active_support/testing/assertions.rb +26 -10
  150. data/lib/active_support/testing/autorun.rb +0 -2
  151. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  152. data/lib/active_support/testing/deprecation.rb +25 -25
  153. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  154. data/lib/active_support/testing/isolation.rb +1 -1
  155. data/lib/active_support/testing/method_call_assertions.rb +21 -8
  156. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  157. data/lib/active_support/testing/stream.rb +1 -1
  158. data/lib/active_support/testing/strict_warnings.rb +39 -0
  159. data/lib/active_support/testing/time_helpers.rb +37 -15
  160. data/lib/active_support/time_with_zone.rb +4 -14
  161. data/lib/active_support/values/time_zone.rb +9 -7
  162. data/lib/active_support/version.rb +1 -1
  163. data/lib/active_support/xml_mini/jdom.rb +3 -10
  164. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  165. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  166. data/lib/active_support/xml_mini/rexml.rb +1 -1
  167. data/lib/active_support/xml_mini.rb +2 -2
  168. data/lib/active_support.rb +14 -3
  169. metadata +103 -16
  170. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  171. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -40
  172. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -36
  173. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  174. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -36
  175. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -5
  176. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  177. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -73
  178. data/lib/active_support/core_ext/uri.rb +0 -5
  179. data/lib/active_support/per_thread_registry.rb +0 -65
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/inflections"
4
- require "active_support/core_ext/object/blank"
5
4
 
6
5
  module ActiveSupport
6
+ # = Active Support \Inflector
7
+ #
7
8
  # The Inflector transforms words from singular to plural, class names to table
8
9
  # names, modularized class names to ones without, and class names to foreign
9
10
  # keys. The default inflections for pluralization, singularization, and
10
11
  # uncountable words are kept in inflections.rb.
11
12
  #
12
- # The Rails core team has stated patches for the inflections library will not
13
+ # The \Rails core team has stated patches for the inflections library will not
13
14
  # be accepted in order to avoid breaking legacy applications which may be
14
15
  # relying on errant inflections. If you discover an incorrect inflection and
15
16
  # require it for your application or wish to define rules for languages other
@@ -71,6 +72,8 @@ module ActiveSupport
71
72
  # String#camelize takes a symbol (:upper or :lower), so here we also support :lower to keep the methods consistent.
72
73
  if !uppercase_first_letter || uppercase_first_letter == :lower
73
74
  string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase! || match }
75
+ elsif string.match?(/\A[a-z\d]*\z/)
76
+ return inflections.acronyms[string]&.dup || string.capitalize
74
77
  else
75
78
  string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize! || match }
76
79
  end
@@ -94,10 +97,10 @@ module ActiveSupport
94
97
  #
95
98
  # camelize(underscore('SSLError')) # => "SslError"
96
99
  def underscore(camel_cased_word)
97
- return camel_cased_word.to_s unless /[A-Z-]|::/.match?(camel_cased_word)
100
+ return camel_cased_word.to_s.dup unless /[A-Z-]|::/.match?(camel_cased_word)
98
101
  word = camel_cased_word.to_s.gsub("::", "/")
99
102
  word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_' }#{$2.downcase}" }
100
- word.gsub!(/([A-Z])(?=[A-Z][a-z])|([a-z\d])(?=[A-Z])/) { ($1 || $2) << "_" }
103
+ word.gsub!(/(?<=[A-Z])(?=[A-Z][a-z])|(?<=[a-z\d])(?=[A-Z])/, "_")
101
104
  word.tr!("-", "_")
102
105
  word.downcase!
103
106
  word
@@ -155,18 +158,27 @@ module ActiveSupport
155
158
  result
156
159
  end
157
160
 
158
- # Converts just the first character to uppercase.
161
+ # Converts the first character in the string to uppercase.
159
162
  #
160
163
  # upcase_first('what a Lovely Day') # => "What a Lovely Day"
161
164
  # upcase_first('w') # => "W"
162
165
  # upcase_first('') # => ""
163
166
  def upcase_first(string)
164
- string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
167
+ string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +""
168
+ end
169
+
170
+ # Converts the first character in the string to lowercase.
171
+ #
172
+ # downcase_first('If they enjoyed The Matrix') # => "if they enjoyed The Matrix"
173
+ # downcase_first('I') # => "i"
174
+ # downcase_first('') # => ""
175
+ def downcase_first(string)
176
+ string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +""
165
177
  end
166
178
 
167
179
  # Capitalizes all the words and replaces some characters in the string to
168
180
  # create a nicer looking title. +titleize+ is meant for creating pretty
169
- # output. It is not used in the Rails internals.
181
+ # output. It is not used in the \Rails internals.
170
182
  #
171
183
  # The trailing '_id','Id'.. can be kept and capitalized by setting the
172
184
  # optional parameter +keep_id_suffix+ to true.
@@ -183,7 +195,7 @@ module ActiveSupport
183
195
  end
184
196
  end
185
197
 
186
- # Creates the name of a table like Rails does for models to table names.
198
+ # Creates the name of a table like \Rails does for models to table names.
187
199
  # This method uses the #pluralize method on the last word in the string.
188
200
  #
189
201
  # tableize('RawScaledScorer') # => "raw_scaled_scorers"
@@ -193,7 +205,7 @@ module ActiveSupport
193
205
  pluralize(underscore(class_name))
194
206
  end
195
207
 
196
- # Creates a class name from a plural table name like Rails does for table
208
+ # Creates a class name from a plural table name like \Rails does for table
197
209
  # names to models. Note that this returns a string and not a Class. (To
198
210
  # convert to an actual class follow +classify+ with #constantize.)
199
211
  #
@@ -226,7 +238,7 @@ module ActiveSupport
226
238
  def demodulize(path)
227
239
  path = path.to_s
228
240
  if i = path.rindex("::")
229
- path[(i + 2)..-1]
241
+ path[(i + 2), path.length]
230
242
  else
231
243
  path
232
244
  end
@@ -345,7 +357,7 @@ module ActiveSupport
345
357
  def const_regexp(camel_cased_word)
346
358
  parts = camel_cased_word.split("::")
347
359
 
348
- return Regexp.escape(camel_cased_word) if parts.blank?
360
+ return Regexp.escape(camel_cased_word) if parts.empty?
349
361
 
350
362
  last = parts.pop
351
363
 
@@ -62,10 +62,12 @@ module ActiveSupport
62
62
  # Transliteration is restricted to UTF-8, US-ASCII, and GB18030 strings.
63
63
  # Other encodings will raise an ArgumentError.
64
64
  def transliterate(string, replacement = "?", locale: nil)
65
- string = string.dup if string.frozen?
66
65
  raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
67
66
  raise ArgumentError, "Cannot transliterate strings with #{string.encoding} encoding" unless ALLOWED_ENCODINGS_FOR_TRANSLITERATE.include?(string.encoding)
68
67
 
68
+ return string.dup if string.ascii_only?
69
+ string = string.dup if string.frozen?
70
+
69
71
  input_encoding = string.encoding
70
72
 
71
73
  # US-ASCII is a subset of UTF-8 so we'll force encoding as UTF-8 if
@@ -4,25 +4,30 @@ require "fiber"
4
4
 
5
5
  module ActiveSupport
6
6
  module IsolatedExecutionState # :nodoc:
7
- @isolation_level = :thread
7
+ @isolation_level = nil
8
8
 
9
9
  Thread.attr_accessor :active_support_execution_state
10
10
  Fiber.attr_accessor :active_support_execution_state
11
11
 
12
12
  class << self
13
- attr_reader :isolation_level
13
+ attr_reader :isolation_level, :scope
14
14
 
15
15
  def isolation_level=(level)
16
+ return if level == @isolation_level
17
+
16
18
  unless %i(thread fiber).include?(level)
17
19
  raise ArgumentError, "isolation_level must be `:thread` or `:fiber`, got: `#{level.inspect}`"
18
20
  end
19
21
 
20
- if level != isolation_level
21
- clear
22
- singleton_class.alias_method(:current, "current_#{level}")
23
- singleton_class.send(:private, :current)
24
- @isolation_level = level
25
- end
22
+ clear if @isolation_level
23
+
24
+ @scope =
25
+ case level
26
+ when :thread; Thread
27
+ when :fiber; Fiber
28
+ end
29
+
30
+ @isolation_level = level
26
31
  end
27
32
 
28
33
  def unique_id
@@ -30,43 +35,42 @@ module ActiveSupport
30
35
  end
31
36
 
32
37
  def [](key)
33
- current[key]
38
+ state[key]
34
39
  end
35
40
 
36
41
  def []=(key, value)
37
- current[key] = value
42
+ state[key] = value
38
43
  end
39
44
 
40
45
  def key?(key)
41
- current.key?(key)
46
+ state.key?(key)
42
47
  end
43
48
 
44
49
  def delete(key)
45
- current.delete(key)
50
+ state.delete(key)
46
51
  end
47
52
 
48
53
  def clear
49
- current.clear
54
+ state.clear
55
+ end
56
+
57
+ def context
58
+ scope.current
50
59
  end
51
60
 
52
61
  def share_with(other)
53
62
  # Action Controller streaming spawns a new thread and copy thread locals.
54
63
  # We do the same here for backward compatibility, but this is very much a hack
55
64
  # and streaming should be rethought.
56
- context = @isolation_level == :thread ? Thread.current : Fiber.current
57
65
  context.active_support_execution_state = other.active_support_execution_state.dup
58
66
  end
59
67
 
60
68
  private
61
- def current_thread
62
- Thread.current.active_support_execution_state ||= {}
63
- end
64
-
65
- def current_fiber
66
- Fiber.current.active_support_execution_state ||= {}
69
+ def state
70
+ context.active_support_execution_state ||= {}
67
71
  end
68
-
69
- alias_method :current, :current_thread
70
72
  end
73
+
74
+ self.isolation_level = :thread
71
75
  end
72
76
  end
@@ -5,7 +5,7 @@ require "active_support/core_ext/module/delegation"
5
5
  require "json"
6
6
 
7
7
  module ActiveSupport
8
- # Look for and parse json strings that look like ISO 8601 times.
8
+ # Look for and parse JSON strings that look like ISO 8601 times.
9
9
  mattr_accessor :parse_json_times
10
10
 
11
11
  module JSON
@@ -28,6 +28,7 @@ module ActiveSupport
28
28
  data
29
29
  end
30
30
  end
31
+ alias_method :load, :decode
31
32
 
32
33
  # Returns the class of the error that will be raised when there is an
33
34
  # error in decoding JSON. Using this method means you won't directly
@@ -18,8 +18,11 @@ module ActiveSupport
18
18
  #
19
19
  # ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
20
20
  # # => "{\"team\":\"rails\",\"players\":\"36\"}"
21
- def self.encode(value, options = nil)
22
- Encoding.json_encoder.new(options).encode(value)
21
+ class << self
22
+ def encode(value, options = nil)
23
+ Encoding.json_encoder.new(options).encode(value)
24
+ end
25
+ alias_method :dump, :encode
23
26
  end
24
27
 
25
28
  module Encoding # :nodoc:
@@ -32,49 +35,27 @@ module ActiveSupport
32
35
 
33
36
  # Encode the given object into a JSON string
34
37
  def encode(value)
35
- stringify jsonify value.as_json(options.dup)
36
- end
38
+ unless options.empty?
39
+ value = value.as_json(options.dup)
40
+ end
41
+ json = stringify(jsonify(value))
37
42
 
38
- private
39
43
  # Rails does more escaping than the JSON gem natively does (we
40
44
  # escape \u2028 and \u2029 and optionally >, <, & to work around
41
45
  # certain browser problems).
42
- ESCAPED_CHARS = {
43
- "\u2028" => '\u2028',
44
- "\u2029" => '\u2029',
45
- ">" => '\u003e',
46
- "<" => '\u003c',
47
- "&" => '\u0026',
48
- }
49
-
50
- ESCAPE_REGEX_WITH_HTML_ENTITIES = /[\u2028\u2029><&]/u
51
- ESCAPE_REGEX_WITHOUT_HTML_ENTITIES = /[\u2028\u2029]/u
52
-
53
- # This class wraps all the strings we see and does the extra escaping
54
- class EscapedString < String # :nodoc:
55
- def to_json(*)
56
- if Encoding.escape_html_entities_in_json
57
- s = super
58
- s.gsub! ESCAPE_REGEX_WITH_HTML_ENTITIES, ESCAPED_CHARS
59
- s
60
- else
61
- s = super
62
- s.gsub! ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, ESCAPED_CHARS
63
- s
64
- end
65
- end
66
-
67
- def to_s
68
- self
69
- end
46
+ if Encoding.escape_html_entities_in_json
47
+ json.gsub!(">", '\u003e')
48
+ json.gsub!("<", '\u003c')
49
+ json.gsub!("&", '\u0026')
70
50
  end
51
+ json.gsub!("\u2028", '\u2028')
52
+ json.gsub!("\u2029", '\u2029')
53
+ json
54
+ end
71
55
 
72
- # Mark these as private so we don't leak encoding-specific constructs
73
- private_constant :ESCAPED_CHARS, :ESCAPE_REGEX_WITH_HTML_ENTITIES,
74
- :ESCAPE_REGEX_WITHOUT_HTML_ENTITIES, :EscapedString
75
-
56
+ private
76
57
  # Convert an object into a "JSON-ready" representation composed of
77
- # primitives like Hash, Array, String, Numeric,
58
+ # primitives like Hash, Array, String, Symbol, Numeric,
78
59
  # and +true+/+false+/+nil+.
79
60
  # Recursively calls #as_json to the object to recursively build a
80
61
  # fully JSON-ready object.
@@ -88,14 +69,15 @@ module ActiveSupport
88
69
  # calls.
89
70
  def jsonify(value)
90
71
  case value
91
- when String
92
- EscapedString.new(value)
93
- when Numeric, NilClass, TrueClass, FalseClass
72
+ when String, Integer, Symbol, nil, true, false
73
+ value
74
+ when Numeric
94
75
  value.as_json
95
76
  when Hash
96
77
  result = {}
97
78
  value.each do |k, v|
98
- result[jsonify(k)] = jsonify(v)
79
+ k = k.to_s unless String === k
80
+ result[k] = jsonify(v)
99
81
  end
100
82
  result
101
83
  when Array
@@ -124,7 +106,7 @@ module ActiveSupport
124
106
  # Defaults to 3 (equivalent to millisecond precision)
125
107
  attr_accessor :time_precision
126
108
 
127
- # Sets the encoder used by Rails to encode Ruby objects into JSON strings
109
+ # Sets the encoder used by \Rails to encode Ruby objects into JSON strings
128
110
  # in +Object#to_json+ and +ActiveSupport::JSON.encode+.
129
111
  attr_accessor :json_encoder
130
112
  end
@@ -4,9 +4,11 @@ require "concurrent/map"
4
4
  require "openssl"
5
5
 
6
6
  module ActiveSupport
7
+ # = Key Generator
8
+ #
7
9
  # KeyGenerator is a simple wrapper around OpenSSL's implementation of PBKDF2.
8
10
  # It can be used to derive a number of keys for various purposes from a given secret.
9
- # This lets Rails applications have a single secure secret, but avoid reusing that
11
+ # This lets \Rails applications have a single secure secret, but avoid reusing that
10
12
  # key in multiple incompatible contexts.
11
13
  class KeyGenerator
12
14
  class << self
@@ -39,8 +41,14 @@ module ActiveSupport
39
41
  def generate_key(salt, key_size = 64)
40
42
  OpenSSL::PKCS5.pbkdf2_hmac(@secret, salt, @iterations, key_size, @hash_digest_class.new)
41
43
  end
44
+
45
+ def inspect # :nodoc:
46
+ "#<#{self.class.name}:#{'%#016x' % (object_id << 1)}>"
47
+ end
42
48
  end
43
49
 
50
+ # = Caching Key Generator
51
+ #
44
52
  # CachingKeyGenerator is a wrapper around KeyGenerator which allows users to avoid
45
53
  # re-executing the key generation process when it's called using the same +salt+ and
46
54
  # +key_size+.
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveSupport
4
- # LazyLoadHooks allows Rails to lazily load a lot of components and thus
4
+ # = Lazy Load Hooks
5
+ #
6
+ # LazyLoadHooks allows \Rails to lazily load a lot of components and thus
5
7
  # making the app boot faster. Because of this feature now there is no need to
6
- # require <tt>ActiveRecord::Base</tt> at boot time purely to apply
8
+ # require +ActiveRecord::Base+ at boot time purely to apply
7
9
  # configuration. Instead a hook is registered that applies configuration once
8
- # <tt>ActiveRecord::Base</tt> is loaded. Here <tt>ActiveRecord::Base</tt> is
10
+ # +ActiveRecord::Base+ is loaded. Here +ActiveRecord::Base+ is
9
11
  # used as example but this feature can be applied elsewhere too.
10
12
  #
11
13
  # Here is an example where on_load method is called to register a hook.
@@ -47,7 +49,7 @@ module ActiveSupport
47
49
  end
48
50
  end
49
51
 
50
- # Declares a block that will be executed when a Rails component is fully
52
+ # Declares a block that will be executed when a \Rails component is fully
51
53
  # loaded. If the component has already loaded, the block is executed
52
54
  # immediately.
53
55
  #
@@ -57,6 +57,7 @@ en:
57
57
  format:
58
58
  # Where is the currency sign? %u is the currency unit, %n is the number (default: $5.00)
59
59
  format: "%u%n"
60
+ negative_format: "-%u%n"
60
61
  unit: "$"
61
62
  # These six are to override number.format and are optional
62
63
  separator: "."
@@ -112,6 +113,7 @@ en:
112
113
  tb: "TB"
113
114
  pb: "PB"
114
115
  eb: "EB"
116
+ zb: "ZB"
115
117
  # Used in NumberHelper.number_to_human()
116
118
  decimal_units:
117
119
  format: "%n %u"
@@ -3,9 +3,12 @@
3
3
  require "active_support/core_ext/module/attribute_accessors"
4
4
  require "active_support/core_ext/class/attribute"
5
5
  require "active_support/subscriber"
6
+ require "active_support/deprecation/proxy_wrappers"
6
7
 
7
8
  module ActiveSupport
8
- # <tt>ActiveSupport::LogSubscriber</tt> is an object set to consume
9
+ # = Active Support Log \Subscriber
10
+ #
11
+ # +ActiveSupport::LogSubscriber+ is an object set to consume
9
12
  # ActiveSupport::Notifications with the sole purpose of logging them.
10
13
  # The log subscriber dispatches notifications to a registered object based
11
14
  # on its given namespace.
@@ -15,29 +18,23 @@ module ActiveSupport
15
18
  #
16
19
  # module ActiveRecord
17
20
  # class LogSubscriber < ActiveSupport::LogSubscriber
21
+ # attach_to :active_record
22
+ #
18
23
  # def sql(event)
19
24
  # info "#{event.payload[:name]} (#{event.duration}) #{event.payload[:sql]}"
20
25
  # end
21
26
  # end
22
27
  # end
23
28
  #
24
- # And it's finally registered as:
25
- #
26
- # ActiveRecord::LogSubscriber.attach_to :active_record
29
+ # ActiveRecord::LogSubscriber.logger must be set as well, but it is assigned
30
+ # automatically in a \Rails environment.
27
31
  #
28
- # Since we need to know all instance methods before attaching the log
29
- # subscriber, the line above should be called after your
30
- # <tt>ActiveRecord::LogSubscriber</tt> definition.
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
- #
35
- # After configured, whenever a <tt>"sql.active_record"</tt> notification is published,
36
- # it will properly dispatch the event
37
- # (<tt>ActiveSupport::Notifications::Event</tt>) to the sql method.
32
+ # After configured, whenever a <tt>"sql.active_record"</tt> notification is
33
+ # published, it will properly dispatch the event
34
+ # (ActiveSupport::Notifications::Event) to the +sql+ method.
38
35
  #
39
36
  # Being an ActiveSupport::Notifications consumer,
40
- # <tt>ActiveSupport::LogSubscriber</tt> exposes a simple interface to check if
37
+ # +ActiveSupport::LogSubscriber+ exposes a simple interface to check if
41
38
  # instrumented code raises an exception. It is common to log a different
42
39
  # message in case of an error, and this can be achieved by extending
43
40
  # the previous example:
@@ -59,15 +56,24 @@ module ActiveSupport
59
56
  # end
60
57
  # end
61
58
  #
62
- # Log subscriber also has some helpers to deal with logging and automatically
63
- # flushes all logs when the request finishes
64
- # (via <tt>action_dispatch.callback</tt> notification) in a Rails environment.
59
+ # +ActiveSupport::LogSubscriber+ also has some helpers to deal with
60
+ # logging. For example, ActiveSupport::LogSubscriber.flush_all! will ensure
61
+ # that all logs are flushed, and it is called in Rails::Rack::Logger after a
62
+ # request finishes.
65
63
  class LogSubscriber < Subscriber
66
64
  # Embed in a String to clear all previous ANSI sequences.
67
- CLEAR = "\e[0m"
68
- BOLD = "\e[1m"
69
-
70
- # Colors
65
+ CLEAR = ActiveSupport::Deprecation::DeprecatedObjectProxy.new("\e[0m", "CLEAR is deprecated! Use MODES[:clear] instead.", ActiveSupport.deprecator)
66
+ BOLD = ActiveSupport::Deprecation::DeprecatedObjectProxy.new("\e[1m", "BOLD is deprecated! Use MODES[:bold] instead.", ActiveSupport.deprecator)
67
+
68
+ # ANSI sequence modes
69
+ MODES = {
70
+ clear: 0,
71
+ bold: 1,
72
+ italic: 3,
73
+ underline: 4,
74
+ }
75
+
76
+ # ANSI sequence colors
71
77
  BLACK = "\e[30m"
72
78
  RED = "\e[31m"
73
79
  GREEN = "\e[32m"
@@ -78,6 +84,13 @@ module ActiveSupport
78
84
  WHITE = "\e[37m"
79
85
 
80
86
  mattr_accessor :colorize_logging, default: true
87
+ class_attribute :log_levels, instance_accessor: false, default: {} # :nodoc:
88
+
89
+ LEVEL_CHECKS = {
90
+ debug: -> (logger) { !logger.debug? },
91
+ info: -> (logger) { !logger.info? },
92
+ error: -> (logger) { !logger.error? },
93
+ }
81
94
 
82
95
  class << self
83
96
  def logger
@@ -86,6 +99,12 @@ module ActiveSupport
86
99
  end
87
100
  end
88
101
 
102
+ def attach_to(...) # :nodoc:
103
+ result = super
104
+ set_event_levels
105
+ result
106
+ end
107
+
89
108
  attr_writer :logger
90
109
 
91
110
  def log_subscribers
@@ -101,20 +120,36 @@ module ActiveSupport
101
120
  def fetch_public_methods(subscriber, inherit_all)
102
121
  subscriber.public_methods(inherit_all) - LogSubscriber.public_instance_methods(true)
103
122
  end
123
+
124
+ def set_event_levels
125
+ if subscriber
126
+ subscriber.event_levels = log_levels.transform_keys { |k| "#{k}.#{namespace}" }
127
+ end
128
+ end
129
+
130
+ def subscribe_log_level(method, level)
131
+ self.log_levels = log_levels.merge(method => LEVEL_CHECKS.fetch(level))
132
+ set_event_levels
133
+ end
134
+ end
135
+
136
+ def initialize
137
+ super
138
+ @event_levels = {}
104
139
  end
105
140
 
106
141
  def logger
107
142
  LogSubscriber.logger
108
143
  end
109
144
 
110
- def start(name, id, payload)
111
- super if logger
145
+ def silenced?(event)
146
+ logger.nil? || @event_levels[event]&.call(logger)
112
147
  end
113
148
 
114
- def finish(name, id, payload)
149
+ def call(event)
115
150
  super if logger
116
151
  rescue => e
117
- log_exception(name, e)
152
+ log_exception(event.name, e)
118
153
  end
119
154
 
120
155
  def publish_event(event)
@@ -123,6 +158,8 @@ module ActiveSupport
123
158
  log_exception(event.name, e)
124
159
  end
125
160
 
161
+ attr_writer :event_levels # :nodoc:
162
+
126
163
  private
127
164
  %w(info debug warn error fatal unknown).each do |level|
128
165
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
@@ -132,15 +169,29 @@ module ActiveSupport
132
169
  METHOD
133
170
  end
134
171
 
135
- # Set color by using a symbol or one of the defined constants. If a third
136
- # option is set to +true+, it also adds bold to the string. This is based
137
- # on the Highline implementation and will automatically append CLEAR to the
138
- # end of the returned String.
139
- def color(text, color, bold = false) # :doc:
172
+ # Set color by using a symbol or one of the defined constants. Set modes
173
+ # by specifying bold, italic, or underline options. Inspired by Highline,
174
+ # this method will automatically clear formatting at the end of the returned String.
175
+ def color(text, color, mode_options = {}) # :doc:
140
176
  return text unless colorize_logging
141
177
  color = self.class.const_get(color.upcase) if color.is_a?(Symbol)
142
- bold = bold ? BOLD : ""
143
- "#{bold}#{color}#{text}#{CLEAR}"
178
+ mode = mode_from(mode_options)
179
+ clear = "\e[#{MODES[:clear]}m"
180
+ "#{mode}#{color}#{text}#{clear}"
181
+ end
182
+
183
+ def mode_from(options)
184
+ if options.is_a?(TrueClass) || options.is_a?(FalseClass)
185
+ ActiveSupport.deprecator.warn(<<~MSG.squish)
186
+ Bolding log text with a positional boolean is deprecated and will be removed
187
+ in Rails 7.2. Use an option hash instead (eg. `color("my text", :red, bold: true)`).
188
+ MSG
189
+ options = { bold: options }
190
+ end
191
+
192
+ modes = MODES.values_at(*options.compact_blank.keys)
193
+
194
+ "\e[#{modes.join(";")}m" if modes.any?
144
195
  end
145
196
 
146
197
  def log_exception(name, e)