any_cache 0.0.0 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -2
  3. data/.rspec +1 -1
  4. data/.rubocop.yml +18 -0
  5. data/.travis.yml +83 -4
  6. data/CHANGELOG.md +5 -0
  7. data/Gemfile +4 -2
  8. data/README.md +241 -18
  9. data/Rakefile +6 -4
  10. data/any_cache.gemspec +21 -7
  11. data/bin/console +5 -11
  12. data/bin/rspec +119 -0
  13. data/gemfiles/active_support.gemfile +7 -0
  14. data/gemfiles/active_support_with_redis.gemfile +8 -0
  15. data/gemfiles/dalli.gemfile +7 -0
  16. data/gemfiles/redis.gemfile +7 -0
  17. data/gemfiles/redis_store.gemfile +7 -0
  18. data/lib/any_cache.rb +49 -3
  19. data/lib/any_cache/adapters.rb +40 -0
  20. data/lib/any_cache/adapters/active_support_file_store.rb +26 -0
  21. data/lib/any_cache/adapters/active_support_file_store/decrement.rb +10 -0
  22. data/lib/any_cache/adapters/active_support_file_store/expire.rb +10 -0
  23. data/lib/any_cache/adapters/active_support_file_store/fetching.rb +28 -0
  24. data/lib/any_cache/adapters/active_support_file_store/increment.rb +10 -0
  25. data/lib/any_cache/adapters/active_support_file_store/operation.rb +10 -0
  26. data/lib/any_cache/adapters/active_support_file_store/persist.rb +10 -0
  27. data/lib/any_cache/adapters/active_support_memory_store.rb +26 -0
  28. data/lib/any_cache/adapters/active_support_memory_store/decrement.rb +10 -0
  29. data/lib/any_cache/adapters/active_support_memory_store/expire.rb +10 -0
  30. data/lib/any_cache/adapters/active_support_memory_store/fetching.rb +16 -0
  31. data/lib/any_cache/adapters/active_support_memory_store/increment.rb +10 -0
  32. data/lib/any_cache/adapters/active_support_memory_store/operation.rb +10 -0
  33. data/lib/any_cache/adapters/active_support_memory_store/persist.rb +10 -0
  34. data/lib/any_cache/adapters/active_support_naive_store.rb +150 -0
  35. data/lib/any_cache/adapters/active_support_naive_store/decrement.rb +72 -0
  36. data/lib/any_cache/adapters/active_support_naive_store/expire.rb +25 -0
  37. data/lib/any_cache/adapters/active_support_naive_store/increment.rb +71 -0
  38. data/lib/any_cache/adapters/active_support_naive_store/operation.rb +64 -0
  39. data/lib/any_cache/adapters/active_support_naive_store/persist.rb +22 -0
  40. data/lib/any_cache/adapters/active_support_redis_cache_store.rb +129 -0
  41. data/lib/any_cache/adapters/basic.rb +118 -0
  42. data/lib/any_cache/adapters/dalli.rb +140 -0
  43. data/lib/any_cache/adapters/delegator.rb +36 -0
  44. data/lib/any_cache/adapters/redis.rb +151 -0
  45. data/lib/any_cache/adapters/redis_store.rb +41 -0
  46. data/lib/any_cache/error.rb +11 -0
  47. data/lib/any_cache/version.rb +5 -2
  48. metadata +127 -5
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportFileStore::Persist < ActiveSupportNaiveStore::Persist
7
+ # @since 0.1.0
8
+ include ActiveSupportFileStore::Fetching
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportMemoryStore < ActiveSupportNaiveStore
7
+ require_relative 'active_support_memory_store/fetching'
8
+ require_relative 'active_support_memory_store/operation'
9
+ require_relative 'active_support_memory_store/increment'
10
+ require_relative 'active_support_memory_store/decrement'
11
+ require_relative 'active_support_memory_store/expire'
12
+ require_relative 'active_support_memory_store/persist'
13
+
14
+ class << self
15
+ # @param driver [Object]
16
+ # @return [Boolean]
17
+ #
18
+ # @api private
19
+ # @since 0.1.0
20
+ def supported_driver?(driver)
21
+ defined?(::ActiveSupport::Cache::MemoryStore) &&
22
+ driver.is_a?(::ActiveSupport::Cache::MemoryStore)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportMemoryStore::Decrement < ActiveSupportNaiveStore::Decrement
7
+ # @since 0.1.0
8
+ include ActiveSupportMemoryStore::Fetching
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportMemoryStore::Expire < ActiveSupportNaiveStore::Expire
7
+ # @since 0.1.0
8
+ include ActiveSupportMemoryStore::Fetching
9
+ end
10
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AnyCache::Adapters::ActiveSupportMemoryStore
4
+ # @api private
5
+ # @since 0.1.0
6
+ module Fetching
7
+ # @param key [String]
8
+ # @return [NilClass, ActiveSupport::Cache::Entry]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def fetch_entry(key)
13
+ driver.instance_eval { read_entry(key, {}) }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportMemoryStore::Increment < ActiveSupportNaiveStore::Increment
7
+ # @since 0.1.0
8
+ include ActiveSupportMemoryStore::Fetching
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportMemoryStore::Operation < ActiveSupportNaiveStore::Operation
7
+ # @since 0.1.0
8
+ include ActiveSupportMemoryStore::Fetching
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportMemoryStore::Persist < ActiveSupportNaiveStore::Persist
7
+ # @since 0.1.0
8
+ include ActiveSupportMemoryStore::Fetching
9
+ end
10
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportNaiveStore < Delegator
7
+ require_relative 'active_support_naive_store/operation'
8
+ require_relative 'active_support_naive_store/increment'
9
+ require_relative 'active_support_naive_store/decrement'
10
+ require_relative 'active_support_naive_store/expire'
11
+ require_relative 'active_support_naive_store/persist'
12
+
13
+ # @param driver [Object]
14
+ # @return [void]
15
+ #
16
+ # @api private
17
+ # @since 0.1.0
18
+ def initialize(driver)
19
+ super
20
+ @lock = Concurrent::ReentrantReadWriteLock.new
21
+ @incr_operation = self.class::Increment.new(driver)
22
+ @decr_operation = self.class::Decrement.new(driver)
23
+ @expr_operation = self.class::Expire.new(driver)
24
+ @pers_operation = self.class::Persist.new(driver)
25
+ end
26
+
27
+ # @param key [String]
28
+ # @param options [Hash]
29
+ # @return [Object]
30
+ #
31
+ # @api private
32
+ # @since 0.1.0
33
+ def read(key, **options)
34
+ lock.with_read_lock { super }
35
+ end
36
+
37
+ # @param key [String]
38
+ # @param options [Hash]
39
+ # @return [void]
40
+ #
41
+ # @api private
42
+ # @since 0.1.0
43
+ def delete(key, **options)
44
+ lock.with_write_lock { super }
45
+ end
46
+
47
+ # @param options [Hash]
48
+ # @return [void]
49
+ #
50
+ # @api private
51
+ # @since 0.1.0
52
+ def clear(**options)
53
+ lock.with_write_lock { super }
54
+ end
55
+
56
+ # @param key [String]
57
+ # @param value [Object]
58
+ # @param options [Hash]
59
+ # @return [void]
60
+ #
61
+ # @api private
62
+ # @since 0.1.0
63
+ def write(key, value, **options)
64
+ lock.with_write_lock do
65
+ expires_in = options.fetch(:expires_in, self.class::Operation::NO_EXPIRATION_TTL)
66
+
67
+ super(key, value, expires_in: expires_in)
68
+ end
69
+ end
70
+
71
+ # @param key [String]
72
+ # @param amount [Integer, Float]
73
+ # @option expires_in [NilClass, Integer]
74
+ # @return [Integer, Float]
75
+ #
76
+ # @api private
77
+ # @since 0.1.0
78
+ def increment(key, amount = self.class::Increment::DEFAULT_AMOUNT, **options)
79
+ lock.with_write_lock do
80
+ expires_in = options.fetch(:expires_in, self.class::Operation::NO_EXPIRATION_TTL)
81
+
82
+ incr_operation.call(key, amount, expires_in: expires_in)
83
+ end
84
+ end
85
+
86
+ # @param key [String]
87
+ # @param amount [Integer, Float]
88
+ # @option expires_in [NilClass, Integer]
89
+ # @return [Integer, Float]
90
+ #
91
+ # @api private
92
+ # @since 0.1.0
93
+ def decrement(key, amount = self.class::Decrement::DEFAULT_AMOUNT, **options)
94
+ lock.with_write_lock do
95
+ expires_in = options.fetch(:expires_in, self.class::Operation::NO_EXPIRATION_TTL)
96
+
97
+ decr_operation.call(key, amount, expires_in: expires_in)
98
+ end
99
+ end
100
+
101
+ # @param key [String]
102
+ # @option expires_in [NilClass, Integer]
103
+ # @return [void]
104
+ #
105
+ # @api private
106
+ # @since 0.1.0
107
+ def expire(key, expires_in: self.class::Operation::DEAD_TTL)
108
+ lock.with_write_lock { expr_operation.call(key, expires_in: expires_in) }
109
+ end
110
+
111
+ # @param key [String]
112
+ # @param options [Hash]
113
+ # @return [void]
114
+ #
115
+ # @api private
116
+ # @since 0.1.0
117
+ def persist(key, **options)
118
+ lock.with_write_lock { pers_operation.call(key) }
119
+ end
120
+
121
+ private
122
+
123
+ # @return [Concurrent::ReentrantReadWriteLock]
124
+ #
125
+ # @api private
126
+ # @since 0.1.0
127
+ attr_reader :lock
128
+
129
+ # @return [Operation::Increment]
130
+ #
131
+ # @api private
132
+ # @since 0.1.0
133
+ attr_reader :incr_operation
134
+
135
+ # @return [Operation::Decrement]
136
+ #
137
+ # @api private
138
+ # @since 0.1.0
139
+ attr_reader :decr_operation
140
+
141
+ # @return [Operation::Expire]
142
+ #
143
+ # @api private
144
+ # @since 0.1.0
145
+ attr_reader :expr_operation
146
+
147
+ # @return [Operation::Persist]
148
+ attr_reader :pers_operation
149
+ end
150
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AnyCache::Adapters::ActiveSupportNaiveStore
4
+ # @api private
5
+ # @since 0.1.0
6
+ class Decrement < Operation
7
+ # @return [Integer]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ DEFAULT_AMOUNT = 1
12
+
13
+ # @since 0.1.0
14
+ def_delegators :driver, :decrement
15
+
16
+ # @param key [String]
17
+ # @param amount [Integer, Float]
18
+ # @option expires_in [NilClass, Integer]
19
+ # @return [Integer, Float]
20
+ #
21
+ # @api private
22
+ # @since 0.1.0
23
+ def call(key, amount = DEFAULT_AMOUNT, expires_in: NO_EXPIRATION_TTL)
24
+ expires_in ? decr_and_expire(key, amount, expires_in) : decr_existing(key, amount)
25
+ end
26
+
27
+ private
28
+
29
+ # @param key [String]
30
+ # @param amount [Integer, Float]
31
+ # @param expires_in [NilClass, Integer]
32
+ # @return [Integer, Float]
33
+ #
34
+ # @api private
35
+ # @since 0.1.0
36
+ def decr_and_expire(key, amount, expires_in)
37
+ new_amount = decrement(key, amount, expires_in: expires_in)
38
+ new_amount || decr_non_existing(key, amount, expires_in)
39
+ end
40
+
41
+ # @param key [String]
42
+ # @param amount [Integer, Float]
43
+ # @return [Integer, Float]
44
+ #
45
+ # @api private
46
+ # @since 0.1.0
47
+ def decr_existing(key, amount)
48
+ new_amount = begin
49
+ entry = fetch_entry(key)
50
+ decrement(key, amount, expires_in: calc_entry_expiration(entry)) if entry
51
+ end
52
+
53
+ new_amount || decr_non_existing(key, amount)
54
+ end
55
+
56
+ # @param key [String]
57
+ # @param amount [Integer, Float]
58
+ # @param expires_in [NilClass, Integer]
59
+ # @return [Integer, Float]
60
+ #
61
+ # @api private
62
+ # @since 0.1.0
63
+ def decr_non_existing(key, amount, expires_in = NO_EXPIRATION_TTL)
64
+ amount = -amount
65
+ (expires_in ? write(key, amount, expires_in: expires_in) : write(key, amount)) && amount
66
+ end
67
+
68
+ # @!method fetch_entry(key)
69
+ # @param key [String]
70
+ # @return [NilClass, ActiveSupport::Cache::Entry]
71
+ end
72
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AnyCache::Adapters::ActiveSupportNaiveStore
4
+ # @api private
5
+ # @since 0.1.0
6
+ class Expire < Operation
7
+ # @param key [String]
8
+ # @option expires_in [Integer, NilClass]
9
+ # @return [void]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ def call(key, expires_in: DEAD_TTL)
14
+ fetch_entry(key).tap do |entry|
15
+ next unless entry
16
+ is_alive = expires_in.positive?
17
+ is_alive ? write(key, entry.value, expires_in: expires_in) : delete(key)
18
+ end
19
+ end
20
+
21
+ # @!method fetch_entry(key)
22
+ # @param key [String]
23
+ # @return [NilClass, ActiveSupport::Cache::Entry]
24
+ end
25
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AnyCache::Adapters::ActiveSupportNaiveStore
4
+ # @api private
5
+ # @since 0.1.0
6
+ class Increment < Operation
7
+ # @return [Integer]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ DEFAULT_AMOUNT = 1
12
+
13
+ # @since 0.1.0
14
+ def_delegators :driver, :increment
15
+
16
+ # @param key [String]
17
+ # @param amount [Integer, Float]
18
+ # @option expires_in [NilClass, Integer]
19
+ # @return [Integer, Float]
20
+ #
21
+ # @api private
22
+ # @since 0.1.0
23
+ def call(key, amount = DEFAULT_AMOUNT, expires_in: NO_EXPIRATION_TTL)
24
+ expires_in ? incr_and_expire(key, amount, expires_in) : incr_existing(key, amount)
25
+ end
26
+
27
+ private
28
+
29
+ # @param key [String]
30
+ # @param amount [Integer, Float]
31
+ # @param expires_in [NilClass, Integer]
32
+ # @return [Integer, Float]
33
+ #
34
+ # @api private
35
+ # @since 0.1.0
36
+ def incr_and_expire(key, amount, expires_in)
37
+ new_amount = increment(key, amount, expires_in: expires_in)
38
+ new_amount || incr_non_existing(key, amount, expires_in)
39
+ end
40
+
41
+ # @param key [String]
42
+ # @param amount [Integer, Float]
43
+ # @return [Integer, Float]
44
+ #
45
+ # @api private
46
+ # @since 0.1.0
47
+ def incr_existing(key, amount)
48
+ new_amount = begin
49
+ entry = fetch_entry(key)
50
+ increment(key, amount, expires_in: calc_entry_expiration(entry)) if entry
51
+ end
52
+
53
+ new_amount || incr_non_existing(key, amount)
54
+ end
55
+
56
+ # @param key [String]
57
+ # @param amount [Integer, Float]
58
+ # @param expires_in [NilClass, Integer]
59
+ # @return [Integer, Float]
60
+ #
61
+ # @api private
62
+ # @since 0.1.0
63
+ def incr_non_existing(key, amount, expires_in = NO_EXPIRATION_TTL)
64
+ (expires_in ? write(key, amount, expires_in: expires_in) : write(key, amount)) && amount
65
+ end
66
+
67
+ # @!method fetch_entry(key)
68
+ # @param key [String]
69
+ # @return [NilClass, ActiveSupport::Cache::Entry]
70
+ end
71
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AnyCache::Adapters::ActiveSupportNaiveStore
4
+ # @api private
5
+ # @since 0.1.0
6
+ class Operation
7
+ # @since 0.1.0
8
+ extend Forwardable
9
+
10
+ # @return [NilClass]
11
+ #
12
+ # @api private
13
+ # @since 0.1.0
14
+ NO_EXPIRATION_TTL = nil
15
+
16
+ # @return [Integer]
17
+ #
18
+ # @api private
19
+ # @since 0.1.0
20
+ DEAD_TTL = 0
21
+
22
+ # @since 0.1.0
23
+ def_delegators :driver, :read, :write, :delete
24
+
25
+ # @param driver [Object]
26
+ # @return [void]
27
+ #
28
+ # @api private
29
+ # @since 0.1.0
30
+ def initialize(driver)
31
+ @driver = driver
32
+ end
33
+
34
+ private
35
+
36
+ # @return [Object]
37
+ #
38
+ # @api private
39
+ # @since 0.1.0
40
+ attr_reader :driver
41
+
42
+ # @option as_integer [Boolean]
43
+ # @return [Integer, Float]
44
+ #
45
+ # @api private
46
+ # @since 0.1.0
47
+ def calc_epoch_time(as_integer: false)
48
+ as_integer ? Time.now.to_i : Time.now.to_f
49
+ end
50
+
51
+ # @param [ActiveSupport::Cache::Entry]
52
+ # @return [NilClass, Integer]
53
+ #
54
+ # @api private
55
+ # @since 0.1.0
56
+ def calc_entry_expiration(entry)
57
+ entry.expires_at ? (entry.expires_at - calc_epoch_time) : NO_EXPIRATION_TTL
58
+ end
59
+
60
+ # @!method fetch_entry(key)
61
+ # @param key [String]
62
+ # @return [NilClass, ActiveSupport::Cache::Entry]
63
+ end
64
+ end