From 24d904f325421155e3a1dfa94af344d640286cea Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Sat, 1 Dec 2018 14:33:47 +0300 Subject: [PATCH 01/13] [marshaling] initial implementation --- lib/any_cache.rb | 1 + lib/any_cache/adapters/dalli.rb | 24 +++++++----- lib/any_cache/adapters/redis.rb | 16 ++++++-- lib/any_cache/adapters/redis_store.rb | 12 ++++-- lib/any_cache/dumper.rb | 53 +++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 16 deletions(-) create mode 100644 lib/any_cache/dumper.rb diff --git a/lib/any_cache.rb b/lib/any_cache.rb index ea329c5..0ad7826 100644 --- a/lib/any_cache.rb +++ b/lib/any_cache.rb @@ -10,6 +10,7 @@ class AnyCache require_relative 'any_cache/version' require_relative 'any_cache/error' + require_relative 'any_cache/dumper' require_relative 'any_cache/drivers' require_relative 'any_cache/adapters' require_relative 'any_cache/logging' diff --git a/lib/any_cache/adapters/dalli.rb b/lib/any_cache/adapters/dalli.rb index c462213..cc23f5b 100644 --- a/lib/any_cache/adapters/dalli.rb +++ b/lib/any_cache/adapters/dalli.rb @@ -57,25 +57,32 @@ def supported_driver?(driver) :flush # @param key [String] - # @param options [Hash] + # @option raw [Boolean] # @return [Object] # # @api private # @since 0.1.0 def read(key, **options) - get(key) + raw = options.fetch(:raw, false) + value = get(key) + + raw ? value : AnyCache::Dumper.load(value) end # @param keys [Array] - # @param options [Hash] + # @option raw [Boolean] # @return [Hash] # # @api private # @since 0.3.0 def read_multi(*keys, **options) - get_multi(*keys).tap do |res| + raw = options.fethc(:raw, false) + + entries = get_multi(*keys).tap do |res| res.merge!(Hash[(keys - res.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) end + + raw ? entires : AnyCache::Dumper.detransform_hash(entries) end # @param key [String] @@ -87,7 +94,8 @@ def read_multi(*keys, **options) # @since 0.1.0 def write(key, value, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) + value = AnyCache::Dumper.dump(value) unless raw set(key, value, expires_in, raw: raw) end @@ -99,9 +107,7 @@ def write(key, value, **options) # @api private # @since 0.3.0 def write_multi(entries, **options) - raw = options.fetch(:raw, true) - - entries.each_pair { |key, value| write(key, value, raw: raw) } + entries.each_pair { |key, value| write(key, value, **options) } end # @param key [String] @@ -117,7 +123,7 @@ def fetch(key, **options, &fallback) force_rewrite = force_rewrite.call(key) if force_rewrite.respond_to?(:call) # NOTE: can conflict with :cache_nils Dalli::Client's config - read(key).tap { |value| return value if value } unless force_rewrite + read(key, **options).tap { |value| return value if value } unless force_rewrite yield(key).tap { |value| write(key, value, **options) } if block_given? end diff --git a/lib/any_cache/adapters/redis.rb b/lib/any_cache/adapters/redis.rb index 956ac6f..0024e23 100644 --- a/lib/any_cache/adapters/redis.rb +++ b/lib/any_cache/adapters/redis.rb @@ -67,7 +67,10 @@ def supported_driver?(driver) # @api private # @since 0.1.0 def read(key, **options) - get(key) + value = get(key) + raw = options.fetch(:raw, false) + + raw ? value : AnyCache::Dumper.load(value) end # @param keys [Array] @@ -77,7 +80,10 @@ def read(key, **options) # @api private # @since 0.3.0 def read_multi(*keys, **options) - mapped_mget(*keys) + raw = options.fetch(:raw, false) + entries = mapped_mget(*keys) + + raw ? entries : AnyCache::Dumper.detransform_hash(entries) end # @param key [String] @@ -88,7 +94,9 @@ def read_multi(*keys, **options) # @api private # @since 0.1.0 def write(key, value, **options) + raw = options.fetch(:raw, false) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) + value = AnyCache::Dumper.dump(value) unless raw expires_in ? setex(key, expires_in, value) : set(key, value) end @@ -100,6 +108,8 @@ def write(key, value, **options) # @api private # @since 0.3.0 def write_multi(entries, **options) + raw = options.fetch(:raw, false) + entries = AnyCache::Dumper.transform_hash(entries) unless raw mapped_mset(entries) end @@ -115,7 +125,7 @@ def fetch(key, **options, &fallback) force_rewrite = force_rewrite.call(key) if force_rewrite.respond_to?(:call) # NOTE: think about #pipelined - read(key).tap { |value| return value if value } unless force_rewrite + read(key, **options).tap { |value| return value if value } unless force_rewrite yield(key).tap { |value| write(key, value, **options) } if block_given? end diff --git a/lib/any_cache/adapters/redis_store.rb b/lib/any_cache/adapters/redis_store.rb index 1039ece..56de6e6 100644 --- a/lib/any_cache/adapters/redis_store.rb +++ b/lib/any_cache/adapters/redis_store.rb @@ -24,9 +24,10 @@ def supported_driver?(driver) # @api private # @since 0.1.0 def read(key, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) + value = get(key, raw: raw) - get(key, raw: raw) + raw ? value : AnyCache::Dumper.load(value) end # @param keys [Array] @@ -49,7 +50,8 @@ def read_multi(*keys, **options) # @since 0.1.0 def write(key, value, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) + value = AnyCache::Dumper.dump(value) unless value expires_in ? setex(key, expires_in, value, raw: raw) : set(key, value, raw: raw) end @@ -61,7 +63,9 @@ def write(key, value, **options) # @api private # @since 0.3.0 def write_multi(entries, **options) - mset(*entries.to_a.flatten!, raw: true) + raw = options.fetch(:raw, false) + entries = AnyCache::Dumper.transform_hash(entries) unless raw + mset(*entries.to_a.flatten!, raw: raw) end end end diff --git a/lib/any_cache/dumper.rb b/lib/any_cache/dumper.rb new file mode 100644 index 0000000..8122950 --- /dev/null +++ b/lib/any_cache/dumper.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +# @api private +# @since 0.4.0 +module AnyCache::Dumper + class << self + # @param hash [Hash] + # @return [Hash] + # + # @api private + # @since 0.4.0 + def transform_hash(hash) + {}.tap do |entries| + hash.each_pair do |key, value| + entries[key] = dump(value) + end + end + end + + # @param hash [Hash] + # @return [Hash] + # + # @api private + # @since 0.4.0 + def detransform_hash(hash) + {}.tap do |entries| + hash.each_pair do |key, value| + entries[key] = load(value) + end + end + end + + # @param value [Object] + # @return [String] + # + # @api private + # @since 0.4.0 + def dump(value) + return value if value.nil? + Zlib::Deflate.deflate(Marshal.dump(value)) + end + + # @param value [String] + # @return [Object] + # + # @api private + # @since 0.4.0 + def load(value) + return value if value.nil? + Marshal.load(Zlib::Inflate.inflate(value)) + end + end +end From ca2bfe1e97a0c68424476ffd606cf2ebe03171a4 Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Sat, 1 Dec 2018 14:34:04 +0300 Subject: [PATCH 02/13] [marshaling] adopted raw-related specs --- spec/features/decrement_spec.rb | 23 +++++++++++++++-------- spec/features/increment_spec.rb | 23 +++++++++++++++-------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/spec/features/decrement_spec.rb b/spec/features/decrement_spec.rb index d6be1c5..e22635c 100644 --- a/spec/features/decrement_spec.rb +++ b/spec/features/decrement_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -describe 'Operation: #decrement' do +describe 'Operation: #decrement', :focus do include_context 'cache store' let(:expiration_time) { 8 } # NOTE: in seconds @@ -31,7 +31,14 @@ end context 'with previously defined temporal entry' do - before { cache_store.write(entry[:key], entry[:value], expires_in: expiration_time) } + before do + cache_store.write( + entry[:key], + entry[:value], + expires_in: expiration_time, + raw: true + ) + end it_behaves_like 'decrementation' @@ -43,10 +50,10 @@ cache_store.decrement(entry[:key], 2, expires_in: expiration_time) sleep(4) # NOTE: remaining time: 4 seconds again, current value: -2 - expect(cache_store.read(entry[:key]).to_i).to eq(-2) | eq(0) + expect(cache_store.read(entry[:key], raw: true).to_i).to eq(-2) | eq(0) sleep(5) # NOTE: remaining time: -1 seconds - expect(cache_store.read(entry[:key])).to eq(nil) + expect(cache_store.read(entry[:key], raw: true)).to eq(nil) end end @@ -59,13 +66,13 @@ # NOTE: new amount: -2, old entry is dead, new entry is permanent expect(new_amount).to eq(-2) | eq(0) sleep(expiration_time + 1) # NOTE: remaining time: -1 esconds, current value: -2 - expect(cache_store.read(entry[:key]).to_i).to eq(-2) | eq(0) + expect(cache_store.read(entry[:key], raw: true).to_i).to eq(-2) | eq(0) end end end context 'with previously defined permanent entry' do - before { cache_store.write(entry[:key], entry[:value]) } + before { cache_store.write(entry[:key], entry[:value], raw: true) } it_behaves_like 'decrementation' @@ -77,10 +84,10 @@ cache_store.decrement(entry[:key], 2, expires_in: expiration_time) sleep(4) # NOTE: remaining time: 4 seconds again, current value: -2 - expect(cache_store.read(entry[:key]).to_i).to eq(-2) | eq(0) + expect(cache_store.read(entry[:key], raw: true).to_i).to eq(-2) | eq(0) sleep(5) # NOTE: remaining time: -1 seconds - expect(cache_store.read(entry[:key])).to eq(nil) + expect(cache_store.read(entry[:key], raw: true)).to eq(nil) end end diff --git a/spec/features/increment_spec.rb b/spec/features/increment_spec.rb index cda6955..7a75c3b 100644 --- a/spec/features/increment_spec.rb +++ b/spec/features/increment_spec.rb @@ -4,7 +4,7 @@ include_context 'cache store' let(:expiration_time) { 8 } # NOTE: in seconds - let(:entry) { { key: SecureRandom.hex, value: 1 } } + let(:entry) { { key: SecureRandom.hex, value: 1 } } shared_examples 'incrementation' do specify 'by default: decrements by 1' do @@ -31,7 +31,14 @@ end context 'with previously defined temporal entry' do - before { cache_store.write(entry[:key], entry[:value], expires_in: expiration_time) } + before do + cache_store.write( + entry[:key], + entry[:value], + expires_in: expiration_time, + raw: true + ) + end it_behaves_like 'incrementation' @@ -43,10 +50,10 @@ cache_store.increment(entry[:key], 2, expires_in: expiration_time) sleep(4) # NOTE: remaining time: 4 seconds again, current value: 4 - expect(cache_store.read(entry[:key]).to_i).to eq(4) + expect(cache_store.read(entry[:key], raw: true).to_i).to eq(4) sleep(5) # NOTE: remaining time: -1 seconds - expect(cache_store.read(entry[:key])).to eq(nil) + expect(cache_store.read(entry[:key], raw: true)).to eq(nil) end end @@ -60,13 +67,13 @@ expect(new_amount).to eq(2) sleep(expiration_time + 1) # NOTE: remaining time: -1 esconds, current value: 2 - expect(cache_store.read(entry[:key]).to_i).to eq(2) + expect(cache_store.read(entry[:key], raw: true).to_i).to eq(2) end end end context 'with previously defined permanent entry' do - before { cache_store.write(entry[:key], entry[:value]) } + before { cache_store.write(entry[:key], entry[:value], raw: true) } it_behaves_like 'incrementation' @@ -78,10 +85,10 @@ cache_store.increment(entry[:key], 2, expires_in: expiration_time) sleep(4) # NOTE: remaining time: 4 seconds again, current value: 4 - expect(cache_store.read(entry[:key]).to_i).to eq(4) + expect(cache_store.read(entry[:key], raw: true).to_i).to eq(4) sleep(5) # NOTE: remaining time: -1 seconds - expect(cache_store.read(entry[:key])).to eq(nil) + expect(cache_store.read(entry[:key], raw: true)).to eq(nil) end end From c367962bcb35dd706eb6853fbf1522f0483fe39f Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Sat, 1 Dec 2018 21:16:02 +0300 Subject: [PATCH 03/13] [marshaling] dumpable interface for adatpers --- lib/any_cache/adapters/basic.rb | 2 ++ lib/any_cache/adapters/dalli.rb | 6 ++-- lib/any_cache/adapters/redis.rb | 9 +++--- lib/any_cache/adapters/redis_store.rb | 13 +++++---- lib/any_cache/dumper.rb | 2 ++ lib/any_cache/dumper/dumpable.rb | 41 +++++++++++++++++++++++++++ spec/features/decrement_spec.rb | 2 +- spec/features/logging_spec.rb | 12 ++++++-- 8 files changed, 71 insertions(+), 16 deletions(-) create mode 100644 lib/any_cache/dumper/dumpable.rb diff --git a/lib/any_cache/adapters/basic.rb b/lib/any_cache/adapters/basic.rb index d93f0cd..f1bde63 100644 --- a/lib/any_cache/adapters/basic.rb +++ b/lib/any_cache/adapters/basic.rb @@ -6,6 +6,8 @@ module AnyCache::Adapters class Basic # @since 0.1.0 extend Forwardable + # @since 0.4.0 + include AnyCache::Dumper::Dumpable class << self # @param driver [Object] diff --git a/lib/any_cache/adapters/dalli.rb b/lib/any_cache/adapters/dalli.rb index cc23f5b..d5d6ba8 100644 --- a/lib/any_cache/adapters/dalli.rb +++ b/lib/any_cache/adapters/dalli.rb @@ -66,7 +66,7 @@ def read(key, **options) raw = options.fetch(:raw, false) value = get(key) - raw ? value : AnyCache::Dumper.load(value) + raw ? value : detransform_value(value) end # @param keys [Array] @@ -82,7 +82,7 @@ def read_multi(*keys, **options) res.merge!(Hash[(keys - res.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) end - raw ? entires : AnyCache::Dumper.detransform_hash(entries) + raw ? entires : detransform_pairset(entries) end # @param key [String] @@ -95,7 +95,7 @@ def read_multi(*keys, **options) def write(key, value, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) raw = options.fetch(:raw, false) - value = AnyCache::Dumper.dump(value) unless raw + value = transform_value(value) unless raw set(key, value, expires_in, raw: raw) end diff --git a/lib/any_cache/adapters/redis.rb b/lib/any_cache/adapters/redis.rb index 0024e23..1846f2d 100644 --- a/lib/any_cache/adapters/redis.rb +++ b/lib/any_cache/adapters/redis.rb @@ -70,7 +70,7 @@ def read(key, **options) value = get(key) raw = options.fetch(:raw, false) - raw ? value : AnyCache::Dumper.load(value) + raw ? value : detransform_value(value) end # @param keys [Array] @@ -83,7 +83,7 @@ def read_multi(*keys, **options) raw = options.fetch(:raw, false) entries = mapped_mget(*keys) - raw ? entries : AnyCache::Dumper.detransform_hash(entries) + raw ? entries : detransform_pairset(entries) end # @param key [String] @@ -96,7 +96,7 @@ def read_multi(*keys, **options) def write(key, value, **options) raw = options.fetch(:raw, false) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) - value = AnyCache::Dumper.dump(value) unless raw + value = transform_value(value) unless raw expires_in ? setex(key, expires_in, value) : set(key, value) end @@ -109,7 +109,8 @@ def write(key, value, **options) # @since 0.3.0 def write_multi(entries, **options) raw = options.fetch(:raw, false) - entries = AnyCache::Dumper.transform_hash(entries) unless raw + entries = transform_pairset(entries) unless raw + mapped_mset(entries) end diff --git a/lib/any_cache/adapters/redis_store.rb b/lib/any_cache/adapters/redis_store.rb index 56de6e6..84f509f 100644 --- a/lib/any_cache/adapters/redis_store.rb +++ b/lib/any_cache/adapters/redis_store.rb @@ -25,9 +25,9 @@ def supported_driver?(driver) # @since 0.1.0 def read(key, **options) raw = options.fetch(:raw, false) - value = get(key, raw: raw) + value = get(key, raw: true) - raw ? value : AnyCache::Dumper.load(value) + raw ? value : detransform_value(value) end # @param keys [Array] @@ -51,9 +51,9 @@ def read_multi(*keys, **options) def write(key, value, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) raw = options.fetch(:raw, false) - value = AnyCache::Dumper.dump(value) unless value + value = transform_value(value) unless raw - expires_in ? setex(key, expires_in, value, raw: raw) : set(key, value, raw: raw) + expires_in ? setex(key, expires_in, value, raw: true) : set(key, value, raw: true) end # @param entries [Hash] @@ -64,8 +64,9 @@ def write(key, value, **options) # @since 0.3.0 def write_multi(entries, **options) raw = options.fetch(:raw, false) - entries = AnyCache::Dumper.transform_hash(entries) unless raw - mset(*entries.to_a.flatten!, raw: raw) + entries = transform_pairset(entries) unless raw + + mset(*entries.to_a.flatten!, raw: true) end end end diff --git a/lib/any_cache/dumper.rb b/lib/any_cache/dumper.rb index 8122950..39f70a9 100644 --- a/lib/any_cache/dumper.rb +++ b/lib/any_cache/dumper.rb @@ -3,6 +3,8 @@ # @api private # @since 0.4.0 module AnyCache::Dumper + require_relative 'dumper/dumpable' + class << self # @param hash [Hash] # @return [Hash] diff --git a/lib/any_cache/dumper/dumpable.rb b/lib/any_cache/dumper/dumpable.rb new file mode 100644 index 0000000..4fe08f5 --- /dev/null +++ b/lib/any_cache/dumper/dumpable.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# @api private +# @since 0.4.0 +module AnyCache::Dumper::Dumpable + # @param value [Object] + # @return [Object] + # + # @api private + # @since 0.4.0 + def transform_value(value) + AnyCache::Dumper.dump(value) + end + + # @param value [Object] + # @return [Object] + # + # @api private + # @since 0.4.0 + def detransform_value(value) + AnyCache::Dumper.load(value) + end + + # @param pairset [Hash] + # @return [Hash] + # + # @api private + # @since 0.4.0 + def transform_pairset(pairset) + AnyCache::Dumper.transform_hash(pairset) + end + + # @param pairset [Hash] + # @return [Hash] + # + # @api private + # @since 0.4.0 + def detransform_pairset(pairset) + AnyCache::Dumper.detransform_hash(pairset) + end +end diff --git a/spec/features/decrement_spec.rb b/spec/features/decrement_spec.rb index e22635c..69c5062 100644 --- a/spec/features/decrement_spec.rb +++ b/spec/features/decrement_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -describe 'Operation: #decrement', :focus do +describe 'Operation: #decrement' do include_context 'cache store' let(:expiration_time) { 8 } # NOTE: in seconds diff --git a/spec/features/logging_spec.rb b/spec/features/logging_spec.rb index c813584..8a142fa 100644 --- a/spec/features/logging_spec.rb +++ b/spec/features/logging_spec.rb @@ -63,7 +63,7 @@ specify '#increment' do log_message = "[AnyCache<#{cacher_name}>/Activity]" - cache_store.write(entry[:key], rand(2..10)) + cache_store.write(entry[:key], rand(2..10), raw: true) expect(output.string).not_to include(log_message) cache_store.increment(entry[:key], rand(1..2), expires_in: expires_in) @@ -72,7 +72,7 @@ specify '#decrmenet' do log_message = "[AnyCache<#{cacher_name}>/Activity]" - cache_store.write(entry[:key], rand(2..10)) + cache_store.write(entry[:key], rand(2..10), raw: true) expect(output.string).not_to include(log_message) cache_store.decrement(entry[:key], rand(1..2), expires_in: expires_in) @@ -122,5 +122,13 @@ end expect(output.string).to include(log_message) end + + specify '#cleanup' do + log_message = "[AnyCache<#{cacher_name}>/Activity]" + + expect(output.string).not_to include(log_message) + cache_store.cleanup(custom_option: SecureRandom.hex(4)) + expect(output.string).to include(log_message) + end end end From d17790dac52df4de4d8744ca70f4a81c7af83ff5 Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Sun, 2 Dec 2018 13:13:53 +0300 Subject: [PATCH 04/13] [marshaling] adpoted #write operation with :raw functionality for ActiveSupport-based cache storages --- README.md | 4 +- bin/rspec | 2 +- .../active_support_mem_cache_store.rb | 19 +++--- .../adapters/active_support_naive_store.rb | 1 - .../active_support_redis_cache_store.rb | 21 ++++--- lib/any_cache/adapters/dalli.rb | 2 +- lib/any_cache/delegation.rb | 2 +- spec/features/write_spec.rb | 62 +++++++++++++++++++ 8 files changed, 89 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 930d279..8a35c60 100644 --- a/README.md +++ b/README.md @@ -353,10 +353,10 @@ params: INSPECTED_ARGUMENTS and options: INSPECTED_OPTIONS ```ruby any_cache.write("data", 123, expires_in: 60) -# I, [2018-09-07T10:04:56.649960 #15761] INFO -- [AnyCache/Activity]: performed operation with params: ["data", 123] and options: {:expires_in=>60}. +# I, [2018-09-07T10:04:56.649960 #15761] INFO -- [AnyCache/Activity]: performed operation with attributes: ["data", 123] and options: {:expires_in=>60}. any_cache.clear -# I, [2018-09-07T10:05:26.999847 #15761] INFO -- [AnyCache/Activity]: performed operation with params: [] and options: {}. +# I, [2018-09-07T10:05:26.999847 #15761] INFO -- [AnyCache/Activity]: performed operation with attributes: [] and options: {}. ``` ## Operations diff --git a/bin/rspec b/bin/rspec index 70ab5f0..6b67e39 100755 --- a/bin/rspec +++ b/bin/rspec @@ -56,7 +56,7 @@ module AnyCacheSpecRunner ) { run_as_memory_store_cache_specs! } opts.on( - '--test-as-mem-cache-store', + '--test-as-memcache-store', 'Run specs with ActiveSupport::Cache::MemCacheStore cache storage' ) { run_as_mem_cache_store_cache_specs! } diff --git a/lib/any_cache/adapters/active_support_mem_cache_store.rb b/lib/any_cache/adapters/active_support_mem_cache_store.rb index 70c00a0..930404b 100644 --- a/lib/any_cache/adapters/active_support_mem_cache_store.rb +++ b/lib/any_cache/adapters/active_support_mem_cache_store.rb @@ -57,7 +57,7 @@ def supported_driver?(driver) # @api private # @since 0.2.0 def read(key, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.read(key, raw: raw) end @@ -69,7 +69,7 @@ def read(key, **options) # @api private # @since 0.3.0 def read_multi(*keys, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.read_multi(*keys, raw: raw).tap do |entries| entries.merge!(Hash[(keys - entries.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) @@ -85,7 +85,7 @@ def read_multi(*keys, **options) # @sicne 0.2.0 def write(key, value, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.write(key, value, expires_in: expires_in, raw: raw) end @@ -97,7 +97,7 @@ def write(key, value, **options) # @api private # @since 0.3.0 def write_multi(entries, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.write_multi(entries, expires_in: NO_EXPIRATION_TTL, raw: raw) end @@ -113,8 +113,9 @@ def fetch(key, **options, &fallback) force_rewrite = options.fetch(:force, false) force_rewrite = force_rewrite.call(key) if force_rewrite.respond_to?(:call) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) + raw = options.fetch(:raw, false) - driver.fetch(key, force: force_rewrite, expires_in: expires_in, &fallback) + driver.fetch(key, force: force_rewrite, expires_in: expires_in, raw: raw, &fallback) end # @param keys [Array] @@ -151,7 +152,7 @@ def increment(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) unless exist?(key) - write(key, amount, expires_in: expires_in) && amount + write(key, amount, expires_in: expires_in, raw: true) && amount else driver.increment(key, amount).tap do expire(key, expires_in: expires_in) if expires_in @@ -174,7 +175,7 @@ def decrement(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) # - non-raw values; # - values lower than zero; # - empty entries; - write(key, INITIAL_DECREMNETED_VALUE, expires_in: expires_in) && INITIAL_DECREMNETED_VALUE + write(key, INITIAL_DECREMNETED_VALUE, expires_in: expires_in, raw: true) && INITIAL_DECREMNETED_VALUE else driver.decrement(key, amount).tap do expire(key, expires_in: expires_in) if expires_in @@ -189,9 +190,9 @@ def decrement(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) # @api private # @since 0.2.0 def expire(key, expires_in: DEAD_TTL) - read(key).tap do |value| + read(key, raw: true).tap do |value| is_alive = expires_in ? expires_in.positive? : false - is_alive ? write(key, value, expires_in: expires_in) : delete(key) + is_alive ? write(key, value, expires_in: expires_in, raw: true) : delete(key) end end diff --git a/lib/any_cache/adapters/active_support_naive_store.rb b/lib/any_cache/adapters/active_support_naive_store.rb index 60de294..2bf4800 100644 --- a/lib/any_cache/adapters/active_support_naive_store.rb +++ b/lib/any_cache/adapters/active_support_naive_store.rb @@ -150,7 +150,6 @@ def fetch_multi(*keys, **options, &fallback) # use own #fetch_multi implementation cuz original #fetch_multi # does not support :force option keys.each_with_object({}) do |key, dataset| - force = force_rewrite.respond_to?(:call) ? force_rewrite.call(key) : force_rewrite dataset[key] = driver.fetch(key, force: force, expires_in: expires_in, &fallback) end end diff --git a/lib/any_cache/adapters/active_support_redis_cache_store.rb b/lib/any_cache/adapters/active_support_redis_cache_store.rb index f1129ab..d24d113 100644 --- a/lib/any_cache/adapters/active_support_redis_cache_store.rb +++ b/lib/any_cache/adapters/active_support_redis_cache_store.rb @@ -51,7 +51,7 @@ def supported_driver?(driver) # @api private # @since 0.1.0 def read(key, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.read(key, raw: raw) end @@ -63,7 +63,7 @@ def read(key, **options) # @api private # @since 0.3.0 def read_multi(*keys, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.read_multi(*keys, raw: raw).tap do |res| res.merge!(Hash[(keys - res.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) @@ -79,7 +79,7 @@ def read_multi(*keys, **options) # @since 0.1.0 def write(key, value, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.write(key, value, expires_in: expires_in, raw: raw) end @@ -91,7 +91,7 @@ def write(key, value, **options) # @api private # @sicne 0.3.0 def write_multi(entries, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.write_multi(entries, expires_in: NO_EXPIRATION_TTL, raw: raw) end @@ -108,7 +108,7 @@ def fetch(key, **options, &fallback) force_rewrite = options.fetch(:force, false) force_rewrite = force_rewrite.call(key) if force_rewrite.respond_to?(:call) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.fetch(key, force: force_rewrite, expires_in: expires_in, raw: raw, &fallback) end @@ -141,7 +141,7 @@ def increment(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) unless exist?(key) - write(key, amount, expires_in: expires_in) && amount + write(key, amount, expires_in: expires_in, raw: true) && amount else driver.increment(key, amount).tap do expire(key, expires_in: expires_in) if expires_in @@ -160,7 +160,7 @@ def decrement(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) unless exist?(key) - write(key, -amount, expires_in: expires_in) && -amount + write(key, -amount, expires_in: expires_in, raw: true) && -amount else driver.decrement(key, amount).tap do expire(key, expires_in: expires_in) if expires_in @@ -175,9 +175,12 @@ def decrement(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) # @api private # @since 0.1.0 def expire(key, expires_in: DEAD_TTL) - read(key).tap do |value| + # NOTE: + # raw is true cuz we want the raw cached value. + # this raw value would be cached again if needed. + read(key, raw: true).tap do |value| is_alive = expires_in ? expires_in.positive? : false - is_alive ? write(key, value, expires_in: expires_in) : delete(key) + is_alive ? write(key, value, expires_in: expires_in, raw: true) : delete(key) end end diff --git a/lib/any_cache/adapters/dalli.rb b/lib/any_cache/adapters/dalli.rb index d5d6ba8..a1b1f11 100644 --- a/lib/any_cache/adapters/dalli.rb +++ b/lib/any_cache/adapters/dalli.rb @@ -76,7 +76,7 @@ def read(key, **options) # @api private # @since 0.3.0 def read_multi(*keys, **options) - raw = options.fethc(:raw, false) + raw = options.fetch(:raw, false) entries = get_multi(*keys).tap do |res| res.merge!(Hash[(keys - res.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) diff --git a/lib/any_cache/delegation.rb b/lib/any_cache/delegation.rb index c4ab4c1..1448612 100644 --- a/lib/any_cache/delegation.rb +++ b/lib/any_cache/delegation.rb @@ -40,7 +40,7 @@ def def_loggable_delegator(receiver, delegat) AnyCache::Logging::Activity.log( self, logger, activity: delegat, message: "performed <#{delegat}> operation with " \ - "params: #{args.inspect} and options: #{opts.inspect}." + "attributes: #{args.inspect} and options: #{opts.inspect}." ) if logger end end diff --git a/spec/features/write_spec.rb b/spec/features/write_spec.rb index 60df90f..cfdb38c 100644 --- a/spec/features/write_spec.rb +++ b/spec/features/write_spec.rb @@ -7,6 +7,68 @@ let(:first_pair) { { key: SecureRandom.hex, value: SecureRandom.hex(4) } } let(:second_pair) { { key: SecureRandom.hex, value: SecureRandom.hex(4) } } + describe 'raw write / non-raw write' do + before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) } + + specify 'non-raw is used by default' do + ruby_object = SimpleRubyObject.new('a', 123, true) + cache_store.write(:ruby_object, ruby_object) + cached_ruby_object = cache_store.read(:ruby_object) + + expect(cached_ruby_object).to be_a(SimpleRubyObject) + expect(cached_ruby_object.a).to eq('a') + expect(cached_ruby_object.b).to eq(123) + expect(cached_ruby_object.c).to eq(true) + end + + context 'write non-raw (:raw option is false)' do + specify 'returns real ruby object' do + # works with initial structures + ruby_object = { a: 1, b: 2, c: 3 } + cache_store.write(:non_raw, ruby_object, raw: false) + cached_ruby_object = cache_store.read(:non_raw, raw: false) + + expect(cached_ruby_object).to be_a(Hash) + expect(cached_ruby_object).to match(ruby_object) + + # works with custom classes + another_ruby_object = SimpleRubyObject.new(1, 2, 3) + cache_store.write(:non_raw, another_ruby_object, raw: false) + cached_another_ruby_object = cache_store.read(:non_raw, raw: false) + + expect(cached_another_ruby_object).to be_a(SimpleRubyObject) + expect(cached_another_ruby_object.a).to eq(1) + expect(cached_another_ruby_object.b).to eq(2) + expect(cached_another_ruby_object.c).to eq(3) + end + end + + context 'write raw (:raw option is true)' do + before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) } + + # NOTE: + # ActiveSupport::Cache::FileStore and ActiveSupport::Cache::ReadStore does not support + # :raw optionality cuz under the hood these classes invokes #write_entry method that uses + # Marshal.dump before the write-to-disk and write-to-memory operations respectively. + specify( + 'returns internal cache-related string-like object', + exclude: %i[as_file_store as_memory_store] + ) do + ruby_object = { a: 1, b: 2, c: 3} + cache_store.write(:raw, ruby_object, raw: true) + cached_ruby_object = cache_store.read(:raw, raw: true) + + expect(cached_ruby_object).to be_a(String) + + another_ruby_object = SimpleRubyObject.new(1, 2, 3) + cache_store.write(:raw, another_ruby_object, raw: true) + cached_another_ruby_object = cache_store.read(:raw, raw: true) + + expect(cached_another_ruby_object).to be_a(String) + end + end + end + context 'without expiration' do it 'writes permanent entry' do # NOTE: permanent entries From b3d567240ace6028e4d827511031ed9a6d890eba Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Sun, 2 Dec 2018 21:48:17 +0300 Subject: [PATCH 05/13] [marshaling] separated raw/non-raw (multi)read/(multi)write spec --- spec/features/raw_non_raw_read_write_spec.rb | 99 ++++++++++++++++++++ spec/features/write_spec.rb | 62 ------------ 2 files changed, 99 insertions(+), 62 deletions(-) create mode 100644 spec/features/raw_non_raw_read_write_spec.rb diff --git a/spec/features/raw_non_raw_read_write_spec.rb b/spec/features/raw_non_raw_read_write_spec.rb new file mode 100644 index 0000000..ee3116e --- /dev/null +++ b/spec/features/raw_non_raw_read_write_spec.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +describe 'raw read/write / non-raw read/write', :focus do + include_context 'cache store' + + before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) } + + specify 'non-raw is used by default' do + ruby_object = SimpleRubyObject.new('a', 123, true) + cache_store.write(:ruby_object, ruby_object) + cached_ruby_object = cache_store.read(:ruby_object) + + expect(cached_ruby_object).to be_a(SimpleRubyObject) + expect(cached_ruby_object.a).to eq('a') + expect(cached_ruby_object.b).to eq(123) + expect(cached_ruby_object.c).to eq(true) + end + + context 'write non-raw (:raw option is false)' do + context 'single read/write' do + specify 'writes real ruby object' do + # works with initial structures + ruby_object = { a: 1, b: 2, c: 3 } + cache_store.write(:non_raw, ruby_object, raw: false) + cached_ruby_object = cache_store.read(:non_raw, raw: false) + + expect(cached_ruby_object).to be_a(Hash) + expect(cached_ruby_object).to match(ruby_object) + + # works with custom classes + another_ruby_object = SimpleRubyObject.new(1, 2, 3) + cache_store.write(:non_raw, another_ruby_object, raw: false) + cached_another_ruby_object = cache_store.read(:non_raw, raw: false) + + expect(cached_another_ruby_object).to be_a(SimpleRubyObject) + expect(cached_another_ruby_object.a).to eq(1) + expect(cached_another_ruby_object.b).to eq(2) + expect(cached_another_ruby_object.c).to eq(3) + end + end + + context 'multi read/write' do + specify 'writes real ruby object' do + # worsk with any adequate type + ruby_entries = { + hash_ruby_obj: { a: 1, b: 2, c: 3 }, + bool_ruby_obj: true, + real_ruby_obj: SimpleRubyObject.new(1, 2, 3) + } + + cache_store.write_multi(ruby_entries, raw: false) + cached_ruby_entries = cache_store.read_multi(*ruby_entries.keys, raw: false) + + expect(cached_ruby_entries).to match(ruby_entries) + end + end + end + + # NOTE: + # ActiveSupport::Cache::FileStore and ActiveSupport::Cache::ReadStore does not support + # raw/non-raw optionality cuz under the hood these classes invokes #write_entry method + # that uses Marshal.dump before the write-to-disk and write-to-memory operations respectively. + context 'write raw (:raw option is true)', exclude: %i[as_file_store as_memory_store] do + before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) } + + context 'single read/write' do + specify 'uses internal cache-related string-like object write operation' do + ruby_object = { a: 1, b: 2, c: 3} + cache_store.write(:raw, ruby_object, raw: true) + cached_ruby_object = cache_store.read(:raw, raw: true) + + expect(cached_ruby_object).to be_a(String) + + another_ruby_object = SimpleRubyObject.new(1, 2, 3) + cache_store.write(:raw, another_ruby_object, raw: true) + cached_another_ruby_object = cache_store.read(:raw, raw: true) + + expect(cached_another_ruby_object).to be_a(String) + end + end + + context 'multi read/write' do + specify 'uses internal cache-related string-like object write operation' do + # works with any adequate type + ruby_entries = { + hash_ruby_obj: { a: 1, b: 2, c: 3 }, + bool_ruby_obj: true, + real_ruby_obj: SimpleRubyObject.new(1, 2, 3) + } + + cache_store.write_multi(ruby_entries, raw: true) + cached_ruby_entries = cache_store.read_multi(*ruby_entries.keys, raw: true) + + expect(cached_ruby_entries.keys).to contain_exactly(*ruby_entries.keys) + expect(cached_ruby_entries.values).to all(be_a(String)) + end + end + end +end diff --git a/spec/features/write_spec.rb b/spec/features/write_spec.rb index cfdb38c..60df90f 100644 --- a/spec/features/write_spec.rb +++ b/spec/features/write_spec.rb @@ -7,68 +7,6 @@ let(:first_pair) { { key: SecureRandom.hex, value: SecureRandom.hex(4) } } let(:second_pair) { { key: SecureRandom.hex, value: SecureRandom.hex(4) } } - describe 'raw write / non-raw write' do - before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) } - - specify 'non-raw is used by default' do - ruby_object = SimpleRubyObject.new('a', 123, true) - cache_store.write(:ruby_object, ruby_object) - cached_ruby_object = cache_store.read(:ruby_object) - - expect(cached_ruby_object).to be_a(SimpleRubyObject) - expect(cached_ruby_object.a).to eq('a') - expect(cached_ruby_object.b).to eq(123) - expect(cached_ruby_object.c).to eq(true) - end - - context 'write non-raw (:raw option is false)' do - specify 'returns real ruby object' do - # works with initial structures - ruby_object = { a: 1, b: 2, c: 3 } - cache_store.write(:non_raw, ruby_object, raw: false) - cached_ruby_object = cache_store.read(:non_raw, raw: false) - - expect(cached_ruby_object).to be_a(Hash) - expect(cached_ruby_object).to match(ruby_object) - - # works with custom classes - another_ruby_object = SimpleRubyObject.new(1, 2, 3) - cache_store.write(:non_raw, another_ruby_object, raw: false) - cached_another_ruby_object = cache_store.read(:non_raw, raw: false) - - expect(cached_another_ruby_object).to be_a(SimpleRubyObject) - expect(cached_another_ruby_object.a).to eq(1) - expect(cached_another_ruby_object.b).to eq(2) - expect(cached_another_ruby_object.c).to eq(3) - end - end - - context 'write raw (:raw option is true)' do - before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) } - - # NOTE: - # ActiveSupport::Cache::FileStore and ActiveSupport::Cache::ReadStore does not support - # :raw optionality cuz under the hood these classes invokes #write_entry method that uses - # Marshal.dump before the write-to-disk and write-to-memory operations respectively. - specify( - 'returns internal cache-related string-like object', - exclude: %i[as_file_store as_memory_store] - ) do - ruby_object = { a: 1, b: 2, c: 3} - cache_store.write(:raw, ruby_object, raw: true) - cached_ruby_object = cache_store.read(:raw, raw: true) - - expect(cached_ruby_object).to be_a(String) - - another_ruby_object = SimpleRubyObject.new(1, 2, 3) - cache_store.write(:raw, another_ruby_object, raw: true) - cached_another_ruby_object = cache_store.read(:raw, raw: true) - - expect(cached_another_ruby_object).to be_a(String) - end - end - end - context 'without expiration' do it 'writes permanent entry' do # NOTE: permanent entries From 4029539d7aea80cb41de8a6d9455fe11be9b1053 Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Sun, 2 Dec 2018 23:43:15 +0300 Subject: [PATCH 06/13] [marshaling/readme] documentation for :raw => true option --- README.md | 58 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8a35c60..90c732f 100644 --- a/README.md +++ b/README.md @@ -382,6 +382,7 @@ any_cache.clear - fetches data from the cache using the given key; - if a `fallback` block has been passed and data with the given key does not exist - that block will be called with the given key and the return value will be written to the cache; + - use `raw: true` if you want to fetch incrementable/decrementable entry; ```ruby # --- entry exists --- @@ -416,6 +417,7 @@ cache_store.fetch("data") # => nil - get a set of entries in hash form from the cache storage using given keys; - works in `#fetch` manner but with a series of entries; - nonexistent entries will be fetched with `nil` values; + - use `raw: true` if you want to fetch incrementable/decrementable entries; ```ruby # --- fetch entries --- @@ -451,6 +453,7 @@ cache_store.fetch_multi("data", "second_data", "last_data", force: true) { |key| ### Read - `AnyCache#read(key)` - get an entry value from the cache storage + - pass `raw: true` if you want to read incrementable/decrementable entries; ```ruby # --- entry exists --- @@ -458,6 +461,9 @@ cache_store.read("data") # => "some_data" # --- entry doesnt exist --- cache_store.read("data") # => nil + +# --- read incrementable/decrementable entry --- +cache_store.read("data", raw: true) # => "2" (for example) ``` --- @@ -467,6 +473,7 @@ cache_store.read("data") # => nil - `AnyCache#read_multi(*keys)` - get entries from the cache storage in hash form; - nonexistent entries will be fetched with `nil` values; + - pass `raw: true` if you want to read incrementable/decrementable entries; ```ruby cache_store.read_multi("data", "another_data", "last_data", "super_data") @@ -477,13 +484,22 @@ cache_store.read_multi("data", "another_data", "last_data", "super_data") "last_data" => "some_data", # exisitng enry "super_data" => nil # existing entry } + +# --- read incrementable/decrementable entries --- +cache_store.read_multi("data", "another_data", raw: true) +# => returns +{ + "data" => "1", + "another_data" => "2", +} ``` --- ### Write -- `AnyCache#write(key, value, [expires_in:])` - write a new entry to the cache storage +- `AnyCache#write(key, value, [expires_in:])` - write a new entry to the cache storage; + - pass `raw: true` if you want to store incrementable/decrementable entries; ```ruby # --- permanent entry --- @@ -491,23 +507,30 @@ cache_store.write("data", 123) # --- temporal entry (expires in 60 seconds) --- cache_store.write("data", 123, expires_in: 60) + +# --- incrementable/decrementable entry --- +cache_store.write("data", 123, raw: true) ``` --- ### Write Multi -- `AnyCache#write_multi(**entries)` - write a set of permanent entries to the cache storage +- `AnyCache#write_multi(**entries)` - write a set of permanent entries to the cache storage; + - pass `raw: true` if you want to store incrementable/decrementable entries; ```ruby cache_store.write_multi("data" => "test", "another_data" => 123) + +# --- incrementable/decrementable entries --- +cache_store.write_multi("data" => 1, "another_data" => 2, raw: true) ``` --- ### Delete -- `AnyCache#delete(key)` - remove entry from the cache storage +- `AnyCache#delete(key)` - remove entry from the cache storage; ```ruby cache_store.delete("data") @@ -519,7 +542,7 @@ cache_store.delete("data") - `AnyCache#delete_matched(pattern)` - removes all entries with keys matching the pattern; - - currently unsupported: `:dalli`, `:as_mem_cache_store`, `:as_dalli_Store`; + - currently unsupported: `:dalli`, `:as_mem_cache_store`, `:as_dalli_store`; ```ruby # --- using a regepx --- @@ -534,11 +557,12 @@ cache_store.delete_matched("data") ### Increment - `AnyCache#increment(key, amount = 1, [expires_in:])` - increment entry's value by the given amount - and set the new expiration time if needed + and set the new expiration time if needed; + - can increment only nonexistent entries OR entries that were written with `raw: true` option; ```ruby # --- increment existing entry --- -cache_store.write("data", 1) +cache_store.write("data", 1, raw: true) # you must provide :raw => true for incrementable entries # --- increment by default value (1) --- cache_store.increment("data") # => 2 @@ -551,6 +575,9 @@ cache_store.incrmeent("data", expires_in: 31) # => 15 # --- increment nonexistent entry (create new entry) --- cache_store.increment("another_data", 5, expires_in: 5) # => 5 + +# --- read incrementable entry --- +cache_store.read("data", raw: true) # you must provide :raw => true for incrementable entries ``` --- @@ -558,11 +585,12 @@ cache_store.increment("another_data", 5, expires_in: 5) # => 5 ### Decrement - `AnyCache#decrement(key, amount = 1, [expires_in:])` - decrement entry's value by the given amount - and set the new expiration time if needed + and set the new expiration time if needed; + - can decrement only nonexistent entries OR entries that were written with `raw: true` option; ```ruby # --- decrement existing entry --- -cache_store.write("data", 15) +cache_store.write("data", 15, raw: true) # you must provide :raw => true for decrementable entries # --- decrement by default value (1) --- cache_store.decrement("data") # => 14 @@ -575,13 +603,16 @@ cache_store.decrememnt("data", expirs_in: 5) # => 3 # --- decrement nonexistent entry (create new entry) --- cache_store.decrememnt("another_data", 2, expires_in: 10) # => -2 (or 0 for Dalli::Client) + +# --- read decrementable entry --- +cache_store.read("data", raw: true) # you must provide :raw => true for decrementable entries ``` --- ### Expire -- `AnyCache#expire(key, [expires_in:])` - expire entry immediately or set the new expiration time +- `AnyCache#expire(key, [expires_in:])` - expire entry immediately or set the new expiration time; ```ruby # --- expire immediately --- @@ -595,7 +626,7 @@ cache_store.expire("data", expires_in: 36) ### Persist -- `AnyCache#persist(key)` - change entry's expiration time to permanent +- `AnyCache#persist(key)` - change entry's expiration time to permanent; ```ruby # --- create temporal entry (30 seconds) --- @@ -609,7 +640,7 @@ cache_store.persist("data") ### Existence -- `AnyCache#exist?(key)` - determine if an entry exists +- `AnyCache#exist?(key)` - determine if an entry exists; ```ruby # --- entry exists --- @@ -623,7 +654,7 @@ cache_store.exist?("another-data") # => false ### Clear -- `AnyCache#clear()` - clear cache database +- `AnyCache#clear()` - clear cache database; ```ruby # --- prepare cache data --- @@ -644,7 +675,8 @@ cache_store.read("another_data") # => nil ### Cleanup -- `AnyCache#cleanup()` - remove expired entries from cache database (make sense only for `:as_file_store` and `:as_memory_store` cache clients) +- `AnyCache#cleanup()` - remove expired entries from cache database + (make sense only for `:as_file_store` and `:as_memory_store` cache clients); ```ruby # --- prepare cache data --- From e53f702cf5322d454a008d3acfa26e7fca5c2498 Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Sun, 2 Dec 2018 23:47:09 +0300 Subject: [PATCH 07/13] [marshaling] CHANGELOG updates --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9e060f..e12249c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - `AnyCache#cleanup` - remove expired entries manually (make sence only for `:as_file_store` and `:as_memory_store` at this moment); +- automatic object marshaling (used in `fetch`, `fetch_multi`, `write`, `write_multi`, `read`, `read_multi`): + - used by default (`raw: false`); + - can be disabled via `raw: true` option; + - `raw: true` is required for incrementable/decrementable entries; ## [0.3.1] - 2018-10-08 ### Added From 3a4b971efd5b5c340145209e91a8f5ab88d91250 Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Mon, 3 Dec 2018 01:00:44 +0300 Subject: [PATCH 08/13] [marshaling] specs, specs, specs... (mutli_operations and dalli bugs) --- .../adapters/active_support_naive_store.rb | 2 +- lib/any_cache/adapters/dalli.rb | 5 +- spec/features/raw_non_raw_read_write_spec.rb | 98 +++++++++++++++---- 3 files changed, 85 insertions(+), 20 deletions(-) diff --git a/lib/any_cache/adapters/active_support_naive_store.rb b/lib/any_cache/adapters/active_support_naive_store.rb index 2bf4800..6338392 100644 --- a/lib/any_cache/adapters/active_support_naive_store.rb +++ b/lib/any_cache/adapters/active_support_naive_store.rb @@ -150,7 +150,7 @@ def fetch_multi(*keys, **options, &fallback) # use own #fetch_multi implementation cuz original #fetch_multi # does not support :force option keys.each_with_object({}) do |key, dataset| - dataset[key] = driver.fetch(key, force: force, expires_in: expires_in, &fallback) + dataset[key] = driver.fetch(key, force: force_rewrite, expires_in: expires_in, &fallback) end end end diff --git a/lib/any_cache/adapters/dalli.rb b/lib/any_cache/adapters/dalli.rb index a1b1f11..fc31a3e 100644 --- a/lib/any_cache/adapters/dalli.rb +++ b/lib/any_cache/adapters/dalli.rb @@ -79,10 +79,13 @@ def read_multi(*keys, **options) raw = options.fetch(:raw, false) entries = get_multi(*keys).tap do |res| + # TODO: returned res.keys items should have consistent types with initial keys items + # (at this moment you cant return requested symbolic keys - + # your keys will be stringifed by dalli) res.merge!(Hash[(keys - res.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) end - raw ? entires : detransform_pairset(entries) + raw ? entries : detransform_pairset(entries) end # @param key [String] diff --git a/spec/features/raw_non_raw_read_write_spec.rb b/spec/features/raw_non_raw_read_write_spec.rb index ee3116e..68b5af3 100644 --- a/spec/features/raw_non_raw_read_write_spec.rb +++ b/spec/features/raw_non_raw_read_write_spec.rb @@ -11,14 +11,12 @@ cached_ruby_object = cache_store.read(:ruby_object) expect(cached_ruby_object).to be_a(SimpleRubyObject) - expect(cached_ruby_object.a).to eq('a') - expect(cached_ruby_object.b).to eq(123) - expect(cached_ruby_object.c).to eq(true) + expect(cached_ruby_object).to have_attributes(a: 'a', b: 123, c: true) end - context 'write non-raw (:raw option is false)' do + context 'write non-raw (write real ruby object) (:raw => false)' do context 'single read/write' do - specify 'writes real ruby object' do + specify '#read/#write works correctly' do # works with initial structures ruby_object = { a: 1, b: 2, c: 3 } cache_store.write(:non_raw, ruby_object, raw: false) @@ -33,19 +31,30 @@ cached_another_ruby_object = cache_store.read(:non_raw, raw: false) expect(cached_another_ruby_object).to be_a(SimpleRubyObject) - expect(cached_another_ruby_object.a).to eq(1) - expect(cached_another_ruby_object.b).to eq(2) - expect(cached_another_ruby_object.c).to eq(3) + expect(cached_another_ruby_object).to have_attributes(a: 1, b: 2, c: 3) + end + + specify '#fetch works correctly' do + returned_ruby_object = cache_store.fetch(:non_raw, raw: false) do |key| + SimpleRubyObject.new(key, 1, false) + end + + cached_ruby_object = cache_store.fetch(:non_raw, raw: false) + + [cached_ruby_object, returned_ruby_object].each do |cached_object| + expect(cached_object).to be_a(SimpleRubyObject) + expect(cached_object).to have_attributes(a: :non_raw, b: 1, c: false) + end end end context 'multi read/write' do - specify 'writes real ruby object' do + specify '#read_multi/#write_multi works correctly' do # worsk with any adequate type ruby_entries = { - hash_ruby_obj: { a: 1, b: 2, c: 3 }, - bool_ruby_obj: true, - real_ruby_obj: SimpleRubyObject.new(1, 2, 3) + 'hash_ruby_obj' => { a: 1, b: 2, c: 3 }, + 'bool_ruby_obj' => true, + 'real_ruby_obj' => SimpleRubyObject.new(1, 2, 3) } cache_store.write_multi(ruby_entries, raw: false) @@ -53,6 +62,24 @@ expect(cached_ruby_entries).to match(ruby_entries) end + + specify '#fetch_multi works correctly' do + returned_ruby_entries = cache_store.fetch_multi(:a, :b, :c, raw: false) do |key| + SimpleRubyObject.new(key, 1, true) + end + + cached_ruby_entries = cache_store.fetch_multi(:a, :b, :c, raw: false) + + [cached_ruby_entries, returned_ruby_entries].each do |cached_entries| + expect(cached_entries[:a]).to be_a(SimpleRubyObject) + expect(cached_entries[:b]).to be_a(SimpleRubyObject) + expect(cached_entries[:c]).to be_a(SimpleRubyObject) + + expect(cached_entries[:a]).to have_attributes(a: :a, b: 1, c: true) + expect(cached_entries[:b]).to have_attributes(a: :b, b: 1, c: true) + expect(cached_entries[:c]).to have_attributes(a: :c, b: 1, c: true) + end + end end end @@ -60,11 +87,15 @@ # ActiveSupport::Cache::FileStore and ActiveSupport::Cache::ReadStore does not support # raw/non-raw optionality cuz under the hood these classes invokes #write_entry method # that uses Marshal.dump before the write-to-disk and write-to-memory operations respectively. - context 'write raw (:raw option is true)', exclude: %i[as_file_store as_memory_store] do + context( + 'write raw (:raw => true) (uses internal cache-related string-like object write operation)', + exclude: %i[as_file_store as_memory_store] + ) do + before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) } context 'single read/write' do - specify 'uses internal cache-related string-like object write operation' do + specify '#read/#write works correctly' do ruby_object = { a: 1, b: 2, c: 3} cache_store.write(:raw, ruby_object, raw: true) cached_ruby_object = cache_store.read(:raw, raw: true) @@ -77,15 +108,30 @@ expect(cached_another_ruby_object).to be_a(String) end + + specify '#fetch works correctly' do + returned_ruby_object = cache_store.fetch(:raw, raw: true) do |key| + SimpleRubyObject.new(key, 1, false) + end + + cached_ruby_object = cache_store.fetch(:raw, raw: true) + + # TODO: think about consistent fetching + # - expect(returned_ruby_object).to be_a(String) + # - nonexistent value (first #fetch invokation) + # will return the &fallback's proc result (real ruby object) + + expect(cached_ruby_object).to be_a(String) + end end context 'multi read/write' do - specify 'uses internal cache-related string-like object write operation' do + specify '#read_multi/#write_multi works correctly' do # works with any adequate type ruby_entries = { - hash_ruby_obj: { a: 1, b: 2, c: 3 }, - bool_ruby_obj: true, - real_ruby_obj: SimpleRubyObject.new(1, 2, 3) + 'hash_ruby_obj' => { a: 1, b: 2, c: 3 }, + 'bool_ruby_obj' => true, + 'real_ruby_obj' => SimpleRubyObject.new(1, 2, 3) } cache_store.write_multi(ruby_entries, raw: true) @@ -94,6 +140,22 @@ expect(cached_ruby_entries.keys).to contain_exactly(*ruby_entries.keys) expect(cached_ruby_entries.values).to all(be_a(String)) end + + specify '#fetch_multi works correctly' do + returned_ruby_entries = cache_store.fetch_multi(:a, :b, raw: true) do |key| + SimpleRubyObject.new(key, true, false) + end + + cached_ruby_entries = cache_store.fetch_multi(:a, :b, raw: true) + + # TODO: think about consistent fetching + # - expect(returned_ruby_entries.values).to all(be_a(String)) and so on + # - nonexistent value (first #fetch invokation) + # will return the &fallback's proc result (real ruby object) + + expect(cached_ruby_entries.keys).to contain_exactly(:a, :b) + expect(cached_ruby_entries.values).to all(be_a(String)) + end end end end From adce940caece72e32664dc6b86b701c963d80468 Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Mon, 3 Dec 2018 01:09:00 +0300 Subject: [PATCH 09/13] [marshaling] fixed as-dalli-store raw/non-raw functionality --- .../adapters/active_support_dalli_store.rb | 20 ++++++++++--------- spec/features/raw_non_raw_read_write_spec.rb | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/any_cache/adapters/active_support_dalli_store.rb b/lib/any_cache/adapters/active_support_dalli_store.rb index 65f68cb..a93d8e1 100644 --- a/lib/any_cache/adapters/active_support_dalli_store.rb +++ b/lib/any_cache/adapters/active_support_dalli_store.rb @@ -55,7 +55,7 @@ def supported_driver?(driver) # @api private # @since 0.3.0 def read(key, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.read(key, raw: raw) end @@ -67,7 +67,7 @@ def read(key, **options) # @api private # @since 0.3.0 def read_multi(*keys, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.read_multi(*keys, raw: raw).tap do |entries| entries.merge!(Hash[(keys - entries.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) @@ -83,7 +83,7 @@ def read_multi(*keys, **options) # @since 0.3.0 def write(key, value, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) driver.write(key, value, expires_in: expires_in, raw: raw) end @@ -95,7 +95,7 @@ def write(key, value, **options) # @api private # @since 0.3.0 def write_multi(entries, **options) - raw = options.fetch(:raw, true) + raw = options.fetch(:raw, false) # NOTE: ActiveSupport::Cache::DalliStore does not support #write_multi :\ entries.each_pair do |key, value| @@ -114,8 +114,9 @@ def fetch(key, **options, &fallback) force_rewrite = options.fetch(:force, false) force_rewrite = force_rewrite.call(key) if force_rewrite.respond_to?(:call) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) + raw = options.fetch(:raw, false) - driver.fetch(key, force: force_rewrite, expires_in: expires_in, &fallback) + driver.fetch(key, force: force_rewrite, expires_in: expires_in, raw: raw, &fallback) end # @param keys [Array] @@ -142,7 +143,7 @@ def increment(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL) unless exist?(key) - write(key, amount, expires_in: expires_in) && amount + write(key, amount, expires_in: expires_in, raw: true) && amount else driver.increment(key, amount).tap do expire(key, expires_in: expires_in) if expires_in @@ -165,7 +166,8 @@ def decrement(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) # - non-raw values; # - values lower than zero; # - empty entries; - write(key, INITIAL_DECREMNETED_VALUE, expires_in: expires_in) && INITIAL_DECREMNETED_VALUE + write(key, INITIAL_DECREMNETED_VALUE, expires_in: expires_in, raw: true) + INITIAL_DECREMNETED_VALUE else driver.decrement(key, amount).tap do expire(key, expires_in: expires_in) if expires_in @@ -190,9 +192,9 @@ def delete_matched(pattern, **options) # @api private # @since 0.3.0 def expire(key, expires_in: DEAD_TTL) - read(key).tap do |value| + read(key, raw: true).tap do |value| is_alive = expires_in ? expires_in.positive? : false - is_alive ? write(key, value, expires_in: expires_in) : delete(key) + is_alive ? write(key, value, expires_in: expires_in, raw: true) : delete(key) end end diff --git a/spec/features/raw_non_raw_read_write_spec.rb b/spec/features/raw_non_raw_read_write_spec.rb index 68b5af3..c4d7cb0 100644 --- a/spec/features/raw_non_raw_read_write_spec.rb +++ b/spec/features/raw_non_raw_read_write_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -describe 'raw read/write / non-raw read/write', :focus do +describe 'raw read/write / non-raw read/write' do include_context 'cache store' before { stub_const('SimpleRubyObject', Struct.new(:a, :b, :c)) } From 18a677cd39c9f8bc58502d5fed9a09ba7283c6dc Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Mon, 3 Dec 2018 01:41:14 +0300 Subject: [PATCH 10/13] [marshaling] fixed inconsistent AnyCache::Adapters::Dalli#read_multi key types --- lib/any_cache/adapters/dalli.rb | 14 ++++++++++---- spec/features/raw_non_raw_read_write_spec.rb | 12 ++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/any_cache/adapters/dalli.rb b/lib/any_cache/adapters/dalli.rb index fc31a3e..3f1d291 100644 --- a/lib/any_cache/adapters/dalli.rb +++ b/lib/any_cache/adapters/dalli.rb @@ -79,10 +79,16 @@ def read_multi(*keys, **options) raw = options.fetch(:raw, false) entries = get_multi(*keys).tap do |res| - # TODO: returned res.keys items should have consistent types with initial keys items - # (at this moment you cant return requested symbolic keys - - # your keys will be stringifed by dalli) - res.merge!(Hash[(keys - res.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) + # NOTE: + # dalli does not return nonexistent entries + # but we want to be consistent with another cache storages + # that returns nonexistent antries as { key => nil } pair + res.merge!(Hash[(keys.map(&:to_s) - res.keys).zip(READ_MULTI_EMPTY_KEYS_SET)]) + + # NOTE: + # dalli stringifies requred keys but we want to be consistent with symbol keys + # cuz another cache storages are already consistent + keys.each { |key| res.key?(key) ? next : (res[key] = res.delete(key.to_s)) } end raw ? entries : detransform_pairset(entries) diff --git a/spec/features/raw_non_raw_read_write_spec.rb b/spec/features/raw_non_raw_read_write_spec.rb index c4d7cb0..9d41218 100644 --- a/spec/features/raw_non_raw_read_write_spec.rb +++ b/spec/features/raw_non_raw_read_write_spec.rb @@ -52,9 +52,9 @@ specify '#read_multi/#write_multi works correctly' do # worsk with any adequate type ruby_entries = { - 'hash_ruby_obj' => { a: 1, b: 2, c: 3 }, - 'bool_ruby_obj' => true, - 'real_ruby_obj' => SimpleRubyObject.new(1, 2, 3) + hash_ruby_obj: { a: 1, b: 2, c: 3 }, + bool_ruby_obj: true, + real_ruby_obj: SimpleRubyObject.new(1, 2, 3) } cache_store.write_multi(ruby_entries, raw: false) @@ -129,9 +129,9 @@ specify '#read_multi/#write_multi works correctly' do # works with any adequate type ruby_entries = { - 'hash_ruby_obj' => { a: 1, b: 2, c: 3 }, - 'bool_ruby_obj' => true, - 'real_ruby_obj' => SimpleRubyObject.new(1, 2, 3) + hash_ruby_obj: { a: 1, b: 2, c: 3 }, + bool_ruby_obj: true, + real_ruby_obj: SimpleRubyObject.new(1, 2, 3) } cache_store.write_multi(ruby_entries, raw: true) From 9470b330edfe1a643a1b2128955ee5844147e55e Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Mon, 3 Dec 2018 02:01:06 +0300 Subject: [PATCH 11/13] [marshaling] udpated docs (method signature documentation) --- lib/any_cache/adapters/active_support_dalli_store.rb | 8 +++++--- .../adapters/active_support_mem_cache_store.rb | 11 +++++++---- lib/any_cache/adapters/active_support_naive_store.rb | 3 ++- .../adapters/active_support_redis_cache_store.rb | 8 +++++--- lib/any_cache/adapters/dalli.rb | 1 + lib/any_cache/adapters/redis.rb | 7 ++++--- lib/any_cache/adapters/redis_store.rb | 5 +++-- lib/any_cache/dumper.rb | 2 +- 8 files changed, 28 insertions(+), 17 deletions(-) diff --git a/lib/any_cache/adapters/active_support_dalli_store.rb b/lib/any_cache/adapters/active_support_dalli_store.rb index a93d8e1..2804f7d 100644 --- a/lib/any_cache/adapters/active_support_dalli_store.rb +++ b/lib/any_cache/adapters/active_support_dalli_store.rb @@ -49,7 +49,7 @@ def supported_driver?(driver) def_delegators :driver, :delete, :clear, :cleanup # @param key [String] - # @param options [Hash] + # @option raw [Boolean] # @return [void] # # @api private @@ -61,7 +61,7 @@ def read(key, **options) end # @param keys [Array] - # @param options [Hash] + # @option raw [Boolean] # @return [Hash] # # @api private @@ -77,6 +77,7 @@ def read_multi(*keys, **options) # @param key [String] # @param value [Object] # @option expires_in [NilClass, Integer] Time in seconds + # @option raw [Boolean] # @return [void] # # @api private @@ -89,7 +90,7 @@ def write(key, value, **options) end # @param entries [Hash] - # @param options [Hash] + # @option raw [Boolean] # @return [void] # # @api private @@ -106,6 +107,7 @@ def write_multi(entries, **options) # @param key [String] # @option expires_in [Integer] # @option force [Boolean, Proc] + # @option raw [Boolean] # @return [Object] # # @api private diff --git a/lib/any_cache/adapters/active_support_mem_cache_store.rb b/lib/any_cache/adapters/active_support_mem_cache_store.rb index 930404b..54bb824 100644 --- a/lib/any_cache/adapters/active_support_mem_cache_store.rb +++ b/lib/any_cache/adapters/active_support_mem_cache_store.rb @@ -51,7 +51,7 @@ def supported_driver?(driver) def_delegators :driver, :delete, :clear # @param key [String] - # @param options [Hash] + # @option raw [Boolean] # @return [Object] # # @api private @@ -63,7 +63,7 @@ def read(key, **options) end # @param keys [Array] - # @param options [Hash] + # @option raw [Boolean] # @return [Hash] # # @api private @@ -79,6 +79,7 @@ def read_multi(*keys, **options) # @param key [String] # @param value [Object] # @option expires_in [NilClass, Integer] Time in seconds + # @option raw [Boolean] # @return [void] # # @api private @@ -91,7 +92,7 @@ def write(key, value, **options) end # @param entries [Hash] - # @param options [Hash] + # @option raw [Boolean] # @return [void] # # @api private @@ -105,6 +106,7 @@ def write_multi(entries, **options) # @param key [String] # @option expires_in [Integer] # @option force [Boolean, Proc] + # @option raw [Boolean] # @return [Object] # # @api private @@ -175,7 +177,8 @@ def decrement(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options) # - non-raw values; # - values lower than zero; # - empty entries; - write(key, INITIAL_DECREMNETED_VALUE, expires_in: expires_in, raw: true) && INITIAL_DECREMNETED_VALUE + write(key, INITIAL_DECREMNETED_VALUE, expires_in: expires_in, raw: true) + INITIAL_DECREMNETED_VALUE else driver.decrement(key, amount).tap do expire(key, expires_in: expires_in) if expires_in diff --git a/lib/any_cache/adapters/active_support_naive_store.rb b/lib/any_cache/adapters/active_support_naive_store.rb index 6338392..60de294 100644 --- a/lib/any_cache/adapters/active_support_naive_store.rb +++ b/lib/any_cache/adapters/active_support_naive_store.rb @@ -150,7 +150,8 @@ def fetch_multi(*keys, **options, &fallback) # use own #fetch_multi implementation cuz original #fetch_multi # does not support :force option keys.each_with_object({}) do |key, dataset| - dataset[key] = driver.fetch(key, force: force_rewrite, expires_in: expires_in, &fallback) + force = force_rewrite.respond_to?(:call) ? force_rewrite.call(key) : force_rewrite + dataset[key] = driver.fetch(key, force: force, expires_in: expires_in, &fallback) end end end diff --git a/lib/any_cache/adapters/active_support_redis_cache_store.rb b/lib/any_cache/adapters/active_support_redis_cache_store.rb index d24d113..c6c0ac7 100644 --- a/lib/any_cache/adapters/active_support_redis_cache_store.rb +++ b/lib/any_cache/adapters/active_support_redis_cache_store.rb @@ -45,7 +45,7 @@ def supported_driver?(driver) def_delegators :driver, :delete, :delete_matched, :clear # @param key [String] - # @param options [Hash] + # @option raw [Boolean] # @return [Object] # # @api private @@ -57,7 +57,7 @@ def read(key, **options) end # @param keys [Array] - # @param options [Hash] + # @option raw [Boolean] # @return [Hash] # # @api private @@ -73,6 +73,7 @@ def read_multi(*keys, **options) # @param key [String] # @param value [Object] # @option expires_in [NilClass, Integer] Time in seconds + # @option raw [Boolean] # @return [void] # # @api private @@ -85,7 +86,7 @@ def write(key, value, **options) end # @param entries [Hash] - # @param options [Hash] + # @option raw [Boolean] # @return [void] # # @api private @@ -100,6 +101,7 @@ def write_multi(entries, **options) # @param fallback [Proc] # @option expires_in [Integer] # @option force [Boolean, Proc] + # @option raw [Boolean] # @return [Object] # # @api private diff --git a/lib/any_cache/adapters/dalli.rb b/lib/any_cache/adapters/dalli.rb index 3f1d291..387bf4f 100644 --- a/lib/any_cache/adapters/dalli.rb +++ b/lib/any_cache/adapters/dalli.rb @@ -96,6 +96,7 @@ def read_multi(*keys, **options) # @param key [String] # @param value [Object] + # @option raw [Boolean] # @option expires_in [Integer] # @return [void] # diff --git a/lib/any_cache/adapters/redis.rb b/lib/any_cache/adapters/redis.rb index 1846f2d..0084343 100644 --- a/lib/any_cache/adapters/redis.rb +++ b/lib/any_cache/adapters/redis.rb @@ -61,7 +61,7 @@ def supported_driver?(driver) :scan # @param key [String] - # @param options [Hash] + # @option raw [Boolean] # @return [Object] # # @api private @@ -74,7 +74,7 @@ def read(key, **options) end # @param keys [Array] - # @param options [Hash] + # @option raw [Boolean] # @return [Hash] # # @api private @@ -88,6 +88,7 @@ def read_multi(*keys, **options) # @param key [String] # @param value [Object] + # @option raw [Boolean] # @option expires_in [NilClass, Integer] Time in seconds # @return [void] # @@ -102,7 +103,7 @@ def write(key, value, **options) end # @param entries [Hash] - # @param options [Hash] + # @option raw [Boolean] # @return [void] # # @api private diff --git a/lib/any_cache/adapters/redis_store.rb b/lib/any_cache/adapters/redis_store.rb index 84f509f..c792162 100644 --- a/lib/any_cache/adapters/redis_store.rb +++ b/lib/any_cache/adapters/redis_store.rb @@ -18,7 +18,7 @@ def supported_driver?(driver) def_delegators :driver, :mset # @param key [String] - # @param options [Hash] + # @option raw [Boolean] # @return [Object] # # @api private @@ -44,6 +44,7 @@ def read_multi(*keys, **options) # @param key [String] # @param value [Object] # @option expires_in [NilClass, Integer] Time in seconds + # @option raw [Boolean] # @return [void] # # @api private @@ -57,7 +58,7 @@ def write(key, value, **options) end # @param entries [Hash] - # @param options [Hash] + # @option raw [Boolean] # @return [void] # # @api private diff --git a/lib/any_cache/dumper.rb b/lib/any_cache/dumper.rb index 39f70a9..37e4a74 100644 --- a/lib/any_cache/dumper.rb +++ b/lib/any_cache/dumper.rb @@ -3,7 +3,7 @@ # @api private # @since 0.4.0 module AnyCache::Dumper - require_relative 'dumper/dumpable' + require_relative 'dumper/interface_access_mixin' class << self # @param hash [Hash] From 75232e3188ce03103f7fff8fd7bc6e3ffaf33393 Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Mon, 3 Dec 2018 02:01:31 +0300 Subject: [PATCH 12/13] [marshaling] right constant name for the dumper interface mixin --- lib/any_cache/adapters/basic.rb | 2 +- lib/any_cache/dumper/{dumpable.rb => interface_access_mixin.rb} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename lib/any_cache/dumper/{dumpable.rb => interface_access_mixin.rb} (93%) diff --git a/lib/any_cache/adapters/basic.rb b/lib/any_cache/adapters/basic.rb index f1bde63..7d366e8 100644 --- a/lib/any_cache/adapters/basic.rb +++ b/lib/any_cache/adapters/basic.rb @@ -7,7 +7,7 @@ class Basic # @since 0.1.0 extend Forwardable # @since 0.4.0 - include AnyCache::Dumper::Dumpable + include AnyCache::Dumper::InterfaceAccessMixin class << self # @param driver [Object] diff --git a/lib/any_cache/dumper/dumpable.rb b/lib/any_cache/dumper/interface_access_mixin.rb similarity index 93% rename from lib/any_cache/dumper/dumpable.rb rename to lib/any_cache/dumper/interface_access_mixin.rb index 4fe08f5..8c62364 100644 --- a/lib/any_cache/dumper/dumpable.rb +++ b/lib/any_cache/dumper/interface_access_mixin.rb @@ -2,7 +2,7 @@ # @api private # @since 0.4.0 -module AnyCache::Dumper::Dumpable +module AnyCache::Dumper::InterfaceAccessMixin # @param value [Object] # @return [Object] # From ed0d7464ee56c1d60616ab6a85941c66cb073f8d Mon Sep 17 00:00:00 2001 From: Rustam Ibragimov Date: Mon, 3 Dec 2018 02:20:39 +0300 Subject: [PATCH 13/13] [marshaling] adopt code style :) --- any_cache.gemspec | 2 +- lib/any_cache/adapters/redis.rb | 2 +- spec/features/cleanup_spec.rb | 8 ++++---- spec/features/raw_non_raw_read_write_spec.rb | 13 ++++++++----- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/any_cache.gemspec b/any_cache.gemspec index 7726b73..4904dc6 100644 --- a/any_cache.gemspec +++ b/any_cache.gemspec @@ -32,7 +32,7 @@ Gem::Specification.new do |spec| spec.add_development_dependency 'coveralls', '~> 0.8' spec.add_development_dependency 'simplecov', '~> 0.16' - spec.add_development_dependency 'armitage-rubocop', '~> 0.12' + spec.add_development_dependency 'armitage-rubocop', '~> 0.13' spec.add_development_dependency 'rspec', '~> 3.8' spec.add_development_dependency 'bundler' diff --git a/lib/any_cache/adapters/redis.rb b/lib/any_cache/adapters/redis.rb index 0084343..1cefccd 100644 --- a/lib/any_cache/adapters/redis.rb +++ b/lib/any_cache/adapters/redis.rb @@ -3,7 +3,7 @@ module AnyCache::Adapters # @api private # @since 0.1.0 - class Redis < Basic + class Redis < Basic # rubocop:disable Metrics/ClassLength class << self # @param driver [Object] # @return [Boolean] diff --git a/spec/features/cleanup_spec.rb b/spec/features/cleanup_spec.rb index eae336b..2d084cb 100644 --- a/spec/features/cleanup_spec.rb +++ b/spec/features/cleanup_spec.rb @@ -15,7 +15,7 @@ key_1: 'key_1_value', key_2: 'key_2_value', key_3: 'key_3_value', - key_4: 'key_4_value', + key_4: 'key_4_value' ) sleep(3) # 4 seconds left @@ -24,7 +24,7 @@ key_1: nil, # expired key_2: 'key_2_value', key_3: 'key_3_value', - key_4: 'key_4_value', + key_4: 'key_4_value' ) sleep(4) # 8 seconds left @@ -33,7 +33,7 @@ key_1: nil, # expired key_2: nil, # expired key_3: 'key_3_value', - key_4: 'key_4_value', + key_4: 'key_4_value' ) sleep(4) # 12 seconds left @@ -42,7 +42,7 @@ key_1: nil, # expired key_2: nil, # expired key_3: nil, # expired - key_4: 'key_4_value', + key_4: 'key_4_value' ) sleep(4) # 16 seconds left diff --git a/spec/features/raw_non_raw_read_write_spec.rb b/spec/features/raw_non_raw_read_write_spec.rb index 9d41218..55da8f4 100644 --- a/spec/features/raw_non_raw_read_write_spec.rb +++ b/spec/features/raw_non_raw_read_write_spec.rb @@ -41,10 +41,9 @@ cached_ruby_object = cache_store.fetch(:non_raw, raw: false) - [cached_ruby_object, returned_ruby_object].each do |cached_object| - expect(cached_object).to be_a(SimpleRubyObject) - expect(cached_object).to have_attributes(a: :non_raw, b: 1, c: false) - end + expect([cached_ruby_object, returned_ruby_object]).to all( + be_a(SimpleRubyObject).and(have_attributes(a: :non_raw, b: 1, c: false)) + ) end end @@ -96,7 +95,7 @@ context 'single read/write' do specify '#read/#write works correctly' do - ruby_object = { a: 1, b: 2, c: 3} + ruby_object = { a: 1, b: 2, c: 3 } cache_store.write(:raw, ruby_object, raw: true) cached_ruby_object = cache_store.read(:raw, raw: true) @@ -110,9 +109,11 @@ end specify '#fetch works correctly' do + # rubocop:disable Lint/UselessAssignment returned_ruby_object = cache_store.fetch(:raw, raw: true) do |key| SimpleRubyObject.new(key, 1, false) end + # rubocop:enable Lint/UselessAssignment cached_ruby_object = cache_store.fetch(:raw, raw: true) @@ -142,9 +143,11 @@ end specify '#fetch_multi works correctly' do + # rubocop:disable Lint/UselessAssignment returned_ruby_entries = cache_store.fetch_multi(:a, :b, raw: true) do |key| SimpleRubyObject.new(key, true, false) end + # rubocop:enable Lint/UselessAssignment cached_ruby_entries = cache_store.fetch_multi(:a, :b, raw: true)