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,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module ClassAttribute # :nodoc:
5
+ class << self
6
+ def redefine(owner, name, namespaced_name, value)
7
+ if owner.singleton_class?
8
+ if owner.attached_object.is_a?(Module)
9
+ redefine_method(owner, namespaced_name, private: true) { value }
10
+ else
11
+ redefine_method(owner, name) { value }
12
+ end
13
+ end
14
+
15
+ redefine_method(owner.singleton_class, namespaced_name, private: true) { value }
16
+
17
+ redefine_method(owner.singleton_class, "#{namespaced_name}=", private: true) do |new_value|
18
+ if owner.equal?(self)
19
+ value = new_value
20
+ else
21
+ ::ActiveSupport::ClassAttribute.redefine(self, name, namespaced_name, new_value)
22
+ end
23
+ end
24
+ end
25
+
26
+ def redefine_method(owner, name, private: false, &block)
27
+ owner.silence_redefinition_of_method(name)
28
+ owner.define_method(name, &block)
29
+ owner.send(:private, name) if private
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ class CodeGenerator # :nodoc:
5
+ class MethodSet
6
+ METHOD_CACHES = Hash.new { |h, k| h[k] = Module.new }
7
+
8
+ def initialize(namespace)
9
+ @cache = METHOD_CACHES[namespace]
10
+ @sources = []
11
+ @methods = {}
12
+ @canonical_methods = {}
13
+ end
14
+
15
+ def define_cached_method(canonical_name, as: nil)
16
+ canonical_name = canonical_name.to_sym
17
+ as = (as || canonical_name).to_sym
18
+
19
+ @methods.fetch(as) do
20
+ unless @cache.method_defined?(canonical_name) || @canonical_methods[canonical_name]
21
+ yield @sources
22
+ end
23
+ @canonical_methods[canonical_name] = true
24
+ @methods[as] = canonical_name
25
+ end
26
+ end
27
+
28
+ def apply(owner, path, line)
29
+ unless @sources.empty?
30
+ @cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
31
+ end
32
+ @canonical_methods.clear
33
+
34
+ @methods.each do |as, canonical_name|
35
+ owner.define_method(as, @cache.instance_method(canonical_name))
36
+ end
37
+ end
38
+ end
39
+
40
+ class << self
41
+ def batch(owner, path, line)
42
+ if owner.is_a?(CodeGenerator)
43
+ yield owner
44
+ else
45
+ instance = new(owner, path, line)
46
+ result = yield instance
47
+ instance.execute
48
+ result
49
+ end
50
+ end
51
+ end
52
+
53
+ def initialize(owner, path, line)
54
+ @owner = owner
55
+ @path = path
56
+ @line = line
57
+ @namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
58
+ @sources = []
59
+ end
60
+
61
+ def class_eval
62
+ yield @sources
63
+ end
64
+
65
+ def define_cached_method(canonical_name, namespace:, as: nil, &block)
66
+ @namespaces[namespace].define_cached_method(canonical_name, as: as, &block)
67
+ end
68
+
69
+ def execute
70
+ @namespaces.each_value do |method_set|
71
+ method_set.apply(@owner, @path, @line - 1)
72
+ end
73
+
74
+ unless @sources.empty?
75
+ @owner.class_eval("# frozen_string_literal: true\n" + @sources.join(";"), @path, @line - 1)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # = Active Support \Concern
5
+ #
6
+ # A typical module looks like this:
7
+ #
8
+ # module M
9
+ # def self.included(base)
10
+ # base.extend ClassMethods
11
+ # base.class_eval do
12
+ # scope :disabled, -> { where(disabled: true) }
13
+ # end
14
+ # end
15
+ #
16
+ # module ClassMethods
17
+ # ...
18
+ # end
19
+ # end
20
+ #
21
+ # By using +ActiveSupport::Concern+ the above module could instead be
22
+ # written as:
23
+ #
24
+ # require "active_support/concern"
25
+ #
26
+ # module M
27
+ # extend ActiveSupport::Concern
28
+ #
29
+ # included do
30
+ # scope :disabled, -> { where(disabled: true) }
31
+ # end
32
+ #
33
+ # class_methods do
34
+ # ...
35
+ # end
36
+ # end
37
+ #
38
+ # Moreover, it gracefully handles module dependencies. Given a +Foo+ module
39
+ # and a +Bar+ module which depends on the former, we would typically write the
40
+ # following:
41
+ #
42
+ # module Foo
43
+ # def self.included(base)
44
+ # base.class_eval do
45
+ # def self.method_injected_by_foo
46
+ # ...
47
+ # end
48
+ # end
49
+ # end
50
+ # end
51
+ #
52
+ # module Bar
53
+ # def self.included(base)
54
+ # base.method_injected_by_foo
55
+ # end
56
+ # end
57
+ #
58
+ # class Host
59
+ # include Foo # We need to include this dependency for Bar
60
+ # include Bar # Bar is the module that Host really needs
61
+ # end
62
+ #
63
+ # But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We
64
+ # could try to hide these from +Host+ directly including +Foo+ in +Bar+:
65
+ #
66
+ # module Bar
67
+ # include Foo
68
+ # def self.included(base)
69
+ # base.method_injected_by_foo
70
+ # end
71
+ # end
72
+ #
73
+ # class Host
74
+ # include Bar
75
+ # end
76
+ #
77
+ # Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt>
78
+ # is the +Bar+ module, not the +Host+ class. With +ActiveSupport::Concern+,
79
+ # module dependencies are properly resolved:
80
+ #
81
+ # require "active_support/concern"
82
+ #
83
+ # module Foo
84
+ # extend ActiveSupport::Concern
85
+ # included do
86
+ # def self.method_injected_by_foo
87
+ # ...
88
+ # end
89
+ # end
90
+ # end
91
+ #
92
+ # module Bar
93
+ # extend ActiveSupport::Concern
94
+ # include Foo
95
+ #
96
+ # included do
97
+ # self.method_injected_by_foo
98
+ # end
99
+ # end
100
+ #
101
+ # class Host
102
+ # include Bar # It works, now Bar takes care of its dependencies
103
+ # end
104
+ #
105
+ # === Prepending concerns
106
+ #
107
+ # Just like <tt>include</tt>, concerns also support <tt>prepend</tt> with a corresponding
108
+ # <tt>prepended do</tt> callback. <tt>module ClassMethods</tt> or <tt>class_methods do</tt> are
109
+ # prepended as well.
110
+ #
111
+ # <tt>prepend</tt> is also used for any dependencies.
112
+ module Concern
113
+ class MultipleIncludedBlocks < StandardError # :nodoc:
114
+ def initialize
115
+ super "Cannot define multiple 'included' blocks for a Concern"
116
+ end
117
+ end
118
+
119
+ class MultiplePrependBlocks < StandardError # :nodoc:
120
+ def initialize
121
+ super "Cannot define multiple 'prepended' blocks for a Concern"
122
+ end
123
+ end
124
+
125
+ def self.extended(base) # :nodoc:
126
+ base.instance_variable_set(:@_dependencies, [])
127
+ end
128
+
129
+ def append_features(base) # :nodoc:
130
+ if base.instance_variable_defined?(:@_dependencies)
131
+ base.instance_variable_get(:@_dependencies) << self
132
+ false
133
+ else
134
+ return false if base < self
135
+ @_dependencies.each { |dep| base.include(dep) }
136
+ super
137
+ base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
138
+ base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
139
+ end
140
+ end
141
+
142
+ def prepend_features(base) # :nodoc:
143
+ if base.instance_variable_defined?(:@_dependencies)
144
+ base.instance_variable_get(:@_dependencies).unshift self
145
+ false
146
+ else
147
+ return false if base < self
148
+ @_dependencies.each { |dep| base.prepend(dep) }
149
+ super
150
+ base.singleton_class.prepend const_get(:ClassMethods) if const_defined?(:ClassMethods)
151
+ base.class_eval(&@_prepended_block) if instance_variable_defined?(:@_prepended_block)
152
+ end
153
+ end
154
+
155
+ # Evaluate given block in context of base class,
156
+ # so that you can write class macros here.
157
+ # When you define more than one +included+ block, it raises an exception.
158
+ def included(base = nil, &block)
159
+ if base.nil?
160
+ if instance_variable_defined?(:@_included_block)
161
+ if @_included_block.source_location != block.source_location
162
+ raise MultipleIncludedBlocks
163
+ end
164
+ else
165
+ @_included_block = block
166
+ end
167
+ else
168
+ super
169
+ end
170
+ end
171
+
172
+ # Evaluate given block in context of base class,
173
+ # so that you can write class macros here.
174
+ # When you define more than one +prepended+ block, it raises an exception.
175
+ def prepended(base = nil, &block)
176
+ if base.nil?
177
+ if instance_variable_defined?(:@_prepended_block)
178
+ if @_prepended_block.source_location != block.source_location
179
+ raise MultiplePrependBlocks
180
+ end
181
+ else
182
+ @_prepended_block = block
183
+ end
184
+ else
185
+ super
186
+ end
187
+ end
188
+
189
+ # Define class methods from given block.
190
+ # You can define private class methods as well.
191
+ #
192
+ # module Example
193
+ # extend ActiveSupport::Concern
194
+ #
195
+ # class_methods do
196
+ # def foo; puts 'foo'; end
197
+ #
198
+ # private
199
+ # def bar; puts 'bar'; end
200
+ # end
201
+ # end
202
+ #
203
+ # class Buzz
204
+ # include Example
205
+ # end
206
+ #
207
+ # Buzz.foo # => "foo"
208
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
209
+ def class_methods(&class_methods_module_definition)
210
+ mod = const_defined?(:ClassMethods, false) ?
211
+ const_get(:ClassMethods) :
212
+ const_set(:ClassMethods, Module.new)
213
+
214
+ mod.module_eval(&class_methods_module_definition)
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
5
+ module ActiveSupport
6
+ module Concurrency
7
+ # A monitor that will permit dependency loading while blocked waiting for
8
+ # the lock.
9
+ LoadInterlockAwareMonitor = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
10
+ "ActiveSupport::Concurrency::LoadInterlockAwareMonitor",
11
+ "::Monitor",
12
+ ActiveSupport.deprecator,
13
+ message: "ActiveSupport::Concurrency::LoadInterlockAwareMonitor is deprecated and will be " \
14
+ "removed in Rails 9.0. Use Monitor directly instead, as the loading interlock is " \
15
+ "no longer used."
16
+ )
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Concurrency
5
+ module NullLock # :nodoc:
6
+ extend self
7
+
8
+ def synchronize
9
+ yield
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,225 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
5
+ module ActiveSupport
6
+ module Concurrency
7
+ # A share/exclusive lock, otherwise known as a read/write lock.
8
+ #
9
+ # https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock
10
+ class ShareLock
11
+ include MonitorMixin
12
+
13
+ # We track Thread objects, instead of just using counters, because
14
+ # we need exclusive locks to be reentrant, and we need to be able
15
+ # to upgrade share locks to exclusive.
16
+
17
+ def raw_state # :nodoc:
18
+ synchronize do
19
+ threads = @sleeping.keys | @sharing.keys | @waiting.keys
20
+ threads |= [@exclusive_thread] if @exclusive_thread
21
+
22
+ data = {}
23
+
24
+ threads.each do |thread|
25
+ purpose, compatible = @waiting[thread]
26
+
27
+ data[thread] = {
28
+ thread: thread,
29
+ sharing: @sharing[thread],
30
+ exclusive: @exclusive_thread == thread,
31
+ purpose: purpose,
32
+ compatible: compatible,
33
+ waiting: !!@waiting[thread],
34
+ sleeper: @sleeping[thread],
35
+ }
36
+ end
37
+
38
+ # NB: Yields while holding our *internal* synchronize lock,
39
+ # which is supposed to be used only for a few instructions at
40
+ # a time. This allows the caller to inspect additional state
41
+ # without things changing out from underneath, but would have
42
+ # disastrous effects upon normal operation. Fortunately, this
43
+ # method is only intended to be called when things have
44
+ # already gone wrong.
45
+ yield data
46
+ end
47
+ end
48
+
49
+ def initialize
50
+ super()
51
+
52
+ @cv = new_cond
53
+
54
+ @sharing = Hash.new(0)
55
+ @waiting = {}
56
+ @sleeping = {}
57
+ @exclusive_thread = nil
58
+ @exclusive_depth = 0
59
+ end
60
+
61
+ # Returns false if +no_wait+ is set and the lock is not
62
+ # immediately available. Otherwise, returns true after the lock
63
+ # has been acquired.
64
+ #
65
+ # +purpose+ and +compatible+ work together; while this thread is
66
+ # waiting for the exclusive lock, it will yield its share (if any)
67
+ # to any other attempt whose +purpose+ appears in this attempt's
68
+ # +compatible+ list. This allows a "loose" upgrade, which, being
69
+ # less strict, prevents some classes of deadlocks.
70
+ #
71
+ # For many resources, loose upgrades are sufficient: if a thread
72
+ # is awaiting a lock, it is not running any other code. With
73
+ # +purpose+ matching, it is possible to yield only to other
74
+ # threads whose activity will not interfere.
75
+ def start_exclusive(purpose: nil, compatible: [], no_wait: false)
76
+ synchronize do
77
+ unless @exclusive_thread == Thread.current
78
+ if busy_for_exclusive?(purpose)
79
+ return false if no_wait
80
+
81
+ yield_shares(purpose: purpose, compatible: compatible, block_share: true) do
82
+ wait_for(:start_exclusive) { busy_for_exclusive?(purpose) }
83
+ end
84
+ end
85
+ @exclusive_thread = Thread.current
86
+ end
87
+ @exclusive_depth += 1
88
+
89
+ true
90
+ end
91
+ end
92
+
93
+ # Relinquish the exclusive lock. Must only be called by the thread
94
+ # that called start_exclusive (and currently holds the lock).
95
+ def stop_exclusive(compatible: [])
96
+ synchronize do
97
+ raise "invalid unlock" if @exclusive_thread != Thread.current
98
+
99
+ @exclusive_depth -= 1
100
+ if @exclusive_depth == 0
101
+ @exclusive_thread = nil
102
+
103
+ if eligible_waiters?(compatible)
104
+ yield_shares(compatible: compatible, block_share: true) do
105
+ wait_for(:stop_exclusive) { @exclusive_thread || eligible_waiters?(compatible) }
106
+ end
107
+ end
108
+ @cv.broadcast
109
+ end
110
+ end
111
+ end
112
+
113
+ def start_sharing
114
+ synchronize do
115
+ if @sharing[Thread.current] > 0 || @exclusive_thread == Thread.current
116
+ # We already hold a lock; nothing to wait for
117
+ elsif @waiting[Thread.current]
118
+ # We're nested inside a +yield_shares+ call: we'll resume as
119
+ # soon as there isn't an exclusive lock in our way
120
+ wait_for(:start_sharing) { @exclusive_thread }
121
+ else
122
+ # This is an initial / outermost share call: any outstanding
123
+ # requests for an exclusive lock get to go first
124
+ wait_for(:start_sharing) { busy_for_sharing?(false) }
125
+ end
126
+ @sharing[Thread.current] += 1
127
+ end
128
+ end
129
+
130
+ def stop_sharing
131
+ synchronize do
132
+ if @sharing[Thread.current] > 1
133
+ @sharing[Thread.current] -= 1
134
+ else
135
+ @sharing.delete Thread.current
136
+ @cv.broadcast
137
+ end
138
+ end
139
+ end
140
+
141
+ # Execute the supplied block while holding the Exclusive lock. If
142
+ # +no_wait+ is set and the lock is not immediately available,
143
+ # returns +nil+ without yielding. Otherwise, returns the result of
144
+ # the block.
145
+ #
146
+ # See +start_exclusive+ for other options.
147
+ def exclusive(purpose: nil, compatible: [], after_compatible: [], no_wait: false)
148
+ if start_exclusive(purpose: purpose, compatible: compatible, no_wait: no_wait)
149
+ begin
150
+ yield
151
+ ensure
152
+ stop_exclusive(compatible: after_compatible)
153
+ end
154
+ end
155
+ end
156
+
157
+ # Execute the supplied block while holding the Share lock.
158
+ def sharing
159
+ start_sharing
160
+ begin
161
+ yield
162
+ ensure
163
+ stop_sharing
164
+ end
165
+ end
166
+
167
+ # Temporarily give up all held Share locks while executing the
168
+ # supplied block, allowing any +compatible+ exclusive lock request
169
+ # to proceed.
170
+ def yield_shares(purpose: nil, compatible: [], block_share: false)
171
+ loose_shares = previous_wait = nil
172
+ synchronize do
173
+ if loose_shares = @sharing.delete(Thread.current)
174
+ if previous_wait = @waiting[Thread.current]
175
+ purpose = nil unless purpose == previous_wait[0]
176
+ compatible &= previous_wait[1]
177
+ end
178
+ compatible |= [false] unless block_share
179
+ @waiting[Thread.current] = [purpose, compatible]
180
+ end
181
+
182
+ @cv.broadcast
183
+ end
184
+
185
+ begin
186
+ yield
187
+ ensure
188
+ synchronize do
189
+ wait_for(:yield_shares) { @exclusive_thread && @exclusive_thread != Thread.current }
190
+
191
+ if previous_wait
192
+ @waiting[Thread.current] = previous_wait
193
+ else
194
+ @waiting.delete Thread.current
195
+ end
196
+ @sharing[Thread.current] = loose_shares if loose_shares
197
+ end
198
+ end
199
+ end
200
+
201
+ private
202
+ # Must be called within synchronize
203
+ def busy_for_exclusive?(purpose)
204
+ busy_for_sharing?(purpose) ||
205
+ @sharing.size > (@sharing[Thread.current] > 0 ? 1 : 0)
206
+ end
207
+
208
+ def busy_for_sharing?(purpose)
209
+ (@exclusive_thread && @exclusive_thread != Thread.current) ||
210
+ @waiting.any? { |t, (_, c)| t != Thread.current && !c.include?(purpose) }
211
+ end
212
+
213
+ def eligible_waiters?(compatible)
214
+ @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
215
+ end
216
+
217
+ def wait_for(method, &block)
218
+ @sleeping[Thread.current] = method
219
+ @cv.wait_while(&block)
220
+ ensure
221
+ @sleeping.delete Thread.current
222
+ end
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Concurrency
5
+ class ThreadMonitor # :nodoc:
6
+ EXCEPTION_NEVER = { Exception => :never }.freeze
7
+ EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
8
+ private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
9
+
10
+ def initialize
11
+ @owner = nil
12
+ @count = 0
13
+ @mutex = Mutex.new
14
+ end
15
+
16
+ def synchronize(&block)
17
+ Thread.handle_interrupt(EXCEPTION_NEVER) do
18
+ mon_enter
19
+
20
+ begin
21
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
22
+ ensure
23
+ mon_exit
24
+ end
25
+ end
26
+ end
27
+
28
+ private
29
+ def mon_try_enter
30
+ if @owner != Thread.current
31
+ return false unless @mutex.try_lock
32
+ @owner = Thread.current
33
+ end
34
+ @count += 1
35
+ end
36
+
37
+ def mon_enter
38
+ @mutex.lock if @owner != Thread.current
39
+ @owner = Thread.current
40
+ @count += 1
41
+ end
42
+
43
+ def mon_exit
44
+ unless @owner == Thread.current
45
+ raise ThreadError, "current thread not owner"
46
+ end
47
+
48
+ @count -= 1
49
+ return unless @count == 0
50
+ @owner = nil
51
+ @mutex.unlock
52
+ end
53
+ end
54
+ end
55
+ end