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,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AnyCache::Adapters::ActiveSupportNaiveStore
4
+ # @api private
5
+ # @since 0.1.0
6
+ class Persist < Operation
7
+ # @param key [String]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def call(key)
13
+ fetch_entry(key).tap do |entry|
14
+ write(key, entry.value, expires_in: NO_EXPIRATION_TTL) if entry
15
+ end
16
+ end
17
+
18
+ # @!method fetch_entry(key)
19
+ # @param key [String]
20
+ # @return [NilClass, ActiveSupport::Cache::Entry]
21
+ end
22
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ActiveSupportRedisCacheStore < Basic
7
+ # TODO: think about locks
8
+
9
+ class << self
10
+ # @param driver [Object]
11
+ # @return [Boolean]
12
+ #
13
+ # @api private
14
+ # @since 0.1.0
15
+ def supported_driver?(driver)
16
+ defined?(::Redis) &&
17
+ defined?(::ActiveSupport::Cache::RedisCacheStore) &&
18
+ driver.is_a?(::ActiveSupport::Cache::RedisCacheStore)
19
+ end
20
+ end
21
+
22
+ # @since 0.1.0
23
+ def_delegators :driver, :delete, :clear
24
+
25
+ # @return [NilClass]
26
+ #
27
+ # @api private
28
+ # @since 0.1.0
29
+ NO_EXPIRATION_TTL = nil
30
+
31
+ # @return [Integer]
32
+ #
33
+ # @api private
34
+ # @since 0.1.0
35
+ DEAD_TTL = 0
36
+
37
+ # @return [Integer]
38
+ #
39
+ # @api private
40
+ # @since 0.1.0
41
+ DEFAULT_INCR_DECR_AMOUNT = 1
42
+
43
+ # @param key
44
+ # @param options [Hash]
45
+ # @return [Object]
46
+ #
47
+ # @api private
48
+ # @since 0.1.0
49
+ def read(key, **options)
50
+ driver.read(key, raw: true)
51
+ end
52
+
53
+ # @param key [String]
54
+ # @param value [Object]
55
+ # @option expires_in [NilClass, Integer] Time in seconds
56
+ # @return [void]
57
+ #
58
+ # @api private
59
+ # @since 0.1.0
60
+ def write(key, value, **options)
61
+ expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL)
62
+
63
+ driver.write(key, value, expires_in: expires_in, raw: true)
64
+ end
65
+
66
+ # @param key [String]
67
+ # @param amount [Integer, Float]
68
+ # @option expires_in [Integer]
69
+ # @return [Integer, Float]
70
+ #
71
+ # @api private
72
+ # @since 0.1.0
73
+ def increment(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options)
74
+ expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL)
75
+ is_initial = expires_in && !read(key)
76
+
77
+ if is_initial
78
+ write(key, amount, expires_in: expires_in) && amount
79
+ else
80
+ driver.increment(key, amount).tap do
81
+ expire(key, expires_in: expires_in) if expires_in
82
+ end
83
+ end
84
+ end
85
+
86
+ # @param key [String]
87
+ # @param amount [Integer, Float]
88
+ # @option expires_in [Integer]
89
+ # @return [Integer, Float]
90
+ #
91
+ # @api private
92
+ # @since 0.1.0
93
+ def decrement(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options)
94
+ expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL)
95
+ is_initial = expires_in && !read(key)
96
+
97
+ if is_initial
98
+ write(key, -amount, expires_in: expires_in) && -amount
99
+ else
100
+ driver.decrement(key, amount).tap do
101
+ expire(key, expires_in: expires_in) if expires_in
102
+ end
103
+ end
104
+ end
105
+
106
+ # @param key [String]
107
+ # @option expires_in [Integer]
108
+ # @return [void]
109
+ #
110
+ # @api private
111
+ # @since 0.1.0
112
+ def expire(key, expires_in: DEAD_TTL)
113
+ read(key).tap do |value|
114
+ is_alive = expires_in ? expires_in.positive? : false
115
+ is_alive ? write(key, value, expires_in: expires_in) : delete(key)
116
+ end
117
+ end
118
+
119
+ # @param key [String]
120
+ # @param options [Hash]
121
+ # @return [void]
122
+ #
123
+ # @api private
124
+ # @since 0.1.0
125
+ def persist(key, **options)
126
+ read(key).tap { |value| write(key, value) }
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class Basic
7
+ # @since 0.1.0
8
+ extend Forwardable
9
+
10
+ class << self
11
+ # @param driver [Object]
12
+ # @return [Boolean]
13
+ #
14
+ # @api private
15
+ # @since 0.1.0
16
+ def supported_driver?(driver)
17
+ false
18
+ end
19
+ end
20
+
21
+ # @return [Object]
22
+ #
23
+ # @api private
24
+ # @since 0.1.0
25
+ attr_reader :driver
26
+
27
+ # @param driver [Object]
28
+ # @return [void]
29
+ #
30
+ # @api private
31
+ # @since 0.1.0
32
+ def initialize(driver)
33
+ @driver = driver
34
+ end
35
+
36
+ # @param key [String]
37
+ # @param options [Hash]
38
+ # @return [Object]
39
+ #
40
+ # @api private
41
+ # @since 0.1.0
42
+ def read(key, **options)
43
+ raise NotImplementedError
44
+ end
45
+
46
+ # @param key [String]
47
+ # @param value [Object]
48
+ # @param options [Hash]
49
+ # @return [void]
50
+ #
51
+ # @api private
52
+ # @sinc 0.1.0
53
+ def write(key, value, **options)
54
+ raise NotImplementedError
55
+ end
56
+
57
+ # @param key [String]
58
+ # @param options [Hash]
59
+ # @return [void]
60
+ #
61
+ # @api private
62
+ # @since 0.1.0
63
+ def delete(key, **options)
64
+ raise NotImplementedError
65
+ end
66
+
67
+ # @param key [String]
68
+ # @param value [Integer, Float]
69
+ # @param options [Hash]
70
+ # @return [Integer, Float]
71
+ #
72
+ # @api private
73
+ # @sinc 0.1.0
74
+ def increment(key, value, **options)
75
+ raise NotImplementedError
76
+ end
77
+
78
+ # @param key [String]
79
+ # @param value [Integer, Float]
80
+ # @param options [Hash]
81
+ # @return [Integer, Float]
82
+ #
83
+ # @api private
84
+ # @since 0.1.0
85
+ def decrement(key, value, **options)
86
+ raise NotImplementedError
87
+ end
88
+
89
+ # @param key [String]
90
+ # @option expires_in [Integer]
91
+ # @return [void]
92
+ #
93
+ # @api private
94
+ # @since 0.1.0
95
+ def expire(key, expires_in:)
96
+ raise NotImplementedError
97
+ end
98
+
99
+ # @param key [String]
100
+ # @param options [Hash]
101
+ # @return [void]
102
+ #
103
+ # @api private
104
+ # @since 0.1.0
105
+ def persist(key, **options)
106
+ raise NotImplementedError
107
+ end
108
+
109
+ # @param options [Hash]
110
+ # @return [void]
111
+ #
112
+ # @api private
113
+ # @since 0.1.0
114
+ def clear(**options)
115
+ raise NotImplementedError
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class Dalli < Basic
7
+ class << self
8
+ # @param driver [Object]
9
+ # @return [Boolean]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ def supported_driver?(driver)
14
+ defined?(::Dalli::Client) && driver.is_a?(::Dalli::Client)
15
+ end
16
+ end
17
+
18
+ # @return [Integer]
19
+ #
20
+ # @api private
21
+ # @since 0.1.0
22
+ NO_EXPIRATION_TTL = 0
23
+
24
+ # @return [NilClass]
25
+ #
26
+ # @api private
27
+ # @since 0.1.0
28
+ DEAD_TTL = nil
29
+
30
+ # @return [Integer]
31
+ #
32
+ # @api private
33
+ # @since 0.1.0
34
+ DEFAULT_INCR_DECR_AMOUNT = 1
35
+
36
+ # @return [Integer]
37
+ #
38
+ # @api private
39
+ # @since 0.1.0
40
+ MIN_DECRESEAD_VAL = 0
41
+
42
+ # @since 0.1.0
43
+ def_delegators :driver,
44
+ :get,
45
+ :set,
46
+ :incr,
47
+ :decr,
48
+ :multi,
49
+ :touch,
50
+ :flush
51
+
52
+ # @param key [String]
53
+ # @param options [Hash]
54
+ # @return [Object]
55
+ #
56
+ # @api private
57
+ # @since 0.1.0
58
+ def read(key, **options)
59
+ get(key)
60
+ end
61
+
62
+ def write(key, value, **options)
63
+ expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL)
64
+
65
+ set(key, value, expires_in, raw: true)
66
+ end
67
+
68
+ # @param key [String]
69
+ # @param options [Hash]
70
+ # @return [void]
71
+ #
72
+ # @api private
73
+ # @since 0.1.0
74
+ def delete(key, **options)
75
+ driver.delete(key)
76
+ end
77
+
78
+ # @param key [String]
79
+ # @param amount [Integer]
80
+ # @option expires_in [NilClass, Integer]
81
+ # @return [NilClass, Integer]
82
+ #
83
+ # @api private
84
+ # @since 0.1.0
85
+ def increment(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options)
86
+ expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL)
87
+
88
+ # TODO: think about #cas and Concurrent::ReentrantReadWriteLock
89
+ incr(key, amount, expires_in, amount).tap do |new_amount|
90
+ touch(key, expires_in) if new_amount && expires_in.positive?
91
+ end
92
+ end
93
+
94
+ # @param key [String]
95
+ # @param amount [Integer]
96
+ # @option expires_in [NilClass, Integer]
97
+ # @return [NilClass, Integer]
98
+ #
99
+ # @api private
100
+ # @since 0.1.0
101
+ def decrement(key, amount = DEFAULT_INCR_DECR_AMOUNT, **options)
102
+ expires_in = options.fetch(:expires_in, NO_EXPIRATION_TTL)
103
+
104
+ # TODO: think about #cas and Concurrent::ReentrantReadWriteLock
105
+ decr(key, amount, expires_in, MIN_DECRESEAD_VAL).tap do |new_amount|
106
+ touch(key, expires_in) if new_amount && expires_in.positive?
107
+ end
108
+ end
109
+
110
+ # @param key [String]
111
+ # @option expires_in [Integer]
112
+ # @return [void]
113
+ #
114
+ # @api private
115
+ # @since 0.1.0
116
+ def expire(key, expires_in: DEAD_TTL)
117
+ is_alive = expires_in ? expires_in.positive? : false
118
+ is_alive ? touch(key, expires_in) : driver.delete(key)
119
+ end
120
+
121
+ # @param key [String]
122
+ # @param options [Hash]
123
+ # @return [void]
124
+ #
125
+ # @api private
126
+ # @since 0.1.0
127
+ def persist(key, **options)
128
+ touch(key, NO_EXPIRATION_TTL)
129
+ end
130
+
131
+ # @param options [Hash]
132
+ # @return [void]
133
+ #
134
+ # @api private
135
+ # @since 0.1.0
136
+ def clear(**options)
137
+ flush(0) # NOTE: 0 is a flush delay
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCache::Adapters
4
+ # @api private
5
+ # @since 0.1.0
6
+ class Delegator < Basic
7
+ class << self
8
+ # @param driver [Object]
9
+ # @return [Boolean]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ def supported_driver?(driver)
14
+ driver.respond_to?(:read) &&
15
+ driver.respond_to?(:write) &&
16
+ driver.respond_to?(:delete) &&
17
+ driver.respond_to?(:increment) &&
18
+ driver.respond_to?(:decrement) &&
19
+ driver.respond_to?(:expire) &&
20
+ driver.respond_to?(:persist) &&
21
+ driver.respond_to?(:clear)
22
+ end
23
+ end
24
+
25
+ # @since 0.1.0
26
+ def_delegators :driver,
27
+ :read,
28
+ :write,
29
+ :delete,
30
+ :increment,
31
+ :decrement,
32
+ :expire,
33
+ :persist,
34
+ :clear
35
+ end
36
+ end