moneta 1.3.0 → 1.4.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/.rubocop.yml +26 -8
- data/CHANGES +6 -0
- data/CONTRIBUTORS +2 -1
- data/Gemfile +7 -5
- data/README.md +2 -6
- data/feature_matrix.yaml +0 -10
- data/lib/moneta.rb +9 -9
- data/lib/moneta/adapters/mongo.rb +256 -7
- data/lib/moneta/adapters/redis.rb +5 -1
- data/lib/moneta/adapters/sequel.rb +45 -464
- data/lib/moneta/adapters/sequel/mysql.rb +66 -0
- data/lib/moneta/adapters/sequel/postgres.rb +80 -0
- data/lib/moneta/adapters/sequel/postgres_hstore.rb +240 -0
- data/lib/moneta/adapters/sequel/sqlite.rb +57 -0
- data/lib/moneta/adapters/sqlite.rb +7 -7
- data/lib/moneta/create_support.rb +21 -0
- data/lib/moneta/dbm_adapter.rb +31 -0
- data/lib/moneta/{mixins.rb → defaults.rb} +1 -302
- data/lib/moneta/each_key_support.rb +27 -0
- data/lib/moneta/expires_support.rb +60 -0
- data/lib/moneta/hash_adapter.rb +68 -0
- data/lib/moneta/increment_support.rb +16 -0
- data/lib/moneta/nil_values.rb +35 -0
- data/lib/moneta/option_support.rb +51 -0
- data/lib/moneta/transformer/helper/bson.rb +5 -15
- data/lib/moneta/version.rb +1 -1
- data/lib/rack/cache/moneta.rb +14 -15
- data/moneta.gemspec +7 -9
- data/script/benchmarks +1 -2
- data/script/contributors +11 -6
- data/spec/active_support/cache_moneta_store_spec.rb +27 -29
- data/spec/features/concurrent_increment.rb +2 -3
- data/spec/features/create_expires.rb +15 -15
- data/spec/features/default_expires.rb +11 -12
- data/spec/features/expires.rb +215 -210
- data/spec/helper.rb +16 -33
- data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +16 -1
- data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +1 -1
- data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +1 -1
- data/spec/moneta/adapters/sequel/adapter_sequel_spec.rb +7 -34
- data/spec/moneta/adapters/sequel/helper.rb +37 -0
- data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +4 -10
- data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +7 -8
- data/spec/moneta/proxies/shared/shared_unix_spec.rb +10 -0
- data/spec/restserver.rb +15 -0
- metadata +39 -58
- data/lib/moneta/adapters/mongo/base.rb +0 -103
- data/lib/moneta/adapters/mongo/moped.rb +0 -166
- data/lib/moneta/adapters/mongo/official.rb +0 -156
- data/spec/moneta/adapters/mongo/adapter_mongo_moped_spec.rb +0 -26
- data/spec/moneta/adapters/mongo/adapter_mongo_moped_with_default_expires_spec.rb +0 -14
- data/spec/moneta/adapters/mongo/adapter_mongo_official_spec.rb +0 -27
- data/spec/moneta/adapters/mongo/adapter_mongo_official_with_default_expires_spec.rb +0 -14
- data/spec/moneta/adapters/mongo/standard_mongo_moped_spec.rb +0 -7
- data/spec/moneta/adapters/mongo/standard_mongo_official_spec.rb +0 -7
- data/spec/quality_spec.rb +0 -51
@@ -0,0 +1,68 @@
|
|
1
|
+
module Moneta
|
2
|
+
# @api private
|
3
|
+
module HashAdapter
|
4
|
+
attr_reader :backend
|
5
|
+
|
6
|
+
# (see Proxy#key?)
|
7
|
+
def key?(key, options = {})
|
8
|
+
@backend.has_key?(key)
|
9
|
+
end
|
10
|
+
|
11
|
+
# (see Proxy#load)
|
12
|
+
def load(key, options = {})
|
13
|
+
@backend[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
# (see Proxy#store)
|
17
|
+
def store(key, value, options = {})
|
18
|
+
@backend[key] = value
|
19
|
+
end
|
20
|
+
|
21
|
+
# (see Proxy#delete)
|
22
|
+
def delete(key, options = {})
|
23
|
+
@backend.delete(key)
|
24
|
+
end
|
25
|
+
|
26
|
+
# (see Proxy#clear)
|
27
|
+
def clear(options = {})
|
28
|
+
@backend.clear
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# (see Defaults#values_at)
|
33
|
+
def values_at(*keys, **options)
|
34
|
+
return super unless @backend.respond_to? :values_at
|
35
|
+
@backend.values_at(*keys)
|
36
|
+
end
|
37
|
+
|
38
|
+
# (see Defaults#fetch_values)
|
39
|
+
def fetch_values(*keys, **options, &defaults)
|
40
|
+
return super unless @backend.respond_to? :fetch_values
|
41
|
+
defaults ||= {} # prevents KeyError
|
42
|
+
@backend.fetch_values(*keys, &defaults)
|
43
|
+
end
|
44
|
+
|
45
|
+
# (see Defaults#slice)
|
46
|
+
def slice(*keys, **options)
|
47
|
+
return super unless @backend.respond_to? :slice
|
48
|
+
@backend.slice(*keys)
|
49
|
+
end
|
50
|
+
|
51
|
+
# (see Defaults#merge!)
|
52
|
+
def merge!(pairs, options = {}, &block)
|
53
|
+
return super unless method = [:merge!, :update].find do |method|
|
54
|
+
@backend.respond_to? method
|
55
|
+
end
|
56
|
+
|
57
|
+
hash = Hash === pairs ? pairs : Hash[pairs.to_a]
|
58
|
+
case method
|
59
|
+
when :merge!
|
60
|
+
@backend.merge!(hash, &block)
|
61
|
+
when :update
|
62
|
+
@backend.update(hash, &block)
|
63
|
+
end
|
64
|
+
|
65
|
+
self
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Moneta
|
2
|
+
# @api private
|
3
|
+
module IncrementSupport
|
4
|
+
# (see Defaults#increment)
|
5
|
+
def increment(key, amount = 1, options = {})
|
6
|
+
existing = load(key, options)
|
7
|
+
value = (existing == nil ? 0 : Integer(existing)) + amount
|
8
|
+
store(key, value.to_s, options)
|
9
|
+
value
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.included(base)
|
13
|
+
base.supports(:increment) if base.respond_to?(:supports)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Moneta
|
2
|
+
# This contains overrides of methods in Defaults where additional nil
|
3
|
+
# checks are required, because nil values are possible in the store.
|
4
|
+
# @api private
|
5
|
+
module NilValues
|
6
|
+
def fetch_values(*keys, **options)
|
7
|
+
values = values_at(*keys, **options)
|
8
|
+
return values unless block_given?
|
9
|
+
keys.zip(values).map do |key, value|
|
10
|
+
if value == nil && !key?(key)
|
11
|
+
yield key
|
12
|
+
else
|
13
|
+
value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def slice(*keys, **options)
|
19
|
+
keys.zip(values_at(*keys, **options)).reject do |key, value|
|
20
|
+
value == nil && !key?(key)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge!(pairs, options = {})
|
25
|
+
pairs.each do |key, value|
|
26
|
+
if block_given? && key?(key, options)
|
27
|
+
existing = load(key, options)
|
28
|
+
value = yield(key, existing, value)
|
29
|
+
end
|
30
|
+
store(key, value, options)
|
31
|
+
end
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Moneta
|
2
|
+
# @api private
|
3
|
+
module OptionSupport
|
4
|
+
# Return Moneta store with default options or additional proxies
|
5
|
+
#
|
6
|
+
# @param [Hash] options Options to merge
|
7
|
+
# @return [Moneta store]
|
8
|
+
#
|
9
|
+
# @api public
|
10
|
+
def with(options = nil, &block)
|
11
|
+
adapter = self
|
12
|
+
if block
|
13
|
+
builder = Builder.new(&block)
|
14
|
+
builder.adapter(adapter)
|
15
|
+
adapter = builder.build.last
|
16
|
+
end
|
17
|
+
options ? OptionMerger.new(adapter, options) : adapter
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return Moneta store with default option raw: true
|
21
|
+
#
|
22
|
+
# @return [OptionMerger]
|
23
|
+
# @api public
|
24
|
+
def raw
|
25
|
+
@raw ||=
|
26
|
+
begin
|
27
|
+
store = with(raw: true, only: [:load, :store, :create, :delete])
|
28
|
+
store.instance_variable_set(:@raw, store)
|
29
|
+
store
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Return Moneta store with default prefix option
|
34
|
+
#
|
35
|
+
# @param [String] prefix Key prefix
|
36
|
+
# @return [OptionMerger]
|
37
|
+
# @api public
|
38
|
+
def prefix(prefix)
|
39
|
+
with(prefix: prefix, except: :clear)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Return Moneta store with default expiration time
|
43
|
+
#
|
44
|
+
# @param [Integer] expires Default expiration time
|
45
|
+
# @return [OptionMerger]
|
46
|
+
# @api public
|
47
|
+
def expires(expires)
|
48
|
+
with(expires: expires, only: [:store, :create, :increment])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -5,22 +5,12 @@ module Moneta
|
|
5
5
|
module BSON
|
6
6
|
extend self
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
12
|
-
|
13
|
-
def dump(value)
|
14
|
-
::BSON::Document['v' => value].to_bson.to_s
|
15
|
-
end
|
16
|
-
else
|
17
|
-
def load(value)
|
18
|
-
::BSON::Document.from_bson(::StringIO.new(value))['v']
|
19
|
-
end
|
8
|
+
def load(value)
|
9
|
+
::BSON::Document.from_bson(::BSON::ByteBuffer.new(value))['v']
|
10
|
+
end
|
20
11
|
|
21
|
-
|
22
|
-
|
23
|
-
end
|
12
|
+
def dump(value)
|
13
|
+
::BSON::Document['v' => value].to_bson.to_s
|
24
14
|
end
|
25
15
|
end
|
26
16
|
end
|
data/lib/moneta/version.rb
CHANGED
data/lib/rack/cache/moneta.rb
CHANGED
@@ -14,21 +14,20 @@ module Rack
|
|
14
14
|
|
15
15
|
def resolve(uri)
|
16
16
|
cache = Rack::Cache::Moneta[uri.to_s.sub(%r{^moneta://}, '')] ||=
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
17
|
+
begin
|
18
|
+
options = parse_query(uri.query).map do |key, value|
|
19
|
+
[key.to_sym,
|
20
|
+
case value
|
21
|
+
when 'true'
|
22
|
+
true
|
23
|
+
when 'false'
|
24
|
+
false
|
25
|
+
else
|
26
|
+
value
|
27
|
+
end]
|
28
|
+
end
|
29
|
+
::Moneta.new(uri.host.to_sym, options.to_h)
|
30
|
+
end
|
32
31
|
new(cache)
|
33
32
|
end
|
34
33
|
end
|
data/moneta.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
1
|
require File.dirname(__FILE__) + '/lib/moneta/version'
|
3
2
|
require 'date'
|
4
3
|
|
@@ -7,7 +6,7 @@ Gem::Specification.new do |s|
|
|
7
6
|
s.version = Moneta::VERSION
|
8
7
|
s.date = Date.today.to_s
|
9
8
|
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
|
9
|
+
s.email = %w{mail@daniel-mendler.de wycats@gmail.com hannes.georg@googlemail.com me@asph.dev}
|
11
10
|
s.description = 'A unified interface to key/value stores'
|
12
11
|
s.extra_rdoc_files = %w{README.md SPEC.md LICENSE}
|
13
12
|
s.files = `git ls-files`.split("\n")
|
@@ -19,19 +18,18 @@ Gem::Specification.new do |s|
|
|
19
18
|
s.summary = %{A unified interface to key/value stores, including Redis, Memcached, TokyoCabinet, ActiveRecord and many more}
|
20
19
|
|
21
20
|
s.metadata = {
|
22
|
-
'bug_tracker_uri'
|
23
|
-
'changelog_uri'
|
21
|
+
'bug_tracker_uri' => 'https://github.com/moneta-rb/moneta/issues',
|
22
|
+
'changelog_uri' => "https://github.com/moneta-rb/moneta/blob/v#{s.version}/CHANGES",
|
24
23
|
'documentation_uri' => "https://www.rubydoc.info/gems/moneta/#{s.version}",
|
25
|
-
'source_code_uri'
|
24
|
+
'source_code_uri' => "https://github.com/moneta-rb/moneta/tree/v#{s.version}",
|
26
25
|
}
|
27
26
|
|
28
27
|
s.required_ruby_version = '>= 2.3.0'
|
29
28
|
|
29
|
+
s.add_development_dependency 'parallel_tests', '~> 2.29.2'
|
30
|
+
s.add_development_dependency 'rantly', '~> 1.2.0'
|
30
31
|
s.add_development_dependency 'rspec', '~> 3.0'
|
31
32
|
s.add_development_dependency 'rspec-retry', '~> 0.6.1'
|
32
|
-
s.add_development_dependency '
|
33
|
-
s.add_development_dependency 'parallel_tests', '~> 2.29.2'
|
33
|
+
s.add_development_dependency 'rubocop', '~> 0.81.0'
|
34
34
|
s.add_development_dependency 'timecop', '~> 0.9.1'
|
35
|
-
s.add_development_dependency 'rubocop', '~> 0.67.2'
|
36
|
-
s.add_development_dependency 'irb', '1.2.1'
|
37
35
|
end
|
data/script/benchmarks
CHANGED
data/script/contributors
CHANGED
@@ -1,7 +1,12 @@
|
|
1
|
-
#!/bin/
|
2
|
-
git log --format='%aN <%aE>' |\
|
3
|
-
sed -e 's/hiddenbek/Scott Wadden/g' |\
|
4
|
-
sed -e 's/Asmod4n/Hendrik Beskow/' |\
|
5
|
-
grep -v 'asppsa@gmail.com\|hannes.georg@xing.com\|spotapov\|yehuda-katzs-mac\|wycats ' |\
|
6
|
-
sort -u | sort > CONTRIBUTORS
|
1
|
+
#!/usr/bin/env ruby
|
7
2
|
|
3
|
+
contributors = `git log --format='%aN <%aE>'`
|
4
|
+
.gsub(/hiddenbek/, 'Scott Wadden')
|
5
|
+
.gsub(/Asmod4n/, 'Hendrik Beskow')
|
6
|
+
.lines
|
7
|
+
.uniq
|
8
|
+
.reject { |line| line.match? /asppsa@gmail.com|hannes.georg@xing.com|spotapov|yehuda-katzs-mac|wycats / }
|
9
|
+
.sort { |str1, str2| str1.casecmp(str2) }
|
10
|
+
|
11
|
+
file = File.open('CONTRIBUTORS', 'w')
|
12
|
+
file << contributors.join
|
@@ -79,40 +79,38 @@ describe "cache_moneta_store" do
|
|
79
79
|
end
|
80
80
|
|
81
81
|
shared_examples :expiry do
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
82
|
+
it 'writes the data with expiration time' do
|
83
|
+
store.write 'rabbit', white_rabbit, expires_in: 0.2.second
|
84
|
+
expect(store.read('rabbit')).to eq white_rabbit
|
85
|
+
sleep 0.3
|
86
|
+
expect(store.read('rabbit')).to be_nil
|
87
|
+
end
|
89
88
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
89
|
+
it 'writes multiple values with expiration time' do
|
90
|
+
store.write_multi({
|
91
|
+
'rabbit' => white_rabbit,
|
92
|
+
'irish whisky' => 'Jameson'
|
93
|
+
}, expires_in: 0.2.second)
|
95
94
|
|
96
|
-
|
97
|
-
|
98
|
-
|
95
|
+
expect(store.read_multi('rabbit', 'irish whisky')).to eq \
|
96
|
+
'rabbit' => white_rabbit,
|
97
|
+
'irish whisky' => 'Jameson'
|
99
98
|
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
sleep 0.3
|
100
|
+
expect(store.read_multi('rabbit', 'irish whisky')).to be_empty
|
101
|
+
end
|
103
102
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
103
|
+
it "sets expiry on cache miss" do
|
104
|
+
store.fetch('rabbit', force: true, expires_in: 0.2.second) { white_rabbit }
|
105
|
+
expect(store.fetch('rabbit')).to eq white_rabbit
|
106
|
+
sleep 0.3
|
107
|
+
expect(store.fetch('rabbit')).to be_nil
|
108
|
+
end
|
110
109
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
end
|
110
|
+
it 'does not set expiry on cache hit' do
|
111
|
+
expect(store.fetch('rabbit', expires_in: 0.2.second) { white_rabbit }).to eq rabbit
|
112
|
+
sleep 0.3
|
113
|
+
expect(store.fetch('rabbit')).to eq rabbit
|
116
114
|
end
|
117
115
|
end
|
118
116
|
|
@@ -8,9 +8,8 @@ shared_examples :concurrent_increment do
|
|
8
8
|
increments = (0...100).map { [] }
|
9
9
|
100.times do
|
10
10
|
100.times do |j|
|
11
|
-
increments[j] << s.increment(j.to_s, 1, expires: false)
|
12
|
-
|
13
|
-
end
|
11
|
+
increments[j] << s.increment(j.to_s, 1, expires: false)
|
12
|
+
Thread.pass if rand(1000) >= 995
|
14
13
|
end
|
15
14
|
end
|
16
15
|
increments
|
@@ -1,19 +1,19 @@
|
|
1
1
|
shared_examples :create_expires do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
it 'creates the given key and expires it' do
|
3
|
+
store.create('key','value', expires: min_ttl).should be true
|
4
|
+
store['key'].should == 'value'
|
5
|
+
advance min_ttl
|
6
|
+
2.times { advance_next_tick }
|
7
|
+
store.key?('key').should be false
|
8
|
+
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
it 'does not change expires if the key exists' do
|
11
|
+
store.store('key', 'value', expires: false).should == 'value'
|
12
|
+
store.create('key','another value', expires: min_ttl).should be false
|
13
|
+
store['key'].should == 'value'
|
14
|
+
advance min_ttl
|
15
|
+
2.times { advance_next_tick }
|
16
|
+
store['key'].should == 'value'
|
17
|
+
store.key?('key').should be true
|
18
18
|
end
|
19
19
|
end
|
@@ -1,15 +1,14 @@
|
|
1
1
|
shared_examples :default_expires do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
2
|
+
it 'sets the default expiration time', default_expires: true do
|
3
|
+
store['key1'] = 'val1'
|
4
|
+
advance(t_res / 4.0) # sleep less than a single time-space
|
5
|
+
store.key?('key1').should be true
|
6
|
+
store.fetch('key1').should == 'val1'
|
7
|
+
store.load('key1').should == 'val1'
|
8
|
+
advance min_ttl
|
9
|
+
2.times { advance_next_tick }
|
10
|
+
store.key?('key1').should be false
|
11
|
+
store.fetch('key1').should be_nil
|
12
|
+
store.load('key1').should be_nil
|
14
13
|
end
|
15
14
|
end
|