any_cache 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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