omg-activesupport 8.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (289) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +86 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support/actionable_error.rb +50 -0
  6. data/lib/active_support/all.rb +5 -0
  7. data/lib/active_support/array_inquirer.rb +50 -0
  8. data/lib/active_support/backtrace_cleaner.rb +163 -0
  9. data/lib/active_support/benchmark.rb +21 -0
  10. data/lib/active_support/benchmarkable.rb +53 -0
  11. data/lib/active_support/broadcast_logger.rb +251 -0
  12. data/lib/active_support/builder.rb +8 -0
  13. data/lib/active_support/cache/coder.rb +153 -0
  14. data/lib/active_support/cache/entry.rb +134 -0
  15. data/lib/active_support/cache/file_store.rb +244 -0
  16. data/lib/active_support/cache/mem_cache_store.rb +290 -0
  17. data/lib/active_support/cache/memory_store.rb +262 -0
  18. data/lib/active_support/cache/null_store.rb +62 -0
  19. data/lib/active_support/cache/redis_cache_store.rb +492 -0
  20. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  21. data/lib/active_support/cache/strategy/local_cache.rb +201 -0
  22. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  23. data/lib/active_support/cache.rb +1104 -0
  24. data/lib/active_support/callbacks.rb +944 -0
  25. data/lib/active_support/class_attribute.rb +26 -0
  26. data/lib/active_support/code_generator.rb +79 -0
  27. data/lib/active_support/concern.rb +217 -0
  28. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +72 -0
  29. data/lib/active_support/concurrency/null_lock.rb +13 -0
  30. data/lib/active_support/concurrency/share_lock.rb +225 -0
  31. data/lib/active_support/configurable.rb +159 -0
  32. data/lib/active_support/configuration_file.rb +60 -0
  33. data/lib/active_support/core_ext/array/access.rb +100 -0
  34. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  35. data/lib/active_support/core_ext/array/extract.rb +21 -0
  36. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  37. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  38. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  39. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  40. data/lib/active_support/core_ext/array.rb +9 -0
  41. data/lib/active_support/core_ext/benchmark.rb +13 -0
  42. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  43. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  44. data/lib/active_support/core_ext/class/attribute.rb +122 -0
  45. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  46. data/lib/active_support/core_ext/class/subclasses.rb +24 -0
  47. data/lib/active_support/core_ext/class.rb +4 -0
  48. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  49. data/lib/active_support/core_ext/date/blank.rb +18 -0
  50. data/lib/active_support/core_ext/date/calculations.rb +161 -0
  51. data/lib/active_support/core_ext/date/conversions.rb +98 -0
  52. data/lib/active_support/core_ext/date/zones.rb +8 -0
  53. data/lib/active_support/core_ext/date.rb +7 -0
  54. data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
  55. data/lib/active_support/core_ext/date_and_time/compatibility.rb +58 -0
  56. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  57. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  58. data/lib/active_support/core_ext/date_time/blank.rb +18 -0
  59. data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
  60. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  61. data/lib/active_support/core_ext/date_time/conversions.rb +106 -0
  62. data/lib/active_support/core_ext/date_time.rb +7 -0
  63. data/lib/active_support/core_ext/digest/uuid.rb +76 -0
  64. data/lib/active_support/core_ext/digest.rb +3 -0
  65. data/lib/active_support/core_ext/enumerable.rb +267 -0
  66. data/lib/active_support/core_ext/erb/util.rb +201 -0
  67. data/lib/active_support/core_ext/file/atomic.rb +72 -0
  68. data/lib/active_support/core_ext/file.rb +3 -0
  69. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  70. data/lib/active_support/core_ext/hash/deep_merge.rb +42 -0
  71. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  72. data/lib/active_support/core_ext/hash/except.rb +12 -0
  73. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  74. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  75. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  76. data/lib/active_support/core_ext/hash/slice.rb +27 -0
  77. data/lib/active_support/core_ext/hash.rb +10 -0
  78. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  79. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  80. data/lib/active_support/core_ext/integer/time.rb +22 -0
  81. data/lib/active_support/core_ext/integer.rb +5 -0
  82. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  83. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  84. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  85. data/lib/active_support/core_ext/kernel.rb +5 -0
  86. data/lib/active_support/core_ext/load_error.rb +9 -0
  87. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  88. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  89. data/lib/active_support/core_ext/module/attr_internal.rb +49 -0
  90. data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
  91. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
  92. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  93. data/lib/active_support/core_ext/module/delegation.rb +225 -0
  94. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  95. data/lib/active_support/core_ext/module/introspection.rb +62 -0
  96. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  97. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  98. data/lib/active_support/core_ext/module.rb +13 -0
  99. data/lib/active_support/core_ext/name_error.rb +59 -0
  100. data/lib/active_support/core_ext/numeric/bytes.rb +75 -0
  101. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  102. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  103. data/lib/active_support/core_ext/numeric.rb +5 -0
  104. data/lib/active_support/core_ext/object/acts_like.rb +45 -0
  105. data/lib/active_support/core_ext/object/blank.rb +199 -0
  106. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  107. data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
  108. data/lib/active_support/core_ext/object/duplicable.rb +69 -0
  109. data/lib/active_support/core_ext/object/inclusion.rb +37 -0
  110. data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
  111. data/lib/active_support/core_ext/object/json.rb +260 -0
  112. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  113. data/lib/active_support/core_ext/object/to_query.rb +87 -0
  114. data/lib/active_support/core_ext/object/try.rb +158 -0
  115. data/lib/active_support/core_ext/object/with.rb +46 -0
  116. data/lib/active_support/core_ext/object/with_options.rb +101 -0
  117. data/lib/active_support/core_ext/object.rb +17 -0
  118. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  119. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  120. data/lib/active_support/core_ext/pathname.rb +4 -0
  121. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  122. data/lib/active_support/core_ext/range/conversions.rb +62 -0
  123. data/lib/active_support/core_ext/range/each.rb +24 -0
  124. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  125. data/lib/active_support/core_ext/range.rb +6 -0
  126. data/lib/active_support/core_ext/regexp.rb +14 -0
  127. data/lib/active_support/core_ext/securerandom.rb +41 -0
  128. data/lib/active_support/core_ext/string/access.rb +95 -0
  129. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  130. data/lib/active_support/core_ext/string/conversions.rb +60 -0
  131. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  132. data/lib/active_support/core_ext/string/filters.rb +151 -0
  133. data/lib/active_support/core_ext/string/indent.rb +45 -0
  134. data/lib/active_support/core_ext/string/inflections.rb +300 -0
  135. data/lib/active_support/core_ext/string/inquiry.rb +16 -0
  136. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  137. data/lib/active_support/core_ext/string/output_safety.rb +228 -0
  138. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/string/strip.rb +27 -0
  140. data/lib/active_support/core_ext/string/zones.rb +16 -0
  141. data/lib/active_support/core_ext/string.rb +15 -0
  142. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  143. data/lib/active_support/core_ext/symbol.rb +3 -0
  144. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  145. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  146. data/lib/active_support/core_ext/time/calculations.rb +386 -0
  147. data/lib/active_support/core_ext/time/compatibility.rb +32 -0
  148. data/lib/active_support/core_ext/time/conversions.rb +75 -0
  149. data/lib/active_support/core_ext/time/zones.rb +97 -0
  150. data/lib/active_support/core_ext/time.rb +7 -0
  151. data/lib/active_support/core_ext.rb +5 -0
  152. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  153. data/lib/active_support/current_attributes.rb +233 -0
  154. data/lib/active_support/deep_mergeable.rb +53 -0
  155. data/lib/active_support/delegation.rb +202 -0
  156. data/lib/active_support/dependencies/autoload.rb +72 -0
  157. data/lib/active_support/dependencies/interlock.rb +49 -0
  158. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  159. data/lib/active_support/dependencies.rb +98 -0
  160. data/lib/active_support/deprecation/behaviors.rb +148 -0
  161. data/lib/active_support/deprecation/constant_accessor.rb +74 -0
  162. data/lib/active_support/deprecation/deprecators.rb +104 -0
  163. data/lib/active_support/deprecation/disallowed.rb +54 -0
  164. data/lib/active_support/deprecation/method_wrappers.rb +68 -0
  165. data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
  166. data/lib/active_support/deprecation/reporting.rb +179 -0
  167. data/lib/active_support/deprecation.rb +81 -0
  168. data/lib/active_support/deprecator.rb +7 -0
  169. data/lib/active_support/descendants_tracker.rb +112 -0
  170. data/lib/active_support/digest.rb +22 -0
  171. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  172. data/lib/active_support/duration/iso8601_serializer.rb +64 -0
  173. data/lib/active_support/duration.rb +520 -0
  174. data/lib/active_support/encrypted_configuration.rb +126 -0
  175. data/lib/active_support/encrypted_file.rb +133 -0
  176. data/lib/active_support/environment_inquirer.rb +40 -0
  177. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  178. data/lib/active_support/error_reporter.rb +265 -0
  179. data/lib/active_support/evented_file_update_checker.rb +182 -0
  180. data/lib/active_support/execution_context/test_helper.rb +13 -0
  181. data/lib/active_support/execution_context.rb +53 -0
  182. data/lib/active_support/execution_wrapper.rb +150 -0
  183. data/lib/active_support/executor/test_helper.rb +7 -0
  184. data/lib/active_support/executor.rb +8 -0
  185. data/lib/active_support/file_update_checker.rb +164 -0
  186. data/lib/active_support/fork_tracker.rb +43 -0
  187. data/lib/active_support/gem_version.rb +17 -0
  188. data/lib/active_support/gzip.rb +40 -0
  189. data/lib/active_support/hash_with_indifferent_access.rb +445 -0
  190. data/lib/active_support/html_safe_translation.rb +56 -0
  191. data/lib/active_support/i18n.rb +17 -0
  192. data/lib/active_support/i18n_railtie.rb +138 -0
  193. data/lib/active_support/inflections.rb +72 -0
  194. data/lib/active_support/inflector/inflections.rb +273 -0
  195. data/lib/active_support/inflector/methods.rb +387 -0
  196. data/lib/active_support/inflector/transliterate.rb +149 -0
  197. data/lib/active_support/inflector.rb +9 -0
  198. data/lib/active_support/isolated_execution_state.rb +75 -0
  199. data/lib/active_support/json/decoding.rb +76 -0
  200. data/lib/active_support/json/encoding.rb +120 -0
  201. data/lib/active_support/json.rb +4 -0
  202. data/lib/active_support/key_generator.rb +66 -0
  203. data/lib/active_support/lazy_load_hooks.rb +107 -0
  204. data/lib/active_support/locale/en.rb +33 -0
  205. data/lib/active_support/locale/en.yml +141 -0
  206. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  207. data/lib/active_support/log_subscriber.rb +192 -0
  208. data/lib/active_support/logger.rb +55 -0
  209. data/lib/active_support/logger_silence.rb +21 -0
  210. data/lib/active_support/logger_thread_safe_level.rb +47 -0
  211. data/lib/active_support/message_encryptor.rb +374 -0
  212. data/lib/active_support/message_encryptors.rb +141 -0
  213. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  214. data/lib/active_support/message_pack/extensions.rb +305 -0
  215. data/lib/active_support/message_pack/serializer.rb +63 -0
  216. data/lib/active_support/message_pack.rb +50 -0
  217. data/lib/active_support/message_verifier.rb +368 -0
  218. data/lib/active_support/message_verifiers.rb +135 -0
  219. data/lib/active_support/messages/codec.rb +65 -0
  220. data/lib/active_support/messages/metadata.rb +146 -0
  221. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  222. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  223. data/lib/active_support/messages/rotator.rb +59 -0
  224. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  225. data/lib/active_support/multibyte/chars.rb +178 -0
  226. data/lib/active_support/multibyte/unicode.rb +42 -0
  227. data/lib/active_support/multibyte.rb +23 -0
  228. data/lib/active_support/notifications/fanout.rb +446 -0
  229. data/lib/active_support/notifications/instrumenter.rb +240 -0
  230. data/lib/active_support/notifications.rb +281 -0
  231. data/lib/active_support/number_helper/number_converter.rb +190 -0
  232. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  233. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  234. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  235. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  236. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  237. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  238. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  239. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  240. data/lib/active_support/number_helper.rb +479 -0
  241. data/lib/active_support/option_merger.rb +38 -0
  242. data/lib/active_support/ordered_hash.rb +50 -0
  243. data/lib/active_support/ordered_options.rb +147 -0
  244. data/lib/active_support/parameter_filter.rb +157 -0
  245. data/lib/active_support/proxy_object.rb +20 -0
  246. data/lib/active_support/rails.rb +26 -0
  247. data/lib/active_support/railtie.rb +161 -0
  248. data/lib/active_support/reloader.rb +138 -0
  249. data/lib/active_support/rescuable.rb +176 -0
  250. data/lib/active_support/secure_compare_rotator.rb +58 -0
  251. data/lib/active_support/security_utils.rb +38 -0
  252. data/lib/active_support/string_inquirer.rb +35 -0
  253. data/lib/active_support/subscriber.rb +146 -0
  254. data/lib/active_support/syntax_error_proxy.rb +60 -0
  255. data/lib/active_support/tagged_logging.rb +152 -0
  256. data/lib/active_support/test_case.rb +304 -0
  257. data/lib/active_support/testing/assertions.rb +332 -0
  258. data/lib/active_support/testing/autorun.rb +5 -0
  259. data/lib/active_support/testing/constant_lookup.rb +51 -0
  260. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  261. data/lib/active_support/testing/declarative.rb +28 -0
  262. data/lib/active_support/testing/deprecation.rb +82 -0
  263. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  264. data/lib/active_support/testing/file_fixtures.rb +38 -0
  265. data/lib/active_support/testing/isolation.rb +121 -0
  266. data/lib/active_support/testing/method_call_assertions.rb +69 -0
  267. data/lib/active_support/testing/parallelization/server.rb +85 -0
  268. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  269. data/lib/active_support/testing/parallelization.rb +55 -0
  270. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  271. data/lib/active_support/testing/setup_and_teardown.rb +57 -0
  272. data/lib/active_support/testing/stream.rb +41 -0
  273. data/lib/active_support/testing/strict_warnings.rb +43 -0
  274. data/lib/active_support/testing/tagged_logging.rb +27 -0
  275. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  276. data/lib/active_support/testing/time_helpers.rb +269 -0
  277. data/lib/active_support/time.rb +20 -0
  278. data/lib/active_support/time_with_zone.rb +609 -0
  279. data/lib/active_support/values/time_zone.rb +614 -0
  280. data/lib/active_support/version.rb +10 -0
  281. data/lib/active_support/xml_mini/jdom.rb +175 -0
  282. data/lib/active_support/xml_mini/libxml.rb +80 -0
  283. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  284. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  285. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  286. data/lib/active_support/xml_mini/rexml.rb +137 -0
  287. data/lib/active_support/xml_mini.rb +211 -0
  288. data/lib/active_support.rb +144 -0
  289. metadata +526 -0
@@ -0,0 +1,176 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+ require "active_support/core_ext/class/attribute"
5
+ require "active_support/core_ext/string/inflections"
6
+
7
+ module ActiveSupport
8
+ # = Active Support \Rescuable
9
+ #
10
+ # Rescuable module adds support for easier exception handling.
11
+ module Rescuable
12
+ extend Concern
13
+
14
+ included do
15
+ class_attribute :rescue_handlers, default: []
16
+ end
17
+
18
+ module ClassMethods
19
+ # Registers exception classes with a handler to be called by <tt>rescue_with_handler</tt>.
20
+ #
21
+ # <tt>rescue_from</tt> receives a series of exception classes or class
22
+ # names, and an exception handler specified by a trailing <tt>:with</tt>
23
+ # option containing the name of a method or a Proc object. Alternatively, a block
24
+ # can be given as the handler.
25
+ #
26
+ # Handlers that take one argument will be called with the exception, so
27
+ # that the exception can be inspected when dealing with it.
28
+ #
29
+ # Handlers are inherited. They are searched from right to left, from
30
+ # bottom to top, and up the hierarchy. The handler of the first class for
31
+ # which <tt>exception.is_a?(klass)</tt> holds true is the one invoked, if
32
+ # any.
33
+ #
34
+ # class ApplicationController < ActionController::Base
35
+ # rescue_from User::NotAuthorized, with: :deny_access
36
+ # rescue_from ActiveRecord::RecordInvalid, with: :show_record_errors
37
+ #
38
+ # rescue_from "MyApp::BaseError" do |exception|
39
+ # redirect_to root_url, alert: exception.message
40
+ # end
41
+ #
42
+ # private
43
+ # def deny_access
44
+ # head :forbidden
45
+ # end
46
+ #
47
+ # def show_record_errors(exception)
48
+ # redirect_back_or_to root_url, alert: exception.record.errors.full_messages.to_sentence
49
+ # end
50
+ # end
51
+ #
52
+ # Exceptions raised inside exception handlers are not propagated up.
53
+ def rescue_from(*klasses, with: nil, &block)
54
+ unless with
55
+ if block_given?
56
+ with = block
57
+ else
58
+ raise ArgumentError, "Need a handler. Pass the with: keyword argument or provide a block."
59
+ end
60
+ end
61
+
62
+ klasses.each do |klass|
63
+ key = if klass.is_a?(Module) && klass.respond_to?(:===)
64
+ klass.name
65
+ elsif klass.is_a?(String)
66
+ klass
67
+ else
68
+ raise ArgumentError, "#{klass.inspect} must be an Exception class or a String referencing an Exception class"
69
+ end
70
+
71
+ # Put the new handler at the end because the list is read in reverse.
72
+ self.rescue_handlers += [[key, with]]
73
+ end
74
+ end
75
+
76
+ # Matches an exception to a handler based on the exception class.
77
+ #
78
+ # If no handler matches the exception, check for a handler matching the
79
+ # (optional) +exception.cause+. If no handler matches the exception or its
80
+ # cause, this returns +nil+, so you can deal with unhandled exceptions.
81
+ # Be sure to re-raise unhandled exceptions if this is what you expect.
82
+ #
83
+ # begin
84
+ # # ...
85
+ # rescue => exception
86
+ # rescue_with_handler(exception) || raise
87
+ # end
88
+ #
89
+ # Returns the exception if it was handled and +nil+ if it was not.
90
+ def rescue_with_handler(exception, object: self, visited_exceptions: [])
91
+ visited_exceptions << exception
92
+
93
+ if handler = handler_for_rescue(exception, object: object)
94
+ handler.call exception
95
+ exception
96
+ elsif exception
97
+ if visited_exceptions.include?(exception.cause)
98
+ nil
99
+ else
100
+ rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions)
101
+ end
102
+ end
103
+ end
104
+
105
+ def handler_for_rescue(exception, object: self) # :nodoc:
106
+ case rescuer = find_rescue_handler(exception)
107
+ when Symbol
108
+ method = object.method(rescuer)
109
+ if method.arity == 0
110
+ -> e { method.call }
111
+ else
112
+ method
113
+ end
114
+ when Proc
115
+ if rescuer.arity == 0
116
+ -> e { object.instance_exec(&rescuer) }
117
+ else
118
+ -> e { object.instance_exec(e, &rescuer) }
119
+ end
120
+ end
121
+ end
122
+
123
+ private
124
+ def find_rescue_handler(exception)
125
+ if exception
126
+ # Handlers are in order of declaration but the most recently declared
127
+ # is the highest priority match, so we search for matching handlers
128
+ # in reverse.
129
+ _, handler = rescue_handlers.reverse_each.detect do |class_or_name, _|
130
+ if klass = constantize_rescue_handler_class(class_or_name)
131
+ klass === exception
132
+ end
133
+ end
134
+
135
+ handler
136
+ end
137
+ end
138
+
139
+ def constantize_rescue_handler_class(class_or_name)
140
+ case class_or_name
141
+ when String, Symbol
142
+ begin
143
+ # Try a lexical lookup first since we support
144
+ #
145
+ # class Super
146
+ # rescue_from 'Error', with: …
147
+ # end
148
+ #
149
+ # class Sub
150
+ # class Error < StandardError; end
151
+ # end
152
+ #
153
+ # so an Error raised in Sub will hit the 'Error' handler.
154
+ const_get class_or_name
155
+ rescue NameError
156
+ class_or_name.safe_constantize
157
+ end
158
+ else
159
+ class_or_name
160
+ end
161
+ end
162
+ end
163
+
164
+ # Delegates to the class method, but uses the instance as the subject for
165
+ # rescue_from handlers (method calls, +instance_exec+ blocks).
166
+ def rescue_with_handler(exception)
167
+ self.class.rescue_with_handler exception, object: self
168
+ end
169
+
170
+ # Internal handler lookup. Delegates to class method. Some libraries call
171
+ # this directly, so keeping it around for compatibility.
172
+ def handler_for_rescue(exception) # :nodoc:
173
+ self.class.handler_for_rescue exception, object: self
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/security_utils"
4
+ require "active_support/messages/rotator"
5
+
6
+ module ActiveSupport
7
+ # = Secure Compare Rotator
8
+ #
9
+ # The ActiveSupport::SecureCompareRotator is a wrapper around ActiveSupport::SecurityUtils.secure_compare
10
+ # and allows you to rotate a previously defined value to a new one.
11
+ #
12
+ # It can be used as follow:
13
+ #
14
+ # rotator = ActiveSupport::SecureCompareRotator.new('new_production_value')
15
+ # rotator.rotate('previous_production_value')
16
+ # rotator.secure_compare!('previous_production_value')
17
+ #
18
+ # One real use case example would be to rotate a basic auth credentials:
19
+ #
20
+ # class MyController < ApplicationController
21
+ # def authenticate_request
22
+ # rotator = ActiveSupport::SecureCompareRotator.new('new_password')
23
+ # rotator.rotate('old_password')
24
+ #
25
+ # authenticate_or_request_with_http_basic do |username, password|
26
+ # rotator.secure_compare!(password)
27
+ # rescue ActiveSupport::SecureCompareRotator::InvalidMatch
28
+ # false
29
+ # end
30
+ # end
31
+ # end
32
+ class SecureCompareRotator
33
+ include SecurityUtils
34
+
35
+ InvalidMatch = Class.new(StandardError)
36
+
37
+ def initialize(value, on_rotation: nil)
38
+ @value = value
39
+ @rotate_values = []
40
+ @on_rotation = on_rotation
41
+ end
42
+
43
+ def rotate(previous_value)
44
+ @rotate_values << previous_value
45
+ end
46
+
47
+ def secure_compare!(other_value, on_rotation: @on_rotation)
48
+ if secure_compare(@value, other_value)
49
+ true
50
+ elsif @rotate_values.any? { |value| secure_compare(value, other_value) }
51
+ on_rotation&.call
52
+ true
53
+ else
54
+ raise InvalidMatch
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module SecurityUtils
5
+ # Constant time string comparison, for fixed length strings.
6
+ #
7
+ # The values compared should be of fixed length, such as strings
8
+ # that have already been processed by HMAC. Raises in case of length mismatch.
9
+
10
+ if defined?(OpenSSL.fixed_length_secure_compare)
11
+ def fixed_length_secure_compare(a, b)
12
+ OpenSSL.fixed_length_secure_compare(a, b)
13
+ end
14
+ else
15
+ def fixed_length_secure_compare(a, b)
16
+ raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize
17
+
18
+ l = a.unpack "C#{a.bytesize}"
19
+
20
+ res = 0
21
+ b.each_byte { |byte| res |= byte ^ l.shift }
22
+ res == 0
23
+ end
24
+ end
25
+ module_function :fixed_length_secure_compare
26
+
27
+ # Secure string comparison for strings of variable length.
28
+ #
29
+ # While a timing attack would not be able to discern the content of
30
+ # a secret compared via secure_compare, it is possible to determine
31
+ # the secret length. This should be considered when using secure_compare
32
+ # to compare weak, short secrets to user input.
33
+ def secure_compare(a, b)
34
+ a.bytesize == b.bytesize && fixed_length_secure_compare(a, b)
35
+ end
36
+ module_function :secure_compare
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # = \String Inquirer
5
+ #
6
+ # Wrapping a string in this class gives you a prettier way to test
7
+ # for equality. The value returned by <tt>Rails.env</tt> is wrapped
8
+ # in a StringInquirer object, so instead of calling this:
9
+ #
10
+ # Rails.env == 'production'
11
+ #
12
+ # you can call this:
13
+ #
14
+ # Rails.env.production?
15
+ #
16
+ # == Instantiating a new \StringInquirer
17
+ #
18
+ # vehicle = ActiveSupport::StringInquirer.new('car')
19
+ # vehicle.car? # => true
20
+ # vehicle.bike? # => false
21
+ class StringInquirer < String
22
+ private
23
+ def respond_to_missing?(method_name, include_private = false)
24
+ method_name.end_with?("?") || super
25
+ end
26
+
27
+ def method_missing(method_name, ...)
28
+ if method_name.end_with?("?")
29
+ self == method_name[0..-2]
30
+ else
31
+ super
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/notifications"
4
+
5
+ module ActiveSupport
6
+ # = Active Support \Subscriber
7
+ #
8
+ # +ActiveSupport::Subscriber+ is an object set to consume
9
+ # ActiveSupport::Notifications. The subscriber dispatches notifications to
10
+ # a registered object based on its given namespace.
11
+ #
12
+ # An example would be an Active Record subscriber responsible for collecting
13
+ # statistics about queries:
14
+ #
15
+ # module ActiveRecord
16
+ # class StatsSubscriber < ActiveSupport::Subscriber
17
+ # attach_to :active_record
18
+ #
19
+ # def sql(event)
20
+ # Statsd.timing("sql.#{event.payload[:name]}", event.duration)
21
+ # end
22
+ # end
23
+ # end
24
+ #
25
+ # After configured, whenever a <tt>"sql.active_record"</tt> notification is
26
+ # published, it will properly dispatch the event
27
+ # (ActiveSupport::Notifications::Event) to the +sql+ method.
28
+ #
29
+ # We can detach a subscriber as well:
30
+ #
31
+ # ActiveRecord::StatsSubscriber.detach_from(:active_record)
32
+ class Subscriber
33
+ class << self
34
+ # Attach the subscriber to a namespace.
35
+ def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications, inherit_all: false)
36
+ @namespace = namespace
37
+ @subscriber = subscriber
38
+ @notifier = notifier
39
+ @inherit_all = inherit_all
40
+
41
+ subscribers << subscriber
42
+
43
+ # Add event subscribers for all existing methods on the class.
44
+ fetch_public_methods(subscriber, inherit_all).each do |event|
45
+ add_event_subscriber(event)
46
+ end
47
+ end
48
+
49
+ # Detach the subscriber from a namespace.
50
+ def detach_from(namespace, notifier = ActiveSupport::Notifications)
51
+ @namespace = namespace
52
+ @subscriber = find_attached_subscriber
53
+ @notifier = notifier
54
+
55
+ return unless subscriber
56
+
57
+ subscribers.delete(subscriber)
58
+
59
+ # Remove event subscribers of all existing methods on the class.
60
+ fetch_public_methods(subscriber, true).each do |event|
61
+ remove_event_subscriber(event)
62
+ end
63
+
64
+ # Reset notifier so that event subscribers will not add for new methods added to the class.
65
+ @notifier = nil
66
+ end
67
+
68
+ # Adds event subscribers for all new methods added to the class.
69
+ def method_added(event)
70
+ super
71
+ # Only public methods are added as subscribers, and only if a notifier
72
+ # has been set up. This means that subscribers will only be set up for
73
+ # classes that call #attach_to.
74
+ if public_method_defined?(event) && notifier
75
+ add_event_subscriber(event)
76
+ end
77
+ end
78
+
79
+ def subscribers
80
+ @@subscribers ||= []
81
+ end
82
+
83
+ private
84
+ attr_reader :subscriber, :notifier, :namespace
85
+
86
+ def add_event_subscriber(event) # :doc:
87
+ return if invalid_event?(event)
88
+
89
+ pattern = prepare_pattern(event)
90
+
91
+ # Don't add multiple subscribers (e.g. if methods are redefined).
92
+ return if pattern_subscribed?(pattern)
93
+
94
+ subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
95
+ end
96
+
97
+ def remove_event_subscriber(event) # :doc:
98
+ return if invalid_event?(event)
99
+
100
+ pattern = prepare_pattern(event)
101
+
102
+ return unless pattern_subscribed?(pattern)
103
+
104
+ notifier.unsubscribe(subscriber.patterns[pattern])
105
+ subscriber.patterns.delete(pattern)
106
+ end
107
+
108
+ def find_attached_subscriber
109
+ subscribers.find { |attached_subscriber| attached_subscriber.instance_of?(self) }
110
+ end
111
+
112
+ def invalid_event?(event)
113
+ %i{ start finish }.include?(event.to_sym)
114
+ end
115
+
116
+ def prepare_pattern(event)
117
+ "#{event}.#{namespace}"
118
+ end
119
+
120
+ def pattern_subscribed?(pattern)
121
+ subscriber.patterns.key?(pattern)
122
+ end
123
+
124
+ def fetch_public_methods(subscriber, inherit_all)
125
+ subscriber.public_methods(inherit_all) - Subscriber.public_instance_methods(true)
126
+ end
127
+ end
128
+
129
+ attr_reader :patterns # :nodoc:
130
+
131
+ def initialize
132
+ @patterns = {}
133
+ super
134
+ end
135
+
136
+ def call(event)
137
+ method = event.name[0, event.name.index(".")]
138
+ send(method, event)
139
+ end
140
+
141
+ def publish_event(event) # :nodoc:
142
+ method = event.name[0, event.name.index(".")]
143
+ send(method, event)
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+
5
+ module ActiveSupport
6
+ # This is a class for wrapping syntax errors. The purpose of this class
7
+ # is to enhance the backtraces on SyntaxError exceptions to include the
8
+ # source location of the syntax error. That way we can display the error
9
+ # source on error pages in development.
10
+ class SyntaxErrorProxy < DelegateClass(SyntaxError) # :nodoc:
11
+ def backtrace
12
+ parse_message_for_trace + super
13
+ end
14
+
15
+ class BacktraceLocation < Struct.new(:path, :lineno, :to_s) # :nodoc:
16
+ def spot(_)
17
+ end
18
+
19
+ def label
20
+ end
21
+ end
22
+
23
+ class BacktraceLocationProxy < DelegateClass(Thread::Backtrace::Location) # :nodoc:
24
+ def initialize(loc, ex)
25
+ super(loc)
26
+ @ex = ex
27
+ end
28
+
29
+ def spot(_)
30
+ super(@ex.__getobj__)
31
+ end
32
+ end
33
+
34
+ def backtrace_locations
35
+ return nil if super.nil?
36
+
37
+ parse_message_for_trace.map { |trace|
38
+ file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
39
+ BacktraceLocation.new(file, line.to_i, trace)
40
+ # We have to wrap these backtrace locations because we need the
41
+ # spot information to come from the originating exception, not the
42
+ # proxy object that's generating these
43
+ } + super.map { |loc| BacktraceLocationProxy.new(loc, self) }
44
+ end
45
+
46
+ private
47
+ def parse_message_for_trace
48
+ if __getobj__.to_s.start_with?("(eval")
49
+ # If the exception is coming from a call to eval, we need to keep
50
+ # the path of the file in which eval was called to ensure we can
51
+ # return the right source fragment to show the location of the
52
+ # error
53
+ location = __getobj__.backtrace_locations[0]
54
+ ["#{location.path}:#{location.lineno}: #{__getobj__}"]
55
+ else
56
+ __getobj__.to_s.split("\n")
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/delegation"
4
+ require "active_support/core_ext/object/blank"
5
+ require "active_support/logger"
6
+
7
+ module ActiveSupport
8
+ # = Active Support Tagged Logging
9
+ #
10
+ # Wraps any standard Logger object to provide tagging capabilities.
11
+ #
12
+ # May be called with a block:
13
+ #
14
+ # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
15
+ # logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
16
+ # logger.tagged('BCX', "Jason") { |tagged_logger| tagged_logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
17
+ # logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
18
+ #
19
+ # If called without a block, a new logger will be returned with applied tags:
20
+ #
21
+ # logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
22
+ # logger.tagged("BCX").info "Stuff" # Logs "[BCX] Stuff"
23
+ # logger.tagged("BCX", "Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
24
+ # logger.tagged("BCX").tagged("Jason").info "Stuff" # Logs "[BCX] [Jason] Stuff"
25
+ #
26
+ # This is used by the default Rails.logger as configured by Railties to make
27
+ # it easy to stamp log lines with subdomains, request ids, and anything else
28
+ # to aid debugging of multi-user production applications.
29
+ module TaggedLogging
30
+ module Formatter # :nodoc:
31
+ # This method is invoked when a log event occurs.
32
+ def call(severity, timestamp, progname, msg)
33
+ super(severity, timestamp, progname, tag_stack.format_message(msg))
34
+ end
35
+
36
+ def tagged(*tags)
37
+ pushed_count = tag_stack.push_tags(tags).size
38
+ yield self
39
+ ensure
40
+ pop_tags(pushed_count)
41
+ end
42
+
43
+ def push_tags(*tags)
44
+ tag_stack.push_tags(tags)
45
+ end
46
+
47
+ def pop_tags(count = 1)
48
+ tag_stack.pop_tags(count)
49
+ end
50
+
51
+ def clear_tags!
52
+ tag_stack.clear
53
+ end
54
+
55
+ def tag_stack
56
+ # We use our object ID here to avoid conflicting with other instances
57
+ @thread_key ||= "activesupport_tagged_logging_tags:#{object_id}"
58
+ IsolatedExecutionState[@thread_key] ||= TagStack.new
59
+ end
60
+
61
+ def current_tags
62
+ tag_stack.tags
63
+ end
64
+
65
+ def tags_text
66
+ tag_stack.format_message("")
67
+ end
68
+ end
69
+
70
+ class TagStack # :nodoc:
71
+ attr_reader :tags
72
+
73
+ def initialize
74
+ @tags = []
75
+ @tags_string = nil
76
+ end
77
+
78
+ def push_tags(tags)
79
+ @tags_string = nil
80
+ tags.flatten!
81
+ tags.reject!(&:blank?)
82
+ @tags.concat(tags)
83
+ tags
84
+ end
85
+
86
+ def pop_tags(count)
87
+ @tags_string = nil
88
+ @tags.pop(count)
89
+ end
90
+
91
+ def clear
92
+ @tags_string = nil
93
+ @tags.clear
94
+ end
95
+
96
+ def format_message(message)
97
+ if @tags.empty?
98
+ message
99
+ elsif @tags.size == 1
100
+ "[#{@tags[0]}] #{message}"
101
+ else
102
+ @tags_string ||= "[#{@tags.join("] [")}] "
103
+ "#{@tags_string}#{message}"
104
+ end
105
+ end
106
+ end
107
+
108
+ module LocalTagStorage # :nodoc:
109
+ attr_accessor :tag_stack
110
+
111
+ def self.extended(base)
112
+ base.tag_stack = TagStack.new
113
+ end
114
+ end
115
+
116
+ def self.new(logger)
117
+ logger = logger.clone
118
+
119
+ if logger.formatter
120
+ logger.formatter = logger.formatter.clone
121
+
122
+ # Workaround for https://bugs.ruby-lang.org/issues/20250
123
+ # Can be removed when Ruby 3.4 is the least supported version.
124
+ logger.formatter.object_id if logger.formatter.is_a?(Proc)
125
+ else
126
+ # Ensure we set a default formatter so we aren't extending nil!
127
+ logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
128
+ end
129
+
130
+ logger.formatter.extend Formatter
131
+ logger.extend(self)
132
+ end
133
+
134
+ delegate :push_tags, :pop_tags, :clear_tags!, to: :formatter
135
+
136
+ def tagged(*tags)
137
+ if block_given?
138
+ formatter.tagged(*tags) { yield self }
139
+ else
140
+ logger = ActiveSupport::TaggedLogging.new(self)
141
+ logger.formatter.extend LocalTagStorage
142
+ logger.push_tags(*formatter.current_tags, *tags)
143
+ logger
144
+ end
145
+ end
146
+
147
+ def flush
148
+ clear_tags!
149
+ super if defined?(super)
150
+ end
151
+ end
152
+ end