moneta 0.8.1 → 1.0.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.
- checksums.yaml +4 -4
- data/CHANGES +6 -0
- data/CONTRIBUTORS +2 -0
- data/Gemfile +1 -0
- data/LICENSE +1 -1
- data/lib/active_support/cache/moneta_store.rb +5 -4
- data/lib/moneta/adapters/sequel.rb +9 -0
- data/lib/moneta/version.rb +1 -1
- data/moneta.gemspec +2 -2
- data/script/parallel-tests +12 -0
- data/spec/active_support/cache_moneta_store_spec.rb +155 -93
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e375eca1c232dfe6bf7732660b158162bd5b887
|
4
|
+
data.tar.gz: 30219ec6a3496650ea09927d1d6140d377f48730
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39edafb80920ff47c04b215fd74d77f9e49363588bdf988649637d24219e1e164b8887c46289be4455a0fbaf5315fe5b768fd0b56f5a594594ba44f28ff1ece9
|
7
|
+
data.tar.gz: ba16585476906490eaa5df9be59c24cd5d49cd82eacdc9b6960f59456bc461a603334abce9c70894e9de12af1f55b13d16710137171a47a4588670e72bf0f4f7
|
data/CHANGES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
1.0.0
|
2
|
+
|
3
|
+
* Adapters::Sequel - allow usage of Sequel extensions and connection validation
|
4
|
+
* ActiveSupport::Cache::MonetaStore - dup options before mutating them
|
5
|
+
* ActiveSupport::Cache::MonetaStore - allow writing raw values
|
6
|
+
|
1
7
|
0.8.1
|
2
8
|
|
3
9
|
* Adapters::TokyoTyrant - more consistent error handling
|
data/CONTRIBUTORS
CHANGED
@@ -26,6 +26,8 @@ Potapov Sergey <blake131313@gmail.com>
|
|
26
26
|
Quin Hoxie <quin@aboutus.org>
|
27
27
|
Ryan T. Hosford <tad.hosford@gmail.com>
|
28
28
|
Scott Wadden <scott.wadden@gmail.com>
|
29
|
+
Timo Goebel <timo.goebel@dm.de>
|
29
30
|
Tom Meier <ozmeier@yahoo.co.uk>
|
31
|
+
Tony Han <h.bing612@gmail.com>
|
30
32
|
Xavier Shay <xavier@rhnh.net>
|
31
33
|
Yehuda Katz <wycats@gmail.com>
|
data/Gemfile
CHANGED
data/LICENSE
CHANGED
@@ -38,7 +38,8 @@ module ActiveSupport
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def write_entry(key, entry, options)
|
41
|
-
|
41
|
+
value = options[:raw] ? entry.value.to_s : entry
|
42
|
+
@store.store(key, value, moneta_options(options))
|
42
43
|
true
|
43
44
|
end
|
44
45
|
|
@@ -50,9 +51,9 @@ module ActiveSupport
|
|
50
51
|
private
|
51
52
|
|
52
53
|
def moneta_options(options)
|
53
|
-
options
|
54
|
-
|
55
|
-
|
54
|
+
new_options = options ? options.dup : {}
|
55
|
+
new_options[:expires] = new_options.delete(:expires_in).to_i if new_options.include?(:expires_in)
|
56
|
+
new_options
|
56
57
|
end
|
57
58
|
end
|
58
59
|
end
|
@@ -17,15 +17,24 @@ module Moneta
|
|
17
17
|
# @param [Hash] options
|
18
18
|
# @option options [String] :db Sequel database
|
19
19
|
# @option options [String/Symbol] :table (:moneta) Table name
|
20
|
+
# @option options [Array] :extensions ([]) List of Sequel extensions
|
21
|
+
# @option options [Integer] :connection_validation_timeout (nil) Sequel connection_validation_timeout
|
20
22
|
# @option options All other options passed to `Sequel#connect`
|
21
23
|
# @option options [Sequel connection] :backend Use existing backend instance
|
22
24
|
def initialize(options = {})
|
23
25
|
table = (options.delete(:table) || :moneta).to_sym
|
26
|
+
extensions = options.delete(:extensions) || []
|
27
|
+
raise ArgumentError, 'Option :extensions must be an Array' unless extensions.is_a?(Array)
|
28
|
+
connection_validation_timeout = options.delete(:connection_validation_timeout)
|
24
29
|
@backend = options[:backend] ||
|
25
30
|
begin
|
26
31
|
raise ArgumentError, 'Option :db is required' unless db = options.delete(:db)
|
27
32
|
::Sequel.connect(db, options)
|
28
33
|
end
|
34
|
+
extensions.each do |extension|
|
35
|
+
@backend.extension(extension.to_sym)
|
36
|
+
end
|
37
|
+
@backend.pool.connection_validation_timeout = connection_validation_timeout if connection_validation_timeout
|
29
38
|
@backend.create_table?(table) do
|
30
39
|
String :k, null: false, primary_key: true
|
31
40
|
File :v
|
data/lib/moneta/version.rb
CHANGED
data/moneta.gemspec
CHANGED
@@ -6,8 +6,8 @@ Gem::Specification.new do |s|
|
|
6
6
|
s.name = 'moneta'
|
7
7
|
s.version = Moneta::VERSION
|
8
8
|
s.date = Date.today.to_s
|
9
|
-
s.authors = ['Daniel Mendler', 'Yehuda Katz', 'Hannes Georg']
|
10
|
-
s.email = %w{mail@daniel-mendler.de wycats@gmail.com hannes.georg@googlemail.com}
|
9
|
+
s.authors = ['Daniel Mendler', 'Yehuda Katz', 'Hannes Georg', 'Alastair Pharo']
|
10
|
+
s.email = %w{mail@daniel-mendler.de wycats@gmail.com hannes.georg@googlemail.com asppsa@gmail.com}
|
11
11
|
s.description = 'A unified interface to key/value stores'
|
12
12
|
s.extra_rdoc_files = %w{README.md SPEC.md LICENSE}
|
13
13
|
s.files = `git ls-files`.split("\n")
|
data/script/parallel-tests
CHANGED
@@ -68,6 +68,18 @@ parallel = []
|
|
68
68
|
parallel << serial
|
69
69
|
end
|
70
70
|
end
|
71
|
+
|
72
|
+
# The activesupport cache specs also use memcached
|
73
|
+
activesupport_cache_specs = specs.grep(/active_support.+cache/)
|
74
|
+
specs -= activesupport_cache_specs
|
75
|
+
|
76
|
+
if memcache_specs = parallel.find{ |serial| serial.all?{ |s| s.match /memcached/ } }
|
77
|
+
activesupport_cache_specs.each(&memcache_specs.method(:push))
|
78
|
+
else
|
79
|
+
parallel += activesupport_cache_specs
|
80
|
+
end
|
81
|
+
|
82
|
+
# All the left-overs
|
71
83
|
parallel += specs.map {|s| [s] }
|
72
84
|
|
73
85
|
threads = []
|
@@ -3,7 +3,20 @@ require 'active_support'
|
|
3
3
|
require 'active_support/cache/moneta_store'
|
4
4
|
require 'ostruct'
|
5
5
|
|
6
|
-
|
6
|
+
module MonetaStoreHelpers
|
7
|
+
def with_notifications
|
8
|
+
described_class.instrument = true
|
9
|
+
yield
|
10
|
+
ensure
|
11
|
+
described_class.instrument = false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.include(MonetaStoreHelpers)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "cache_moneta_store" do
|
7
20
|
before(:all) do
|
8
21
|
@events = []
|
9
22
|
ActiveSupport::Notifications.subscribe(/^cache_(.*)\.active_support$/) do |*args|
|
@@ -13,185 +26,234 @@ describe ActiveSupport::Cache::MonetaStore do
|
|
13
26
|
|
14
27
|
before(:each) do
|
15
28
|
@events.clear
|
16
|
-
@store = ActiveSupport::Cache::MonetaStore.new(store: Moneta.new(:Memory))
|
17
|
-
@rabbit = OpenStruct.new name: 'bunny'
|
18
|
-
@white_rabbit = OpenStruct.new color: 'white'
|
19
|
-
|
20
|
-
@store.write 'rabbit', @rabbit
|
21
|
-
@store.delete 'counter'
|
22
|
-
@store.delete 'rub-a-dub'
|
23
29
|
end
|
24
30
|
|
25
|
-
|
26
|
-
|
27
|
-
|
31
|
+
# All stores should implement this basic behavior.
|
32
|
+
shared_examples :basic_store do
|
33
|
+
before(:each) do
|
34
|
+
@rabbit = OpenStruct.new name: 'bunny'
|
35
|
+
@white_rabbit = OpenStruct.new color: 'white'
|
28
36
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
37
|
+
store.clear
|
38
|
+
store.write 'rabbit', @rabbit
|
39
|
+
end
|
33
40
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
sleep 2
|
38
|
-
@store.read('rabbit').should be_nil
|
39
|
-
end
|
41
|
+
it 'reads the data' do
|
42
|
+
store.read('rabbit').should == @rabbit
|
43
|
+
end
|
40
44
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
+
it 'writes the data' do
|
46
|
+
store.write 'rabbit', @white_rabbit
|
47
|
+
store.read('rabbit').should == @white_rabbit
|
48
|
+
end
|
45
49
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
+
it 'deletes data' do
|
51
|
+
store.delete 'rabbit'
|
52
|
+
store.read('rabbit').should be_nil
|
53
|
+
end
|
50
54
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
@store.fetch('rub-a-dub').should == 'Flora de Cana'
|
56
|
-
@store.fetch('rabbit', force: true) # force cache miss
|
57
|
-
@store.fetch('rabbit', force: true, expires_in: 1.second) { @white_rabbit }
|
58
|
-
@store.fetch('rabbit').should == @white_rabbit
|
59
|
-
sleep 2
|
60
|
-
@store.fetch('rabbit').should be_nil
|
61
|
-
end
|
55
|
+
it 'verifies existence of an object in the store' do
|
56
|
+
store.exist?('rabbit').should be true
|
57
|
+
(!!store.exist?('rab-a-dub')).should be false
|
58
|
+
end
|
62
59
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
60
|
+
it 'fetches data' do
|
61
|
+
store.fetch('rabbit').should == @rabbit
|
62
|
+
store.fetch('rub-a-dub').should be_nil
|
63
|
+
store.fetch('rub-a-dub') { 'Flora de Cana' }
|
64
|
+
store.fetch('rub-a-dub').should == 'Flora de Cana'
|
65
|
+
end
|
69
66
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
67
|
+
it 'reads multiple keys' do
|
68
|
+
store.write 'irish whisky', 'Jameson'
|
69
|
+
result = store.read_multi 'rabbit', 'irish whisky'
|
70
|
+
result['rabbit'].should == @rabbit
|
71
|
+
result['irish whisky'].should == 'Jameson'
|
72
|
+
end
|
76
73
|
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
it 'reads multiple keys and returns only the matched ones' do
|
75
|
+
store.delete 'irish whisky'
|
76
|
+
result = store.read_multi 'rabbit', 'irish whisky'
|
77
|
+
result.should_not include('irish whisky')
|
78
|
+
result.should include('rabbit')
|
79
|
+
end
|
80
80
|
end
|
81
81
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
82
|
+
shared_examples :expiry do
|
83
|
+
it 'writes the data with expiration time' do
|
84
|
+
store.write 'rabbit', @white_rabbit, expires_in: 1.second
|
85
|
+
store.read('rabbit').should == @white_rabbit
|
86
|
+
sleep 2
|
87
|
+
store.read('rabbit').should be_nil
|
88
|
+
end
|
89
|
+
|
90
|
+
it "sets expiry on cache miss" do
|
91
|
+
store.fetch('rabbit', force: true) # force cache miss
|
92
|
+
store.fetch('rabbit', force: true, expires_in: 1.second) { @white_rabbit }
|
93
|
+
store.fetch('rabbit').should == @white_rabbit
|
94
|
+
sleep 2
|
95
|
+
store.fetch('rabbit').should be_nil
|
96
|
+
end
|
87
97
|
|
88
|
-
|
89
|
-
|
90
|
-
|
98
|
+
it 'does not set expiry on cache hit' do
|
99
|
+
store.fetch('rabbit', expires_in: 1.second) { @white_rabbit }.should == @rabbit
|
100
|
+
sleep 2
|
101
|
+
store.fetch('rabbit').should == @rabbit
|
102
|
+
end
|
91
103
|
end
|
92
104
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
105
|
+
# A store *may* implement this
|
106
|
+
shared_examples :increment_decrement do
|
107
|
+
it 'increments a key' do
|
108
|
+
store.write 'counter', 0, raw: true
|
109
|
+
3.times { store.increment 'counter' }
|
110
|
+
store.read('counter', raw: true).to_i.should == 3
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'decrements a key' do
|
114
|
+
store.write 'counter', 0, raw: true
|
115
|
+
3.times { store.increment 'counter' }
|
116
|
+
2.times { store.decrement 'counter' }
|
117
|
+
store.read('counter', raw: true).to_i.should == 1
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'increments a key by given value' do
|
121
|
+
store.write 'counter', 0, raw: true
|
122
|
+
store.increment 'counter', 3
|
123
|
+
store.read('counter', raw: true).to_i.should == 3
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'decrements a key by given value' do
|
127
|
+
store.write 'counter', 0, raw: true
|
128
|
+
3.times { store.increment 'counter' }
|
129
|
+
store.decrement 'counter', 2
|
130
|
+
store.read('counter', raw: true).to_i.should == 1
|
131
|
+
end
|
97
132
|
end
|
98
133
|
|
99
|
-
|
134
|
+
shared_examples :basic_instrumentation do
|
100
135
|
it 'notifies on #fetch' do
|
101
136
|
with_notifications do
|
102
|
-
|
137
|
+
store.fetch('radiohead') { 'House Of Cards' }
|
103
138
|
end
|
104
139
|
|
105
|
-
read
|
106
|
-
|
140
|
+
read = @events.shift
|
107
141
|
read.name.should == 'cache_read.active_support'
|
108
142
|
read.payload.should == { key: 'radiohead', super_operation: :fetch }
|
109
143
|
|
144
|
+
generate = @events.shift
|
110
145
|
generate.name.should == 'cache_generate.active_support'
|
111
146
|
generate.payload.should == { key: 'radiohead' }
|
112
147
|
|
148
|
+
write = @events.shift
|
113
149
|
write.name.should == 'cache_write.active_support'
|
114
150
|
write.payload.should == { key: 'radiohead' }
|
115
151
|
end
|
116
152
|
|
117
153
|
it 'notifies on #read' do
|
118
154
|
with_notifications do
|
119
|
-
|
155
|
+
store.read 'metallica'
|
120
156
|
end
|
121
157
|
|
122
|
-
read = @events.
|
158
|
+
read = @events.shift
|
123
159
|
read.name.should == 'cache_read.active_support'
|
124
160
|
read.payload.should == { key: 'metallica', hit: false }
|
125
161
|
end
|
126
162
|
|
127
163
|
it 'notifies on #write' do
|
128
164
|
with_notifications do
|
129
|
-
|
165
|
+
store.write 'depeche mode', 'Enjoy The Silence'
|
130
166
|
end
|
131
167
|
|
132
|
-
write = @events.
|
168
|
+
write = @events.shift
|
133
169
|
write.name.should == 'cache_write.active_support'
|
134
170
|
write.payload.should == { key: 'depeche mode' }
|
135
171
|
end
|
136
172
|
|
137
173
|
it 'notifies on #delete' do
|
138
174
|
with_notifications do
|
139
|
-
|
175
|
+
store.delete 'the new cardigans'
|
140
176
|
end
|
141
177
|
|
142
|
-
delete = @events.
|
178
|
+
delete = @events.shift
|
143
179
|
delete.name.should == 'cache_delete.active_support'
|
144
180
|
delete.payload.should == { key: 'the new cardigans' }
|
145
181
|
end
|
146
182
|
|
147
183
|
it 'notifies on #exist?' do
|
148
184
|
with_notifications do
|
149
|
-
|
185
|
+
store.exist? 'the smiths'
|
150
186
|
end
|
151
187
|
|
152
|
-
exist = @events.
|
188
|
+
exist = @events.shift
|
153
189
|
exist.name.should == 'cache_exist?.active_support'
|
154
190
|
exist.payload.should == { key: 'the smiths' }
|
155
191
|
end
|
156
192
|
|
193
|
+
end
|
194
|
+
|
195
|
+
# This doesn't seem to be documented at all, so we follow the
|
196
|
+
# behavior of MemCacheStore.
|
197
|
+
shared_examples :increment_decrement_instrumentation do
|
157
198
|
it 'notifies on #increment' do
|
158
199
|
with_notifications do
|
159
|
-
|
200
|
+
store.increment 'pearl jam'
|
160
201
|
end
|
161
202
|
|
162
|
-
increment = @events.
|
203
|
+
increment = @events.shift
|
163
204
|
increment.name.should == 'cache_increment.active_support'
|
164
205
|
increment.payload.should == { key: 'pearl jam', amount: 1 }
|
165
206
|
end
|
166
207
|
|
167
208
|
it 'notifies on #decrement' do
|
168
209
|
with_notifications do
|
169
|
-
|
210
|
+
store.decrement 'placebo'
|
170
211
|
end
|
171
212
|
|
172
|
-
decrement = @events.
|
213
|
+
decrement = @events.shift
|
173
214
|
decrement.name.should == 'cache_decrement.active_support'
|
174
215
|
decrement.payload.should == { key: 'placebo', amount: 1 }
|
175
216
|
end
|
217
|
+
end
|
176
218
|
|
177
|
-
|
219
|
+
describe ActiveSupport::Cache::MonetaStore do
|
220
|
+
let(:store){ described_class.new(store: Moneta.new(:Memory)) }
|
221
|
+
|
222
|
+
include_examples :basic_store
|
223
|
+
include_examples :expiry
|
224
|
+
include_examples :increment_decrement
|
225
|
+
include_examples :basic_instrumentation
|
226
|
+
include_examples :increment_decrement_instrumentation
|
227
|
+
|
228
|
+
# FIXME: no other store does this -- perhaps this should be
|
229
|
+
# removed.
|
230
|
+
it 'notifies on #clear' do
|
178
231
|
with_notifications do
|
179
|
-
|
232
|
+
store.clear
|
180
233
|
end
|
181
234
|
|
182
|
-
clear = @events.
|
235
|
+
clear = @events.shift
|
183
236
|
clear.name.should == 'cache_clear.active_support'
|
184
237
|
clear.payload.should == { key: nil }
|
185
238
|
end
|
186
239
|
end
|
187
240
|
|
188
|
-
|
241
|
+
describe ActiveSupport::Cache::MemoryStore do
|
242
|
+
let(:store){ described_class.new }
|
189
243
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
ActiveSupport::Cache::MonetaStore.instrument = false
|
244
|
+
include_examples :basic_store
|
245
|
+
include_examples :expiry
|
246
|
+
include_examples :increment_decrement
|
247
|
+
include_examples :basic_instrumentation
|
195
248
|
end
|
196
|
-
end
|
197
249
|
|
250
|
+
describe ActiveSupport::Cache::MemCacheStore do
|
251
|
+
let(:store){ described_class.new }
|
252
|
+
|
253
|
+
include_examples :basic_store
|
254
|
+
include_examples :expiry
|
255
|
+
include_examples :increment_decrement
|
256
|
+
include_examples :basic_instrumentation
|
257
|
+
include_examples :increment_decrement_instrumentation
|
258
|
+
end
|
259
|
+
end
|
metadata
CHANGED
@@ -1,22 +1,24 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: moneta
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Mendler
|
8
8
|
- Yehuda Katz
|
9
9
|
- Hannes Georg
|
10
|
+
- Alastair Pharo
|
10
11
|
autorequire:
|
11
12
|
bindir: bin
|
12
13
|
cert_chain: []
|
13
|
-
date:
|
14
|
+
date: 2017-03-08 00:00:00.000000000 Z
|
14
15
|
dependencies: []
|
15
16
|
description: A unified interface to key/value stores
|
16
17
|
email:
|
17
18
|
- mail@daniel-mendler.de
|
18
19
|
- wycats@gmail.com
|
19
20
|
- hannes.georg@googlemail.com
|
21
|
+
- asppsa@gmail.com
|
20
22
|
executables: []
|
21
23
|
extensions: []
|
22
24
|
extra_rdoc_files:
|