juno 0.1.0 → 0.1.1
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.
- data/.gitignore +1 -0
- data/.travis.yml +2 -5
- data/Gemfile +21 -8
- data/README.md +3 -1
- data/{unsupported/benchmarks.rb → benchmarks/run.rb} +20 -83
- data/lib/juno.rb +4 -4
- data/lib/juno/activerecord.rb +2 -5
- data/lib/juno/base.rb +4 -0
- data/{unsupported → lib/juno}/cassandra.rb +11 -11
- data/lib/juno/datamapper.rb +1 -1
- data/{unsupported → lib/juno}/fog.rb +7 -19
- data/lib/juno/null.rb +23 -0
- data/lib/juno/redis.rb +13 -1
- data/lib/juno/sequel.rb +3 -6
- data/lib/juno/stack.rb +41 -0
- data/lib/juno/version.rb +1 -1
- data/test/helper.rb +160 -130
- data/test/{test_active_record.rb → test_activerecord.rb} +2 -5
- data/{unsupported → test}/test_cassandra.rb +1 -1
- data/test/test_couch.rb +1 -1
- data/test/test_datamapper.rb +2 -2
- data/test/test_dbm.rb +1 -1
- data/test/test_expires.rb +1 -2
- data/test/test_file.rb +1 -1
- data/test/test_fog.rb +17 -0
- data/test/test_gdbm.rb +1 -1
- data/test/test_hashfile.rb +1 -1
- data/test/test_localmemcache.rb +1 -1
- data/test/test_memcached.rb +1 -2
- data/test/test_memcached_dalli.rb +1 -2
- data/test/test_memcached_native.rb +1 -2
- data/test/test_memory.rb +1 -1
- data/test/test_mongodb.rb +1 -1
- data/test/test_null.rb +9 -0
- data/test/test_proxy.rb +1 -1
- data/test/test_pstore.rb +1 -1
- data/test/test_redis.rb +1 -1
- data/test/test_riak.rb +1 -1
- data/test/test_sdbm.rb +1 -1
- data/test/test_sequel.rb +4 -4
- data/test/test_sqlite.rb +1 -1
- data/test/test_stack.rb +10 -0
- data/test/test_tokyocabinet.rb +1 -1
- data/test/test_yaml.rb +1 -1
- metadata +20 -13
- data/unsupported/test_rackspace.rb +0 -15
- data/unsupported/test_s3.rb +0 -15
data/lib/juno/sequel.rb
CHANGED
@@ -6,13 +6,10 @@ module Juno
|
|
6
6
|
raise 'No option :db specified' unless db = options.delete(:db)
|
7
7
|
@table = options.delete(:table) || :juno
|
8
8
|
@db = ::Sequel.connect(db, options)
|
9
|
-
|
10
|
-
|
11
|
-
def migrate
|
12
|
-
@db.create_table @table do
|
9
|
+
@db.create_table?(@table) do
|
13
10
|
primary_key :k
|
14
|
-
|
15
|
-
|
11
|
+
blob :k
|
12
|
+
blob :v
|
16
13
|
end
|
17
14
|
end
|
18
15
|
|
data/lib/juno/stack.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
module Juno
|
2
|
+
class Stack < Base
|
3
|
+
def initialize(options = {})
|
4
|
+
raise 'No option :stores specified' unless @stores = options[:stores]
|
5
|
+
end
|
6
|
+
|
7
|
+
def key?(key, options = {})
|
8
|
+
@stores.any? {|s| s.key?(key) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](key)
|
12
|
+
@stores.each do |s|
|
13
|
+
value = s[key]
|
14
|
+
return value if value
|
15
|
+
end
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def store(key, value, options = {})
|
20
|
+
@stores.each {|s| s.store(key, value, options) }
|
21
|
+
value
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(key, options = {})
|
25
|
+
@stores.inject(nil) do |value, s|
|
26
|
+
v = s.delete(key, options)
|
27
|
+
value || v
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def clear(options = {})
|
32
|
+
@stores.each {|s| s.clear }
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def close
|
37
|
+
@stores.each {|s| s.close }
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/juno/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'minitest/autorun'
|
2
3
|
require 'juno'
|
3
4
|
require 'fileutils'
|
@@ -10,173 +11,202 @@ module Helper
|
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
before do
|
17
|
-
@store = new_store
|
18
|
-
@store.clear
|
19
|
-
end
|
20
|
-
|
21
|
-
after do
|
22
|
-
@store.close.must_equal nil if @store
|
23
|
-
end
|
24
|
-
|
25
|
-
types = {
|
14
|
+
module Juno
|
15
|
+
TYPES = {
|
26
16
|
'String' => ['key', 'key2'],
|
27
17
|
'Object' => [{:foo => :bar}, {:bar => :baz}]
|
28
18
|
}
|
29
19
|
|
30
|
-
|
31
|
-
|
32
|
-
@store[key].must_equal nil
|
33
|
-
end
|
20
|
+
NullSpecification = proc do
|
21
|
+
include Helper
|
34
22
|
|
35
|
-
|
36
|
-
@store
|
37
|
-
@store
|
23
|
+
before do
|
24
|
+
@store = new_store
|
25
|
+
@store.clear
|
38
26
|
end
|
39
27
|
|
40
|
-
|
41
|
-
|
42
|
-
(@store[key] = value).must_be_same_as value
|
43
|
-
@store[key].wont_be_same_as(value)
|
28
|
+
after do
|
29
|
+
@store.close.must_equal nil if @store
|
44
30
|
end
|
45
31
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
32
|
+
TYPES.each do |type, (key, key2)|
|
33
|
+
it "reads from keys that are #{type}s like a Hash" do
|
34
|
+
@store[key].must_equal nil
|
35
|
+
end
|
51
36
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
37
|
+
it "guarantees that the same String value is returned when setting a #{type} key" do
|
38
|
+
value = 'value'
|
39
|
+
(@store[key] = value).must_be_same_as value
|
40
|
+
end
|
57
41
|
|
58
|
-
|
59
|
-
|
60
|
-
|
42
|
+
it "guarantees that the same Object value is returned when setting a #{type} key" do
|
43
|
+
value = {:foo => :bar}
|
44
|
+
(@store[key] = value).must_be_same_as value
|
45
|
+
end
|
61
46
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
47
|
+
it "returns false from key? if a #{type} key is not available" do
|
48
|
+
@store.key?(key).must_equal false
|
49
|
+
end
|
66
50
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
@store.key?(key).must_equal false
|
71
|
-
end
|
51
|
+
it "returns nil from delete if an element for a #{type} key does not exist" do
|
52
|
+
@store.delete(key).must_equal nil
|
53
|
+
end
|
72
54
|
|
73
|
-
|
74
|
-
|
75
|
-
|
55
|
+
it "removes all #{type} keys from the store with clear" do
|
56
|
+
@store[key] = 'value'
|
57
|
+
@store[key2] = 'value2'
|
58
|
+
@store.clear.must_equal nil
|
59
|
+
@store.key?(key).wont_equal true
|
60
|
+
@store.key?(key2).wont_equal true
|
61
|
+
end
|
76
62
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
@store.clear.must_equal nil
|
81
|
-
@store.key?(key).wont_equal true
|
82
|
-
@store.key?(key2).wont_equal true
|
83
|
-
end
|
63
|
+
it "fetches a #{type} key with a default value with fetch, if the key is not available" do
|
64
|
+
@store.fetch(key, 'value').must_equal 'value'
|
65
|
+
end
|
84
66
|
|
85
|
-
|
86
|
-
|
87
|
-
|
67
|
+
it "fetches a #{type} key with a block with fetch, if the key is not available" do
|
68
|
+
@store.fetch(key) { |k| 'value' }.must_equal 'value'
|
69
|
+
end
|
88
70
|
|
89
|
-
|
90
|
-
|
71
|
+
it 'must accept options' do
|
72
|
+
@store.key?(key, :foo => 42).must_equal false
|
73
|
+
@store.fetch(key, nil, :foo => 42).must_equal nil
|
74
|
+
@store.delete(key, :foo => 42).must_equal nil
|
75
|
+
@store.clear(:foo => 42).must_equal nil
|
76
|
+
@store.store(key, 'value', :foo => 42).must_equal 'value'
|
77
|
+
end
|
91
78
|
end
|
79
|
+
end
|
92
80
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
81
|
+
Specification = proc do
|
82
|
+
class_eval(&NullSpecification)
|
83
|
+
|
84
|
+
TYPES.each do |type, (key, key2)|
|
85
|
+
it "writes String values to keys that are #{type}s like a Hash" do
|
86
|
+
@store[key] = 'value'
|
87
|
+
@store[key].must_equal 'value'
|
88
|
+
end
|
89
|
+
|
90
|
+
it "writes Object values to keys that are #{type}s like a Hash" do
|
91
|
+
value = {:foo => :bar}
|
92
|
+
@store[key] = value
|
93
|
+
@store[key].must_equal(:foo => :bar)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "guarantees that a different String value is retrieved from the #{type} key" do
|
97
|
+
value = 'value'
|
98
|
+
@store[key] = value
|
99
|
+
@store[key].wont_be_same_as(value)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "guarantees that a different Object value is retrieved from the #{type} key" do
|
103
|
+
value = {:foo => :bar}
|
104
|
+
@store[key] = value
|
105
|
+
@store[key].wont_be_same_as(:foo => :bar)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "returns true from key? if a #{type} key is available" do
|
109
|
+
@store[key] = 'value'
|
110
|
+
@store.key?(key).must_equal true
|
111
|
+
end
|
112
|
+
|
113
|
+
it "removes and returns an element with a #{type} key from the backing store via delete if it exists" do
|
114
|
+
@store[key] = 'value'
|
115
|
+
@store.delete(key).must_equal 'value'
|
116
|
+
@store.key?(key).must_equal false
|
117
|
+
end
|
99
118
|
|
100
|
-
|
101
|
-
|
102
|
-
|
119
|
+
it "does not run the block if the #{type} key is available" do
|
120
|
+
@store[key] = 'value'
|
121
|
+
unaltered = "unaltered"
|
122
|
+
@store.fetch(key) { unaltered = "altered" }
|
123
|
+
unaltered.must_equal "unaltered"
|
124
|
+
end
|
125
|
+
|
126
|
+
it "fetches a #{type} key with a default value with fetch, if the key is available" do
|
127
|
+
@store[key] = 'value2'
|
128
|
+
@store.fetch(key, 'value').must_equal 'value2'
|
129
|
+
end
|
130
|
+
|
131
|
+
it "stores #{key} values with #store" do
|
132
|
+
@store.store(key, 'value').must_equal 'value'
|
133
|
+
@store[key].must_equal 'value'
|
134
|
+
end
|
103
135
|
end
|
104
136
|
|
105
|
-
|
106
|
-
|
107
|
-
|
137
|
+
def marshal_error
|
138
|
+
# HACK: Marshalling structs in rubinius without class name throws
|
139
|
+
# NoMethodError (to_sym). TODO: Create an issue for rubinius!
|
140
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
141
|
+
RUBY_VERSION < '1.9' ? ArgumentError : NoMethodError
|
142
|
+
else
|
143
|
+
TypeError
|
144
|
+
end
|
108
145
|
end
|
109
146
|
|
110
|
-
it
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
@store.delete(key, :foo => 42).must_equal 'value'
|
115
|
-
@store.key?(key, :foo => 42).must_equal false
|
116
|
-
@store.clear(:foo => 42).must_equal nil
|
147
|
+
it "refuses to #[] from keys that cannot be marshalled" do
|
148
|
+
lambda do
|
149
|
+
@store[Struct.new(:foo).new(:bar)]
|
150
|
+
end.must_raise(marshal_error)
|
117
151
|
end
|
118
|
-
end
|
119
152
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
153
|
+
it "refuses to fetch from keys that cannot be marshalled" do
|
154
|
+
lambda do
|
155
|
+
@store.fetch(Struct.new(:foo).new(:bar), true)
|
156
|
+
end.must_raise(marshal_error)
|
157
|
+
end
|
125
158
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
159
|
+
it "refuses to #[]= to keys that cannot be marshalled" do
|
160
|
+
lambda do
|
161
|
+
@store[Struct.new(:foo).new(:bar)] = 'value'
|
162
|
+
end.must_raise(marshal_error)
|
163
|
+
end
|
131
164
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
165
|
+
it "refuses to store to keys that cannot be marshalled" do
|
166
|
+
lambda do
|
167
|
+
@store.store Struct.new(:foo).new(:bar), 'value'
|
168
|
+
end.must_raise(marshal_error)
|
169
|
+
end
|
137
170
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
171
|
+
it "refuses to check for key? if the key cannot be marshalled" do
|
172
|
+
lambda do
|
173
|
+
@store.key? Struct.new(:foo).new(:bar)
|
174
|
+
end.must_raise(marshal_error)
|
175
|
+
end
|
143
176
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
177
|
+
it "refuses to delete a key if the key cannot be marshalled" do
|
178
|
+
lambda do
|
179
|
+
@store.delete Struct.new(:foo).new(:bar)
|
180
|
+
end.must_raise(marshal_error)
|
181
|
+
end
|
148
182
|
end
|
149
183
|
|
150
|
-
|
151
|
-
|
152
|
-
@store.delete Struct.new(:foo).new(:bar)
|
153
|
-
end.must_raise(TypeError)
|
154
|
-
end
|
155
|
-
end
|
184
|
+
ExpiresSpecification = proc do
|
185
|
+
class_eval(&Specification)
|
156
186
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
187
|
+
it 'should support expires on store' do
|
188
|
+
@store.store('key', 'value', :expires => 2)
|
189
|
+
@store['key'].must_equal 'value'
|
190
|
+
sleep 3
|
191
|
+
@store['key'].must_equal nil
|
192
|
+
end
|
164
193
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
194
|
+
it 'should support updating the expiration time in fetch' do
|
195
|
+
@store.store('key2', 'value2', :expires => 2)
|
196
|
+
@store['key2'].must_equal 'value2'
|
197
|
+
sleep 1
|
198
|
+
@store.fetch('key2', nil, :expires => 3).must_equal 'value2'
|
199
|
+
sleep 1
|
200
|
+
@store['key2'].must_equal 'value2'
|
201
|
+
sleep 3
|
202
|
+
@store['key2'].must_equal nil
|
203
|
+
end
|
175
204
|
|
176
|
-
|
177
|
-
|
205
|
+
it 'should respect expires in delete' do
|
206
|
+
@store.store('key', 'value', :expires => 2)
|
178
207
|
@store['key'].must_equal 'value'
|
179
208
|
sleep 3
|
180
209
|
@store.delete('key').must_equal nil
|
181
210
|
end
|
182
211
|
end
|
212
|
+
end
|
@@ -4,12 +4,10 @@ begin
|
|
4
4
|
describe Juno::ActiveRecord do
|
5
5
|
describe 'with connection option set' do
|
6
6
|
def new_store
|
7
|
-
|
8
|
-
store.migrate
|
9
|
-
store
|
7
|
+
Juno::ActiveRecord.new(:connection => { :adapter => 'sqlite3', :database => File.join(make_tempdir, 'db.sqlite3')})
|
10
8
|
end
|
11
9
|
|
12
|
-
class_eval(&
|
10
|
+
class_eval(&Juno::Specification)
|
13
11
|
|
14
12
|
it 'updates an existing key/value' do
|
15
13
|
@store['foo/bar'] = 4
|
@@ -26,7 +24,6 @@ begin
|
|
26
24
|
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => File.join(make_tempdir, 'db.sqlite3')
|
27
25
|
|
28
26
|
store = Juno::ActiveRecord.new
|
29
|
-
store.migrate
|
30
27
|
store.table.table_exists?.must_equal true
|
31
28
|
end
|
32
29
|
end
|
data/test/test_couch.rb
CHANGED
data/test/test_datamapper.rb
CHANGED
@@ -15,7 +15,7 @@ begin
|
|
15
15
|
Juno::DataMapper::Store.auto_migrate!(:juno)
|
16
16
|
end
|
17
17
|
|
18
|
-
class_eval(&
|
18
|
+
class_eval(&Juno::Specification)
|
19
19
|
end
|
20
20
|
|
21
21
|
describe 'when :repository specified' do
|
@@ -27,7 +27,7 @@ begin
|
|
27
27
|
Juno::DataMapper::Store.auto_migrate!(:sample)
|
28
28
|
end
|
29
29
|
|
30
|
-
class_eval(&
|
30
|
+
class_eval(&Juno::Specification)
|
31
31
|
end
|
32
32
|
|
33
33
|
describe 'with multiple stores' do
|