moneta 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +26 -8
  3. data/CHANGES +6 -0
  4. data/CONTRIBUTORS +2 -1
  5. data/Gemfile +7 -5
  6. data/README.md +2 -6
  7. data/feature_matrix.yaml +0 -10
  8. data/lib/moneta.rb +9 -9
  9. data/lib/moneta/adapters/mongo.rb +256 -7
  10. data/lib/moneta/adapters/redis.rb +5 -1
  11. data/lib/moneta/adapters/sequel.rb +45 -464
  12. data/lib/moneta/adapters/sequel/mysql.rb +66 -0
  13. data/lib/moneta/adapters/sequel/postgres.rb +80 -0
  14. data/lib/moneta/adapters/sequel/postgres_hstore.rb +240 -0
  15. data/lib/moneta/adapters/sequel/sqlite.rb +57 -0
  16. data/lib/moneta/adapters/sqlite.rb +7 -7
  17. data/lib/moneta/create_support.rb +21 -0
  18. data/lib/moneta/dbm_adapter.rb +31 -0
  19. data/lib/moneta/{mixins.rb → defaults.rb} +1 -302
  20. data/lib/moneta/each_key_support.rb +27 -0
  21. data/lib/moneta/expires_support.rb +60 -0
  22. data/lib/moneta/hash_adapter.rb +68 -0
  23. data/lib/moneta/increment_support.rb +16 -0
  24. data/lib/moneta/nil_values.rb +35 -0
  25. data/lib/moneta/option_support.rb +51 -0
  26. data/lib/moneta/transformer/helper/bson.rb +5 -15
  27. data/lib/moneta/version.rb +1 -1
  28. data/lib/rack/cache/moneta.rb +14 -15
  29. data/moneta.gemspec +7 -9
  30. data/script/benchmarks +1 -2
  31. data/script/contributors +11 -6
  32. data/spec/active_support/cache_moneta_store_spec.rb +27 -29
  33. data/spec/features/concurrent_increment.rb +2 -3
  34. data/spec/features/create_expires.rb +15 -15
  35. data/spec/features/default_expires.rb +11 -12
  36. data/spec/features/expires.rb +215 -210
  37. data/spec/helper.rb +16 -33
  38. data/spec/moneta/adapters/mongo/adapter_mongo_spec.rb +16 -1
  39. data/spec/moneta/adapters/mongo/adapter_mongo_with_default_expires_spec.rb +1 -1
  40. data/spec/moneta/adapters/mongo/standard_mongo_spec.rb +1 -1
  41. data/spec/moneta/adapters/sequel/adapter_sequel_spec.rb +7 -34
  42. data/spec/moneta/adapters/sequel/helper.rb +37 -0
  43. data/spec/moneta/adapters/sequel/standard_sequel_spec.rb +4 -10
  44. data/spec/moneta/adapters/sequel/standard_sequel_with_expires_spec.rb +7 -8
  45. data/spec/moneta/proxies/shared/shared_unix_spec.rb +10 -0
  46. data/spec/restserver.rb +15 -0
  47. metadata +39 -58
  48. data/lib/moneta/adapters/mongo/base.rb +0 -103
  49. data/lib/moneta/adapters/mongo/moped.rb +0 -166
  50. data/lib/moneta/adapters/mongo/official.rb +0 -156
  51. data/spec/moneta/adapters/mongo/adapter_mongo_moped_spec.rb +0 -26
  52. data/spec/moneta/adapters/mongo/adapter_mongo_moped_with_default_expires_spec.rb +0 -14
  53. data/spec/moneta/adapters/mongo/adapter_mongo_official_spec.rb +0 -27
  54. data/spec/moneta/adapters/mongo/adapter_mongo_official_with_default_expires_spec.rb +0 -14
  55. data/spec/moneta/adapters/mongo/standard_mongo_moped_spec.rb +0 -7
  56. data/spec/moneta/adapters/mongo/standard_mongo_official_spec.rb +0 -7
  57. 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
- if ::BSON::VERSION >= '4.0.0'
9
- def load(value)
10
- ::BSON::Document.from_bson(::BSON::ByteBuffer.new(value))['v']
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
- def dump(value)
22
- ::BSON::Document['v' => value].to_bson
23
- end
12
+ def dump(value)
13
+ ::BSON::Document['v' => value].to_bson.to_s
24
14
  end
25
15
  end
26
16
  end
@@ -1,5 +1,5 @@
1
1
  module Moneta
2
2
  # Moneta version number
3
3
  # @api public
4
- VERSION = '1.3.0'.freeze
4
+ VERSION = '1.4.0'.freeze
5
5
  end
@@ -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
- begin
18
- options = parse_query(uri.query)
19
- options.keys.each do |key|
20
- options[key.to_sym] =
21
- case value = options.delete(key)
22
- when 'true'
23
- true
24
- when 'false'
25
- false
26
- else
27
- value
28
- end
29
- end
30
- ::Moneta.new(uri.host.to_sym, options)
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
@@ -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 asppsa@gmail.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' => 'https://github.com/moneta-rb/moneta/issues',
23
- 'changelog_uri' => "https://github.com/moneta-rb/moneta/blob/v#{s.version}/CHANGES",
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' => "https://github.com/moneta-rb/moneta/tree/v#{s.version}",
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 'rantly', '~> 1.2.0'
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
@@ -164,8 +164,7 @@ class MonetaBenchmarks
164
164
  {name: "MemcachedNative"}
165
165
  end,
166
166
  {name: "Memory"},
167
- {name: "MongoMoped"},
168
- {name: "MongoOfficial"},
167
+ {name: "Mongo"},
169
168
  {name: "PStore", options: { file: "#{DIR}/pstore" }},
170
169
  {name: "Redis"},
171
170
  {
@@ -1,7 +1,12 @@
1
- #!/bin/sh
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
- at_each_usec do
83
- it 'writes the data with expiration time' do
84
- store.write 'rabbit', white_rabbit, expires_in: 0.2.second
85
- expect(store.read('rabbit')).to eq white_rabbit
86
- sleep 0.3
87
- expect(store.read('rabbit')).to be_nil
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
- it 'writes multiple values with expiration time' do
91
- store.write_multi({
92
- 'rabbit' => white_rabbit,
93
- 'irish whisky' => 'Jameson'
94
- }, expires_in: 0.2.second)
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
- expect(store.read_multi('rabbit', 'irish whisky')).to eq \
97
- 'rabbit' => white_rabbit,
98
- 'irish whisky' => 'Jameson'
95
+ expect(store.read_multi('rabbit', 'irish whisky')).to eq \
96
+ 'rabbit' => white_rabbit,
97
+ 'irish whisky' => 'Jameson'
99
98
 
100
- sleep 0.3
101
- expect(store.read_multi('rabbit', 'irish whisky')).to be_empty
102
- end
99
+ sleep 0.3
100
+ expect(store.read_multi('rabbit', 'irish whisky')).to be_empty
101
+ end
103
102
 
104
- it "sets expiry on cache miss" do
105
- store.fetch('rabbit', force: true, expires_in: 0.2.second) { white_rabbit }
106
- expect(store.fetch('rabbit')).to eq white_rabbit
107
- sleep 0.3
108
- expect(store.fetch('rabbit')).to be_nil
109
- end
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
- it 'does not set expiry on cache hit' do
112
- expect(store.fetch('rabbit', expires_in: 0.2.second) { white_rabbit }).to eq rabbit
113
- sleep 0.3
114
- expect(store.fetch('rabbit')).to eq rabbit
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).tap do
12
- Thread.pass if rand(1000) >= 995
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
- at_each_usec do
3
- it 'creates the given key and expires it' do
4
- store.create('key','value', expires: min_ttl).should be true
5
- store['key'].should == 'value'
6
- advance min_ttl + t_res
7
- store.key?('key').should be false
8
- end
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
- 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 + t_res
15
- store['key'].should == 'value'
16
- store.key?('key').should be true
17
- end
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
- at_each_usec do
3
- it 'sets the default expiration time', default_expires: true do
4
- store['key1'] = 'val1'
5
- advance(t_res / 4.0) # sleep less than a single time-space
6
- store.key?('key1').should be true
7
- store.fetch('key1').should == 'val1'
8
- store.load('key1').should == 'val1'
9
- advance min_ttl + t_res
10
- store.key?('key1').should be false
11
- store.fetch('key1').should be_nil
12
- store.load('key1').should be_nil
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