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.
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