activesupport 7.0.3.1 → 7.2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +261 -246
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +3 -1
  6. data/lib/active_support/array_inquirer.rb +3 -1
  7. data/lib/active_support/backtrace_cleaner.rb +39 -7
  8. data/lib/active_support/benchmarkable.rb +1 -0
  9. data/lib/active_support/broadcast_logger.rb +238 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +51 -19
  14. data/lib/active_support/cache/mem_cache_store.rb +114 -134
  15. data/lib/active_support/cache/memory_store.rb +85 -30
  16. data/lib/active_support/cache/null_store.rb +8 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +175 -154
  18. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +64 -13
  20. data/lib/active_support/cache.rb +455 -378
  21. data/lib/active_support/callbacks.rb +121 -136
  22. data/lib/active_support/code_generator.rb +15 -10
  23. data/lib/active_support/concern.rb +4 -2
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +42 -3
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/configurable.rb +10 -0
  27. data/lib/active_support/core_ext/array/conversions.rb +1 -2
  28. data/lib/active_support/core_ext/array.rb +0 -1
  29. data/lib/active_support/core_ext/benchmark.rb +1 -0
  30. data/lib/active_support/core_ext/class/attribute.rb +2 -2
  31. data/lib/active_support/core_ext/class/subclasses.rb +17 -34
  32. data/lib/active_support/core_ext/date/blank.rb +4 -0
  33. data/lib/active_support/core_ext/date/calculations.rb +15 -0
  34. data/lib/active_support/core_ext/date/conversions.rb +1 -2
  35. data/lib/active_support/core_ext/date.rb +0 -1
  36. data/lib/active_support/core_ext/date_and_time/calculations.rb +10 -0
  37. data/lib/active_support/core_ext/date_and_time/compatibility.rb +28 -1
  38. data/lib/active_support/core_ext/date_time/blank.rb +4 -0
  39. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  40. data/lib/active_support/core_ext/date_time/conversions.rb +6 -4
  41. data/lib/active_support/core_ext/date_time.rb +0 -1
  42. data/lib/active_support/core_ext/digest/uuid.rb +7 -10
  43. data/lib/active_support/core_ext/enumerable.rb +25 -80
  44. data/lib/active_support/core_ext/erb/util.rb +201 -0
  45. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  46. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  47. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  48. data/lib/active_support/core_ext/hash/keys.rb +7 -7
  49. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  50. data/lib/active_support/core_ext/module/attr_internal.rb +17 -6
  51. data/lib/active_support/core_ext/module/attribute_accessors.rb +6 -0
  52. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +34 -16
  53. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  54. data/lib/active_support/core_ext/module/delegation.rb +20 -119
  55. data/lib/active_support/core_ext/module/deprecation.rb +12 -12
  56. data/lib/active_support/core_ext/module/introspection.rb +3 -1
  57. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  58. data/lib/active_support/core_ext/numeric/conversions.rb +5 -3
  59. data/lib/active_support/core_ext/numeric.rb +0 -1
  60. data/lib/active_support/core_ext/object/blank.rb +45 -1
  61. data/lib/active_support/core_ext/object/deep_dup.rb +16 -0
  62. data/lib/active_support/core_ext/object/duplicable.rb +25 -16
  63. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  64. data/lib/active_support/core_ext/object/instance_variables.rb +4 -2
  65. data/lib/active_support/core_ext/object/json.rb +17 -7
  66. data/lib/active_support/core_ext/object/to_query.rb +0 -2
  67. data/lib/active_support/core_ext/object/try.rb +2 -2
  68. data/lib/active_support/core_ext/object/with.rb +46 -0
  69. data/lib/active_support/core_ext/object/with_options.rb +9 -9
  70. data/lib/active_support/core_ext/object.rb +1 -0
  71. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  72. data/lib/active_support/core_ext/pathname/existence.rb +2 -0
  73. data/lib/active_support/core_ext/pathname.rb +1 -0
  74. data/lib/active_support/core_ext/range/conversions.rb +28 -7
  75. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  76. data/lib/active_support/core_ext/range/sole.rb +17 -0
  77. data/lib/active_support/core_ext/range.rb +2 -2
  78. data/lib/active_support/core_ext/securerandom.rb +24 -12
  79. data/lib/active_support/core_ext/string/conversions.rb +1 -1
  80. data/lib/active_support/core_ext/string/filters.rb +24 -18
  81. data/lib/active_support/core_ext/string/indent.rb +1 -1
  82. data/lib/active_support/core_ext/string/inflections.rb +16 -9
  83. data/lib/active_support/core_ext/string/multibyte.rb +3 -3
  84. data/lib/active_support/core_ext/string/output_safety.rb +41 -178
  85. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  86. data/lib/active_support/core_ext/time/calculations.rb +40 -30
  87. data/lib/active_support/core_ext/time/compatibility.rb +24 -0
  88. data/lib/active_support/core_ext/time/conversions.rb +1 -3
  89. data/lib/active_support/core_ext/time/zones.rb +7 -8
  90. data/lib/active_support/core_ext/time.rb +0 -1
  91. data/lib/active_support/core_ext.rb +0 -1
  92. data/lib/active_support/current_attributes.rb +60 -46
  93. data/lib/active_support/deep_mergeable.rb +53 -0
  94. data/lib/active_support/delegation.rb +202 -0
  95. data/lib/active_support/dependencies/autoload.rb +9 -16
  96. data/lib/active_support/deprecation/behaviors.rb +64 -41
  97. data/lib/active_support/deprecation/constant_accessor.rb +47 -25
  98. data/lib/active_support/deprecation/deprecators.rb +104 -0
  99. data/lib/active_support/deprecation/disallowed.rb +6 -8
  100. data/lib/active_support/deprecation/method_wrappers.rb +6 -23
  101. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -22
  102. data/lib/active_support/deprecation/reporting.rb +49 -27
  103. data/lib/active_support/deprecation.rb +39 -9
  104. data/lib/active_support/deprecator.rb +7 -0
  105. data/lib/active_support/descendants_tracker.rb +66 -172
  106. data/lib/active_support/duration/iso8601_parser.rb +2 -2
  107. data/lib/active_support/duration/iso8601_serializer.rb +1 -4
  108. data/lib/active_support/duration.rb +13 -7
  109. data/lib/active_support/encrypted_configuration.rb +63 -11
  110. data/lib/active_support/encrypted_file.rb +29 -13
  111. data/lib/active_support/environment_inquirer.rb +22 -2
  112. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  113. data/lib/active_support/error_reporter.rb +163 -36
  114. data/lib/active_support/evented_file_update_checker.rb +17 -3
  115. data/lib/active_support/execution_wrapper.rb +5 -6
  116. data/lib/active_support/file_update_checker.rb +6 -4
  117. data/lib/active_support/fork_tracker.rb +4 -32
  118. data/lib/active_support/gem_version.rb +2 -2
  119. data/lib/active_support/gzip.rb +2 -0
  120. data/lib/active_support/hash_with_indifferent_access.rb +50 -30
  121. data/lib/active_support/html_safe_translation.rb +19 -6
  122. data/lib/active_support/i18n.rb +1 -1
  123. data/lib/active_support/i18n_railtie.rb +20 -13
  124. data/lib/active_support/inflector/inflections.rb +2 -0
  125. data/lib/active_support/inflector/methods.rb +28 -18
  126. data/lib/active_support/inflector/transliterate.rb +3 -1
  127. data/lib/active_support/isolated_execution_state.rb +26 -22
  128. data/lib/active_support/json/decoding.rb +3 -2
  129. data/lib/active_support/json/encoding.rb +48 -48
  130. data/lib/active_support/key_generator.rb +9 -1
  131. data/lib/active_support/lazy_load_hooks.rb +22 -7
  132. data/lib/active_support/locale/en.yml +2 -0
  133. data/lib/active_support/log_subscriber.rb +74 -34
  134. data/lib/active_support/logger.rb +22 -59
  135. data/lib/active_support/logger_thread_safe_level.rb +10 -32
  136. data/lib/active_support/message_encryptor.rb +197 -53
  137. data/lib/active_support/message_encryptors.rb +141 -0
  138. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  139. data/lib/active_support/message_pack/extensions.rb +305 -0
  140. data/lib/active_support/message_pack/serializer.rb +63 -0
  141. data/lib/active_support/message_pack.rb +50 -0
  142. data/lib/active_support/message_verifier.rb +229 -89
  143. data/lib/active_support/message_verifiers.rb +137 -0
  144. data/lib/active_support/messages/codec.rb +65 -0
  145. data/lib/active_support/messages/metadata.rb +111 -45
  146. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  147. data/lib/active_support/messages/rotator.rb +38 -31
  148. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  149. data/lib/active_support/multibyte/chars.rb +8 -3
  150. data/lib/active_support/multibyte/unicode.rb +9 -37
  151. data/lib/active_support/notifications/fanout.rb +248 -87
  152. data/lib/active_support/notifications/instrumenter.rb +93 -25
  153. data/lib/active_support/notifications.rb +36 -29
  154. data/lib/active_support/number_helper/number_converter.rb +16 -7
  155. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -6
  156. data/lib/active_support/number_helper/number_to_delimited_converter.rb +17 -2
  157. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -3
  158. data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -0
  159. data/lib/active_support/number_helper.rb +379 -317
  160. data/lib/active_support/option_merger.rb +4 -4
  161. data/lib/active_support/ordered_hash.rb +3 -3
  162. data/lib/active_support/ordered_options.rb +67 -15
  163. data/lib/active_support/parameter_filter.rb +103 -84
  164. data/lib/active_support/proxy_object.rb +8 -3
  165. data/lib/active_support/railtie.rb +25 -20
  166. data/lib/active_support/reloader.rb +12 -4
  167. data/lib/active_support/rescuable.rb +10 -8
  168. data/lib/active_support/secure_compare_rotator.rb +16 -9
  169. data/lib/active_support/string_inquirer.rb +4 -2
  170. data/lib/active_support/subscriber.rb +10 -27
  171. data/lib/active_support/syntax_error_proxy.rb +60 -0
  172. data/lib/active_support/tagged_logging.rb +64 -40
  173. data/lib/active_support/test_case.rb +160 -7
  174. data/lib/active_support/testing/assertions.rb +28 -12
  175. data/lib/active_support/testing/autorun.rb +0 -2
  176. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  177. data/lib/active_support/testing/deprecation.rb +20 -27
  178. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  179. data/lib/active_support/testing/isolation.rb +46 -33
  180. data/lib/active_support/testing/method_call_assertions.rb +7 -8
  181. data/lib/active_support/testing/parallelization/server.rb +18 -2
  182. data/lib/active_support/testing/parallelization/worker.rb +2 -2
  183. data/lib/active_support/testing/parallelization.rb +12 -1
  184. data/lib/active_support/testing/parallelize_executor.rb +8 -3
  185. data/lib/active_support/testing/setup_and_teardown.rb +2 -0
  186. data/lib/active_support/testing/stream.rb +1 -1
  187. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  188. data/lib/active_support/testing/time_helpers.rb +38 -16
  189. data/lib/active_support/time_with_zone.rb +18 -44
  190. data/lib/active_support/values/time_zone.rb +25 -14
  191. data/lib/active_support/version.rb +1 -1
  192. data/lib/active_support/xml_mini/jdom.rb +3 -10
  193. data/lib/active_support/xml_mini/nokogiri.rb +1 -1
  194. data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
  195. data/lib/active_support/xml_mini/rexml.rb +1 -1
  196. data/lib/active_support/xml_mini.rb +14 -3
  197. data/lib/active_support.rb +15 -3
  198. metadata +148 -24
  199. data/lib/active_support/core_ext/array/deprecated_conversions.rb +0 -25
  200. data/lib/active_support/core_ext/date/deprecated_conversions.rb +0 -26
  201. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +0 -22
  202. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +0 -60
  203. data/lib/active_support/core_ext/range/deprecated_conversions.rb +0 -26
  204. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -7
  205. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  206. data/lib/active_support/core_ext/time/deprecated_conversions.rb +0 -22
  207. data/lib/active_support/core_ext/uri.rb +0 -5
  208. data/lib/active_support/deprecation/instance_delegator.rb +0 -38
  209. data/lib/active_support/per_thread_registry.rb +0 -65
  210. data/lib/active_support/ruby_features.rb +0 -7
@@ -13,13 +13,34 @@ module ActiveSupport
13
13
  end
14
14
 
15
15
  module JSON
16
- # Dumps objects in JSON (JavaScript Object Notation).
17
- # See http://www.json.org for more info.
18
- #
19
- # ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
20
- # # => "{\"team\":\"rails\",\"players\":\"36\"}"
21
- def self.encode(value, options = nil)
22
- Encoding.json_encoder.new(options).encode(value)
16
+ class << self
17
+ # Dumps objects in JSON (JavaScript Object Notation).
18
+ # See http://www.json.org for more info.
19
+ #
20
+ # ActiveSupport::JSON.encode({ team: 'rails', players: '36' })
21
+ # # => "{\"team\":\"rails\",\"players\":\"36\"}"
22
+ #
23
+ # Generates JSON that is safe to include in JavaScript as it escapes
24
+ # U+2028 (Line Separator) and U+2029 (Paragraph Separator):
25
+ #
26
+ # ActiveSupport::JSON.encode({ key: "\u2028" })
27
+ # # => "{\"key\":\"\\u2028\"}"
28
+ #
29
+ # By default, it also generates JSON that is safe to include in HTML, as
30
+ # it escapes <tt><</tt>, <tt>></tt>, and <tt>&</tt>:
31
+ #
32
+ # ActiveSupport::JSON.encode({ key: "<>&" })
33
+ # # => "{\"key\":\"\\u003c\\u003e\\u0026\"}"
34
+ #
35
+ # This can be changed with the +escape_html_entities+ option, or the
36
+ # global escape_html_entities_in_json configuration option.
37
+ #
38
+ # ActiveSupport::JSON.encode({ key: "<>&" }, escape_html_entities: false)
39
+ # # => "{\"key\":\"<>&\"}"
40
+ def encode(value, options = nil)
41
+ Encoding.json_encoder.new(options).encode(value)
42
+ end
43
+ alias_method :dump, :encode
23
44
  end
24
45
 
25
46
  module Encoding # :nodoc:
@@ -32,49 +53,27 @@ module ActiveSupport
32
53
 
33
54
  # Encode the given object into a JSON string
34
55
  def encode(value)
35
- stringify jsonify value.as_json(options.dup)
36
- end
56
+ unless options.empty?
57
+ value = value.as_json(options.dup)
58
+ end
59
+ json = stringify(jsonify(value))
37
60
 
38
- private
39
61
  # Rails does more escaping than the JSON gem natively does (we
40
62
  # escape \u2028 and \u2029 and optionally >, <, & to work around
41
63
  # 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
64
+ if Encoding.escape_html_entities_in_json
65
+ json.gsub!(">", '\u003e')
66
+ json.gsub!("<", '\u003c')
67
+ json.gsub!("&", '\u0026')
70
68
  end
69
+ json.gsub!("\u2028", '\u2028')
70
+ json.gsub!("\u2029", '\u2029')
71
+ json
72
+ end
71
73
 
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
-
74
+ private
76
75
  # Convert an object into a "JSON-ready" representation composed of
77
- # primitives like Hash, Array, String, Numeric,
76
+ # primitives like Hash, Array, String, Symbol, Numeric,
78
77
  # and +true+/+false+/+nil+.
79
78
  # Recursively calls #as_json to the object to recursively build a
80
79
  # fully JSON-ready object.
@@ -88,14 +87,15 @@ module ActiveSupport
88
87
  # calls.
89
88
  def jsonify(value)
90
89
  case value
91
- when String
92
- EscapedString.new(value)
93
- when Numeric, NilClass, TrueClass, FalseClass
90
+ when String, Integer, Symbol, nil, true, false
91
+ value
92
+ when Numeric
94
93
  value.as_json
95
94
  when Hash
96
95
  result = {}
97
96
  value.each do |k, v|
98
- result[jsonify(k)] = jsonify(v)
97
+ k = k.to_s unless Symbol === k || String === k
98
+ result[k] = jsonify(v)
99
99
  end
100
100
  result
101
101
  when Array
@@ -124,7 +124,7 @@ module ActiveSupport
124
124
  # Defaults to 3 (equivalent to millisecond precision)
125
125
  attr_accessor :time_precision
126
126
 
127
- # Sets the encoder used by Rails to encode Ruby objects into JSON strings
127
+ # Sets the encoder used by \Rails to encode Ruby objects into JSON strings
128
128
  # in +Object#to_json+ and +ActiveSupport::JSON.encode+.
129
129
  attr_accessor :json_encoder
130
130
  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.
@@ -26,6 +28,18 @@ module ActiveSupport
26
28
  # run_load_hooks will then execute all the hooks that were registered
27
29
  # with the on_load method. In the case of the above example, it will
28
30
  # execute the block of code that is in the +initializer+.
31
+ #
32
+ # Registering a hook that has already run results in that hook executing
33
+ # immediately. This allows hooks to be nested for code that relies on
34
+ # multiple lazily loaded components:
35
+ #
36
+ # initializer "action_text.renderer" do
37
+ # ActiveSupport.on_load(:action_controller_base) do
38
+ # ActiveSupport.on_load(:action_text_content) do
39
+ # self.default_renderer = Class.new(ActionController::Base).renderer
40
+ # end
41
+ # end
42
+ # end
29
43
  module LazyLoadHooks
30
44
  def self.extended(base) # :nodoc:
31
45
  base.class_eval do
@@ -35,10 +49,11 @@ module ActiveSupport
35
49
  end
36
50
  end
37
51
 
38
- # Declares a block that will be executed when a Rails component is fully
39
- # loaded.
52
+ # Declares a block that will be executed when a \Rails component is fully
53
+ # loaded. If the component has already loaded, the block is executed
54
+ # immediately.
40
55
  #
41
- # Options:
56
+ # ==== Options
42
57
  #
43
58
  # * <tt>:yield</tt> - Yields the object that run_load_hooks to +block+.
44
59
  # * <tt>:run_once</tt> - Given +block+ will run only once.
@@ -53,7 +68,7 @@ module ActiveSupport
53
68
  # Executes all blocks registered to +name+ via on_load, using +base+ as the
54
69
  # evaluation context.
55
70
  #
56
- # ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
71
+ # ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
57
72
  #
58
73
  # In the case of the above example, it will execute all hooks registered
59
74
  # for +:active_record+ within the class +ActiveRecord::Base+.
@@ -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"
@@ -2,10 +2,14 @@
2
2
 
3
3
  require "active_support/core_ext/module/attribute_accessors"
4
4
  require "active_support/core_ext/class/attribute"
5
+ require "active_support/core_ext/enumerable"
5
6
  require "active_support/subscriber"
7
+ require "active_support/deprecation/proxy_wrappers"
6
8
 
7
9
  module ActiveSupport
8
- # <tt>ActiveSupport::LogSubscriber</tt> is an object set to consume
10
+ # = Active Support Log \Subscriber
11
+ #
12
+ # +ActiveSupport::LogSubscriber+ is an object set to consume
9
13
  # ActiveSupport::Notifications with the sole purpose of logging them.
10
14
  # The log subscriber dispatches notifications to a registered object based
11
15
  # on its given namespace.
@@ -15,29 +19,23 @@ module ActiveSupport
15
19
  #
16
20
  # module ActiveRecord
17
21
  # class LogSubscriber < ActiveSupport::LogSubscriber
22
+ # attach_to :active_record
23
+ #
18
24
  # def sql(event)
19
25
  # info "#{event.payload[:name]} (#{event.duration}) #{event.payload[:sql]}"
20
26
  # end
21
27
  # end
22
28
  # end
23
29
  #
24
- # And it's finally registered as:
25
- #
26
- # ActiveRecord::LogSubscriber.attach_to :active_record
30
+ # ActiveRecord::LogSubscriber.logger must be set as well, but it is assigned
31
+ # automatically in a \Rails environment.
27
32
  #
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.
33
+ # After configured, whenever a <tt>"sql.active_record"</tt> notification is
34
+ # published, it will properly dispatch the event
35
+ # (ActiveSupport::Notifications::Event) to the +sql+ method.
38
36
  #
39
37
  # Being an ActiveSupport::Notifications consumer,
40
- # <tt>ActiveSupport::LogSubscriber</tt> exposes a simple interface to check if
38
+ # +ActiveSupport::LogSubscriber+ exposes a simple interface to check if
41
39
  # instrumented code raises an exception. It is common to log a different
42
40
  # message in case of an error, and this can be achieved by extending
43
41
  # the previous example:
@@ -59,15 +57,20 @@ module ActiveSupport
59
57
  # end
60
58
  # end
61
59
  #
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.
60
+ # +ActiveSupport::LogSubscriber+ also has some helpers to deal with
61
+ # logging. For example, ActiveSupport::LogSubscriber.flush_all! will ensure
62
+ # that all logs are flushed, and it is called in Rails::Rack::Logger after a
63
+ # request finishes.
65
64
  class LogSubscriber < Subscriber
66
- # Embed in a String to clear all previous ANSI sequences.
67
- CLEAR = "\e[0m"
68
- BOLD = "\e[1m"
69
-
70
- # Colors
65
+ # ANSI sequence modes
66
+ MODES = {
67
+ clear: 0,
68
+ bold: 1,
69
+ italic: 3,
70
+ underline: 4,
71
+ }
72
+
73
+ # ANSI sequence colors
71
74
  BLACK = "\e[30m"
72
75
  RED = "\e[31m"
73
76
  GREEN = "\e[32m"
@@ -78,6 +81,13 @@ module ActiveSupport
78
81
  WHITE = "\e[37m"
79
82
 
80
83
  mattr_accessor :colorize_logging, default: true
84
+ class_attribute :log_levels, instance_accessor: false, default: {} # :nodoc:
85
+
86
+ LEVEL_CHECKS = {
87
+ debug: -> (logger) { !logger.debug? },
88
+ info: -> (logger) { !logger.info? },
89
+ error: -> (logger) { !logger.error? },
90
+ }
81
91
 
82
92
  class << self
83
93
  def logger
@@ -86,6 +96,12 @@ module ActiveSupport
86
96
  end
87
97
  end
88
98
 
99
+ def attach_to(...) # :nodoc:
100
+ result = super
101
+ set_event_levels
102
+ result
103
+ end
104
+
89
105
  attr_writer :logger
90
106
 
91
107
  def log_subscribers
@@ -101,20 +117,36 @@ module ActiveSupport
101
117
  def fetch_public_methods(subscriber, inherit_all)
102
118
  subscriber.public_methods(inherit_all) - LogSubscriber.public_instance_methods(true)
103
119
  end
120
+
121
+ def set_event_levels
122
+ if subscriber
123
+ subscriber.event_levels = log_levels.transform_keys { |k| "#{k}.#{namespace}" }
124
+ end
125
+ end
126
+
127
+ def subscribe_log_level(method, level)
128
+ self.log_levels = log_levels.merge(method => LEVEL_CHECKS.fetch(level))
129
+ set_event_levels
130
+ end
131
+ end
132
+
133
+ def initialize
134
+ super
135
+ @event_levels = {}
104
136
  end
105
137
 
106
138
  def logger
107
139
  LogSubscriber.logger
108
140
  end
109
141
 
110
- def start(name, id, payload)
111
- super if logger
142
+ def silenced?(event)
143
+ logger.nil? || @event_levels[event]&.call(logger)
112
144
  end
113
145
 
114
- def finish(name, id, payload)
146
+ def call(event)
115
147
  super if logger
116
148
  rescue => e
117
- log_exception(name, e)
149
+ log_exception(event.name, e)
118
150
  end
119
151
 
120
152
  def publish_event(event)
@@ -123,6 +155,8 @@ module ActiveSupport
123
155
  log_exception(event.name, e)
124
156
  end
125
157
 
158
+ attr_writer :event_levels # :nodoc:
159
+
126
160
  private
127
161
  %w(info debug warn error fatal unknown).each do |level|
128
162
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
@@ -132,15 +166,21 @@ module ActiveSupport
132
166
  METHOD
133
167
  end
134
168
 
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:
169
+ # Set color by using a symbol or one of the defined constants. Set modes
170
+ # by specifying bold, italic, or underline options. Inspired by Highline,
171
+ # this method will automatically clear formatting at the end of the returned String.
172
+ def color(text, color, mode_options = {}) # :doc:
140
173
  return text unless colorize_logging
141
174
  color = self.class.const_get(color.upcase) if color.is_a?(Symbol)
142
- bold = bold ? BOLD : ""
143
- "#{bold}#{color}#{text}#{CLEAR}"
175
+ mode = mode_from(mode_options)
176
+ clear = "\e[#{MODES[:clear]}m"
177
+ "#{mode}#{color}#{text}#{clear}"
178
+ end
179
+
180
+ def mode_from(options)
181
+ modes = MODES.values_at(*options.compact_blank.keys)
182
+
183
+ "\e[#{modes.join(";")}m" if modes.any?
144
184
  end
145
185
 
146
186
  def log_exception(name, e)
@@ -13,72 +13,26 @@ module ActiveSupport
13
13
  # logger = Logger.new(STDOUT)
14
14
  # ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
15
15
  # # => true
16
+ #
17
+ # logger = Logger.new('/var/log/rails.log')
18
+ # ActiveSupport::Logger.logger_outputs_to?(logger, '/var/log/rails.log')
19
+ # # => true
16
20
  def self.logger_outputs_to?(logger, *sources)
17
- logdev = logger.instance_variable_get(:@logdev)
18
- logger_source = logdev.dev if logdev.respond_to?(:dev)
19
- sources.any? { |source| source == logger_source }
20
- end
21
-
22
- # Broadcasts logs to multiple loggers.
23
- def self.broadcast(logger) # :nodoc:
24
- Module.new do
25
- define_singleton_method(:extended) do |base|
26
- base.public_send(:broadcast_to, logger) if base.respond_to?(:broadcast_to)
27
- end
28
-
29
- define_method(:add) do |*args, &block|
30
- logger.add(*args, &block)
31
- super(*args, &block)
32
- end
33
-
34
- define_method(:<<) do |x|
35
- logger << x
36
- super(x)
37
- end
38
-
39
- define_method(:close) do
40
- logger.close
41
- super()
42
- end
43
-
44
- define_method(:progname=) do |name|
45
- logger.progname = name
46
- super(name)
47
- end
48
-
49
- define_method(:level=) do |level|
50
- logger.level = level
51
- super(level)
52
- end
21
+ loggers = if logger.is_a?(BroadcastLogger)
22
+ logger.broadcasts
23
+ else
24
+ [logger]
25
+ end
53
26
 
54
- define_method(:local_level=) do |level|
55
- logger.local_level = level if logger.respond_to?(:local_level=)
56
- super(level) if respond_to?(:local_level=)
57
- end
27
+ logdevs = loggers.map { |logger| logger.instance_variable_get(:@logdev) }
28
+ logger_sources = logdevs.filter_map { |logdev| logdev.try(:filename) || logdev.try(:dev) }
58
29
 
59
- define_method(:silence) do |level = Logger::ERROR, &block|
60
- if logger.respond_to?(:silence)
61
- logger.silence(level) do
62
- if defined?(super)
63
- super(level, &block)
64
- else
65
- block.call(self)
66
- end
67
- end
68
- else
69
- if defined?(super)
70
- super(level, &block)
71
- else
72
- block.call(self)
73
- end
74
- end
75
- end
76
- end
30
+ normalize_sources(sources).intersect?(normalize_sources(logger_sources))
77
31
  end
78
32
 
79
33
  def initialize(*args, **kwargs)
80
34
  super
81
- @formatter = SimpleFormatter.new
35
+ @formatter ||= SimpleFormatter.new
82
36
  end
83
37
 
84
38
  # Simple formatter which only displays the message.
@@ -88,5 +42,14 @@ module ActiveSupport
88
42
  "#{String === msg ? msg : msg.inspect}\n"
89
43
  end
90
44
  end
45
+
46
+ private
47
+ def self.normalize_sources(sources)
48
+ sources.map do |source|
49
+ source = source.path if source.respond_to?(:path)
50
+ source = File.realpath(source) if source.is_a?(String) && File.exist?(source)
51
+ source
52
+ end
53
+ end
91
54
  end
92
55
  end
@@ -1,24 +1,14 @@
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"
6
- require "fiber"
4
+ require "logger"
7
5
 
8
6
  module ActiveSupport
9
7
  module LoggerThreadSafeLevel # :nodoc:
10
8
  extend ActiveSupport::Concern
11
9
 
12
- Logger::Severity.constants.each do |severity|
13
- class_eval(<<-EOT, __FILE__, __LINE__ + 1)
14
- def #{severity.downcase}? # def debug?
15
- Logger::#{severity} >= level # DEBUG >= level
16
- end # end
17
- EOT
18
- end
19
-
20
10
  def local_level
21
- IsolatedExecutionState[:logger_thread_safe_level]
11
+ IsolatedExecutionState[local_level_key]
22
12
  end
23
13
 
24
14
  def local_level=(level)
@@ -30,7 +20,11 @@ module ActiveSupport
30
20
  else
31
21
  raise ArgumentError, "Invalid log level: #{level.inspect}"
32
22
  end
33
- IsolatedExecutionState[:logger_thread_safe_level] = level
23
+ if level.nil?
24
+ IsolatedExecutionState.delete(local_level_key)
25
+ else
26
+ IsolatedExecutionState[local_level_key] = level
27
+ end
34
28
  end
35
29
 
36
30
  def level
@@ -45,25 +39,9 @@ module ActiveSupport
45
39
  self.local_level = old_local_level
46
40
  end
47
41
 
48
- # Redefined to check severity against #level, and thus the thread-local level, rather than +@level+.
49
- # FIXME: Remove when the minimum Ruby version supports overriding Logger#level.
50
- def add(severity, message = nil, progname = nil, &block) # :nodoc:
51
- severity ||= UNKNOWN
52
- progname ||= @progname
53
-
54
- return true if @logdev.nil? || severity < level
55
-
56
- if message.nil?
57
- if block_given?
58
- message = yield
59
- else
60
- message = progname
61
- progname = @progname
62
- end
42
+ private
43
+ def local_level_key
44
+ @local_level_key ||= :"logger_thread_safe_level_#{object_id}"
63
45
  end
64
-
65
- @logdev.write \
66
- format_message(format_severity(severity), Time.now, progname, message)
67
- end
68
46
  end
69
47
  end