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,288 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "dalli"
5
+ rescue LoadError => e
6
+ warn "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
7
+ raise e
8
+ end
9
+
10
+ require "connection_pool"
11
+ require "delegate"
12
+ require "active_support/core_ext/enumerable"
13
+ require "active_support/core_ext/array/extract_options"
14
+ require "active_support/core_ext/numeric/time"
15
+
16
+ module ActiveSupport
17
+ module Cache
18
+ # = Memcached \Cache \Store
19
+ #
20
+ # A cache store implementation which stores data in Memcached:
21
+ # https://memcached.org
22
+ #
23
+ # This is currently the most popular cache store for production websites.
24
+ #
25
+ # Special features:
26
+ # - Clustering and load balancing. One can specify multiple memcached servers,
27
+ # and +MemCacheStore+ will load balance between all available servers. If a
28
+ # server goes down, then +MemCacheStore+ will ignore it until it comes back up.
29
+ #
30
+ # +MemCacheStore+ implements the Strategy::LocalCache strategy which
31
+ # implements an in-memory cache inside of a block.
32
+ class MemCacheStore < Store
33
+ # These options represent behavior overridden by this implementation and should
34
+ # not be allowed to get down to the Dalli client
35
+ OVERRIDDEN_OPTIONS = UNIVERSAL_OPTIONS
36
+
37
+ # Advertise cache versioning support.
38
+ def self.supports_cache_versioning?
39
+ true
40
+ end
41
+
42
+ prepend Strategy::LocalCache
43
+
44
+ ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
45
+
46
+ # Creates a new Dalli::Client instance with specified addresses and options.
47
+ # If no addresses are provided, we give nil to Dalli::Client, so it uses its fallbacks:
48
+ # - ENV["MEMCACHE_SERVERS"] (if defined)
49
+ # - "127.0.0.1:11211" (otherwise)
50
+ #
51
+ # ActiveSupport::Cache::MemCacheStore.build_mem_cache
52
+ # # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
53
+ # ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
54
+ # # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
55
+ def self.build_mem_cache(*addresses) # :nodoc:
56
+ addresses = addresses.flatten
57
+ options = addresses.extract_options!
58
+ addresses = nil if addresses.compact.empty?
59
+ pool_options = retrieve_pool_options(options)
60
+
61
+ if pool_options
62
+ ConnectionPool.new(**pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
63
+ else
64
+ Dalli::Client.new(addresses, options)
65
+ end
66
+ end
67
+
68
+ # Creates a new +MemCacheStore+ object, with the given memcached server
69
+ # addresses. Each address is either a host name, or a host-with-port string
70
+ # in the form of "host_name:port". For example:
71
+ #
72
+ # ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
73
+ #
74
+ # If no addresses are provided, but <tt>ENV['MEMCACHE_SERVERS']</tt> is defined, it will be used instead. Otherwise,
75
+ # +MemCacheStore+ will connect to localhost:11211 (the default memcached port).
76
+ def initialize(*addresses)
77
+ addresses = addresses.flatten
78
+ options = addresses.extract_options!
79
+ if options.key?(:cache_nils)
80
+ options[:skip_nil] = !options.delete(:cache_nils)
81
+ end
82
+ options[:max_key_size] ||= MAX_KEY_SIZE
83
+ super(options)
84
+
85
+ unless [String, Dalli::Client, NilClass].include?(addresses.first.class)
86
+ raise ArgumentError, "First argument must be an empty array, address, or array of addresses."
87
+ end
88
+
89
+ @mem_cache_options = options.dup
90
+ # The value "compress: false" prevents duplicate compression within Dalli.
91
+ @mem_cache_options[:compress] = false
92
+ (OVERRIDDEN_OPTIONS - %i(compress)).each { |name| @mem_cache_options.delete(name) }
93
+ @data = self.class.build_mem_cache(*(addresses + [@mem_cache_options]))
94
+ end
95
+
96
+ def inspect
97
+ instance = @data || @mem_cache_options
98
+ "#<#{self.class} options=#{options.inspect} mem_cache=#{instance.inspect}>"
99
+ end
100
+
101
+ ##
102
+ # :method: write
103
+ # :call-seq: write(name, value, options = nil)
104
+ #
105
+ # Behaves the same as ActiveSupport::Cache::Store#write, but supports
106
+ # additional options specific to memcached.
107
+ #
108
+ # ==== Additional Options
109
+ #
110
+ # * <tt>raw: true</tt> - Sends the value directly to the server as raw
111
+ # bytes. The value must be a string or number. You can use memcached
112
+ # direct operations like +increment+ and +decrement+ only on raw values.
113
+
114
+ # Increment a cached integer value using the memcached incr atomic operator.
115
+ # Returns the updated value.
116
+ #
117
+ # If the key is unset or has expired, it will be set to +amount+:
118
+ #
119
+ # cache.increment("foo") # => 1
120
+ # cache.increment("bar", 100) # => 100
121
+ #
122
+ # To set a specific value, call #write passing <tt>raw: true</tt>:
123
+ #
124
+ # cache.write("baz", 5, raw: true)
125
+ # cache.increment("baz") # => 6
126
+ #
127
+ # Incrementing a non-numeric value, or a value written without
128
+ # <tt>raw: true</tt>, will fail and return +nil+.
129
+ #
130
+ # To read the value later, call #read_counter:
131
+ #
132
+ # cache.increment("baz") # => 7
133
+ # cache.read_counter("baz") # 7
134
+ def increment(name, amount = 1, options = nil)
135
+ options = merged_options(options)
136
+ key = normalize_key(name, options)
137
+
138
+ instrument(:increment, key, amount: amount) do
139
+ rescue_error_with nil do
140
+ @data.with { |c| c.incr(key, amount, options[:expires_in], amount) }
141
+ end
142
+ end
143
+ end
144
+
145
+ # Decrement a cached integer value using the memcached decr atomic operator.
146
+ # Returns the updated value.
147
+ #
148
+ # If the key is unset or has expired, it will be set to 0. Memcached
149
+ # does not support negative counters.
150
+ #
151
+ # cache.decrement("foo") # => 0
152
+ #
153
+ # To set a specific value, call #write passing <tt>raw: true</tt>:
154
+ #
155
+ # cache.write("baz", 5, raw: true)
156
+ # cache.decrement("baz") # => 4
157
+ #
158
+ # Decrementing a non-numeric value, or a value written without
159
+ # <tt>raw: true</tt>, will fail and return +nil+.
160
+ #
161
+ # To read the value later, call #read_counter:
162
+ #
163
+ # cache.decrement("baz") # => 3
164
+ # cache.read_counter("baz") # 3
165
+ def decrement(name, amount = 1, options = nil)
166
+ options = merged_options(options)
167
+ key = normalize_key(name, options)
168
+
169
+ instrument(:decrement, key, amount: amount) do
170
+ rescue_error_with nil do
171
+ @data.with { |c| c.decr(key, amount, options[:expires_in], 0) }
172
+ end
173
+ end
174
+ end
175
+
176
+ # Clear the entire cache on all memcached servers. This method should
177
+ # be used with care when shared cache is being used.
178
+ def clear(options = nil)
179
+ rescue_error_with(nil) { @data.with { |c| c.flush_all } }
180
+ end
181
+
182
+ # Get the statistics from the memcached servers.
183
+ def stats
184
+ @data.with { |c| c.stats }
185
+ end
186
+
187
+ private
188
+ # Read an entry from the cache.
189
+ def read_entry(key, **options)
190
+ deserialize_entry(read_serialized_entry(key, **options), **options)
191
+ end
192
+
193
+ def read_serialized_entry(key, **options)
194
+ rescue_error_with(nil) do
195
+ @data.with { |c| c.get(key, options) }
196
+ end
197
+ end
198
+
199
+ # Write an entry to the cache.
200
+ def write_entry(key, entry, **options)
201
+ write_serialized_entry(key, serialize_entry(entry, **options), **options)
202
+ end
203
+
204
+ def write_serialized_entry(key, payload, **options)
205
+ method = options[:unless_exist] ? :add : :set
206
+ expires_in = options[:expires_in].to_i
207
+ if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
208
+ # Set the memcache expire a few minutes in the future to support race condition ttls on read
209
+ expires_in += 5.minutes
210
+ end
211
+ rescue_error_with nil do
212
+ # Don't pass compress option to Dalli since we are already dealing with compression.
213
+ options.delete(:compress)
214
+ @data.with { |c| !!c.send(method, key, payload, expires_in, **options) }
215
+ end
216
+ end
217
+
218
+ # Reads multiple entries from the cache implementation.
219
+ def read_multi_entries(names, **options)
220
+ keys_to_names = names.index_by { |name| normalize_key(name, options) }
221
+
222
+ rescue_error_with({}) do
223
+ raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
224
+
225
+ values = {}
226
+
227
+ raw_values.each do |key, value|
228
+ entry = deserialize_entry(value, raw: options[:raw])
229
+
230
+ unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
231
+ begin
232
+ values[keys_to_names[key]] = entry.value
233
+ rescue DeserializationError
234
+ end
235
+ end
236
+ end
237
+
238
+ values
239
+ end
240
+ end
241
+
242
+ # Delete an entry from the cache.
243
+ def delete_entry(key, **options)
244
+ rescue_error_with(false) { @data.with { |c| c.delete(key) } }
245
+ end
246
+
247
+ def serialize_entry(entry, raw: false, **options)
248
+ if raw
249
+ entry.value.to_s
250
+ else
251
+ super(entry, raw: raw, **options)
252
+ end
253
+ end
254
+
255
+ # Memcache keys are binaries. So we need to force their encoding to binary
256
+ # before applying the regular expression to ensure we are escaping all
257
+ # characters properly.
258
+ def normalize_key(key, options)
259
+ key = expand_and_namespace_key(key, options)
260
+ if key
261
+ key = key.dup.force_encoding(Encoding::ASCII_8BIT)
262
+ key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
263
+ end
264
+ truncate_key(key)
265
+ end
266
+
267
+ def deserialize_entry(payload, raw: false, **)
268
+ if payload && raw
269
+ Entry.new(payload)
270
+ else
271
+ super(payload)
272
+ end
273
+ end
274
+
275
+ def rescue_error_with(fallback)
276
+ yield
277
+ rescue Dalli::DalliError, ConnectionPool::Error, ConnectionPool::TimeoutError => error
278
+ logger.error("DalliError (#{error}): #{error.message}") if logger
279
+ ActiveSupport.error_reporter&.report(
280
+ error,
281
+ severity: :warning,
282
+ source: "mem_cache_store.active_support",
283
+ )
284
+ fallback
285
+ end
286
+ end
287
+ end
288
+ end
@@ -0,0 +1,264 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "monitor"
4
+
5
+ module ActiveSupport
6
+ module Cache
7
+ # = Memory \Cache \Store
8
+ #
9
+ # A cache store implementation which stores everything into memory in the
10
+ # same process. If you're running multiple Ruby on \Rails server processes
11
+ # (which is the case if you're using Phusion Passenger or puma clustered mode),
12
+ # then this means that \Rails server process instances won't be able
13
+ # to share cache data with each other and this may not be the most
14
+ # appropriate cache in that scenario.
15
+ #
16
+ # This cache has a bounded size specified by the +:size+ options to the
17
+ # initializer (default is 32Mb). When the cache exceeds the allotted size,
18
+ # a cleanup will occur which tries to prune the cache down to three quarters
19
+ # of the maximum size by removing the least recently used entries.
20
+ #
21
+ # Unlike other Cache store implementations, +MemoryStore+ does not compress
22
+ # values by default. +MemoryStore+ does not benefit from compression as much
23
+ # as other Store implementations, as it does not send data over a network.
24
+ # However, when compression is enabled, it still pays the full cost of
25
+ # compression in terms of cpu use.
26
+ #
27
+ # +MemoryStore+ is thread-safe.
28
+ class MemoryStore < Store
29
+ prepend Strategy::LocalCache
30
+
31
+ module DupCoder # :nodoc:
32
+ extend self
33
+
34
+ def dump(entry)
35
+ if entry.value && entry.value != true && !entry.value.is_a?(Numeric)
36
+ Cache::Entry.new(dump_value(entry.value), expires_at: entry.expires_at, version: entry.version)
37
+ else
38
+ entry
39
+ end
40
+ end
41
+
42
+ def dump_compressed(entry, threshold)
43
+ compressed_entry = entry.compressed(threshold)
44
+ compressed_entry.compressed? ? compressed_entry : dump(entry)
45
+ end
46
+
47
+ def load(entry)
48
+ if !entry.compressed? && entry.value.is_a?(String)
49
+ Cache::Entry.new(load_value(entry.value), expires_at: entry.expires_at, version: entry.version)
50
+ else
51
+ entry
52
+ end
53
+ end
54
+
55
+ private
56
+ MARSHAL_SIGNATURE = "\x04\x08".b.freeze
57
+
58
+ def dump_value(value)
59
+ if value.is_a?(String) && !value.start_with?(MARSHAL_SIGNATURE)
60
+ value.dup
61
+ else
62
+ Marshal.dump(value)
63
+ end
64
+ end
65
+
66
+ def load_value(string)
67
+ if string.start_with?(MARSHAL_SIGNATURE)
68
+ Marshal.load(string)
69
+ else
70
+ string.dup
71
+ end
72
+ end
73
+ end
74
+
75
+ def initialize(options = nil)
76
+ options ||= {}
77
+ options[:coder] = DupCoder unless options.key?(:coder) || options.key?(:serializer)
78
+ # Disable compression by default.
79
+ options[:compress] ||= false
80
+ super(options)
81
+ @data = {}
82
+ @max_size = options[:size] || 32.megabytes
83
+ @max_prune_time = options[:max_prune_time] || 2
84
+ @cache_size = 0
85
+ @monitor = Monitor.new
86
+ @pruning = false
87
+ end
88
+
89
+ # Advertise cache versioning support.
90
+ def self.supports_cache_versioning?
91
+ true
92
+ end
93
+
94
+ # Delete all data stored in a given cache store.
95
+ def clear(options = nil)
96
+ synchronize do
97
+ @data.clear
98
+ @cache_size = 0
99
+ end
100
+ end
101
+
102
+ # Preemptively iterates through all stored keys and removes the ones which have expired.
103
+ def cleanup(options = nil)
104
+ options = merged_options(options)
105
+ _instrument(:cleanup, size: @data.size) do
106
+ keys = synchronize { @data.keys }
107
+ keys.each do |key|
108
+ entry = @data[key]
109
+ delete_entry(key, **options) if entry && entry.expired?
110
+ end
111
+ end
112
+ end
113
+
114
+ # To ensure entries fit within the specified memory prune the cache by removing the least
115
+ # recently accessed entries.
116
+ def prune(target_size, max_time = nil)
117
+ return if pruning?
118
+ @pruning = true
119
+ begin
120
+ start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
121
+ cleanup
122
+ instrument(:prune, target_size, from: @cache_size) do
123
+ keys = synchronize { @data.keys }
124
+ keys.each do |key|
125
+ delete_entry(key, **options)
126
+ return if @cache_size <= target_size || (max_time && Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time > max_time)
127
+ end
128
+ end
129
+ ensure
130
+ @pruning = false
131
+ end
132
+ end
133
+
134
+ # Returns true if the cache is currently being pruned.
135
+ def pruning?
136
+ @pruning
137
+ end
138
+
139
+ # Increment a cached integer value. Returns the updated value.
140
+ #
141
+ # If the key is unset, it will be set to +amount+:
142
+ #
143
+ # cache.increment("foo") # => 1
144
+ # cache.increment("bar", 100) # => 100
145
+ #
146
+ # To set a specific value, call #write:
147
+ #
148
+ # cache.write("baz", 5)
149
+ # cache.increment("baz") # => 6
150
+ #
151
+ def increment(name, amount = 1, **options)
152
+ instrument(:increment, name, amount: amount) do
153
+ modify_value(name, amount, **options)
154
+ end
155
+ end
156
+
157
+ # Decrement a cached integer value. Returns the updated value.
158
+ #
159
+ # If the key is unset or has expired, it will be set to +-amount+.
160
+ #
161
+ # cache.decrement("foo") # => -1
162
+ #
163
+ # To set a specific value, call #write:
164
+ #
165
+ # cache.write("baz", 5)
166
+ # cache.decrement("baz") # => 4
167
+ #
168
+ def decrement(name, amount = 1, **options)
169
+ instrument(:decrement, name, amount: amount) do
170
+ modify_value(name, -amount, **options)
171
+ end
172
+ end
173
+
174
+ # Deletes cache entries if the cache key matches a given pattern.
175
+ def delete_matched(matcher, options = nil)
176
+ options = merged_options(options)
177
+ matcher = key_matcher(matcher, options)
178
+
179
+ instrument(:delete_matched, matcher.inspect) do
180
+ keys = synchronize { @data.keys }
181
+ keys.each do |key|
182
+ delete_entry(key, **options) if key.match(matcher)
183
+ end
184
+ end
185
+ end
186
+
187
+ def inspect # :nodoc:
188
+ "#<#{self.class.name} entries=#{@data.size}, size=#{@cache_size}, options=#{@options.inspect}>"
189
+ end
190
+
191
+ # Synchronize calls to the cache. This should be called wherever the underlying cache implementation
192
+ # is not thread safe.
193
+ def synchronize(&block) # :nodoc:
194
+ @monitor.synchronize(&block)
195
+ end
196
+
197
+ private
198
+ PER_ENTRY_OVERHEAD = 240
199
+
200
+ def cached_size(key, payload)
201
+ key.to_s.bytesize + payload.bytesize + PER_ENTRY_OVERHEAD
202
+ end
203
+
204
+ def read_entry(key, **options)
205
+ entry = nil
206
+ synchronize do
207
+ payload = @data.delete(key)
208
+ if payload
209
+ @data[key] = payload
210
+ entry = deserialize_entry(payload)
211
+ end
212
+ end
213
+ entry
214
+ end
215
+
216
+ def write_entry(key, entry, **options)
217
+ payload = serialize_entry(entry, **options)
218
+ synchronize do
219
+ return false if options[:unless_exist] && exist?(key, namespace: nil)
220
+
221
+ old_payload = @data[key]
222
+ if old_payload
223
+ @cache_size -= (old_payload.bytesize - payload.bytesize)
224
+ else
225
+ @cache_size += cached_size(key, payload)
226
+ end
227
+ @data[key] = payload
228
+ prune(@max_size * 0.75, @max_prune_time) if @cache_size > @max_size
229
+ true
230
+ end
231
+ end
232
+
233
+ def delete_entry(key, **options)
234
+ synchronize do
235
+ payload = @data.delete(key)
236
+ @cache_size -= cached_size(key, payload) if payload
237
+ !!payload
238
+ end
239
+ end
240
+
241
+ # Modifies the amount of an integer value that is stored in the cache.
242
+ # If the key is not found it is created and set to +amount+.
243
+ def modify_value(name, amount, **options)
244
+ options = merged_options(options)
245
+ key = normalize_key(name, options)
246
+ version = normalize_version(name, options)
247
+
248
+ synchronize do
249
+ entry = read_entry(key, **options)
250
+
251
+ if !entry || entry.expired? || entry.mismatched?(version)
252
+ write(name, Integer(amount), options)
253
+ amount
254
+ else
255
+ num = entry.value.to_i + amount
256
+ entry = Entry.new(num, expires_at: entry.expires_at, version: entry.version)
257
+ write_entry(key, entry)
258
+ num
259
+ end
260
+ end
261
+ end
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Cache
5
+ # = Null \Cache \Store
6
+ #
7
+ # A cache store implementation which doesn't actually store anything. Useful in
8
+ # development and test environments where you don't want caching turned on but
9
+ # need to go through the caching interface.
10
+ #
11
+ # This cache does implement the local cache strategy, so values will actually
12
+ # be cached inside blocks that utilize this strategy. See
13
+ # ActiveSupport::Cache::Strategy::LocalCache for more details.
14
+ class NullStore < Store
15
+ prepend Strategy::LocalCache
16
+
17
+ # Advertise cache versioning support.
18
+ def self.supports_cache_versioning?
19
+ true
20
+ end
21
+
22
+ def clear(options = nil)
23
+ end
24
+
25
+ def cleanup(options = nil)
26
+ end
27
+
28
+ def increment(name, amount = 1, **options)
29
+ end
30
+
31
+ def decrement(name, amount = 1, **options)
32
+ end
33
+
34
+ def delete_matched(matcher, options = nil)
35
+ end
36
+
37
+ def inspect # :nodoc:
38
+ "#<#{self.class.name} options=#{@options.inspect}>"
39
+ end
40
+
41
+ private
42
+ def read_entry(key, **s)
43
+ deserialize_entry(read_serialized_entry(key))
44
+ end
45
+
46
+ def read_serialized_entry(_key, **)
47
+ end
48
+
49
+ def write_entry(key, entry, **)
50
+ write_serialized_entry(key, serialize_entry(entry))
51
+ end
52
+
53
+ def write_serialized_entry(_key, _payload, **)
54
+ true
55
+ end
56
+
57
+ def delete_entry(key, **options)
58
+ false
59
+ end
60
+ end
61
+ end
62
+ end