activesupport 4.0.12 → 7.0.2.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (295) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +249 -501
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -5
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +48 -0
  8. data/lib/active_support/backtrace_cleaner.rb +41 -13
  9. data/lib/active_support/benchmarkable.rb +7 -15
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +96 -74
  12. data/lib/active_support/cache/mem_cache_store.rb +211 -103
  13. data/lib/active_support/cache/memory_store.rb +90 -58
  14. data/lib/active_support/cache/null_store.rb +19 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +468 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +86 -83
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  18. data/lib/active_support/cache.rb +580 -241
  19. data/lib/active_support/callbacks.rb +812 -425
  20. data/lib/active_support/code_generator.rb +65 -0
  21. data/lib/active_support/concern.rb +103 -14
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +33 -0
  23. data/lib/active_support/concurrency/share_lock.rb +226 -0
  24. data/lib/active_support/configurable.rb +21 -19
  25. data/lib/active_support/configuration_file.rb +51 -0
  26. data/lib/active_support/core_ext/array/access.rb +47 -1
  27. data/lib/active_support/core_ext/array/conversions.rb +35 -44
  28. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +26 -16
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  34. data/lib/active_support/core_ext/array.rb +10 -7
  35. data/lib/active_support/core_ext/benchmark.rb +5 -3
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +9 -26
  37. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  38. data/lib/active_support/core_ext/class/attribute.rb +52 -49
  39. data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
  40. data/lib/active_support/core_ext/class/subclasses.rb +25 -26
  41. data/lib/active_support/core_ext/class.rb +4 -4
  42. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  43. data/lib/active_support/core_ext/date/blank.rb +14 -0
  44. data/lib/active_support/core_ext/date/calculations.rb +31 -18
  45. data/lib/active_support/core_ext/date/conversions.rb +43 -32
  46. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  47. data/lib/active_support/core_ext/date/zones.rb +5 -34
  48. data/lib/active_support/core_ext/date.rb +7 -4
  49. data/lib/active_support/core_ext/date_and_time/calculations.rb +198 -66
  50. data/lib/active_support/core_ext/date_and_time/compatibility.rb +31 -0
  51. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +79 -38
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +31 -26
  57. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  58. data/lib/active_support/core_ext/date_time.rb +8 -4
  59. data/lib/active_support/core_ext/digest/uuid.rb +79 -0
  60. data/lib/active_support/core_ext/digest.rb +3 -0
  61. data/lib/active_support/core_ext/enumerable.rb +249 -17
  62. data/lib/active_support/core_ext/file/atomic.rb +41 -32
  63. data/lib/active_support/core_ext/file.rb +3 -1
  64. data/lib/active_support/core_ext/hash/conversions.rb +71 -49
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +14 -5
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  69. data/lib/active_support/core_ext/hash/keys.rb +39 -56
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  71. data/lib/active_support/core_ext/hash/slice.rb +8 -23
  72. data/lib/active_support/core_ext/hash.rb +10 -8
  73. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  74. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  75. data/lib/active_support/core_ext/integer/time.rb +11 -33
  76. data/lib/active_support/core_ext/integer.rb +5 -3
  77. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  78. data/lib/active_support/core_ext/kernel/reporting.rb +9 -78
  79. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  80. data/lib/active_support/core_ext/kernel.rb +5 -4
  81. data/lib/active_support/core_ext/load_error.rb +5 -21
  82. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  83. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  84. data/lib/active_support/core_ext/module/attr_internal.rb +8 -8
  85. data/lib/active_support/core_ext/module/attribute_accessors.rb +186 -44
  86. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +157 -0
  87. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  88. data/lib/active_support/core_ext/module/delegation.rb +172 -45
  89. data/lib/active_support/core_ext/module/deprecation.rb +3 -3
  90. data/lib/active_support/core_ext/module/introspection.rb +23 -38
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  93. data/lib/active_support/core_ext/module.rb +13 -10
  94. data/lib/active_support/core_ext/name_error.rb +45 -4
  95. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +135 -127
  97. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +37 -50
  99. data/lib/active_support/core_ext/numeric.rb +6 -3
  100. data/lib/active_support/core_ext/object/acts_like.rb +41 -6
  101. data/lib/active_support/core_ext/object/blank.rb +70 -20
  102. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  103. data/lib/active_support/core_ext/object/deep_dup.rb +19 -10
  104. data/lib/active_support/core_ext/object/duplicable.rb +17 -47
  105. data/lib/active_support/core_ext/object/inclusion.rb +18 -15
  106. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  107. data/lib/active_support/core_ext/object/json.rb +244 -0
  108. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  109. data/lib/active_support/core_ext/object/to_query.rb +21 -8
  110. data/lib/active_support/core_ext/object/try.rb +106 -26
  111. data/lib/active_support/core_ext/object/with_options.rb +64 -5
  112. data/lib/active_support/core_ext/object.rb +14 -12
  113. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  114. data/lib/active_support/core_ext/pathname.rb +3 -0
  115. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  116. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  117. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  118. data/lib/active_support/core_ext/range/each.rb +18 -17
  119. data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
  120. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  121. data/lib/active_support/core_ext/range.rb +7 -4
  122. data/lib/active_support/core_ext/regexp.rb +10 -1
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string/access.rb +42 -51
  125. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  126. data/lib/active_support/core_ext/string/conversions.rb +18 -13
  127. data/lib/active_support/core_ext/string/exclude.rb +5 -3
  128. data/lib/active_support/core_ext/string/filters.rb +97 -7
  129. data/lib/active_support/core_ext/string/indent.rb +6 -4
  130. data/lib/active_support/core_ext/string/inflections.rb +106 -25
  131. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  132. data/lib/active_support/core_ext/string/multibyte.rb +18 -9
  133. data/lib/active_support/core_ext/string/output_safety.rb +227 -54
  134. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  135. data/lib/active_support/core_ext/string/strip.rb +6 -5
  136. data/lib/active_support/core_ext/string/zones.rb +4 -1
  137. data/lib/active_support/core_ext/string.rb +15 -13
  138. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/symbol.rb +3 -0
  140. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  141. data/lib/active_support/core_ext/time/calculations.rb +178 -116
  142. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  143. data/lib/active_support/core_ext/time/conversions.rb +37 -25
  144. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  145. data/lib/active_support/core_ext/time/zones.rb +44 -42
  146. data/lib/active_support/core_ext/time.rb +8 -5
  147. data/lib/active_support/core_ext/uri.rb +4 -25
  148. data/lib/active_support/core_ext.rb +4 -2
  149. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  150. data/lib/active_support/current_attributes.rb +226 -0
  151. data/lib/active_support/dependencies/autoload.rb +3 -1
  152. data/lib/active_support/dependencies/interlock.rb +49 -0
  153. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  154. data/lib/active_support/dependencies.rb +71 -696
  155. data/lib/active_support/deprecation/behaviors.rb +65 -16
  156. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  157. data/lib/active_support/deprecation/disallowed.rb +56 -0
  158. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  159. data/lib/active_support/deprecation/method_wrappers.rb +62 -21
  160. data/lib/active_support/deprecation/proxy_wrappers.rb +82 -31
  161. data/lib/active_support/deprecation/reporting.rb +81 -18
  162. data/lib/active_support/deprecation.rb +19 -11
  163. data/lib/active_support/descendants_tracker.rb +192 -34
  164. data/lib/active_support/digest.rb +22 -0
  165. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  166. data/lib/active_support/duration/iso8601_serializer.rb +67 -0
  167. data/lib/active_support/duration.rb +437 -39
  168. data/lib/active_support/encrypted_configuration.rb +56 -0
  169. data/lib/active_support/encrypted_file.rb +117 -0
  170. data/lib/active_support/environment_inquirer.rb +20 -0
  171. data/lib/active_support/error_reporter.rb +117 -0
  172. data/lib/active_support/evented_file_update_checker.rb +170 -0
  173. data/lib/active_support/execution_context/test_helper.rb +13 -0
  174. data/lib/active_support/execution_context.rb +53 -0
  175. data/lib/active_support/execution_wrapper.rb +151 -0
  176. data/lib/active_support/executor/test_helper.rb +7 -0
  177. data/lib/active_support/executor.rb +8 -0
  178. data/lib/active_support/file_update_checker.rb +62 -37
  179. data/lib/active_support/fork_tracker.rb +71 -0
  180. data/lib/active_support/gem_version.rb +17 -0
  181. data/lib/active_support/gzip.rb +7 -5
  182. data/lib/active_support/hash_with_indifferent_access.rb +207 -54
  183. data/lib/active_support/html_safe_translation.rb +43 -0
  184. data/lib/active_support/i18n.rb +10 -6
  185. data/lib/active_support/i18n_railtie.rb +48 -19
  186. data/lib/active_support/inflections.rb +19 -12
  187. data/lib/active_support/inflector/inflections.rb +97 -37
  188. data/lib/active_support/inflector/methods.rb +192 -157
  189. data/lib/active_support/inflector/transliterate.rb +83 -33
  190. data/lib/active_support/inflector.rb +7 -5
  191. data/lib/active_support/isolated_execution_state.rb +64 -0
  192. data/lib/active_support/json/decoding.rb +37 -42
  193. data/lib/active_support/json/encoding.rb +93 -293
  194. data/lib/active_support/json.rb +4 -2
  195. data/lib/active_support/key_generator.rb +30 -47
  196. data/lib/active_support/lazy_load_hooks.rb +54 -21
  197. data/lib/active_support/locale/en.rb +33 -0
  198. data/lib/active_support/locale/en.yml +10 -4
  199. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  200. data/lib/active_support/log_subscriber.rb +61 -18
  201. data/lib/active_support/logger.rb +40 -4
  202. data/lib/active_support/logger_silence.rb +17 -20
  203. data/lib/active_support/logger_thread_safe_level.rb +69 -0
  204. data/lib/active_support/message_encryptor.rb +178 -55
  205. data/lib/active_support/message_verifier.rb +195 -26
  206. data/lib/active_support/messages/metadata.rb +80 -0
  207. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  208. data/lib/active_support/messages/rotator.rb +57 -0
  209. data/lib/active_support/multibyte/chars.rb +45 -92
  210. data/lib/active_support/multibyte/unicode.rb +44 -377
  211. data/lib/active_support/multibyte.rb +5 -3
  212. data/lib/active_support/notifications/fanout.rb +177 -44
  213. data/lib/active_support/notifications/instrumenter.rb +117 -17
  214. data/lib/active_support/notifications.rb +106 -39
  215. data/lib/active_support/number_helper/number_converter.rb +181 -0
  216. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  217. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  218. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  219. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  220. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  221. data/lib/active_support/number_helper/number_to_phone_converter.rb +59 -0
  222. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  223. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  224. data/lib/active_support/number_helper.rb +152 -394
  225. data/lib/active_support/option_merger.rb +18 -5
  226. data/lib/active_support/ordered_hash.rb +8 -6
  227. data/lib/active_support/ordered_options.rb +43 -7
  228. data/lib/active_support/parameter_filter.rb +138 -0
  229. data/lib/active_support/per_thread_registry.rb +24 -11
  230. data/lib/active_support/proxy_object.rb +2 -0
  231. data/lib/active_support/rails.rb +10 -11
  232. data/lib/active_support/railtie.rb +118 -12
  233. data/lib/active_support/reloader.rb +130 -0
  234. data/lib/active_support/rescuable.rb +112 -57
  235. data/lib/active_support/ruby_features.rb +7 -0
  236. data/lib/active_support/secure_compare_rotator.rb +51 -0
  237. data/lib/active_support/security_utils.rb +38 -0
  238. data/lib/active_support/string_inquirer.rb +11 -4
  239. data/lib/active_support/subscriber.rb +109 -39
  240. data/lib/active_support/tagged_logging.rb +54 -17
  241. data/lib/active_support/test_case.rb +121 -37
  242. data/lib/active_support/testing/assertions.rb +177 -39
  243. data/lib/active_support/testing/autorun.rb +5 -3
  244. data/lib/active_support/testing/constant_lookup.rb +3 -6
  245. data/lib/active_support/testing/declarative.rb +10 -22
  246. data/lib/active_support/testing/deprecation.rb +65 -11
  247. data/lib/active_support/testing/file_fixtures.rb +38 -0
  248. data/lib/active_support/testing/isolation.rb +56 -87
  249. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  250. data/lib/active_support/testing/parallelization/server.rb +82 -0
  251. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  252. data/lib/active_support/testing/parallelization.rb +55 -0
  253. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  254. data/lib/active_support/testing/setup_and_teardown.rb +30 -10
  255. data/lib/active_support/testing/stream.rb +41 -0
  256. data/lib/active_support/testing/tagged_logging.rb +6 -4
  257. data/lib/active_support/testing/time_helpers.rb +246 -0
  258. data/lib/active_support/time.rb +13 -13
  259. data/lib/active_support/time_with_zone.rb +315 -90
  260. data/lib/active_support/values/time_zone.rb +306 -135
  261. data/lib/active_support/version.rb +6 -7
  262. data/lib/active_support/xml_mini/jdom.rb +117 -115
  263. data/lib/active_support/xml_mini/libxml.rb +22 -21
  264. data/lib/active_support/xml_mini/libxmlsax.rb +17 -19
  265. data/lib/active_support/xml_mini/nokogiri.rb +19 -19
  266. data/lib/active_support/xml_mini/nokogirisax.rb +16 -17
  267. data/lib/active_support/xml_mini/rexml.rb +25 -17
  268. data/lib/active_support/xml_mini.rb +67 -56
  269. data/lib/active_support.rb +58 -3
  270. metadata +125 -66
  271. data/lib/active_support/basic_object.rb +0 -11
  272. data/lib/active_support/buffered_logger.rb +0 -21
  273. data/lib/active_support/concurrency/latch.rb +0 -27
  274. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  275. data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
  276. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -40
  277. data/lib/active_support/core_ext/date_time/zones.rb +0 -24
  278. data/lib/active_support/core_ext/hash/diff.rb +0 -14
  279. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  280. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  281. data/lib/active_support/core_ext/logger.rb +0 -67
  282. data/lib/active_support/core_ext/marshal.rb +0 -21
  283. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  284. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  285. data/lib/active_support/core_ext/object/to_json.rb +0 -27
  286. data/lib/active_support/core_ext/proc.rb +0 -17
  287. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  288. data/lib/active_support/core_ext/string/encoding.rb +0 -8
  289. data/lib/active_support/core_ext/struct.rb +0 -6
  290. data/lib/active_support/core_ext/thread.rb +0 -79
  291. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  292. data/lib/active_support/file_watcher.rb +0 -36
  293. data/lib/active_support/json/variable.rb +0 -18
  294. data/lib/active_support/testing/pending.rb +0 -14
  295. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/execution_wrapper"
4
+ require "active_support/executor"
5
+
6
+ module ActiveSupport
7
+ #--
8
+ # This class defines several callbacks:
9
+ #
10
+ # to_prepare -- Run once at application startup, and also from
11
+ # +to_run+.
12
+ #
13
+ # to_run -- Run before a work run that is reloading. If
14
+ # +reload_classes_only_on_change+ is true (the default), the class
15
+ # unload will have already occurred.
16
+ #
17
+ # to_complete -- Run after a work run that has reloaded. If
18
+ # +reload_classes_only_on_change+ is false, the class unload will
19
+ # have occurred after the work run, but before this callback.
20
+ #
21
+ # before_class_unload -- Run immediately before the classes are
22
+ # unloaded.
23
+ #
24
+ # after_class_unload -- Run immediately after the classes are
25
+ # unloaded.
26
+ #
27
+ class Reloader < ExecutionWrapper
28
+ define_callbacks :prepare
29
+
30
+ define_callbacks :class_unload
31
+
32
+ # Registers a callback that will run once at application startup and every time the code is reloaded.
33
+ def self.to_prepare(*args, &block)
34
+ set_callback(:prepare, *args, &block)
35
+ end
36
+
37
+ # Registers a callback that will run immediately before the classes are unloaded.
38
+ def self.before_class_unload(*args, &block)
39
+ set_callback(:class_unload, *args, &block)
40
+ end
41
+
42
+ # Registers a callback that will run immediately after the classes are unloaded.
43
+ def self.after_class_unload(*args, &block)
44
+ set_callback(:class_unload, :after, *args, &block)
45
+ end
46
+
47
+ to_run(:after) { self.class.prepare! }
48
+
49
+ # Initiate a manual reload
50
+ def self.reload!
51
+ executor.wrap do
52
+ new.tap do |instance|
53
+ instance.run!
54
+ ensure
55
+ instance.complete!
56
+ end
57
+ end
58
+ prepare!
59
+ end
60
+
61
+ def self.run!(reset: false) # :nodoc:
62
+ if check!
63
+ super
64
+ else
65
+ Null
66
+ end
67
+ end
68
+
69
+ # Run the supplied block as a work unit, reloading code as needed
70
+ def self.wrap
71
+ executor.wrap do
72
+ super
73
+ end
74
+ end
75
+
76
+ class_attribute :executor, default: Executor
77
+ class_attribute :check, default: lambda { false }
78
+
79
+ def self.check! # :nodoc:
80
+ @should_reload ||= check.call
81
+ end
82
+
83
+ def self.reloaded! # :nodoc:
84
+ @should_reload = false
85
+ end
86
+
87
+ def self.prepare! # :nodoc:
88
+ new.run_callbacks(:prepare)
89
+ end
90
+
91
+ def initialize
92
+ super
93
+ @locked = false
94
+ end
95
+
96
+ # Acquire the ActiveSupport::Dependencies::Interlock unload lock,
97
+ # ensuring it will be released automatically
98
+ def require_unload_lock!
99
+ unless @locked
100
+ ActiveSupport::Dependencies.interlock.start_unloading
101
+ @locked = true
102
+ end
103
+ end
104
+
105
+ # Release the unload lock if it has been previously obtained
106
+ def release_unload_lock!
107
+ if @locked
108
+ @locked = false
109
+ ActiveSupport::Dependencies.interlock.done_unloading
110
+ end
111
+ end
112
+
113
+ def run! # :nodoc:
114
+ super
115
+ release_unload_lock!
116
+ end
117
+
118
+ def class_unload!(&block) # :nodoc:
119
+ require_unload_lock!
120
+ run_callbacks(:class_unload, &block)
121
+ end
122
+
123
+ def complete! # :nodoc:
124
+ super
125
+ self.class.reloaded!
126
+ ensure
127
+ release_unload_lock!
128
+ end
129
+ end
130
+ end
@@ -1,7 +1,8 @@
1
- require 'active_support/concern'
2
- require 'active_support/core_ext/class/attribute'
3
- require 'active_support/core_ext/string/inflections'
4
- require 'active_support/core_ext/array/extract_options'
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"
5
6
 
6
7
  module ActiveSupport
7
8
  # Rescuable module adds support for easier exception handling.
@@ -9,17 +10,16 @@ module ActiveSupport
9
10
  extend Concern
10
11
 
11
12
  included do
12
- class_attribute :rescue_handlers
13
- self.rescue_handlers = []
13
+ class_attribute :rescue_handlers, default: []
14
14
  end
15
15
 
16
16
  module ClassMethods
17
- # Rescue exceptions raised in controller actions.
17
+ # Registers exception classes with a handler to be called by <tt>rescue_with_handler</tt>.
18
18
  #
19
19
  # <tt>rescue_from</tt> receives a series of exception classes or class
20
- # names, and a trailing <tt>:with</tt> option with the name of a method
21
- # or a Proc object to be called to handle them. Alternatively a block can
22
- # be given.
20
+ # names, and an exception handler specified by a trailing <tt>:with</tt>
21
+ # option containing the name of a method or a Proc object. Alternatively, a block
22
+ # can be given as the handler.
23
23
  #
24
24
  # Handlers that take one argument will be called with the exception, so
25
25
  # that the exception can be inspected when dealing with it.
@@ -37,7 +37,7 @@ module ActiveSupport
37
37
  # render xml: exception, status: 500
38
38
  # end
39
39
  #
40
- # protected
40
+ # private
41
41
  # def deny_access
42
42
  # ...
43
43
  # end
@@ -48,72 +48,127 @@ module ActiveSupport
48
48
  # end
49
49
  #
50
50
  # Exceptions raised inside exception handlers are not propagated up.
51
- def rescue_from(*klasses, &block)
52
- options = klasses.extract_options!
53
-
54
- unless options.has_key?(:with)
51
+ def rescue_from(*klasses, with: nil, &block)
52
+ unless with
55
53
  if block_given?
56
- options[:with] = block
54
+ with = block
57
55
  else
58
- raise ArgumentError, "Need a handler. Supply an options hash that has a :with key as the last argument."
56
+ raise ArgumentError, "Need a handler. Pass the with: keyword argument or provide a block."
59
57
  end
60
58
  end
61
59
 
62
60
  klasses.each do |klass|
63
- key = if klass.is_a?(Class) && klass <= Exception
61
+ key = if klass.is_a?(Module) && klass.respond_to?(:===)
64
62
  klass.name
65
63
  elsif klass.is_a?(String)
66
64
  klass
67
65
  else
68
- raise ArgumentError, "#{klass} is neither an Exception nor a String"
66
+ raise ArgumentError, "#{klass.inspect} must be an Exception class or a String referencing an Exception class"
69
67
  end
70
68
 
71
- # put the new handler at the end because the list is read in reverse
72
- self.rescue_handlers += [[key, options[:with]]]
69
+ # Put the new handler at the end because the list is read in reverse.
70
+ self.rescue_handlers += [[key, with]]
73
71
  end
74
72
  end
75
- end
76
73
 
77
- # Tries to rescue the exception by looking up and calling a registered handler.
78
- def rescue_with_handler(exception)
79
- if handler = handler_for_rescue(exception)
80
- handler.arity != 0 ? handler.call(exception) : handler.call
81
- true # don't rely on the return value of the handler
82
- end
83
- end
74
+ # Matches an exception to a handler based on the exception class.
75
+ #
76
+ # If no handler matches the exception, check for a handler matching the
77
+ # (optional) exception.cause. If no handler matches the exception or its
78
+ # cause, this returns +nil+, so you can deal with unhandled exceptions.
79
+ # Be sure to re-raise unhandled exceptions if this is what you expect.
80
+ #
81
+ # begin
82
+ # …
83
+ # rescue => exception
84
+ # rescue_with_handler(exception) || raise
85
+ # end
86
+ #
87
+ # Returns the exception if it was handled and +nil+ if it was not.
88
+ def rescue_with_handler(exception, object: self, visited_exceptions: [])
89
+ visited_exceptions << exception
84
90
 
85
- def handler_for_rescue(exception)
86
- # We go from right to left because pairs are pushed onto rescue_handlers
87
- # as rescue_from declarations are found.
88
- _, rescuer = self.class.rescue_handlers.reverse.detect do |klass_name, handler|
89
- # The purpose of allowing strings in rescue_from is to support the
90
- # declaration of handler associations for exception classes whose
91
- # definition is yet unknown.
92
- #
93
- # Since this loop needs the constants it would be inconsistent to
94
- # assume they should exist at this point. An early raised exception
95
- # could trigger some other handler and the array could include
96
- # precisely a string whose corresponding constant has not yet been
97
- # seen. This is why we are tolerant to unknown constants.
98
- #
99
- # Note that this tolerance only matters if the exception was given as
100
- # a string, otherwise a NameError will be raised by the interpreter
101
- # itself when rescue_from CONSTANT is executed.
102
- klass = self.class.const_get(klass_name) rescue nil
103
- klass ||= klass_name.constantize rescue nil
104
- exception.is_a?(klass) if klass
91
+ if handler = handler_for_rescue(exception, object: object)
92
+ handler.call exception
93
+ exception
94
+ elsif exception
95
+ if visited_exceptions.include?(exception.cause)
96
+ nil
97
+ else
98
+ rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions)
99
+ end
100
+ end
105
101
  end
106
102
 
107
- case rescuer
108
- when Symbol
109
- method(rescuer)
110
- when Proc
111
- if rescuer.arity == 0
112
- Proc.new { instance_exec(&rescuer) }
113
- else
114
- Proc.new { |_exception| instance_exec(_exception, &rescuer) }
103
+ def handler_for_rescue(exception, object: self) # :nodoc:
104
+ case rescuer = find_rescue_handler(exception)
105
+ when Symbol
106
+ method = object.method(rescuer)
107
+ if method.arity == 0
108
+ -> e { method.call }
109
+ else
110
+ method
111
+ end
112
+ when Proc
113
+ if rescuer.arity == 0
114
+ -> e { object.instance_exec(&rescuer) }
115
+ else
116
+ -> e { object.instance_exec(e, &rescuer) }
117
+ end
115
118
  end
116
119
  end
120
+
121
+ private
122
+ def find_rescue_handler(exception)
123
+ if exception
124
+ # Handlers are in order of declaration but the most recently declared
125
+ # is the highest priority match, so we search for matching handlers
126
+ # in reverse.
127
+ _, handler = rescue_handlers.reverse_each.detect do |class_or_name, _|
128
+ if klass = constantize_rescue_handler_class(class_or_name)
129
+ klass === exception
130
+ end
131
+ end
132
+
133
+ handler
134
+ end
135
+ end
136
+
137
+ def constantize_rescue_handler_class(class_or_name)
138
+ case class_or_name
139
+ when String, Symbol
140
+ begin
141
+ # Try a lexical lookup first since we support
142
+ #
143
+ # class Super
144
+ # rescue_from 'Error', with: …
145
+ # end
146
+ #
147
+ # class Sub
148
+ # class Error < StandardError; end
149
+ # end
150
+ #
151
+ # so an Error raised in Sub will hit the 'Error' handler.
152
+ const_get class_or_name
153
+ rescue NameError
154
+ class_or_name.safe_constantize
155
+ end
156
+ else
157
+ class_or_name
158
+ end
159
+ end
160
+ end
161
+
162
+ # Delegates to the class method, but uses the instance as the subject for
163
+ # rescue_from handlers (method calls, instance_exec blocks).
164
+ def rescue_with_handler(exception)
165
+ self.class.rescue_with_handler exception, object: self
166
+ end
167
+
168
+ # Internal handler lookup. Delegates to class method. Some libraries call
169
+ # this directly, so keeping it around for compatibility.
170
+ def handler_for_rescue(exception) # :nodoc:
171
+ self.class.handler_for_rescue exception, object: self
117
172
  end
118
173
  end
119
174
  end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module RubyFeatures # :nodoc:
5
+ CLASS_SUBCLASSES = Class.method_defined?(:subclasses) # RUBY_VERSION >= "3.1"
6
+ end
7
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/security_utils"
4
+ require "active_support/messages/rotator"
5
+
6
+ module ActiveSupport
7
+ # The ActiveSupport::SecureCompareRotator is a wrapper around +ActiveSupport::SecurityUtils.secure_compare+
8
+ # and allows you to rotate a previously defined value to a new one.
9
+ #
10
+ # It can be used as follow:
11
+ #
12
+ # rotator = ActiveSupport::SecureCompareRotator.new('new_production_value')
13
+ # rotator.rotate('previous_production_value')
14
+ # rotator.secure_compare!('previous_production_value')
15
+ #
16
+ # One real use case example would be to rotate a basic auth credentials:
17
+ #
18
+ # class MyController < ApplicationController
19
+ # def authenticate_request
20
+ # rotator = ActiveSupport::SecureCompareRotator.new('new_password')
21
+ # rotator.rotate('old_password')
22
+ #
23
+ # authenticate_or_request_with_http_basic do |username, password|
24
+ # rotator.secure_compare!(password)
25
+ # rescue ActiveSupport::SecureCompareRotator::InvalidMatch
26
+ # false
27
+ # end
28
+ # end
29
+ # end
30
+ class SecureCompareRotator
31
+ include SecurityUtils
32
+ prepend Messages::Rotator
33
+
34
+ InvalidMatch = Class.new(StandardError)
35
+
36
+ def initialize(value, **_options)
37
+ @value = value
38
+ end
39
+
40
+ def secure_compare!(other_value, on_rotation: @on_rotation)
41
+ secure_compare(@value, other_value) ||
42
+ run_rotations(on_rotation) { |wrapper| wrapper.secure_compare!(other_value) } ||
43
+ raise(InvalidMatch)
44
+ end
45
+
46
+ private
47
+ def build_rotation(previous_value, _options)
48
+ self.class.new(previous_value)
49
+ end
50
+ end
51
+ 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
@@ -1,22 +1,29 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  # Wrapping a string in this class gives you a prettier way to test
3
5
  # for equality. The value returned by <tt>Rails.env</tt> is wrapped
4
- # in a StringInquirer object so instead of calling this:
6
+ # in a StringInquirer object, so instead of calling this:
5
7
  #
6
8
  # Rails.env == 'production'
7
9
  #
8
10
  # you can call this:
9
11
  #
10
12
  # Rails.env.production?
13
+ #
14
+ # == Instantiating a new StringInquirer
15
+ #
16
+ # vehicle = ActiveSupport::StringInquirer.new('car')
17
+ # vehicle.car? # => true
18
+ # vehicle.bike? # => false
11
19
  class StringInquirer < String
12
20
  private
13
-
14
21
  def respond_to_missing?(method_name, include_private = false)
15
- method_name[-1] == '?'
22
+ method_name.end_with?("?") || super
16
23
  end
17
24
 
18
25
  def method_missing(method_name, *arguments)
19
- if method_name[-1] == '?'
26
+ if method_name.end_with?("?")
20
27
  self == method_name[0..-2]
21
28
  else
22
29
  super
@@ -1,93 +1,163 @@
1
- require 'active_support/per_thread_registry'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/notifications"
2
4
 
3
5
  module ActiveSupport
4
6
  # ActiveSupport::Subscriber is an object set to consume
5
7
  # ActiveSupport::Notifications. The subscriber dispatches notifications to
6
8
  # a registered object based on its given namespace.
7
9
  #
8
- # An example would be Active Record subscriber responsible for collecting
10
+ # An example would be an Active Record subscriber responsible for collecting
9
11
  # statistics about queries:
10
12
  #
11
13
  # module ActiveRecord
12
14
  # class StatsSubscriber < ActiveSupport::Subscriber
15
+ # attach_to :active_record
16
+ #
13
17
  # def sql(event)
14
18
  # Statsd.timing("sql.#{event.payload[:name]}", event.duration)
15
19
  # end
16
20
  # end
17
21
  # end
18
22
  #
19
- # And it's finally registered as:
20
- #
21
- # ActiveRecord::StatsSubscriber.attach_to :active_record
22
- #
23
- # Since we need to know all instance methods before attaching the log
24
- # subscriber, the line above should be called after your subscriber definition.
25
- #
26
23
  # After configured, whenever a "sql.active_record" notification is published,
27
24
  # it will properly dispatch the event (ActiveSupport::Notifications::Event) to
28
25
  # the +sql+ method.
26
+ #
27
+ # We can detach a subscriber as well:
28
+ #
29
+ # ActiveRecord::StatsSubscriber.detach_from(:active_record)
29
30
  class Subscriber
30
31
  class << self
31
-
32
32
  # Attach the subscriber to a namespace.
33
- def attach_to(namespace, subscriber=new, notifier=ActiveSupport::Notifications)
33
+ def attach_to(namespace, subscriber = new, notifier = ActiveSupport::Notifications, inherit_all: false)
34
+ @namespace = namespace
35
+ @subscriber = subscriber
36
+ @notifier = notifier
37
+ @inherit_all = inherit_all
38
+
34
39
  subscribers << subscriber
35
40
 
36
- subscriber.public_methods(false).each do |event|
37
- next if %w{ start finish }.include?(event.to_s)
41
+ # Add event subscribers for all existing methods on the class.
42
+ fetch_public_methods(subscriber, inherit_all).each do |event|
43
+ add_event_subscriber(event)
44
+ end
45
+ end
46
+
47
+ # Detach the subscriber from a namespace.
48
+ def detach_from(namespace, notifier = ActiveSupport::Notifications)
49
+ @namespace = namespace
50
+ @subscriber = find_attached_subscriber
51
+ @notifier = notifier
52
+
53
+ return unless subscriber
38
54
 
39
- notifier.subscribe("#{event}.#{namespace}", subscriber)
55
+ subscribers.delete(subscriber)
56
+
57
+ # Remove event subscribers of all existing methods on the class.
58
+ fetch_public_methods(subscriber, true).each do |event|
59
+ remove_event_subscriber(event)
60
+ end
61
+
62
+ # Reset notifier so that event subscribers will not add for new methods added to the class.
63
+ @notifier = nil
64
+ end
65
+
66
+ # Adds event subscribers for all new methods added to the class.
67
+ def method_added(event)
68
+ # Only public methods are added as subscribers, and only if a notifier
69
+ # has been set up. This means that subscribers will only be set up for
70
+ # classes that call #attach_to.
71
+ if public_method_defined?(event) && notifier
72
+ add_event_subscriber(event)
40
73
  end
41
74
  end
42
75
 
43
76
  def subscribers
44
77
  @@subscribers ||= []
45
78
  end
79
+
80
+ private
81
+ attr_reader :subscriber, :notifier, :namespace
82
+
83
+ def add_event_subscriber(event) # :doc:
84
+ return if invalid_event?(event)
85
+
86
+ pattern = prepare_pattern(event)
87
+
88
+ # Don't add multiple subscribers (e.g. if methods are redefined).
89
+ return if pattern_subscribed?(pattern)
90
+
91
+ subscriber.patterns[pattern] = notifier.subscribe(pattern, subscriber)
92
+ end
93
+
94
+ def remove_event_subscriber(event) # :doc:
95
+ return if invalid_event?(event)
96
+
97
+ pattern = prepare_pattern(event)
98
+
99
+ return unless pattern_subscribed?(pattern)
100
+
101
+ notifier.unsubscribe(subscriber.patterns[pattern])
102
+ subscriber.patterns.delete(pattern)
103
+ end
104
+
105
+ def find_attached_subscriber
106
+ subscribers.find { |attached_subscriber| attached_subscriber.instance_of?(self) }
107
+ end
108
+
109
+ def invalid_event?(event)
110
+ %i{ start finish }.include?(event.to_sym)
111
+ end
112
+
113
+ def prepare_pattern(event)
114
+ "#{event}.#{namespace}"
115
+ end
116
+
117
+ def pattern_subscribed?(pattern)
118
+ subscriber.patterns.key?(pattern)
119
+ end
120
+
121
+ def fetch_public_methods(subscriber, inherit_all)
122
+ subscriber.public_methods(inherit_all) - Subscriber.public_instance_methods(true)
123
+ end
46
124
  end
47
125
 
126
+ attr_reader :patterns # :nodoc:
127
+
48
128
  def initialize
49
129
  @queue_key = [self.class.name, object_id].join "-"
130
+ @patterns = {}
50
131
  super
51
132
  end
52
133
 
53
134
  def start(name, id, payload)
54
- e = ActiveSupport::Notifications::Event.new(name, Time.now, nil, id, payload)
135
+ event = ActiveSupport::Notifications::Event.new(name, nil, nil, id, payload)
136
+ event.start!
55
137
  parent = event_stack.last
56
- parent << e if parent
138
+ parent << event if parent
57
139
 
58
- event_stack.push e
140
+ event_stack.push event
59
141
  end
60
142
 
61
143
  def finish(name, id, payload)
62
- finished = Time.now
63
- event = event_stack.pop
64
- event.end = finished
144
+ event = event_stack.pop
145
+ event.finish!
65
146
  event.payload.merge!(payload)
66
147
 
67
- method = name.split('.').first
148
+ method = name.split(".").first
68
149
  send(method, event)
69
150
  end
70
151
 
71
- private
152
+ def publish_event(event) # :nodoc:
153
+ method = event.name.split(".").first
154
+ send(method, event)
155
+ end
72
156
 
157
+ private
73
158
  def event_stack
74
- SubscriberQueueRegistry.get_queue(@queue_key)
159
+ registry = ActiveSupport::IsolatedExecutionState[:active_support_subscriber_queue_registry] ||= {}
160
+ registry[@queue_key] ||= []
75
161
  end
76
162
  end
77
-
78
- # This is a registry for all the event stacks kept for subscribers.
79
- #
80
- # See the documentation of <tt>ActiveSupport::PerThreadRegistry</tt>
81
- # for further details.
82
- class SubscriberQueueRegistry # :nodoc:
83
- extend PerThreadRegistry
84
-
85
- def initialize
86
- @registry = {}
87
- end
88
-
89
- def get_queue(queue_key)
90
- @registry[queue_key] ||= []
91
- end
92
- end
93
163
  end