activesupport 1.2.4 → 8.1.2

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 (309) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +505 -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 +234 -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 +238 -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 +288 -0
  17. data/lib/active_support/cache/memory_store.rb +264 -0
  18. data/lib/active_support/cache/null_store.rb +62 -0
  19. data/lib/active_support/cache/redis_cache_store.rb +498 -0
  20. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  21. data/lib/active_support/cache/strategy/local_cache.rb +246 -0
  22. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  23. data/lib/active_support/cache.rb +1170 -0
  24. data/lib/active_support/callbacks.rb +960 -0
  25. data/lib/active_support/class_attribute.rb +33 -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 +18 -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/concurrency/thread_monitor.rb +55 -0
  32. data/lib/active_support/configurable.rb +193 -0
  33. data/lib/active_support/configuration_file.rb +60 -0
  34. data/lib/active_support/continuous_integration.rb +145 -0
  35. data/lib/active_support/core_ext/array/access.rb +100 -0
  36. data/lib/active_support/core_ext/array/conversions.rb +209 -26
  37. data/lib/active_support/core_ext/array/extract.rb +21 -0
  38. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  39. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  40. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  41. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  42. data/lib/active_support/core_ext/array.rb +8 -4
  43. data/lib/active_support/core_ext/benchmark.rb +6 -0
  44. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  45. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  46. data/lib/active_support/core_ext/class/attribute.rb +137 -0
  47. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  48. data/lib/active_support/core_ext/class/subclasses.rb +24 -0
  49. data/lib/active_support/core_ext/class.rb +4 -0
  50. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  51. data/lib/active_support/core_ext/date/blank.rb +18 -0
  52. data/lib/active_support/core_ext/date/calculations.rb +161 -0
  53. data/lib/active_support/core_ext/date/conversions.rb +95 -28
  54. data/lib/active_support/core_ext/date/zones.rb +8 -0
  55. data/lib/active_support/core_ext/date.rb +6 -5
  56. data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
  57. data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
  58. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  59. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  60. data/lib/active_support/core_ext/date_time/blank.rb +18 -0
  61. data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
  62. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  63. data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
  64. data/lib/active_support/core_ext/date_time.rb +7 -0
  65. data/lib/active_support/core_ext/digest/uuid.rb +76 -0
  66. data/lib/active_support/core_ext/digest.rb +3 -0
  67. data/lib/active_support/core_ext/enumerable.rb +277 -7
  68. data/lib/active_support/core_ext/erb/util.rb +201 -0
  69. data/lib/active_support/core_ext/file/atomic.rb +72 -0
  70. data/lib/active_support/core_ext/file.rb +3 -0
  71. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  72. data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
  73. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  74. data/lib/active_support/core_ext/hash/except.rb +12 -0
  75. data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
  76. data/lib/active_support/core_ext/hash/keys.rb +134 -44
  77. data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
  78. data/lib/active_support/core_ext/hash/slice.rb +27 -0
  79. data/lib/active_support/core_ext/hash.rb +9 -8
  80. data/lib/active_support/core_ext/integer/inflections.rb +29 -13
  81. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  82. data/lib/active_support/core_ext/integer/time.rb +22 -0
  83. data/lib/active_support/core_ext/integer.rb +4 -6
  84. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  85. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  86. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  87. data/lib/active_support/core_ext/kernel.rb +4 -78
  88. data/lib/active_support/core_ext/load_error.rb +6 -35
  89. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  90. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  91. data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
  92. data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
  93. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
  94. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  95. data/lib/active_support/core_ext/module/delegation.rb +225 -0
  96. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  97. data/lib/active_support/core_ext/module/introspection.rb +65 -0
  98. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  99. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  100. data/lib/active_support/core_ext/module.rb +13 -0
  101. data/lib/active_support/core_ext/name_error.rb +59 -0
  102. data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
  103. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  104. data/lib/active_support/core_ext/numeric/time.rb +64 -57
  105. data/lib/active_support/core_ext/numeric.rb +4 -6
  106. data/lib/active_support/core_ext/object/acts_like.rb +45 -0
  107. data/lib/active_support/core_ext/object/blank.rb +199 -0
  108. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  109. data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
  110. data/lib/active_support/core_ext/object/duplicable.rb +69 -0
  111. data/lib/active_support/core_ext/object/inclusion.rb +37 -0
  112. data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
  113. data/lib/active_support/core_ext/object/json.rb +267 -0
  114. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  115. data/lib/active_support/core_ext/object/to_query.rb +93 -0
  116. data/lib/active_support/core_ext/object/try.rb +158 -0
  117. data/lib/active_support/core_ext/object/with.rb +46 -0
  118. data/lib/active_support/core_ext/object/with_options.rb +101 -0
  119. data/lib/active_support/core_ext/object.rb +17 -0
  120. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  121. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  122. data/lib/active_support/core_ext/pathname.rb +4 -0
  123. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  124. data/lib/active_support/core_ext/range/conversions.rb +58 -17
  125. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  126. data/lib/active_support/core_ext/range/sole.rb +17 -0
  127. data/lib/active_support/core_ext/range.rb +5 -4
  128. data/lib/active_support/core_ext/regexp.rb +14 -0
  129. data/lib/active_support/core_ext/securerandom.rb +57 -0
  130. data/lib/active_support/core_ext/string/access.rb +93 -56
  131. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  132. data/lib/active_support/core_ext/string/conversions.rb +57 -16
  133. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  134. data/lib/active_support/core_ext/string/filters.rb +151 -0
  135. data/lib/active_support/core_ext/string/indent.rb +45 -0
  136. data/lib/active_support/core_ext/string/inflections.rb +297 -54
  137. data/lib/active_support/core_ext/string/inquiry.rb +16 -0
  138. data/lib/active_support/core_ext/string/multibyte.rb +67 -0
  139. data/lib/active_support/core_ext/string/output_safety.rb +235 -0
  140. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
  141. data/lib/active_support/core_ext/string/strip.rb +27 -0
  142. data/lib/active_support/core_ext/string/zones.rb +16 -0
  143. data/lib/active_support/core_ext/string.rb +14 -10
  144. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  145. data/lib/active_support/core_ext/symbol.rb +3 -0
  146. data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
  147. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  148. data/lib/active_support/core_ext/time/calculations.rb +358 -153
  149. data/lib/active_support/core_ext/time/compatibility.rb +15 -0
  150. data/lib/active_support/core_ext/time/conversions.rb +69 -30
  151. data/lib/active_support/core_ext/time/zones.rb +97 -0
  152. data/lib/active_support/core_ext/time.rb +6 -6
  153. data/lib/active_support/core_ext.rb +5 -1
  154. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  155. data/lib/active_support/current_attributes.rb +243 -0
  156. data/lib/active_support/deep_mergeable.rb +53 -0
  157. data/lib/active_support/delegation.rb +183 -0
  158. data/lib/active_support/dependencies/autoload.rb +72 -0
  159. data/lib/active_support/dependencies/interlock.rb +55 -0
  160. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  161. data/lib/active_support/dependencies.rb +84 -222
  162. data/lib/active_support/deprecation/behaviors.rb +148 -0
  163. data/lib/active_support/deprecation/constant_accessor.rb +74 -0
  164. data/lib/active_support/deprecation/deprecators.rb +104 -0
  165. data/lib/active_support/deprecation/disallowed.rb +54 -0
  166. data/lib/active_support/deprecation/method_wrappers.rb +68 -0
  167. data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
  168. data/lib/active_support/deprecation/reporting.rb +162 -0
  169. data/lib/active_support/deprecation.rb +81 -0
  170. data/lib/active_support/deprecator.rb +7 -0
  171. data/lib/active_support/descendants_tracker.rb +112 -0
  172. data/lib/active_support/digest.rb +22 -0
  173. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  174. data/lib/active_support/duration/iso8601_serializer.rb +64 -0
  175. data/lib/active_support/duration.rb +524 -0
  176. data/lib/active_support/editor.rb +70 -0
  177. data/lib/active_support/encrypted_configuration.rb +126 -0
  178. data/lib/active_support/encrypted_file.rb +133 -0
  179. data/lib/active_support/environment_inquirer.rb +40 -0
  180. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  181. data/lib/active_support/error_reporter.rb +318 -0
  182. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  183. data/lib/active_support/event_reporter.rb +592 -0
  184. data/lib/active_support/evented_file_update_checker.rb +185 -0
  185. data/lib/active_support/execution_context/test_helper.rb +13 -0
  186. data/lib/active_support/execution_context.rb +110 -0
  187. data/lib/active_support/execution_wrapper.rb +150 -0
  188. data/lib/active_support/executor/test_helper.rb +7 -0
  189. data/lib/active_support/executor.rb +8 -0
  190. data/lib/active_support/file_update_checker.rb +166 -0
  191. data/lib/active_support/fork_tracker.rb +43 -0
  192. data/lib/active_support/gem_version.rb +17 -0
  193. data/lib/active_support/gzip.rb +41 -0
  194. data/lib/active_support/hash_with_indifferent_access.rb +464 -0
  195. data/lib/active_support/html_safe_translation.rb +56 -0
  196. data/lib/active_support/i18n.rb +17 -0
  197. data/lib/active_support/i18n_railtie.rb +140 -0
  198. data/lib/active_support/inflections.rb +68 -49
  199. data/lib/active_support/inflector/inflections.rb +290 -0
  200. data/lib/active_support/inflector/methods.rb +387 -0
  201. data/lib/active_support/inflector/transliterate.rb +147 -0
  202. data/lib/active_support/inflector.rb +7 -164
  203. data/lib/active_support/isolated_execution_state.rb +76 -0
  204. data/lib/active_support/json/decoding.rb +78 -0
  205. data/lib/active_support/json/encoding.rb +256 -0
  206. data/lib/active_support/json.rb +4 -0
  207. data/lib/active_support/key_generator.rb +66 -0
  208. data/lib/active_support/lazy_load_hooks.rb +107 -0
  209. data/lib/active_support/locale/en.rb +33 -0
  210. data/lib/active_support/locale/en.yml +141 -0
  211. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  212. data/lib/active_support/log_subscriber.rb +188 -0
  213. data/lib/active_support/logger.rb +55 -0
  214. data/lib/active_support/logger_silence.rb +21 -0
  215. data/lib/active_support/logger_thread_safe_level.rb +50 -0
  216. data/lib/active_support/message_encryptor.rb +374 -0
  217. data/lib/active_support/message_encryptors.rb +193 -0
  218. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  219. data/lib/active_support/message_pack/extensions.rb +310 -0
  220. data/lib/active_support/message_pack/serializer.rb +63 -0
  221. data/lib/active_support/message_pack.rb +50 -0
  222. data/lib/active_support/message_verifier.rb +377 -0
  223. data/lib/active_support/message_verifiers.rb +189 -0
  224. data/lib/active_support/messages/codec.rb +65 -0
  225. data/lib/active_support/messages/metadata.rb +146 -0
  226. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  227. data/lib/active_support/messages/rotation_coordinator.rb +102 -0
  228. data/lib/active_support/messages/rotator.rb +69 -0
  229. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  230. data/lib/active_support/multibyte/chars.rb +188 -0
  231. data/lib/active_support/multibyte/unicode.rb +42 -0
  232. data/lib/active_support/multibyte.rb +27 -0
  233. data/lib/active_support/notifications/fanout.rb +467 -0
  234. data/lib/active_support/notifications/instrumenter.rb +240 -0
  235. data/lib/active_support/notifications.rb +281 -0
  236. data/lib/active_support/number_helper/number_converter.rb +190 -0
  237. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  238. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  239. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  240. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  241. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  242. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  243. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  244. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  245. data/lib/active_support/number_helper.rb +479 -0
  246. data/lib/active_support/option_merger.rb +38 -0
  247. data/lib/active_support/ordered_hash.rb +50 -0
  248. data/lib/active_support/ordered_options.rb +141 -25
  249. data/lib/active_support/parameter_filter.rb +157 -0
  250. data/lib/active_support/rails.rb +26 -0
  251. data/lib/active_support/railtie.rb +180 -0
  252. data/lib/active_support/reloader.rb +138 -0
  253. data/lib/active_support/rescuable.rb +176 -0
  254. data/lib/active_support/secure_compare_rotator.rb +58 -0
  255. data/lib/active_support/security_utils.rb +38 -0
  256. data/lib/active_support/string_inquirer.rb +35 -0
  257. data/lib/active_support/structured_event_subscriber.rb +99 -0
  258. data/lib/active_support/subscriber.rb +141 -0
  259. data/lib/active_support/syntax_error_proxy.rb +67 -0
  260. data/lib/active_support/tagged_logging.rb +157 -0
  261. data/lib/active_support/test_case.rb +365 -0
  262. data/lib/active_support/testing/assertions.rb +369 -0
  263. data/lib/active_support/testing/autorun.rb +10 -0
  264. data/lib/active_support/testing/constant_lookup.rb +51 -0
  265. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  266. data/lib/active_support/testing/declarative.rb +28 -0
  267. data/lib/active_support/testing/deprecation.rb +82 -0
  268. data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
  269. data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
  270. data/lib/active_support/testing/file_fixtures.rb +38 -0
  271. data/lib/active_support/testing/isolation.rb +121 -0
  272. data/lib/active_support/testing/method_call_assertions.rb +69 -0
  273. data/lib/active_support/testing/notification_assertions.rb +92 -0
  274. data/lib/active_support/testing/parallelization/server.rb +98 -0
  275. data/lib/active_support/testing/parallelization/worker.rb +107 -0
  276. data/lib/active_support/testing/parallelization.rb +79 -0
  277. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  278. data/lib/active_support/testing/setup_and_teardown.rb +57 -0
  279. data/lib/active_support/testing/stream.rb +41 -0
  280. data/lib/active_support/testing/tagged_logging.rb +27 -0
  281. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  282. data/lib/active_support/testing/time_helpers.rb +273 -0
  283. data/lib/active_support/time.rb +20 -0
  284. data/lib/active_support/time_with_zone.rb +613 -0
  285. data/lib/active_support/values/time_zone.rb +599 -158
  286. data/lib/active_support/version.rb +7 -6
  287. data/lib/active_support/xml_mini/jdom.rb +175 -0
  288. data/lib/active_support/xml_mini/libxml.rb +80 -0
  289. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  290. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  291. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  292. data/lib/active_support/xml_mini/rexml.rb +137 -0
  293. data/lib/active_support/xml_mini.rb +212 -0
  294. data/lib/active_support.rb +122 -10
  295. metadata +524 -93
  296. data/CHANGELOG +0 -283
  297. data/lib/active_support/binding_of_caller.rb +0 -84
  298. data/lib/active_support/breakpoint.rb +0 -523
  299. data/lib/active_support/class_attribute_accessors.rb +0 -57
  300. data/lib/active_support/class_inheritable_attributes.rb +0 -117
  301. data/lib/active_support/clean_logger.rb +0 -36
  302. data/lib/active_support/core_ext/blank.rb +0 -38
  303. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
  304. data/lib/active_support/core_ext/cgi.rb +0 -5
  305. data/lib/active_support/core_ext/exception.rb +0 -29
  306. data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
  307. data/lib/active_support/core_ext/object_and_class.rb +0 -44
  308. data/lib/active_support/module_attribute_accessors.rb +0 -57
  309. data/lib/active_support/whiny_nil.rb +0 -38
@@ -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,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/subscriber"
4
+
5
+ module ActiveSupport
6
+ # = Active Support Structured Event \Subscriber
7
+ #
8
+ # +ActiveSupport::StructuredEventSubscriber+ consumes ActiveSupport::Notifications
9
+ # in order to emit structured events via +Rails.event+.
10
+ #
11
+ # An example would be the Action Controller structured event subscriber, responsible for
12
+ # emitting request processing events:
13
+ #
14
+ # module ActionController
15
+ # class StructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber
16
+ # attach_to :action_controller
17
+ #
18
+ # def start_processing(event)
19
+ # emit_event("controller.request_started",
20
+ # controller: event.payload[:controller],
21
+ # action: event.payload[:action],
22
+ # format: event.payload[:format]
23
+ # )
24
+ # end
25
+ # end
26
+ # end
27
+ #
28
+ # After configured, whenever a <tt>"start_processing.action_controller"</tt> notification is published,
29
+ # it will properly dispatch the event (+ActiveSupport::Notifications::Event+) to the +start_processing+ method.
30
+ # The subscriber can then emit a structured event via the +emit_event+ method.
31
+ class StructuredEventSubscriber < Subscriber
32
+ class_attribute :debug_methods, instance_accessor: false, default: [] # :nodoc:
33
+
34
+ DEBUG_CHECK = proc { !ActiveSupport.event_reporter.debug_mode? }
35
+
36
+ class << self
37
+ def attach_to(...) # :nodoc:
38
+ result = super
39
+ set_silenced_events
40
+ result
41
+ end
42
+
43
+ private
44
+ def set_silenced_events
45
+ if subscriber
46
+ subscriber.silenced_events = debug_methods.to_h { |method| ["#{method}.#{namespace}", DEBUG_CHECK] }
47
+ end
48
+ end
49
+
50
+ def debug_only(method)
51
+ self.debug_methods << method
52
+ set_silenced_events
53
+ end
54
+ end
55
+
56
+ def initialize
57
+ super
58
+ @silenced_events = {}
59
+ end
60
+
61
+ def silenced?(event)
62
+ ActiveSupport.event_reporter.subscribers.none? || @silenced_events[event]&.call
63
+ end
64
+
65
+ attr_writer :silenced_events # :nodoc:
66
+
67
+ # Emit a structured event via Rails.event.notify.
68
+ #
69
+ # ==== Arguments
70
+ #
71
+ # * +name+ - The event name as a string or symbol
72
+ # * +payload+ - The event payload as a hash or object
73
+ # * +caller_depth+ - Stack depth for source location (default: 1)
74
+ # * +kwargs+ - Additional payload data merged with the payload hash
75
+ def emit_event(name, payload = nil, caller_depth: 1, **kwargs)
76
+ ActiveSupport.event_reporter.notify(name, payload, caller_depth: caller_depth + 1, **kwargs)
77
+ rescue => e
78
+ handle_event_error(name, e)
79
+ end
80
+
81
+ # Like +emit_event+, but only emits when the event reporter is in debug mode
82
+ def emit_debug_event(name, payload = nil, caller_depth: 1, **kwargs)
83
+ ActiveSupport.event_reporter.debug(name, payload, caller_depth: caller_depth + 1, **kwargs)
84
+ rescue => e
85
+ handle_event_error(name, e)
86
+ end
87
+
88
+ def call(event)
89
+ super
90
+ rescue => e
91
+ handle_event_error(event.name, e)
92
+ end
93
+
94
+ private
95
+ def handle_event_error(name, error)
96
+ ActiveSupport.error_reporter.report(error, source: name)
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,141 @@
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
+ end
141
+ end
@@ -0,0 +1,67 @@
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
+
22
+ def base_label
23
+ end
24
+
25
+ def absolute_path
26
+ path
27
+ end
28
+ end
29
+
30
+ class BacktraceLocationProxy < DelegateClass(Thread::Backtrace::Location) # :nodoc:
31
+ def initialize(loc, ex)
32
+ super(loc)
33
+ @ex = ex
34
+ end
35
+
36
+ def spot(_)
37
+ super(@ex.__getobj__)
38
+ end
39
+ end
40
+
41
+ def backtrace_locations
42
+ return nil if super.nil?
43
+
44
+ parse_message_for_trace.map { |trace|
45
+ file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
46
+ BacktraceLocation.new(file, line.to_i, trace)
47
+ # We have to wrap these backtrace locations because we need the
48
+ # spot information to come from the originating exception, not the
49
+ # proxy object that's generating these
50
+ } + super.map { |loc| BacktraceLocationProxy.new(loc, self) }
51
+ end
52
+
53
+ private
54
+ def parse_message_for_trace
55
+ if __getobj__.to_s.start_with?("(eval")
56
+ # If the exception is coming from a call to eval, we need to keep
57
+ # the path of the file in which eval was called to ensure we can
58
+ # return the right source fragment to show the location of the
59
+ # error
60
+ location = __getobj__.backtrace_locations[0]
61
+ ["#{location.path}:#{location.lineno}: #{__getobj__}"]
62
+ else
63
+ __getobj__.to_s.split("\n")
64
+ end
65
+ end
66
+ end
67
+ end