readthis 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 076d20cf4f8bffa4b9a6b6ced603f65020bea46c
4
- data.tar.gz: bcb7899c7aa4f98d206ae7fea3e6fc388c7036b4
3
+ metadata.gz: 513263f9ac89cdc3d8bfc354404778e49902460b
4
+ data.tar.gz: 525ab985b197507e19c000bcb6dc21683ba068d9
5
5
  SHA512:
6
- metadata.gz: be88ade839408848ba227ece979dc2d4bb5b4621cdca98eb1f6a3b61fae3d00468940cb9c32eb02b3ca6438e882c680019035583f65c54ed58bd69e33f2c5e3d
7
- data.tar.gz: dcb48683aaa8ef72cf0e6770f0334245db4f6198fa244486115123a497ee9bc897568687727ef582ec40b220f81f6b1c1c1221b9c1527a80df714f090a1c4fa5
6
+ metadata.gz: f9207fe0c1d9746337d17ac05a23acd4bfde8c9d943d1814daa7426160a39fb8d932ea2fd7c69e898097afdf0427eab59cfad320362053547d4e40b3f2a4d4ee
7
+ data.tar.gz: 14ae7680da85fe6591cc6b623c9f13e2c11dd7905add114288d6ed4138490b4a63a67d0832d0069706246cac73f5fe9de14774f0316e4a4db933ed418e6c60aa
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ services:
5
+ - redis-server
6
+ script: bin/rspec
@@ -1,3 +1,10 @@
1
+ ## v0.2.0 2014-11-24
2
+
3
+ - Instrument all caching methods. Will use `ActiveSupport::Notifications`
4
+ if available, otherwise falls back to a polyfill.
5
+ - Expand objects with a `cache_key` method and arrays of strings or objects into
6
+ consistent naespaced keys.
7
+
1
8
  ## v0.1.0 2014-11-22
2
9
 
3
10
  - Initial release! Working as a drop in replacement for `redis_store`.
data/README.md CHANGED
@@ -1,3 +1,6 @@
1
+ [![Gem Version](https://badge.fury.io/rb/readthis.svg)](http://badge.fury.io/rb/readthis)
2
+ [![Build Status](https://travis-ci.org/sorentwo/readthis.svg?branch=master)](https://travis-ci.org/sorentwo/readthis)
3
+
1
4
  # Readthis
2
5
 
3
6
  An ActiveSupport::Cache compatible redis based cache focused on speed,
@@ -1,3 +1,5 @@
1
+ require 'readthis/expanders'
2
+ require 'readthis/notifications'
1
3
  require 'redis'
2
4
  require 'connection_pool'
3
5
 
@@ -5,8 +7,22 @@ module Readthis
5
7
  class Cache
6
8
  attr_reader :expires_in, :namespace, :pool
7
9
 
10
+ # Provide a class level lookup of the proper notifications module.
11
+ # Instrumention is expected to occur within applications that have
12
+ # ActiveSupport::Notifications available, but needs to work even when it
13
+ # isn't.
14
+ def self.notifications
15
+ if Object.const_defined?('ActiveSupport::Notifications')
16
+ ActiveSupport::Notifications
17
+ else
18
+ Readthis::Notifications
19
+ end
20
+ end
21
+
8
22
  # Creates a new Readthis::Cache object with the given redis URL. The URL
9
23
  # is parsed by the redis client directly.
24
+ #
25
+ # Readthis::Cache.new('redis://localhost:6379/0', namespace: 'cache')
10
26
  def initialize(url, options = {})
11
27
  @expires_in = options.fetch(:expires_in, nil)
12
28
  @namespace = options.fetch(:namespace, nil)
@@ -17,8 +33,10 @@ module Readthis
17
33
  end
18
34
 
19
35
  def read(key, options = {})
20
- with do |store|
21
- store.get(namespaced_key(key, merged_options(options)))
36
+ instrument(:read, key) do
37
+ with do |store|
38
+ store.get(namespaced_key(key, merged_options(options)))
39
+ end
22
40
  end
23
41
  end
24
42
 
@@ -26,18 +44,22 @@ module Readthis
26
44
  options = merged_options(options)
27
45
  namespaced = namespaced_key(key, options)
28
46
 
29
- with do |store|
30
- if expiration = options[:expires_in]
31
- store.setex(namespaced, expiration, value)
32
- else
33
- store.set(namespaced, value)
47
+ instrument(:write, key) do
48
+ with do |store|
49
+ if expiration = options[:expires_in]
50
+ store.setex(namespaced, expiration, value)
51
+ else
52
+ store.set(namespaced, value)
53
+ end
34
54
  end
35
55
  end
36
56
  end
37
57
 
38
58
  def delete(key, options = {})
39
- with do |store|
40
- store.del(namespaced_key(key, merged_options(options)))
59
+ instrument(:delete, key) do
60
+ with do |store|
61
+ store.del(namespaced_key(key, merged_options(options)))
62
+ end
41
63
  end
42
64
  end
43
65
 
@@ -53,14 +75,18 @@ module Readthis
53
75
  end
54
76
 
55
77
  def increment(key, options = {})
56
- with do |store|
57
- store.incr(namespaced_key(key, merged_options(options)))
78
+ instrument(:incremenet, key) do
79
+ with do |store|
80
+ store.incr(namespaced_key(key, merged_options(options)))
81
+ end
58
82
  end
59
83
  end
60
84
 
61
85
  def decrement(key, options = {})
62
- with do |store|
63
- store.decr(namespaced_key(key, merged_options(options)))
86
+ instrument(:decrement, key) do
87
+ with do |store|
88
+ store.decr(namespaced_key(key, merged_options(options)))
89
+ end
64
90
  end
65
91
  end
66
92
 
@@ -68,50 +94,70 @@ module Readthis
68
94
  options = merged_options(extract_options!(keys))
69
95
  results = []
70
96
 
71
- with do |store|
72
- results = store.pipelined do
73
- keys.each { |key| store.get(namespaced_key(key, options)) }
97
+ instrument(:read_multi, keys) do
98
+ with do |store|
99
+ results = store.pipelined do
100
+ keys.each { |key| store.get(namespaced_key(key, options)) }
101
+ end
74
102
  end
75
- end
76
103
 
77
- keys.zip(results).to_h
104
+ keys.zip(results).to_h
105
+ end
78
106
  end
79
107
 
80
- # This must be done in two separate blocks. Redis pipelines return
81
- # futures, which can not be resolved until the pipeline has exited.
108
+ # Fetches multiple keys from the cache using a single call to the server
109
+ # and filling in any cache misses. All read and write operations are
110
+ # executed atomically.
111
+ #
112
+ # cache.fetch_multi('alpha', 'beta') do |key|
113
+ # "#{key}-was-missing"
114
+ # end
82
115
  def fetch_multi(*keys)
83
116
  results = read_multi(*keys)
84
117
  options = merged_options(extract_options!(keys))
85
118
 
86
- with do |store|
87
- store.pipelined do
88
- results.each do |key, value|
89
- if value.nil?
90
- value = yield key
91
- write(key, value, options)
92
- results[key] = value
119
+ instrument(:fetch_multi, keys) do
120
+ with do |store|
121
+ store.pipelined do
122
+ results.each do |key, value|
123
+ if value.nil?
124
+ value = yield key
125
+ write(key, value, options)
126
+ results[key] = value
127
+ end
93
128
  end
94
129
  end
95
130
  end
96
- end
97
131
 
98
- results
132
+ results
133
+ end
99
134
  end
100
135
 
101
136
  def exist?(key, options = {})
102
- with do |store|
103
- store.exists(namespaced_key(key, merged_options(options)))
137
+ instrument(:exist?, key) do
138
+ with do |store|
139
+ store.exists(namespaced_key(key, merged_options(options)))
140
+ end
104
141
  end
105
142
  end
106
143
 
107
144
  def clear
108
- with do |store|
109
- store.flushdb
145
+ instrument(:clear, '*') do
146
+ with do |store|
147
+ store.flushdb
148
+ end
110
149
  end
111
150
  end
112
151
 
113
152
  private
114
153
 
154
+ def instrument(operation, key)
155
+ name = "cache_#{operation}.active_support"
156
+ payload = { key: key }
157
+
158
+ self.class.notifications.instrument(name, key) { yield(payload) }
159
+ end
160
+
115
161
  def with(&block)
116
162
  pool.with(&block)
117
163
  end
@@ -132,9 +178,7 @@ module Readthis
132
178
  end
133
179
 
134
180
  def namespaced_key(key, options)
135
- namespace = options[:namespace]
136
-
137
- [namespace, key].compact.join(':')
181
+ Readthis::Expanders.expand(key, options[:namespace])
138
182
  end
139
183
  end
140
184
  end
@@ -0,0 +1,15 @@
1
+ module Readthis
2
+ module Expanders
3
+ def self.expand(key, namespace = nil)
4
+ expanded = if key.respond_to?(:cache_key)
5
+ key.cache_key
6
+ elsif key.is_a?(Array)
7
+ key.flat_map { |elem| expand(elem) }.join(':')
8
+ else
9
+ key
10
+ end
11
+
12
+ namespace ? "#{namespace}:#{expanded}" : expanded
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Readthis
2
+ module Notifications
3
+ def self.instrument(name, payload)
4
+ yield(payload)
5
+ end
6
+ end
7
+ end
@@ -1,3 +1,3 @@
1
1
  module Readthis
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  spec.add_dependency 'redis', '~> 3.0'
21
21
  spec.add_dependency 'connection_pool', '~> 2.1'
22
22
 
23
- spec.add_development_dependency 'bundler', '~> 1.7'
24
- spec.add_development_dependency 'rake', '~> 10.0'
25
- spec.add_development_dependency 'rspec', '~> 3.1'
23
+ spec.add_development_dependency 'bundler'
24
+ spec.add_development_dependency 'rake'
25
+ spec.add_development_dependency 'rspec', '~> 3.1'
26
26
  end
@@ -43,6 +43,14 @@ RSpec.describe Readthis::Cache do
43
43
  sleep 1.01
44
44
  expect(cache.read('some-key')).to be_nil
45
45
  end
46
+
47
+ it 'expands non-string keys' do
48
+ key_obj = double(cache_key: 'custom-key')
49
+
50
+ cache.write(key_obj, 'some-value')
51
+
52
+ expect(cache.read('custom-key')).to eq('some-value')
53
+ end
46
54
  end
47
55
 
48
56
  describe '#fetch' do
@@ -0,0 +1,26 @@
1
+ require 'readthis/expanders'
2
+
3
+ RSpec.describe Readthis::Expanders do
4
+ def expand(key, namespace = nil)
5
+ Readthis::Expanders.expand(key, namespace)
6
+ end
7
+
8
+ describe '#expand' do
9
+ it 'namespaces a plain string' do
10
+ expect(expand('thing', 'space')).to eq('space:thing')
11
+ end
12
+
13
+ it 'expands an object that has a cache_key method' do
14
+ object = double(cache_key: 'custom-key')
15
+
16
+ expect(expand(object)).to eq('custom-key')
17
+ end
18
+
19
+ it 'expands an array of objects' do
20
+ object = double(cache_key: 'gamma')
21
+
22
+ expect(expand(['alpha', 'beta'])).to eq('alpha:beta')
23
+ expect(expand([object, object])).to eq('gamma:gamma')
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ require 'readthis/notifications'
2
+
3
+ RSpec.describe Readthis::Notifications do
4
+ describe '#instrument' do
5
+ it 'yields the provided block' do
6
+ inner = double(:inner)
7
+
8
+ expect(inner).to receive(:call)
9
+
10
+ Readthis::Notifications.instrument('operation', key: 'key') do
11
+ inner.call
12
+ end
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: readthis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Parker Selbert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-23 00:00:00.000000000 Z
11
+ date: 2014-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -42,30 +42,30 @@ dependencies:
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '1.7'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '1.7'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '10.0'
68
+ version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -89,6 +89,7 @@ extra_rdoc_files: []
89
89
  files:
90
90
  - ".gitignore"
91
91
  - ".rspec"
92
+ - ".travis.yml"
92
93
  - CHANGELOG.md
93
94
  - Gemfile
94
95
  - LICENSE.txt
@@ -98,9 +99,13 @@ files:
98
99
  - lib/active_support/cache/readthis_store.rb
99
100
  - lib/readthis.rb
100
101
  - lib/readthis/cache.rb
102
+ - lib/readthis/expanders.rb
103
+ - lib/readthis/notifications.rb
101
104
  - lib/readthis/version.rb
102
105
  - readthis.gemspec
103
106
  - spec/readthis/cache_spec.rb
107
+ - spec/readthis/expanders_spec.rb
108
+ - spec/readthis/notifications_spec.rb
104
109
  - spec/spec_helper.rb
105
110
  homepage: https://github.com/sorentwo/readthis
106
111
  licenses:
@@ -128,4 +133,6 @@ specification_version: 4
128
133
  summary: Pooled active support compliant caching with redis
129
134
  test_files:
130
135
  - spec/readthis/cache_spec.rb
136
+ - spec/readthis/expanders_spec.rb
137
+ - spec/readthis/notifications_spec.rb
131
138
  - spec/spec_helper.rb