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,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "entry"
4
+
5
+ module ActiveSupport
6
+ module Cache
7
+ class Coder # :nodoc:
8
+ def initialize(serializer, compressor, legacy_serializer: false)
9
+ @serializer = serializer
10
+ @compressor = compressor
11
+ @legacy_serializer = legacy_serializer
12
+ end
13
+
14
+ def dump(entry)
15
+ return @serializer.dump(entry) if @legacy_serializer
16
+
17
+ dump_compressed(entry, Float::INFINITY)
18
+ end
19
+
20
+ def dump_compressed(entry, threshold)
21
+ return @serializer.dump_compressed(entry, threshold) if @legacy_serializer
22
+
23
+ # If value is a string with a supported encoding, use it as the payload
24
+ # instead of passing it through the serializer.
25
+ if type = type_for_string(entry.value)
26
+ payload = entry.value.b
27
+ else
28
+ type = OBJECT_DUMP_TYPE
29
+ payload = @serializer.dump(entry.value)
30
+ end
31
+
32
+ if compressed = try_compress(payload, threshold)
33
+ payload = compressed
34
+ type = type | COMPRESSED_FLAG
35
+ end
36
+
37
+ expires_at = entry.expires_at || -1.0
38
+
39
+ version = dump_version(entry.version) if entry.version
40
+ version_length = version&.bytesize || -1
41
+
42
+ packed = SIGNATURE.b
43
+ packed << [type, expires_at, version_length].pack(PACKED_TEMPLATE)
44
+ packed << version if version
45
+ packed << payload
46
+ end
47
+
48
+ def load(dumped)
49
+ return @serializer.load(dumped) if !signature?(dumped)
50
+
51
+ type = dumped.unpack1(PACKED_TYPE_TEMPLATE)
52
+ expires_at = dumped.unpack1(PACKED_EXPIRES_AT_TEMPLATE)
53
+ version_length = dumped.unpack1(PACKED_VERSION_LENGTH_TEMPLATE)
54
+
55
+ expires_at = nil if expires_at < 0
56
+ version = load_version(dumped.byteslice(PACKED_VERSION_INDEX, version_length)) if version_length >= 0
57
+ payload = dumped.byteslice((PACKED_VERSION_INDEX + [version_length, 0].max)..)
58
+
59
+ compressor = @compressor if type & COMPRESSED_FLAG > 0
60
+ serializer = STRING_DESERIALIZERS[type & ~COMPRESSED_FLAG] || @serializer
61
+
62
+ LazyEntry.new(serializer, compressor, payload, version: version, expires_at: expires_at)
63
+ end
64
+
65
+ private
66
+ SIGNATURE = "\x00\x11".b.freeze
67
+
68
+ OBJECT_DUMP_TYPE = 0x01
69
+
70
+ STRING_ENCODINGS = {
71
+ 0x02 => Encoding::UTF_8,
72
+ 0x03 => Encoding::BINARY,
73
+ 0x04 => Encoding::US_ASCII,
74
+ }
75
+
76
+ COMPRESSED_FLAG = 0x80
77
+
78
+ PACKED_TEMPLATE = "CEl<"
79
+ PACKED_TYPE_TEMPLATE = "@#{SIGNATURE.bytesize}C"
80
+ PACKED_EXPIRES_AT_TEMPLATE = "@#{[0].pack(PACKED_TYPE_TEMPLATE).bytesize}E"
81
+ PACKED_VERSION_LENGTH_TEMPLATE = "@#{[0].pack(PACKED_EXPIRES_AT_TEMPLATE).bytesize}l<"
82
+ PACKED_VERSION_INDEX = [0].pack(PACKED_VERSION_LENGTH_TEMPLATE).bytesize
83
+
84
+ MARSHAL_SIGNATURE = "\x04\x08".b.freeze
85
+
86
+ class StringDeserializer
87
+ def initialize(encoding)
88
+ @encoding = encoding
89
+ end
90
+
91
+ def load(payload)
92
+ payload.force_encoding(@encoding)
93
+ end
94
+ end
95
+
96
+ STRING_DESERIALIZERS = STRING_ENCODINGS.transform_values { |encoding| StringDeserializer.new(encoding) }
97
+
98
+ class LazyEntry < Cache::Entry
99
+ def initialize(serializer, compressor, payload, **options)
100
+ super(payload, **options)
101
+ @serializer = serializer
102
+ @compressor = compressor
103
+ @resolved = false
104
+ end
105
+
106
+ def value
107
+ if !@resolved
108
+ @value = @serializer.load(@compressor ? @compressor.inflate(@value) : @value)
109
+ @resolved = true
110
+ end
111
+ @value
112
+ end
113
+
114
+ def mismatched?(version)
115
+ super.tap { |mismatched| value if !mismatched }
116
+ rescue Cache::DeserializationError
117
+ true
118
+ end
119
+ end
120
+
121
+ def signature?(dumped)
122
+ dumped.is_a?(String) && dumped.start_with?(SIGNATURE)
123
+ end
124
+
125
+ def type_for_string(value)
126
+ STRING_ENCODINGS.key(value.encoding) if value.instance_of?(String)
127
+ end
128
+
129
+ def try_compress(string, threshold)
130
+ if @compressor && string.bytesize >= threshold
131
+ compressed = @compressor.deflate(string)
132
+ compressed if compressed.bytesize < string.bytesize
133
+ end
134
+ end
135
+
136
+ def dump_version(version)
137
+ if version.encoding != Encoding::UTF_8 || version.start_with?(MARSHAL_SIGNATURE)
138
+ Marshal.dump(version)
139
+ else
140
+ version.b
141
+ end
142
+ end
143
+
144
+ def load_version(dumped_version)
145
+ if dumped_version.start_with?(MARSHAL_SIGNATURE)
146
+ Marshal.load(dumped_version)
147
+ else
148
+ dumped_version.force_encoding(Encoding::UTF_8)
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zlib"
4
+
5
+ module ActiveSupport
6
+ module Cache
7
+ # This class is used to represent cache entries. Cache entries have a value, an optional
8
+ # expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
9
+ # on the cache. The version is used to support the :version option on the cache for rejecting
10
+ # mismatches.
11
+ #
12
+ # Since cache entries in most instances will be serialized, the internals of this class are highly optimized
13
+ # using short instance variable names that are lazily defined.
14
+ class Entry # :nodoc:
15
+ class << self
16
+ def unpack(members)
17
+ new(members[0], expires_at: members[1], version: members[2])
18
+ end
19
+ end
20
+
21
+ attr_reader :version
22
+
23
+ # Creates a new cache entry for the specified value. Options supported are
24
+ # +:compressed+, +:version+, +:expires_at+ and +:expires_in+.
25
+ def initialize(value, compressed: false, version: nil, expires_in: nil, expires_at: nil, **)
26
+ @value = value
27
+ @version = version
28
+ @created_at = 0.0
29
+ @expires_in = expires_at&.to_f || expires_in && (expires_in.to_f + Time.now.to_f)
30
+ @compressed = true if compressed
31
+ end
32
+
33
+ def value
34
+ compressed? ? uncompress(@value) : @value
35
+ end
36
+
37
+ def mismatched?(version)
38
+ @version && version && @version != version
39
+ end
40
+
41
+ # Checks if the entry is expired. The +expires_in+ parameter can override
42
+ # the value set when the entry was created.
43
+ def expired?
44
+ @expires_in && @created_at + @expires_in <= Time.now.to_f
45
+ end
46
+
47
+ def expires_at
48
+ @expires_in ? @created_at + @expires_in : nil
49
+ end
50
+
51
+ def expires_at=(value)
52
+ if value
53
+ @expires_in = value.to_f - @created_at
54
+ else
55
+ @expires_in = nil
56
+ end
57
+ end
58
+
59
+ # Returns the size of the cached value. This could be less than
60
+ # <tt>value.bytesize</tt> if the data is compressed.
61
+ def bytesize
62
+ case value
63
+ when NilClass
64
+ 0
65
+ when String
66
+ @value.bytesize
67
+ else
68
+ @s ||= Marshal.dump(@value).bytesize
69
+ end
70
+ end
71
+
72
+ def compressed? # :nodoc:
73
+ defined?(@compressed)
74
+ end
75
+
76
+ def compressed(compress_threshold)
77
+ return self if compressed?
78
+
79
+ case @value
80
+ when nil, true, false, Numeric
81
+ uncompressed_size = 0
82
+ when String
83
+ uncompressed_size = @value.bytesize
84
+ else
85
+ serialized = Marshal.dump(@value)
86
+ uncompressed_size = serialized.bytesize
87
+ end
88
+
89
+ if uncompressed_size >= compress_threshold
90
+ serialized ||= Marshal.dump(@value)
91
+ compressed = Zlib::Deflate.deflate(serialized)
92
+
93
+ if compressed.bytesize < uncompressed_size
94
+ return Entry.new(compressed, compressed: true, expires_at: expires_at, version: version)
95
+ end
96
+ end
97
+ self
98
+ end
99
+
100
+ def local?
101
+ false
102
+ end
103
+
104
+ # Duplicates the value in a class. This is used by cache implementations that don't natively
105
+ # serialize entries to protect against accidental cache modifications.
106
+ def dup_value!
107
+ if @value && !compressed? && !(@value.is_a?(Numeric) || @value == true || @value == false)
108
+ if @value.is_a?(String)
109
+ @value = @value.dup
110
+ else
111
+ @value = Marshal.load(Marshal.dump(@value))
112
+ end
113
+ end
114
+ end
115
+
116
+ def pack
117
+ members = [value, expires_at, version]
118
+ members.pop while !members.empty? && members.last.nil?
119
+ members
120
+ end
121
+
122
+ private
123
+ def uncompress(value)
124
+ marshal_load(Zlib::Inflate.inflate(value))
125
+ end
126
+
127
+ def marshal_load(payload)
128
+ Marshal.load(payload)
129
+ rescue ArgumentError => error
130
+ raise Cache::DeserializationError, error.message
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,244 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/file/atomic"
4
+ require "active_support/core_ext/string/conversions"
5
+ require "uri/common"
6
+
7
+ module ActiveSupport
8
+ module Cache
9
+ # = \File \Cache \Store
10
+ #
11
+ # A cache store implementation which stores everything on the filesystem.
12
+ class FileStore < Store
13
+ attr_reader :cache_path
14
+
15
+ DIR_FORMATTER = "%03X"
16
+ FILENAME_MAX_SIZE = 226 # max filename size on file system is 255, minus room for timestamp, pid, and random characters appended by Tempfile (used by atomic write)
17
+ FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
18
+ GITKEEP_FILES = [".gitkeep", ".keep"].freeze
19
+
20
+ def initialize(cache_path, **options)
21
+ super(options)
22
+ @cache_path = cache_path.to_s
23
+ end
24
+
25
+ # Advertise cache versioning support.
26
+ def self.supports_cache_versioning?
27
+ true
28
+ end
29
+
30
+ # Deletes all items from the cache. In this case it deletes all the entries in the specified
31
+ # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
32
+ # config file when using +FileStore+ because everything in that directory will be deleted.
33
+ def clear(options = nil)
34
+ root_dirs = (Dir.children(cache_path) - GITKEEP_FILES)
35
+ FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
36
+ rescue Errno::ENOENT, Errno::ENOTEMPTY
37
+ end
38
+
39
+ # Preemptively iterates through all stored keys and removes the ones which have expired.
40
+ def cleanup(options = nil)
41
+ options = merged_options(options)
42
+ search_dir(cache_path) do |fname|
43
+ entry = read_entry(fname, **options)
44
+ delete_entry(fname, **options) if entry && entry.expired?
45
+ end
46
+ end
47
+
48
+ # Increment a cached integer value. Returns the updated value.
49
+ #
50
+ # If the key is unset, it starts from +0+:
51
+ #
52
+ # cache.increment("foo") # => 1
53
+ # cache.increment("bar", 100) # => 100
54
+ #
55
+ # To set a specific value, call #write:
56
+ #
57
+ # cache.write("baz", 5)
58
+ # cache.increment("baz") # => 6
59
+ #
60
+ def increment(name, amount = 1, **options)
61
+ options = merged_options(options)
62
+ key = normalize_key(name, options)
63
+
64
+ instrument(:increment, key, amount: amount) do
65
+ modify_value(name, amount, options)
66
+ end
67
+ end
68
+
69
+ # Decrement a cached integer value. Returns the updated value.
70
+ #
71
+ # If the key is unset, it will be set to +-amount+.
72
+ #
73
+ # cache.decrement("foo") # => -1
74
+ #
75
+ # To set a specific value, call #write:
76
+ #
77
+ # cache.write("baz", 5)
78
+ # cache.decrement("baz") # => 4
79
+ #
80
+ def decrement(name, amount = 1, **options)
81
+ options = merged_options(options)
82
+ key = normalize_key(name, options)
83
+
84
+ instrument(:decrement, key, amount: amount) do
85
+ modify_value(name, -amount, options)
86
+ end
87
+ end
88
+
89
+ def delete_matched(matcher, options = nil)
90
+ options = merged_options(options)
91
+ matcher = key_matcher(matcher, options)
92
+
93
+ instrument(:delete_matched, matcher.inspect) do
94
+ search_dir(cache_path) do |path|
95
+ key = file_path_key(path)
96
+ delete_entry(path, **options) if key.match(matcher)
97
+ end
98
+ end
99
+ end
100
+
101
+ def inspect # :nodoc:
102
+ "#<#{self.class.name} cache_path=#{@cache_path}, options=#{@options.inspect}>"
103
+ end
104
+
105
+ private
106
+ def read_entry(key, **options)
107
+ if payload = read_serialized_entry(key, **options)
108
+ entry = deserialize_entry(payload)
109
+ entry if entry.is_a?(Cache::Entry)
110
+ end
111
+ end
112
+
113
+ def read_serialized_entry(key, **)
114
+ File.binread(key) if File.exist?(key)
115
+ rescue => error
116
+ logger.error("FileStoreError (#{error}): #{error.message}") if logger
117
+ nil
118
+ end
119
+
120
+ def write_entry(key, entry, **options)
121
+ write_serialized_entry(key, serialize_entry(entry, **options), **options)
122
+ end
123
+
124
+ def write_serialized_entry(key, payload, **options)
125
+ return false if options[:unless_exist] && File.exist?(key)
126
+ ensure_cache_path(File.dirname(key))
127
+ File.atomic_write(key, cache_path) { |f| f.write(payload) }
128
+ true
129
+ end
130
+
131
+ def delete_entry(key, **options)
132
+ if File.exist?(key)
133
+ begin
134
+ File.delete(key)
135
+ delete_empty_directories(File.dirname(key))
136
+ true
137
+ rescue
138
+ # Just in case the error was caused by another process deleting the file first.
139
+ raise if File.exist?(key)
140
+ false
141
+ end
142
+ else
143
+ false
144
+ end
145
+ end
146
+
147
+ # Lock a file for a block so only one process can modify it at a time.
148
+ def lock_file(file_name, &block)
149
+ if File.exist?(file_name)
150
+ File.open(file_name, "r+") do |f|
151
+ f.flock File::LOCK_EX
152
+ yield
153
+ ensure
154
+ f.flock File::LOCK_UN
155
+ end
156
+ else
157
+ yield
158
+ end
159
+ end
160
+
161
+ # Translate a key into a file path.
162
+ def normalize_key(key, options)
163
+ key = super
164
+ fname = URI.encode_www_form_component(key)
165
+
166
+ if fname.size > FILEPATH_MAX_SIZE
167
+ fname = ActiveSupport::Digest.hexdigest(key)
168
+ end
169
+
170
+ hash = Zlib.adler32(fname)
171
+ hash, dir_1 = hash.divmod(0x1000)
172
+ dir_2 = hash.modulo(0x1000)
173
+
174
+ # Make sure file name doesn't exceed file system limits.
175
+ if fname.length < FILENAME_MAX_SIZE
176
+ fname_paths = fname
177
+ else
178
+ fname_paths = []
179
+ begin
180
+ fname_paths << fname[0, FILENAME_MAX_SIZE]
181
+ fname = fname[FILENAME_MAX_SIZE..-1]
182
+ end until fname.blank?
183
+ end
184
+
185
+ File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, fname_paths)
186
+ end
187
+
188
+ # Translate a file path into a key.
189
+ def file_path_key(path)
190
+ fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last.delete(File::SEPARATOR)
191
+ URI.decode_www_form_component(fname, Encoding::UTF_8)
192
+ end
193
+
194
+ # Delete empty directories in the cache.
195
+ def delete_empty_directories(dir)
196
+ return if File.realpath(dir) == File.realpath(cache_path)
197
+ if Dir.children(dir).empty?
198
+ Dir.delete(dir) rescue nil
199
+ delete_empty_directories(File.dirname(dir))
200
+ end
201
+ end
202
+
203
+ # Make sure a file path's directories exist.
204
+ def ensure_cache_path(path)
205
+ FileUtils.makedirs(path) unless File.exist?(path)
206
+ end
207
+
208
+ def search_dir(dir, &callback)
209
+ return if !File.exist?(dir)
210
+ Dir.each_child(dir) do |d|
211
+ name = File.join(dir, d)
212
+ if File.directory?(name)
213
+ search_dir(name, &callback)
214
+ else
215
+ callback.call name
216
+ end
217
+ end
218
+ end
219
+
220
+ # Modifies the amount of an integer value that is stored in the cache.
221
+ # If the key is not found it is created and set to +amount+.
222
+ def modify_value(name, amount, options)
223
+ options = merged_options(options)
224
+ key = normalize_key(name, options)
225
+ version = normalize_version(name, options)
226
+ amount = Integer(amount)
227
+
228
+ lock_file(key) do
229
+ entry = read_entry(key, **options)
230
+
231
+ if !entry || entry.expired? || entry.mismatched?(version)
232
+ write(name, amount, options)
233
+ amount
234
+ else
235
+ num = entry.value.to_i + amount
236
+ entry = Entry.new(num, expires_at: entry.expires_at, version: entry.version)
237
+ write_entry(key, entry)
238
+ num
239
+ end
240
+ end
241
+ end
242
+ end
243
+ end
244
+ end