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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +505 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +40 -0
- data/lib/active_support/actionable_error.rb +50 -0
- data/lib/active_support/all.rb +5 -0
- data/lib/active_support/array_inquirer.rb +50 -0
- data/lib/active_support/backtrace_cleaner.rb +234 -0
- data/lib/active_support/benchmark.rb +21 -0
- data/lib/active_support/benchmarkable.rb +53 -0
- data/lib/active_support/broadcast_logger.rb +238 -0
- data/lib/active_support/builder.rb +8 -0
- data/lib/active_support/cache/coder.rb +153 -0
- data/lib/active_support/cache/entry.rb +134 -0
- data/lib/active_support/cache/file_store.rb +244 -0
- data/lib/active_support/cache/mem_cache_store.rb +288 -0
- data/lib/active_support/cache/memory_store.rb +264 -0
- data/lib/active_support/cache/null_store.rb +62 -0
- data/lib/active_support/cache/redis_cache_store.rb +498 -0
- data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
- data/lib/active_support/cache/strategy/local_cache.rb +246 -0
- data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
- data/lib/active_support/cache.rb +1170 -0
- data/lib/active_support/callbacks.rb +960 -0
- data/lib/active_support/class_attribute.rb +33 -0
- data/lib/active_support/code_generator.rb +79 -0
- data/lib/active_support/concern.rb +217 -0
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
- data/lib/active_support/concurrency/null_lock.rb +13 -0
- data/lib/active_support/concurrency/share_lock.rb +225 -0
- data/lib/active_support/concurrency/thread_monitor.rb +55 -0
- data/lib/active_support/configurable.rb +193 -0
- data/lib/active_support/configuration_file.rb +60 -0
- data/lib/active_support/continuous_integration.rb +145 -0
- data/lib/active_support/core_ext/array/access.rb +100 -0
- data/lib/active_support/core_ext/array/conversions.rb +209 -26
- data/lib/active_support/core_ext/array/extract.rb +21 -0
- data/lib/active_support/core_ext/array/extract_options.rb +31 -0
- data/lib/active_support/core_ext/array/grouping.rb +109 -0
- data/lib/active_support/core_ext/array/inquiry.rb +19 -0
- data/lib/active_support/core_ext/array/wrap.rb +48 -0
- data/lib/active_support/core_ext/array.rb +8 -4
- data/lib/active_support/core_ext/benchmark.rb +6 -0
- data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
- data/lib/active_support/core_ext/big_decimal.rb +3 -0
- data/lib/active_support/core_ext/class/attribute.rb +137 -0
- data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
- data/lib/active_support/core_ext/class/subclasses.rb +24 -0
- data/lib/active_support/core_ext/class.rb +4 -0
- data/lib/active_support/core_ext/date/acts_like.rb +10 -0
- data/lib/active_support/core_ext/date/blank.rb +18 -0
- data/lib/active_support/core_ext/date/calculations.rb +161 -0
- data/lib/active_support/core_ext/date/conversions.rb +95 -28
- data/lib/active_support/core_ext/date/zones.rb +8 -0
- data/lib/active_support/core_ext/date.rb +6 -5
- data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
- data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
- data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
- data/lib/active_support/core_ext/date_time/blank.rb +18 -0
- data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
- data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
- data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
- data/lib/active_support/core_ext/date_time.rb +7 -0
- data/lib/active_support/core_ext/digest/uuid.rb +76 -0
- data/lib/active_support/core_ext/digest.rb +3 -0
- data/lib/active_support/core_ext/enumerable.rb +277 -7
- data/lib/active_support/core_ext/erb/util.rb +201 -0
- data/lib/active_support/core_ext/file/atomic.rb +72 -0
- data/lib/active_support/core_ext/file.rb +3 -0
- data/lib/active_support/core_ext/hash/conversions.rb +262 -0
- data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
- data/lib/active_support/core_ext/hash/except.rb +12 -0
- data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
- data/lib/active_support/core_ext/hash/keys.rb +134 -44
- data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
- data/lib/active_support/core_ext/hash/slice.rb +27 -0
- data/lib/active_support/core_ext/hash.rb +9 -8
- data/lib/active_support/core_ext/integer/inflections.rb +29 -13
- data/lib/active_support/core_ext/integer/multiple.rb +12 -0
- data/lib/active_support/core_ext/integer/time.rb +22 -0
- data/lib/active_support/core_ext/integer.rb +4 -6
- data/lib/active_support/core_ext/kernel/concern.rb +14 -0
- data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
- data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
- data/lib/active_support/core_ext/kernel.rb +4 -78
- data/lib/active_support/core_ext/load_error.rb +6 -35
- data/lib/active_support/core_ext/module/aliasing.rb +31 -0
- data/lib/active_support/core_ext/module/anonymous.rb +30 -0
- data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
- data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
- data/lib/active_support/core_ext/module/concerning.rb +140 -0
- data/lib/active_support/core_ext/module/delegation.rb +225 -0
- data/lib/active_support/core_ext/module/deprecation.rb +25 -0
- data/lib/active_support/core_ext/module/introspection.rb +65 -0
- data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
- data/lib/active_support/core_ext/module/remove_method.rb +17 -0
- data/lib/active_support/core_ext/module.rb +13 -0
- data/lib/active_support/core_ext/name_error.rb +59 -0
- data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
- data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
- data/lib/active_support/core_ext/numeric/time.rb +64 -57
- data/lib/active_support/core_ext/numeric.rb +4 -6
- data/lib/active_support/core_ext/object/acts_like.rb +45 -0
- data/lib/active_support/core_ext/object/blank.rb +199 -0
- data/lib/active_support/core_ext/object/conversions.rb +6 -0
- data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
- data/lib/active_support/core_ext/object/duplicable.rb +69 -0
- data/lib/active_support/core_ext/object/inclusion.rb +37 -0
- data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
- data/lib/active_support/core_ext/object/json.rb +267 -0
- data/lib/active_support/core_ext/object/to_param.rb +3 -0
- data/lib/active_support/core_ext/object/to_query.rb +93 -0
- data/lib/active_support/core_ext/object/try.rb +158 -0
- data/lib/active_support/core_ext/object/with.rb +46 -0
- data/lib/active_support/core_ext/object/with_options.rb +101 -0
- data/lib/active_support/core_ext/object.rb +17 -0
- data/lib/active_support/core_ext/pathname/blank.rb +20 -0
- data/lib/active_support/core_ext/pathname/existence.rb +23 -0
- data/lib/active_support/core_ext/pathname.rb +4 -0
- data/lib/active_support/core_ext/range/compare_range.rb +57 -0
- data/lib/active_support/core_ext/range/conversions.rb +58 -17
- data/lib/active_support/core_ext/range/overlap.rb +40 -0
- data/lib/active_support/core_ext/range/sole.rb +17 -0
- data/lib/active_support/core_ext/range.rb +5 -4
- data/lib/active_support/core_ext/regexp.rb +14 -0
- data/lib/active_support/core_ext/securerandom.rb +57 -0
- data/lib/active_support/core_ext/string/access.rb +93 -56
- data/lib/active_support/core_ext/string/behavior.rb +8 -0
- data/lib/active_support/core_ext/string/conversions.rb +57 -16
- data/lib/active_support/core_ext/string/exclude.rb +13 -0
- data/lib/active_support/core_ext/string/filters.rb +151 -0
- data/lib/active_support/core_ext/string/indent.rb +45 -0
- data/lib/active_support/core_ext/string/inflections.rb +297 -54
- data/lib/active_support/core_ext/string/inquiry.rb +16 -0
- data/lib/active_support/core_ext/string/multibyte.rb +67 -0
- data/lib/active_support/core_ext/string/output_safety.rb +235 -0
- data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
- data/lib/active_support/core_ext/string/strip.rb +27 -0
- data/lib/active_support/core_ext/string/zones.rb +16 -0
- data/lib/active_support/core_ext/string.rb +14 -10
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
- data/lib/active_support/core_ext/time/acts_like.rb +10 -0
- data/lib/active_support/core_ext/time/calculations.rb +358 -153
- data/lib/active_support/core_ext/time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/time/conversions.rb +69 -30
- data/lib/active_support/core_ext/time/zones.rb +97 -0
- data/lib/active_support/core_ext/time.rb +6 -6
- data/lib/active_support/core_ext.rb +5 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +243 -0
- data/lib/active_support/deep_mergeable.rb +53 -0
- data/lib/active_support/delegation.rb +183 -0
- data/lib/active_support/dependencies/autoload.rb +72 -0
- data/lib/active_support/dependencies/interlock.rb +55 -0
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +84 -222
- data/lib/active_support/deprecation/behaviors.rb +148 -0
- data/lib/active_support/deprecation/constant_accessor.rb +74 -0
- data/lib/active_support/deprecation/deprecators.rb +104 -0
- data/lib/active_support/deprecation/disallowed.rb +54 -0
- data/lib/active_support/deprecation/method_wrappers.rb +68 -0
- data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
- data/lib/active_support/deprecation/reporting.rb +162 -0
- data/lib/active_support/deprecation.rb +81 -0
- data/lib/active_support/deprecator.rb +7 -0
- data/lib/active_support/descendants_tracker.rb +112 -0
- data/lib/active_support/digest.rb +22 -0
- data/lib/active_support/duration/iso8601_parser.rb +123 -0
- data/lib/active_support/duration/iso8601_serializer.rb +64 -0
- data/lib/active_support/duration.rb +524 -0
- data/lib/active_support/editor.rb +70 -0
- data/lib/active_support/encrypted_configuration.rb +126 -0
- data/lib/active_support/encrypted_file.rb +133 -0
- data/lib/active_support/environment_inquirer.rb +40 -0
- data/lib/active_support/error_reporter/test_helper.rb +15 -0
- data/lib/active_support/error_reporter.rb +318 -0
- data/lib/active_support/event_reporter/test_helper.rb +32 -0
- data/lib/active_support/event_reporter.rb +592 -0
- data/lib/active_support/evented_file_update_checker.rb +185 -0
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +110 -0
- data/lib/active_support/execution_wrapper.rb +150 -0
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/executor.rb +8 -0
- data/lib/active_support/file_update_checker.rb +166 -0
- data/lib/active_support/fork_tracker.rb +43 -0
- data/lib/active_support/gem_version.rb +17 -0
- data/lib/active_support/gzip.rb +41 -0
- data/lib/active_support/hash_with_indifferent_access.rb +464 -0
- data/lib/active_support/html_safe_translation.rb +56 -0
- data/lib/active_support/i18n.rb +17 -0
- data/lib/active_support/i18n_railtie.rb +140 -0
- data/lib/active_support/inflections.rb +68 -49
- data/lib/active_support/inflector/inflections.rb +290 -0
- data/lib/active_support/inflector/methods.rb +387 -0
- data/lib/active_support/inflector/transliterate.rb +147 -0
- data/lib/active_support/inflector.rb +7 -164
- data/lib/active_support/isolated_execution_state.rb +76 -0
- data/lib/active_support/json/decoding.rb +78 -0
- data/lib/active_support/json/encoding.rb +256 -0
- data/lib/active_support/json.rb +4 -0
- data/lib/active_support/key_generator.rb +66 -0
- data/lib/active_support/lazy_load_hooks.rb +107 -0
- data/lib/active_support/locale/en.rb +33 -0
- data/lib/active_support/locale/en.yml +141 -0
- data/lib/active_support/log_subscriber/test_helper.rb +106 -0
- data/lib/active_support/log_subscriber.rb +188 -0
- data/lib/active_support/logger.rb +55 -0
- data/lib/active_support/logger_silence.rb +21 -0
- data/lib/active_support/logger_thread_safe_level.rb +50 -0
- data/lib/active_support/message_encryptor.rb +374 -0
- data/lib/active_support/message_encryptors.rb +193 -0
- data/lib/active_support/message_pack/cache_serializer.rb +23 -0
- data/lib/active_support/message_pack/extensions.rb +310 -0
- data/lib/active_support/message_pack/serializer.rb +63 -0
- data/lib/active_support/message_pack.rb +50 -0
- data/lib/active_support/message_verifier.rb +377 -0
- data/lib/active_support/message_verifiers.rb +189 -0
- data/lib/active_support/messages/codec.rb +65 -0
- data/lib/active_support/messages/metadata.rb +146 -0
- data/lib/active_support/messages/rotation_configuration.rb +23 -0
- data/lib/active_support/messages/rotation_coordinator.rb +102 -0
- data/lib/active_support/messages/rotator.rb +69 -0
- data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
- data/lib/active_support/multibyte/chars.rb +188 -0
- data/lib/active_support/multibyte/unicode.rb +42 -0
- data/lib/active_support/multibyte.rb +27 -0
- data/lib/active_support/notifications/fanout.rb +467 -0
- data/lib/active_support/notifications/instrumenter.rb +240 -0
- data/lib/active_support/notifications.rb +281 -0
- data/lib/active_support/number_helper/number_converter.rb +190 -0
- data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
- data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
- data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
- data/lib/active_support/number_helper/rounding_helper.rb +46 -0
- data/lib/active_support/number_helper.rb +479 -0
- data/lib/active_support/option_merger.rb +38 -0
- data/lib/active_support/ordered_hash.rb +50 -0
- data/lib/active_support/ordered_options.rb +141 -25
- data/lib/active_support/parameter_filter.rb +157 -0
- data/lib/active_support/rails.rb +26 -0
- data/lib/active_support/railtie.rb +180 -0
- data/lib/active_support/reloader.rb +138 -0
- data/lib/active_support/rescuable.rb +176 -0
- data/lib/active_support/secure_compare_rotator.rb +58 -0
- data/lib/active_support/security_utils.rb +38 -0
- data/lib/active_support/string_inquirer.rb +35 -0
- data/lib/active_support/structured_event_subscriber.rb +99 -0
- data/lib/active_support/subscriber.rb +141 -0
- data/lib/active_support/syntax_error_proxy.rb +67 -0
- data/lib/active_support/tagged_logging.rb +157 -0
- data/lib/active_support/test_case.rb +365 -0
- data/lib/active_support/testing/assertions.rb +369 -0
- data/lib/active_support/testing/autorun.rb +10 -0
- data/lib/active_support/testing/constant_lookup.rb +51 -0
- data/lib/active_support/testing/constant_stubbing.rb +54 -0
- data/lib/active_support/testing/declarative.rb +28 -0
- data/lib/active_support/testing/deprecation.rb +82 -0
- data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
- data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
- data/lib/active_support/testing/file_fixtures.rb +38 -0
- data/lib/active_support/testing/isolation.rb +121 -0
- data/lib/active_support/testing/method_call_assertions.rb +69 -0
- data/lib/active_support/testing/notification_assertions.rb +92 -0
- data/lib/active_support/testing/parallelization/server.rb +98 -0
- data/lib/active_support/testing/parallelization/worker.rb +107 -0
- data/lib/active_support/testing/parallelization.rb +79 -0
- data/lib/active_support/testing/parallelize_executor.rb +81 -0
- data/lib/active_support/testing/setup_and_teardown.rb +57 -0
- data/lib/active_support/testing/stream.rb +41 -0
- data/lib/active_support/testing/tagged_logging.rb +27 -0
- data/lib/active_support/testing/tests_without_assertions.rb +19 -0
- data/lib/active_support/testing/time_helpers.rb +273 -0
- data/lib/active_support/time.rb +20 -0
- data/lib/active_support/time_with_zone.rb +613 -0
- data/lib/active_support/values/time_zone.rb +599 -158
- data/lib/active_support/version.rb +7 -6
- data/lib/active_support/xml_mini/jdom.rb +175 -0
- data/lib/active_support/xml_mini/libxml.rb +80 -0
- data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
- data/lib/active_support/xml_mini/nokogiri.rb +83 -0
- data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
- data/lib/active_support/xml_mini/rexml.rb +137 -0
- data/lib/active_support/xml_mini.rb +212 -0
- data/lib/active_support.rb +122 -10
- metadata +524 -93
- data/CHANGELOG +0 -283
- data/lib/active_support/binding_of_caller.rb +0 -84
- data/lib/active_support/breakpoint.rb +0 -523
- data/lib/active_support/class_attribute_accessors.rb +0 -57
- data/lib/active_support/class_inheritable_attributes.rb +0 -117
- data/lib/active_support/clean_logger.rb +0 -36
- data/lib/active_support/core_ext/blank.rb +0 -38
- data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
- data/lib/active_support/core_ext/cgi.rb +0 -5
- data/lib/active_support/core_ext/exception.rb +0 -29
- data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
- data/lib/active_support/core_ext/object_and_class.rb +0 -44
- data/lib/active_support/module_attribute_accessors.rb +0 -57
- 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
|