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,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Multibyte
5
+ module Unicode
6
+ extend self
7
+
8
+ # The Unicode version that is supported by the implementation
9
+ UNICODE_VERSION = RbConfig::CONFIG["UNICODE_VERSION"]
10
+
11
+ # Decompose composed characters to the decomposed form.
12
+ def decompose(type, codepoints)
13
+ if type == :compatibility
14
+ codepoints.pack("U*").unicode_normalize(:nfkd).codepoints
15
+ else
16
+ codepoints.pack("U*").unicode_normalize(:nfd).codepoints
17
+ end
18
+ end
19
+
20
+ # Compose decomposed characters to the composed form.
21
+ def compose(codepoints)
22
+ codepoints.pack("U*").unicode_normalize(:nfc).codepoints
23
+ end
24
+
25
+ # Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
26
+ # resulting in a valid UTF-8 string.
27
+ #
28
+ # Passing +true+ will forcibly tidy all bytes, assuming that the string's
29
+ # encoding is entirely CP1252 or ISO-8859-1.
30
+ def tidy_bytes(string, force = false)
31
+ return string if string.empty? || string.ascii_only?
32
+ return recode_windows1252_chars(string) if force
33
+ string.scrub { |bad| recode_windows1252_chars(bad) }
34
+ end
35
+
36
+ private
37
+ def recode_windows1252_chars(string)
38
+ string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport # :nodoc:
4
+ module Multibyte
5
+ autoload :Chars, "active_support/multibyte/chars"
6
+ autoload :Unicode, "active_support/multibyte/unicode"
7
+
8
+ # The proxy class returned when calling mb_chars. You can use this accessor
9
+ # to configure your own proxy class so you can support other encodings. See
10
+ # the ActiveSupport::Multibyte::Chars implementation for an example how to
11
+ # do this.
12
+ #
13
+ # ActiveSupport::Multibyte.proxy_class = CharsForUTF32
14
+ def self.proxy_class=(klass)
15
+ ActiveSupport.deprecator.warn(
16
+ "ActiveSupport::Multibyte.proxy_class= is deprecated and will be removed in Rails 8.2. " \
17
+ "Use normal string methods instead."
18
+ )
19
+ @proxy_class = klass
20
+ end
21
+
22
+ # Returns the current proxy class.
23
+ def self.proxy_class
24
+ @proxy_class ||= ActiveSupport::Multibyte::Chars
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,467 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "concurrent/map"
4
+ require "active_support/core_ext/object/try"
5
+
6
+ module ActiveSupport
7
+ module Notifications
8
+ class InstrumentationSubscriberError < RuntimeError
9
+ attr_reader :exceptions
10
+
11
+ def initialize(exceptions)
12
+ @exceptions = exceptions
13
+ exception_class_names = exceptions.map { |e| e.class.name }
14
+ super "Exception(s) occurred within instrumentation subscribers: #{exception_class_names.join(', ')}"
15
+ end
16
+ end
17
+
18
+ module FanoutIteration # :nodoc:
19
+ private
20
+ def iterate_guarding_exceptions(collection, &block)
21
+ case collection.size
22
+ when 0
23
+ when 1
24
+ collection.each(&block)
25
+ else
26
+ exceptions = nil
27
+
28
+ collection.each do |s|
29
+ yield s
30
+ rescue Exception => e
31
+ exceptions ||= []
32
+ exceptions << e
33
+ end
34
+
35
+ if exceptions
36
+ exceptions = exceptions.flat_map do |exception|
37
+ exception.is_a?(InstrumentationSubscriberError) ? exception.exceptions : [exception]
38
+ end
39
+ if exceptions.size == 1
40
+ raise exceptions.first
41
+ else
42
+ raise InstrumentationSubscriberError.new(exceptions), cause: exceptions.first
43
+ end
44
+ end
45
+ end
46
+
47
+ collection
48
+ end
49
+ end
50
+
51
+ # This is a default queue implementation that ships with Notifications.
52
+ # It just pushes events to all registered log subscribers.
53
+ #
54
+ # This class is thread safe. All methods are reentrant.
55
+ class Fanout
56
+ def initialize
57
+ @mutex = Mutex.new
58
+ @string_subscribers = Concurrent::Map.new { |h, k| h.compute_if_absent(k) { [] } }
59
+ @other_subscribers = []
60
+ @all_listeners_for = Concurrent::Map.new
61
+ @groups_for = Concurrent::Map.new
62
+ end
63
+
64
+ def inspect # :nodoc:
65
+ total_patterns = @string_subscribers.size + @other_subscribers.size
66
+ "#<#{self.class} (#{total_patterns} patterns)>"
67
+ end
68
+
69
+ def subscribe(pattern = nil, callable = nil, monotonic: false, &block)
70
+ subscriber = Subscribers.new(pattern, callable || block, monotonic)
71
+ @mutex.synchronize do
72
+ case pattern
73
+ when String
74
+ @string_subscribers[pattern] << subscriber
75
+ clear_cache(pattern)
76
+ when NilClass, Regexp
77
+ @other_subscribers << subscriber
78
+ clear_cache
79
+ else
80
+ raise ArgumentError, "pattern must be specified as a String, Regexp or empty"
81
+ end
82
+ end
83
+ subscriber
84
+ end
85
+
86
+ def unsubscribe(subscriber_or_name)
87
+ @mutex.synchronize do
88
+ case subscriber_or_name
89
+ when String
90
+ @string_subscribers[subscriber_or_name].clear
91
+ clear_cache(subscriber_or_name)
92
+ @other_subscribers.each { |sub| sub.unsubscribe!(subscriber_or_name) }
93
+ else
94
+ pattern = subscriber_or_name.try(:pattern)
95
+ if String === pattern
96
+ @string_subscribers[pattern].delete(subscriber_or_name)
97
+ clear_cache(pattern)
98
+ else
99
+ @other_subscribers.delete(subscriber_or_name)
100
+ clear_cache
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def clear_cache(key = nil) # :nodoc:
107
+ if key
108
+ @all_listeners_for.delete(key)
109
+ @groups_for.delete(key)
110
+ else
111
+ @all_listeners_for.clear
112
+ @groups_for.clear
113
+ end
114
+ end
115
+
116
+ class BaseGroup # :nodoc:
117
+ include FanoutIteration
118
+
119
+ def initialize(listeners, name, id, payload)
120
+ @listeners = listeners
121
+ end
122
+
123
+ def each(&block)
124
+ iterate_guarding_exceptions(@listeners, &block)
125
+ end
126
+ end
127
+
128
+ class BaseTimeGroup < BaseGroup # :nodoc:
129
+ def start(name, id, payload)
130
+ @start_time = now
131
+ end
132
+
133
+ def finish(name, id, payload)
134
+ stop_time = now
135
+ each do |listener|
136
+ listener.call(name, @start_time, stop_time, id, payload)
137
+ end
138
+ end
139
+ end
140
+
141
+ class MonotonicTimedGroup < BaseTimeGroup # :nodoc:
142
+ private
143
+ def now
144
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
145
+ end
146
+ end
147
+
148
+ class TimedGroup < BaseTimeGroup # :nodoc:
149
+ private
150
+ def now
151
+ Time.now
152
+ end
153
+ end
154
+
155
+ class EventedGroup < BaseGroup # :nodoc:
156
+ def start(name, id, payload)
157
+ each do |s|
158
+ s.start(name, id, payload)
159
+ end
160
+ end
161
+
162
+ def finish(name, id, payload)
163
+ each do |s|
164
+ s.finish(name, id, payload)
165
+ end
166
+ end
167
+ end
168
+
169
+ class EventObjectGroup < BaseGroup # :nodoc:
170
+ def start(name, id, payload)
171
+ @event = build_event(name, id, payload)
172
+ @event.start!
173
+ end
174
+
175
+ def finish(name, id, payload)
176
+ @event.payload = payload
177
+ @event.finish!
178
+
179
+ each do |s|
180
+ s.call(@event)
181
+ end
182
+ end
183
+
184
+ private
185
+ def build_event(name, id, payload)
186
+ ActiveSupport::Notifications::Event.new name, nil, nil, id, payload
187
+ end
188
+ end
189
+
190
+ def group_listeners(listeners) # :nodoc:
191
+ listeners.group_by(&:group_class).transform_values do |s|
192
+ s.map(&:delegate).freeze
193
+ end.freeze
194
+ end
195
+
196
+ def groups_for(name) # :nodoc:
197
+ silenceable_groups, groups = @groups_for.compute_if_absent(name) do
198
+ listeners = all_listeners_for(name)
199
+ listeners.partition(&:silenceable).map { |l| group_listeners(l) }
200
+ end
201
+
202
+ unless silenceable_groups.empty?
203
+ silenceable_groups.each do |group_class, subscriptions|
204
+ active_subscriptions = subscriptions.reject { |s| s.silenced?(name) }
205
+ unless active_subscriptions.empty?
206
+ groups = groups.dup if groups.frozen?
207
+ base_groups = groups[group_class]
208
+ groups[group_class] = base_groups ? base_groups + active_subscriptions : active_subscriptions
209
+ end
210
+ end
211
+ end
212
+
213
+ groups
214
+ end
215
+
216
+ # A +Handle+ is used to record the start and finish time of event.
217
+ #
218
+ # Both #start and #finish must each be called exactly once.
219
+ #
220
+ # Where possible, it's best to use the block form: ActiveSupport::Notifications.instrument.
221
+ # +Handle+ is a low-level API intended for cases where the block form can't be used.
222
+ #
223
+ # handle = ActiveSupport::Notifications.instrumenter.build_handle("my.event", {})
224
+ # begin
225
+ # handle.start
226
+ # # work to be instrumented
227
+ # ensure
228
+ # handle.finish
229
+ # end
230
+ class Handle
231
+ include FanoutIteration
232
+
233
+ def initialize(notifier, name, id, groups, payload) # :nodoc:
234
+ @name = name
235
+ @id = id
236
+ @payload = payload
237
+ @groups = groups
238
+ @state = :initialized
239
+ end
240
+
241
+ def start
242
+ ensure_state! :initialized
243
+ @state = :started
244
+
245
+ iterate_guarding_exceptions(@groups) do |group|
246
+ group.start(@name, @id, @payload)
247
+ end
248
+ end
249
+
250
+ def finish
251
+ finish_with_values(@name, @id, @payload)
252
+ end
253
+
254
+ def finish_with_values(name, id, payload) # :nodoc:
255
+ ensure_state! :started
256
+ @state = :finished
257
+
258
+ iterate_guarding_exceptions(@groups) do |group|
259
+ group.finish(name, id, payload)
260
+ end
261
+ end
262
+
263
+ private
264
+ def ensure_state!(expected)
265
+ if @state != expected
266
+ raise ArgumentError, "expected state to be #{expected.inspect} but was #{@state.inspect}"
267
+ end
268
+ end
269
+ end
270
+
271
+ module NullHandle # :nodoc:
272
+ extend self
273
+
274
+ def start
275
+ end
276
+
277
+ def finish
278
+ end
279
+
280
+ def finish_with_values(_name, _id, _payload)
281
+ end
282
+ end
283
+
284
+ include FanoutIteration
285
+
286
+ def build_handle(name, id, payload)
287
+ groups = groups_for(name).map do |group_klass, grouped_listeners|
288
+ group_klass.new(grouped_listeners, name, id, payload)
289
+ end
290
+
291
+ if groups.empty?
292
+ NullHandle
293
+ else
294
+ Handle.new(self, name, id, groups, payload)
295
+ end
296
+ end
297
+
298
+ def start(name, id, payload)
299
+ handle_stack = (IsolatedExecutionState[:_fanout_handle_stack] ||= [])
300
+ handle = build_handle(name, id, payload)
301
+ handle_stack << handle
302
+ handle.start
303
+ end
304
+
305
+ def finish(name, id, payload, listeners = nil)
306
+ handle_stack = IsolatedExecutionState[:_fanout_handle_stack]
307
+ handle = handle_stack.pop
308
+ handle.finish_with_values(name, id, payload)
309
+ end
310
+
311
+ def publish(name, ...)
312
+ iterate_guarding_exceptions(listeners_for(name)) { |s| s.publish(name, ...) }
313
+ end
314
+
315
+ def publish_event(event)
316
+ iterate_guarding_exceptions(listeners_for(event.name)) { |s| s.publish_event(event) }
317
+ end
318
+
319
+ def all_listeners_for(name)
320
+ # this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
321
+ @all_listeners_for[name] || @mutex.synchronize do
322
+ # use synchronisation when accessing @subscribers
323
+ @all_listeners_for[name] ||=
324
+ @string_subscribers[name] + @other_subscribers.select { |s| s.subscribed_to?(name) }
325
+ end
326
+ end
327
+
328
+ def listeners_for(name)
329
+ all_listeners_for(name).reject { |s| s.silenced?(name) }
330
+ end
331
+
332
+ def listening?(name)
333
+ all_listeners_for(name).any? { |s| !s.silenced?(name) }
334
+ end
335
+
336
+ # This is a sync queue, so there is no waiting.
337
+ def wait
338
+ end
339
+
340
+ module Subscribers # :nodoc:
341
+ def self.new(pattern, listener, monotonic)
342
+ subscriber_class = monotonic ? MonotonicTimed : Timed
343
+
344
+ if listener.respond_to?(:start) && listener.respond_to?(:finish)
345
+ subscriber_class = Evented
346
+ else
347
+ # Doing this to detect a single argument block or callable
348
+ # like `proc { |x| }` vs `proc { |*x| }`, `proc { |**x| }`,
349
+ # or `proc { |x, **y| }`
350
+ procish = listener.respond_to?(:parameters) ? listener : listener.method(:call)
351
+
352
+ if procish.arity == 1 && procish.parameters.length == 1
353
+ subscriber_class = EventObject
354
+ end
355
+ end
356
+
357
+ subscriber_class.new(pattern, listener)
358
+ end
359
+
360
+ class Matcher # :nodoc:
361
+ attr_reader :pattern, :exclusions
362
+
363
+ def self.wrap(pattern)
364
+ if String === pattern
365
+ pattern
366
+ elsif pattern.nil?
367
+ AllMessages.new
368
+ else
369
+ new(pattern)
370
+ end
371
+ end
372
+
373
+ def initialize(pattern)
374
+ @pattern = pattern
375
+ @exclusions = Set.new
376
+ end
377
+
378
+ def unsubscribe!(name)
379
+ exclusions << -name if pattern === name
380
+ end
381
+
382
+ def ===(name)
383
+ pattern === name && !exclusions.include?(name)
384
+ end
385
+
386
+ class AllMessages
387
+ def ===(name)
388
+ true
389
+ end
390
+
391
+ def unsubscribe!(*)
392
+ false
393
+ end
394
+ end
395
+ end
396
+
397
+ class Evented # :nodoc:
398
+ attr_reader :pattern, :delegate, :silenceable
399
+
400
+ def initialize(pattern, delegate)
401
+ @pattern = Matcher.wrap(pattern)
402
+ @delegate = delegate
403
+ @silenceable = delegate.respond_to?(:silenced?)
404
+ @can_publish = delegate.respond_to?(:publish)
405
+ @can_publish_event = delegate.respond_to?(:publish_event)
406
+ end
407
+
408
+ def group_class
409
+ EventedGroup
410
+ end
411
+
412
+ def publish(...)
413
+ if @can_publish
414
+ @delegate.publish(...)
415
+ end
416
+ end
417
+
418
+ def publish_event(event)
419
+ if @can_publish_event
420
+ @delegate.publish_event event
421
+ else
422
+ publish(event.name, event.time, event.end, event.transaction_id, event.payload)
423
+ end
424
+ end
425
+
426
+ def silenced?(name)
427
+ @silenceable && @delegate.silenced?(name)
428
+ end
429
+
430
+ def subscribed_to?(name)
431
+ pattern === name
432
+ end
433
+
434
+ def unsubscribe!(name)
435
+ pattern.unsubscribe!(name)
436
+ end
437
+ end
438
+
439
+ class Timed < Evented # :nodoc:
440
+ def group_class
441
+ TimedGroup
442
+ end
443
+
444
+ def publish(...)
445
+ @delegate.call(...)
446
+ end
447
+ end
448
+
449
+ class MonotonicTimed < Timed # :nodoc:
450
+ def group_class
451
+ MonotonicTimedGroup
452
+ end
453
+ end
454
+
455
+ class EventObject < Evented
456
+ def group_class
457
+ EventObjectGroup
458
+ end
459
+
460
+ def publish_event(event)
461
+ @delegate.call event
462
+ end
463
+ end
464
+ end
465
+ end
466
+ end
467
+ end