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,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ gem "listen", "~> 3.5"
4
+ require "listen"
5
+
6
+ require "pathname"
7
+ require "concurrent/atomic/atomic_boolean"
8
+
9
+ module ActiveSupport
10
+ # Allows you to "listen" to changes in a file system.
11
+ # The evented file updater does not hit disk when checking for updates.
12
+ # Instead, it uses platform-specific file system events to trigger a change
13
+ # in state.
14
+ #
15
+ # The file checker takes an array of files to watch or a hash specifying directories
16
+ # and file extensions to watch. It also takes a block that is called when
17
+ # EventedFileUpdateChecker#execute is run or when EventedFileUpdateChecker#execute_if_updated
18
+ # is run and there have been changes to the file system.
19
+ #
20
+ # Example:
21
+ #
22
+ # checker = ActiveSupport::EventedFileUpdateChecker.new(["/tmp/foo"]) { puts "changed" }
23
+ # checker.updated?
24
+ # # => false
25
+ # checker.execute_if_updated
26
+ # # => nil
27
+ #
28
+ # FileUtils.touch("/tmp/foo")
29
+ #
30
+ # checker.updated?
31
+ # # => true
32
+ # checker.execute_if_updated
33
+ # # => "changed"
34
+ #
35
+ class EventedFileUpdateChecker # :nodoc: all
36
+ def initialize(files, dirs = {}, &block)
37
+ unless block
38
+ raise ArgumentError, "A block is required to initialize an EventedFileUpdateChecker"
39
+ end
40
+
41
+ @block = block
42
+ @core = Core.new(files, dirs)
43
+ ObjectSpace.define_finalizer(self, @core.finalizer)
44
+ end
45
+
46
+ def inspect
47
+ "#<ActiveSupport::EventedFileUpdateChecker:#{object_id} @files=#{@core.files.to_a.inspect}"
48
+ end
49
+
50
+ def updated?
51
+ if @core.restart?
52
+ @core.thread_safely(&:restart)
53
+ @core.updated.make_true
54
+ end
55
+
56
+ @core.updated.true?
57
+ end
58
+
59
+ def execute
60
+ @core.updated.make_false
61
+ @block.call
62
+ end
63
+
64
+ def execute_if_updated
65
+ if updated?
66
+ yield if block_given?
67
+ execute
68
+ true
69
+ end
70
+ end
71
+
72
+ class Core
73
+ attr_reader :updated, :files
74
+
75
+ def initialize(files, dirs)
76
+ gem_paths = Gem.path
77
+ files = files.map { |f| Pathname(f).expand_path }
78
+ files.reject! { |f| f.to_s.start_with?(*gem_paths) }
79
+ @files = files.to_set
80
+
81
+ @dirs = dirs.each_with_object({}) do |(dir, exts), hash|
82
+ next if dir.start_with?(*gem_paths)
83
+ hash[Pathname(dir).expand_path] = Array(exts).map { |ext| ext.to_s.sub(/\A\.?/, ".") }.to_set
84
+ end
85
+
86
+ @common_path = common_path(@dirs.keys)
87
+
88
+ @dtw = directories_to_watch
89
+ @missing = []
90
+
91
+ @updated = Concurrent::AtomicBoolean.new(false)
92
+ @mutex = Mutex.new
93
+
94
+ start
95
+ # inotify / FSEvents file descriptors are inherited on fork, so
96
+ # we need to reopen them otherwise only the parent or the child
97
+ # will be notified.
98
+ # FIXME: this callback is keeping a reference on the instance
99
+ @after_fork = ActiveSupport::ForkTracker.after_fork { start }
100
+ end
101
+
102
+ def finalizer
103
+ proc do
104
+ stop
105
+ ActiveSupport::ForkTracker.unregister(@after_fork)
106
+ end
107
+ end
108
+
109
+ def thread_safely
110
+ @mutex.synchronize do
111
+ yield self
112
+ end
113
+ end
114
+
115
+ def start
116
+ normalize_dirs!
117
+ @dtw, @missing = [*@dtw, *@missing].partition(&:exist?)
118
+ @listener = @dtw.any? ? Listen.to(*@dtw, &method(:changed)) : nil
119
+ @listener&.start
120
+
121
+ # Wait for the listener to be ready to avoid race conditions
122
+ # Unfortunately this isn't quite enough on macOS because the Darwin backend
123
+ # has an extra private thread we can't wait on.
124
+ @listener&.wait_for_state(:processing_events)
125
+ end
126
+
127
+ def stop
128
+ @listener&.stop
129
+ end
130
+
131
+ def restart
132
+ stop
133
+ start
134
+ end
135
+
136
+ def restart?
137
+ @missing.any?(&:exist?)
138
+ end
139
+
140
+ def normalize_dirs!
141
+ @dirs.transform_keys! do |dir|
142
+ dir.exist? ? dir.realpath : dir
143
+ end
144
+ end
145
+
146
+ def changed(modified, added, removed)
147
+ unless @updated.true?
148
+ @updated.make_true if (modified + added + removed).any? { |f| watching?(f) }
149
+ end
150
+ end
151
+
152
+ def watching?(file)
153
+ file = Pathname(file)
154
+
155
+ if @files.member?(file)
156
+ true
157
+ elsif file.directory?
158
+ false
159
+ else
160
+ ext = file.extname
161
+
162
+ file.dirname.ascend do |dir|
163
+ matching = @dirs[dir]
164
+
165
+ if matching && (matching.empty? || matching.include?(ext))
166
+ break true
167
+ elsif dir == @common_path || dir.root?
168
+ break false
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ def directories_to_watch
175
+ dtw = @dirs.keys | @files.map(&:dirname)
176
+ accounted_for = dtw.to_set + Gem.path.map { |path| Pathname(path) }
177
+ dtw.reject { |dir| dir.ascend.drop(1).any? { |parent| accounted_for.include?(parent) } }
178
+ end
179
+
180
+ def common_path(paths)
181
+ paths.map { |path| path.ascend.to_a }.reduce(&:&)&.first
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport::ExecutionContext::TestHelper # :nodoc:
4
+ def before_setup
5
+ ActiveSupport::ExecutionContext.clear
6
+ super
7
+ end
8
+
9
+ def after_teardown
10
+ super
11
+ ActiveSupport::ExecutionContext.clear
12
+ end
13
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module ExecutionContext # :nodoc:
5
+ class Record
6
+ attr_reader :store, :current_attributes_instances
7
+
8
+ def initialize
9
+ @store = {}
10
+ @current_attributes_instances = {}
11
+ @stack = []
12
+ end
13
+
14
+ def push
15
+ @stack << @store << @current_attributes_instances
16
+ @store = {}
17
+ @current_attributes_instances = {}
18
+ self
19
+ end
20
+
21
+ def pop
22
+ @current_attributes_instances = @stack.pop
23
+ @store = @stack.pop
24
+ self
25
+ end
26
+ end
27
+
28
+ @after_change_callbacks = []
29
+
30
+ # Execution context nesting should only legitimately happen during test
31
+ # because the test case itself is wrapped in an executor, and it might call
32
+ # into a controller or job which should be executed with their own fresh context.
33
+ # However in production this should never happen, and for extra safety we make sure to
34
+ # fully clear the state at the end of the request or job cycle.
35
+ @nestable = false
36
+
37
+ class << self
38
+ attr_accessor :nestable
39
+
40
+ def after_change(&block)
41
+ @after_change_callbacks << block
42
+ end
43
+
44
+ # Updates the execution context. If a block is given, it resets the provided keys to their
45
+ # previous value once the block exits.
46
+ def set(**options)
47
+ options.symbolize_keys!
48
+ keys = options.keys
49
+
50
+ store = record.store
51
+
52
+ previous_context = if block_given?
53
+ keys.zip(store.values_at(*keys)).to_h
54
+ end
55
+
56
+ store.merge!(options)
57
+ @after_change_callbacks.each(&:call)
58
+
59
+ if block_given?
60
+ begin
61
+ yield
62
+ ensure
63
+ store.merge!(previous_context)
64
+ @after_change_callbacks.each(&:call)
65
+ end
66
+ end
67
+ end
68
+
69
+ def []=(key, value)
70
+ record.store[key.to_sym] = value
71
+ @after_change_callbacks.each(&:call)
72
+ end
73
+
74
+ def to_h
75
+ record.store.dup
76
+ end
77
+
78
+ def push
79
+ if @nestable
80
+ record.push
81
+ else
82
+ clear
83
+ end
84
+ self
85
+ end
86
+
87
+ def pop
88
+ if @nestable
89
+ record.pop
90
+ else
91
+ clear
92
+ end
93
+ self
94
+ end
95
+
96
+ def clear
97
+ IsolatedExecutionState[:active_support_execution_context] = nil
98
+ end
99
+
100
+ def current_attributes_instances
101
+ record.current_attributes_instances
102
+ end
103
+
104
+ private
105
+ def record
106
+ IsolatedExecutionState[:active_support_execution_context] ||= Record.new
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/error_reporter"
4
+ require "active_support/callbacks"
5
+
6
+ module ActiveSupport
7
+ class ExecutionWrapper
8
+ include ActiveSupport::Callbacks
9
+
10
+ Null = Object.new # :nodoc:
11
+ def Null.complete! # :nodoc:
12
+ end
13
+
14
+ define_callbacks :run
15
+ define_callbacks :complete
16
+
17
+ def self.to_run(*args, &block)
18
+ set_callback(:run, *args, &block)
19
+ end
20
+
21
+ def self.to_complete(*args, &block)
22
+ set_callback(:complete, *args, &block)
23
+ end
24
+
25
+ RunHook = Struct.new(:hook) do # :nodoc:
26
+ def before(target)
27
+ hook_state = target.send(:hook_state)
28
+ hook_state[hook] = hook.run
29
+ end
30
+ end
31
+
32
+ CompleteHook = Struct.new(:hook) do # :nodoc:
33
+ def before(target)
34
+ hook_state = target.send(:hook_state)
35
+ if hook_state.key?(hook)
36
+ hook.complete hook_state[hook]
37
+ end
38
+ end
39
+ alias after before
40
+ end
41
+
42
+ # Register an object to be invoked during both the +run+ and
43
+ # +complete+ steps.
44
+ #
45
+ # +hook.complete+ will be passed the value returned from +hook.run+,
46
+ # and will only be invoked if +run+ has previously been called.
47
+ # (Mostly, this means it won't be invoked if an exception occurs in
48
+ # a preceding +to_run+ block; all ordinary +to_complete+ blocks are
49
+ # invoked in that situation.)
50
+ def self.register_hook(hook, outer: false)
51
+ if outer
52
+ to_run RunHook.new(hook), prepend: true
53
+ to_complete :after, CompleteHook.new(hook)
54
+ else
55
+ to_run RunHook.new(hook)
56
+ to_complete CompleteHook.new(hook)
57
+ end
58
+ end
59
+
60
+ # Run this execution.
61
+ #
62
+ # Returns an instance, whose +complete!+ method *must* be invoked
63
+ # after the work has been performed.
64
+ #
65
+ # Where possible, prefer +wrap+.
66
+ def self.run!(reset: false)
67
+ if reset
68
+ lost_instance = IsolatedExecutionState.delete(active_key)
69
+ lost_instance&.complete!
70
+ else
71
+ return Null if active?
72
+ end
73
+
74
+ new.tap do |instance|
75
+ success = nil
76
+ begin
77
+ instance.run!
78
+ success = true
79
+ ensure
80
+ instance.complete! unless success
81
+ end
82
+ end
83
+ end
84
+
85
+ # Perform the work in the supplied block as an execution.
86
+ def self.wrap(source: "application.active_support")
87
+ return yield if active?
88
+
89
+ instance = run!
90
+ begin
91
+ yield
92
+ rescue Exception => error
93
+ error_reporter&.report(error, handled: false, source: source)
94
+ raise
95
+ ensure
96
+ instance.complete!
97
+ end
98
+ end
99
+
100
+ def self.perform # :nodoc:
101
+ instance = new
102
+ instance.run
103
+ begin
104
+ yield
105
+ ensure
106
+ instance.complete
107
+ end
108
+ end
109
+
110
+ def self.error_reporter # :nodoc:
111
+ ActiveSupport.error_reporter
112
+ end
113
+
114
+ def self.active_key # :nodoc:
115
+ @active_key ||= :"active_execution_wrapper_#{object_id}"
116
+ end
117
+
118
+ def self.active? # :nodoc:
119
+ IsolatedExecutionState.key?(active_key)
120
+ end
121
+
122
+ def run! # :nodoc:
123
+ IsolatedExecutionState[self.class.active_key] = self
124
+ run
125
+ end
126
+
127
+ def run # :nodoc:
128
+ run_callbacks(:run)
129
+ end
130
+
131
+ # Complete this in-flight execution. This method *must* be called
132
+ # exactly once on the result of any call to +run!+.
133
+ #
134
+ # Where possible, prefer +wrap+.
135
+ def complete!
136
+ complete
137
+ ensure
138
+ IsolatedExecutionState.delete(self.class.active_key)
139
+ end
140
+
141
+ def complete # :nodoc:
142
+ run_callbacks(:complete)
143
+ end
144
+
145
+ private
146
+ def hook_state
147
+ @_hook_state ||= {}
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport::Executor::TestHelper # :nodoc:
4
+ def run(...)
5
+ Rails.application.executor.perform { super }
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/execution_wrapper"
4
+
5
+ module ActiveSupport
6
+ class Executor < ExecutionWrapper
7
+ end
8
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/time/calculations"
4
+
5
+ module ActiveSupport
6
+ # = \File Update Checker
7
+ #
8
+ # FileUpdateChecker specifies the API used by \Rails to watch files
9
+ # and control reloading. The API depends on four methods:
10
+ #
11
+ # * +initialize+ which expects two parameters and one block as
12
+ # described below.
13
+ #
14
+ # * +updated?+ which returns a boolean if there were updates in
15
+ # the filesystem or not.
16
+ #
17
+ # * +execute+ which executes the given block on initialization
18
+ # and updates the latest watched files and timestamp.
19
+ #
20
+ # * +execute_if_updated+ which just executes the block if it was updated.
21
+ #
22
+ # After initialization, a call to +execute_if_updated+ must execute
23
+ # the block only if there was really a change in the filesystem.
24
+ #
25
+ # This class is used by \Rails to reload the I18n framework whenever
26
+ # they are changed upon a new request.
27
+ #
28
+ # i18n_reloader = ActiveSupport::FileUpdateChecker.new(paths) do
29
+ # I18n.reload!
30
+ # end
31
+ #
32
+ # ActiveSupport::Reloader.to_prepare do
33
+ # i18n_reloader.execute_if_updated
34
+ # end
35
+ class FileUpdateChecker
36
+ # It accepts two parameters on initialization. The first is an array
37
+ # of files and the second is an optional hash of directories. The hash must
38
+ # have directories as keys and the value is an array of extensions to be
39
+ # watched under that directory.
40
+ #
41
+ # This method must also receive a block that will be called once a path
42
+ # changes. The array of files and list of directories cannot be changed
43
+ # after FileUpdateChecker has been initialized.
44
+ def initialize(files, dirs = {}, &block)
45
+ unless block
46
+ raise ArgumentError, "A block is required to initialize a FileUpdateChecker"
47
+ end
48
+
49
+ gem_paths = Gem.path
50
+ @files = files.reject { |file| File.expand_path(file).start_with?(*gem_paths) }.freeze
51
+
52
+ @globs = compile_glob(dirs)&.reject { |dir| dir.start_with?(*gem_paths) }
53
+
54
+ @block = block
55
+
56
+ @watched = nil
57
+ @updated_at = nil
58
+
59
+ @last_watched = watched
60
+ @last_update_at = updated_at(@last_watched)
61
+ end
62
+
63
+ # Check if any of the entries were updated. If so, the watched and/or
64
+ # updated_at values are cached until the block is executed via +execute+
65
+ # or +execute_if_updated+.
66
+ def updated?
67
+ current_watched = watched
68
+ if @last_watched.size != current_watched.size
69
+ @watched = current_watched
70
+ true
71
+ else
72
+ current_updated_at = updated_at(current_watched)
73
+ if @last_update_at < current_updated_at
74
+ @watched = current_watched
75
+ @updated_at = current_updated_at
76
+ true
77
+ else
78
+ false
79
+ end
80
+ end
81
+ end
82
+
83
+ # Executes the given block and updates the latest watched files and
84
+ # timestamp.
85
+ def execute
86
+ @last_watched = watched
87
+ @last_update_at = updated_at(@last_watched)
88
+ @block.call
89
+ ensure
90
+ @watched = nil
91
+ @updated_at = nil
92
+ end
93
+
94
+ # Execute the block given if updated.
95
+ def execute_if_updated
96
+ if updated?
97
+ yield if block_given?
98
+ execute
99
+ true
100
+ else
101
+ false
102
+ end
103
+ end
104
+
105
+ private
106
+ def watched
107
+ @watched || begin
108
+ all = @files.select { |f| File.exist?(f) }
109
+ all.concat(Dir[*@globs]) if @globs
110
+ all.tap(&:uniq!)
111
+ end
112
+ end
113
+
114
+ def updated_at(paths)
115
+ @updated_at || max_mtime(paths) || Time.at(0)
116
+ end
117
+
118
+ # This method returns the maximum mtime of the files in +paths+, or +nil+
119
+ # if the array is empty.
120
+ #
121
+ # Files with a mtime in the future are ignored. Such abnormal situation
122
+ # can happen for example if the user changes the clock by hand. It is
123
+ # healthy to consider this edge case because with mtimes in the future
124
+ # reloading is not triggered.
125
+ def max_mtime(paths)
126
+ time_now = Time.at(0, Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond), :nanosecond)
127
+ max_mtime = nil
128
+
129
+ # Time comparisons are performed with #compare_without_coercion because
130
+ # AS redefines these operators in a way that is much slower and does not
131
+ # bring any benefit in this particular code.
132
+ #
133
+ # Read t1.compare_without_coercion(t2) < 0 as t1 < t2.
134
+ paths.each do |path|
135
+ mtime = File.mtime(path)
136
+
137
+ next if time_now.compare_without_coercion(mtime) < 0
138
+
139
+ if max_mtime.nil? || max_mtime.compare_without_coercion(mtime) < 0
140
+ max_mtime = mtime
141
+ end
142
+ end
143
+
144
+ max_mtime
145
+ end
146
+
147
+ def compile_glob(hash)
148
+ hash.freeze # Freeze so changes aren't accidentally pushed
149
+ return if hash.empty?
150
+
151
+ hash.map do |key, value|
152
+ "#{escape(key)}/**/*#{compile_ext(value)}"
153
+ end
154
+ end
155
+
156
+ def escape(key)
157
+ key.gsub(",", '\,')
158
+ end
159
+
160
+ def compile_ext(array)
161
+ array = Array(array)
162
+ return if array.empty?
163
+ ".{#{array.join(",")}}"
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module ForkTracker # :nodoc:
5
+ module CoreExt
6
+ def _fork
7
+ pid = super
8
+ if pid == 0
9
+ ForkTracker.after_fork_callback
10
+ end
11
+ pid
12
+ end
13
+ end
14
+
15
+ @pid = Process.pid
16
+ @callbacks = []
17
+
18
+ class << self
19
+ def after_fork_callback
20
+ new_pid = Process.pid
21
+ if @pid != new_pid
22
+ @callbacks.each(&:call)
23
+ @pid = new_pid
24
+ end
25
+ end
26
+
27
+ def hook!
28
+ ::Process.singleton_class.prepend(CoreExt)
29
+ end
30
+
31
+ def after_fork(&block)
32
+ @callbacks << block
33
+ block
34
+ end
35
+
36
+ def unregister(callback)
37
+ @callbacks.delete(callback)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ ActiveSupport::ForkTracker.hook!
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # Returns the currently loaded version of Active Support as a +Gem::Version+.
5
+ def self.gem_version
6
+ Gem::Version.new VERSION::STRING
7
+ end
8
+
9
+ module VERSION
10
+ MAJOR = 8
11
+ MINOR = 1
12
+ TINY = 2
13
+ PRE = nil
14
+
15
+ STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
+ end
17
+ end