rufus-tokyo 1.0.3 → 1.0.4
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 +4 -0
- data/CHANGELOG.txt +6 -0
- data/Rakefile +91 -0
- data/doc/decision_table.numbers +0 -0
- data/lib/rufus/edo/README.txt +101 -0
- data/lib/rufus/edo/tabcore.rb +1 -3
- data/lib/rufus/tokyo.rb +1 -2
- data/lib/rufus/tokyo/cabinet/lib.rb +4 -7
- data/lib/rufus/tokyo/cabinet/table.rb +10 -13
- data/lib/rufus/tokyo/cabinet/util.rb +4 -1
- data/lib/rufus/tokyo/hmethods.rb +4 -4
- data/lib/rufus/tokyo/outlen.rb +5 -1
- data/lib/rufus/tokyo/tyrant/abstract.rb +8 -0
- data/lib/rufus/tokyo/tyrant/lib.rb +6 -6
- data/lib/rufus/tokyo/tyrant/table.rb +9 -1
- data/lib/rufus/tokyo/version.rb +32 -0
- data/rufus-tokyo.gemspec +135 -0
- data/spec/cabinet_btree_spec.rb +92 -0
- data/spec/cabinet_fixed_spec.rb +33 -0
- data/spec/cabinet_spec.rb +291 -0
- data/spec/cabinetconfig_spec.rb +82 -0
- data/spec/dystopia_core_spec.rb +124 -0
- data/spec/edo_cabinet_btree_spec.rb +123 -0
- data/spec/edo_cabinet_fixed_spec.rb +42 -0
- data/spec/edo_cabinet_spec.rb +286 -0
- data/spec/edo_ntyrant_spec.rb +224 -0
- data/spec/edo_ntyrant_table_spec.rb +296 -0
- data/spec/edo_table_spec.rb +292 -0
- data/spec/hmethods_spec.rb +73 -0
- data/spec/incr.lua +23 -0
- data/spec/openable_spec.rb +51 -0
- data/spec/shared_abstract_spec.rb +426 -0
- data/spec/shared_table_spec.rb +675 -0
- data/spec/shared_tyrant_spec.rb +42 -0
- data/spec/spec_base.rb +23 -0
- data/spec/start_tyrants.sh +28 -0
- data/spec/stop_tyrants.sh +9 -0
- data/spec/table_spec.rb +267 -0
- data/spec/tyrant_spec.rb +218 -0
- data/spec/tyrant_table_spec.rb +298 -0
- data/spec/util_list_spec.rb +197 -0
- data/spec/util_map_spec.rb +130 -0
- data/tasks/dev.rb +70 -0
- data/test/bm0.rb +353 -0
- data/test/bm1_compression.rb +54 -0
- data/test/con0.rb +30 -0
- data/test/mem.rb +49 -0
- data/test/mem1.rb +44 -0
- data/test/readme0.rb +17 -0
- data/test/readme1.rb +21 -0
- data/test/readme2.rb +15 -0
- data/test/readme3.rb +24 -0
- data/test/readmes_test.sh +17 -0
- metadata +81 -21
- data/MIGRATED.txt +0 -1
@@ -0,0 +1,292 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-tokyo
|
4
|
+
#
|
5
|
+
# Mon Feb 23 11:11:10 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), 'spec_base')
|
9
|
+
require File.join(File.dirname(__FILE__), 'shared_table_spec')
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'rufus/edo'
|
13
|
+
rescue LoadError
|
14
|
+
end
|
15
|
+
|
16
|
+
if defined?(TokyoCabinet)
|
17
|
+
|
18
|
+
FileUtils.mkdir('tmp') rescue nil
|
19
|
+
|
20
|
+
|
21
|
+
describe Rufus::Edo::Table do
|
22
|
+
|
23
|
+
it 'should open in write/create mode by default' do
|
24
|
+
|
25
|
+
t = Rufus::Edo::Table.new('tmp/default.tct')
|
26
|
+
t.close
|
27
|
+
File.exist?('tmp/default.tct').should.equal(true)
|
28
|
+
FileUtils.rm('tmp/default.tct')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should raise an error when file is missing' do
|
32
|
+
|
33
|
+
lambda {
|
34
|
+
Rufus::Edo::Table.new('tmp/missing.tct', :mode => 'r')
|
35
|
+
}.should.raise(
|
36
|
+
Rufus::Edo::EdoError).message.should.equal('(err 3) file not found')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe Rufus::Edo::Table do
|
41
|
+
|
42
|
+
it 'should use open with a block will auto close the db correctly' do
|
43
|
+
|
44
|
+
res = Rufus::Edo::Table.open('tmp/spec_source.tct') do |table|
|
45
|
+
10.times { |i| table["key #{i}"] = {:val => i} }
|
46
|
+
table.size.should.equal(10)
|
47
|
+
:result
|
48
|
+
end
|
49
|
+
|
50
|
+
res.should.equal(:result)
|
51
|
+
|
52
|
+
table = Rufus::Edo::Table.new('tmp/spec_source.tct')
|
53
|
+
10.times do |i|
|
54
|
+
table["key #{i}"].should.equal({"val" => i.to_s})
|
55
|
+
end
|
56
|
+
table.close
|
57
|
+
|
58
|
+
FileUtils.rm('tmp/spec_source.tct')
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
it 'should use open without a block just like calling new correctly' do
|
63
|
+
|
64
|
+
table = Rufus::Edo::Table.open('tmp/spec_source.tct')
|
65
|
+
10.times { |i| table["key #{i}"] = {:val => i} }
|
66
|
+
table.size.should.equal(10)
|
67
|
+
table.close
|
68
|
+
|
69
|
+
table = Rufus::Edo::Table.new('tmp/spec_source.tct')
|
70
|
+
10.times do |i|
|
71
|
+
table["key #{i}"].should.equal({"val" => i.to_s})
|
72
|
+
end
|
73
|
+
table.close
|
74
|
+
|
75
|
+
FileUtils.rm('tmp/spec_source.tct')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe Rufus::Edo::Table do
|
80
|
+
|
81
|
+
before do
|
82
|
+
@t = Rufus::Edo::Table.new('tmp/table.tct')
|
83
|
+
@t.clear
|
84
|
+
end
|
85
|
+
after do
|
86
|
+
@t.close
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should return its path' do
|
90
|
+
|
91
|
+
@t.path.should.equal('tmp/table.tct')
|
92
|
+
end
|
93
|
+
|
94
|
+
behaves_like 'table'
|
95
|
+
end
|
96
|
+
|
97
|
+
describe Rufus::Edo::Table do
|
98
|
+
|
99
|
+
before do
|
100
|
+
@t = Rufus::Edo::Table.new('tmp/table.tct')
|
101
|
+
@t.clear
|
102
|
+
end
|
103
|
+
after do
|
104
|
+
@t.close
|
105
|
+
end
|
106
|
+
|
107
|
+
behaves_like 'table with transactions'
|
108
|
+
end
|
109
|
+
|
110
|
+
# DONE
|
111
|
+
|
112
|
+
describe 'Rufus::Edo::Table #keys' do
|
113
|
+
|
114
|
+
before do
|
115
|
+
@n = 50
|
116
|
+
@t = Rufus::Edo::Table.new('tmp/test_new.tct')
|
117
|
+
@t.clear
|
118
|
+
@n.times { |i| @t["person#{i}"] = { 'name' => 'whoever' } }
|
119
|
+
@n.times { |i| @t["animal#{i}"] = { 'name' => 'whichever' } }
|
120
|
+
@t["toto#{0.chr}5"] = { 'name' => 'toto' }
|
121
|
+
end
|
122
|
+
after do
|
123
|
+
@t.close
|
124
|
+
end
|
125
|
+
|
126
|
+
behaves_like 'table #keys'
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def prepare_table_with_data
|
131
|
+
|
132
|
+
t = Rufus::Edo::Table.new('tmp/test_new.tct')
|
133
|
+
t.clear
|
134
|
+
t['pk0'] = { 'name' => 'jim', 'age' => '25', 'lang' => 'ja,en' }
|
135
|
+
t['pk1'] = { 'name' => 'jeff', 'age' => '32', 'lang' => 'en,es' }
|
136
|
+
t['pk2'] = { 'name' => 'jack', 'age' => '44', 'lang' => 'en' }
|
137
|
+
t['pk3'] = { 'name' => 'jake', 'age' => '45', 'lang' => 'en,li' }
|
138
|
+
t
|
139
|
+
end
|
140
|
+
|
141
|
+
describe 'Rufus::Edo::Table' do
|
142
|
+
|
143
|
+
before do
|
144
|
+
@t = prepare_table_with_data
|
145
|
+
end
|
146
|
+
after do
|
147
|
+
@t.close
|
148
|
+
end
|
149
|
+
|
150
|
+
behaves_like 'table indexes'
|
151
|
+
end
|
152
|
+
|
153
|
+
describe 'Rufus::Edo::Table#lget' do
|
154
|
+
|
155
|
+
before do
|
156
|
+
@t = prepare_table_with_data
|
157
|
+
end
|
158
|
+
after do
|
159
|
+
@t.close
|
160
|
+
end
|
161
|
+
|
162
|
+
behaves_like 'table lget'
|
163
|
+
end
|
164
|
+
|
165
|
+
describe 'Rufus::Edo::Table, like a Ruby Hash,' do
|
166
|
+
|
167
|
+
before do
|
168
|
+
@t = prepare_table_with_data
|
169
|
+
end
|
170
|
+
after do
|
171
|
+
@t.close
|
172
|
+
end
|
173
|
+
|
174
|
+
behaves_like 'table like a hash'
|
175
|
+
end
|
176
|
+
|
177
|
+
describe 'queries on Rufus::Edo::Table' do
|
178
|
+
|
179
|
+
before do
|
180
|
+
@t = prepare_table_with_data
|
181
|
+
end
|
182
|
+
after do
|
183
|
+
@t.close
|
184
|
+
end
|
185
|
+
|
186
|
+
behaves_like 'table query'
|
187
|
+
|
188
|
+
#if TokyoCabinet::TDBQRY.public_instance_methods.collect { |e|
|
189
|
+
# e.to_s }.include?('setlimit')
|
190
|
+
|
191
|
+
# it 'can be limited and have an offset' do
|
192
|
+
|
193
|
+
# @t.query { |q|
|
194
|
+
# q.add 'lang', :includes, 'en'
|
195
|
+
# q.order_by 'name', :desc
|
196
|
+
# q.limit 2, 0
|
197
|
+
# }.collect { |e| e['name'] }.should.equal(%w{ jim jeff })
|
198
|
+
# @t.query { |q|
|
199
|
+
# q.add 'lang', :includes, 'en'
|
200
|
+
# q.order_by 'name', :desc
|
201
|
+
# q.limit 2, 2
|
202
|
+
# }.collect { |e| e['name'] }.should.equal(%w{ jake jack })
|
203
|
+
# end
|
204
|
+
#end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe 'Queries on Tokyo Tyrant tables (via Rufus::Edo)' do
|
208
|
+
|
209
|
+
before do
|
210
|
+
@t = Rufus::Edo::Table.new('tmp/test_new.tct')
|
211
|
+
@t.clear
|
212
|
+
[
|
213
|
+
"consul readableness choleric hopperdozer juckies",
|
214
|
+
"fume overharshness besprinkler whirling erythrene",
|
215
|
+
"trumper defiable detractively cattiness superioress",
|
216
|
+
"vivificative consul agglomerated Peterloo way",
|
217
|
+
"unkilned bituminate antimatrimonial uran polyphony",
|
218
|
+
"kurumaya unannexed renownedly apetaloid consul",
|
219
|
+
"overdare nescience seronegative nagster overfatten",
|
220
|
+
].each_with_index { |w, i|
|
221
|
+
@t["pk#{i}"] = { 'name' => "lambda#{i}", 'words' => w }
|
222
|
+
}
|
223
|
+
end
|
224
|
+
after do
|
225
|
+
@t.close
|
226
|
+
end
|
227
|
+
|
228
|
+
behaves_like 'table query (fts)'
|
229
|
+
end
|
230
|
+
|
231
|
+
describe 'Rufus::Tokyo::TableQuery#process' do
|
232
|
+
|
233
|
+
before do
|
234
|
+
@t = prepare_table_with_data
|
235
|
+
end
|
236
|
+
after do
|
237
|
+
@t.close
|
238
|
+
end
|
239
|
+
|
240
|
+
behaves_like 'table query #process'
|
241
|
+
end
|
242
|
+
|
243
|
+
describe 'results from Rufus::Edo::Table queries' do
|
244
|
+
|
245
|
+
before do
|
246
|
+
@t = prepare_table_with_data
|
247
|
+
end
|
248
|
+
after do
|
249
|
+
@t.close
|
250
|
+
end
|
251
|
+
|
252
|
+
behaves_like 'table query results'
|
253
|
+
end
|
254
|
+
|
255
|
+
describe Rufus::Edo::Table do
|
256
|
+
|
257
|
+
before do
|
258
|
+
@t = Rufus::Edo::Table.new('tmp/table.tct')
|
259
|
+
@t.clear
|
260
|
+
end
|
261
|
+
after do
|
262
|
+
@t.close
|
263
|
+
end
|
264
|
+
|
265
|
+
behaves_like 'a table structure flattening keys and values'
|
266
|
+
end
|
267
|
+
|
268
|
+
describe 'Rufus::Edo::Table\'s queries' do
|
269
|
+
|
270
|
+
before do
|
271
|
+
@t = prepare_table_with_data
|
272
|
+
end
|
273
|
+
after do
|
274
|
+
@t.close
|
275
|
+
end
|
276
|
+
|
277
|
+
behaves_like 'a table structure to_s-ing query stuff'
|
278
|
+
end
|
279
|
+
|
280
|
+
describe 'Rufus::Edo::Table and metasearch' do
|
281
|
+
|
282
|
+
before do
|
283
|
+
@t = prepare_table_with_data
|
284
|
+
end
|
285
|
+
after do
|
286
|
+
@t.close
|
287
|
+
end
|
288
|
+
|
289
|
+
behaves_like 'table query metasearch'
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-tokyo
|
4
|
+
#
|
5
|
+
# Sun Feb 8 14:15:31 JST 2009
|
6
|
+
#
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + '/spec_base'
|
9
|
+
|
10
|
+
require 'rufus/tokyo/hmethods'
|
11
|
+
|
12
|
+
|
13
|
+
class MyHash
|
14
|
+
include Rufus::Tokyo::HashMethods
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
super
|
18
|
+
@default_proc = nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def get (k)
|
22
|
+
k.to_i % 2 == 0 ? k : nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'an instance that include HashMethods' do
|
27
|
+
|
28
|
+
before do
|
29
|
+
@h = MyHash.new
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should be ready for testing' do # :(
|
33
|
+
@h[1].should.be.nil
|
34
|
+
@h[2].should.equal(2)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should accept a default value' do
|
38
|
+
@h.default = :default
|
39
|
+
@h.default.should.equal(:default)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'an instance that has a default proc' do
|
44
|
+
|
45
|
+
before do
|
46
|
+
@h = MyHash.new
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should accept a default_proc' do
|
50
|
+
@h.default_proc = lambda { |h, k| k * 2 }
|
51
|
+
@h[1].should.equal(2)
|
52
|
+
@h[2].should.equal(2)
|
53
|
+
@h[3].should.equal(6)
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should respond nil to #default(k) when no default proc' do
|
57
|
+
@h.default.should.be.nil
|
58
|
+
@h.default(2).should.be.nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should respond to #default(k) with the correct default' do
|
62
|
+
@h.default = 'cat'
|
63
|
+
@h.default.should.equal('cat')
|
64
|
+
@h.default(2).should.equal('cat')
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should respond to #default(k) with the correct default (2)' do
|
68
|
+
@h.default_proc = lambda { |h, k| k * 3 }
|
69
|
+
@h.default.should.be.nil
|
70
|
+
@h.default(2).should.equal(6)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
data/spec/incr.lua
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
|
2
|
+
--
|
3
|
+
-- Taken from http://tokyocabinet.sourceforge.net/tyrantdoc/#luaext
|
4
|
+
--
|
5
|
+
|
6
|
+
function incr (key, value)
|
7
|
+
value = tonumber(value)
|
8
|
+
if not value then
|
9
|
+
return nil
|
10
|
+
end
|
11
|
+
local old = tonumber(_get(key))
|
12
|
+
if old then
|
13
|
+
value = value + old
|
14
|
+
end
|
15
|
+
if not _put(key, value) then
|
16
|
+
return nil
|
17
|
+
end
|
18
|
+
return value
|
19
|
+
end
|
20
|
+
|
21
|
+
function hi()
|
22
|
+
return "Hi!"
|
23
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_base'
|
2
|
+
|
3
|
+
require 'rufus/tokyo/openable'
|
4
|
+
|
5
|
+
|
6
|
+
class MyOpenable
|
7
|
+
extend Rufus::Tokyo::Openable
|
8
|
+
|
9
|
+
def initialize(*args)
|
10
|
+
@args = args
|
11
|
+
@closed = false
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :args
|
15
|
+
|
16
|
+
def close
|
17
|
+
@closed = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def closed?
|
21
|
+
@closed
|
22
|
+
end
|
23
|
+
end
|
24
|
+
openable = lambda { |obj| obj.is_a? MyOpenable }
|
25
|
+
|
26
|
+
describe 'an instance that extends Openable' do
|
27
|
+
it 'should pass all arguments from open() down to new()' do
|
28
|
+
MyOpenable.open(1).args.should.equal([1])
|
29
|
+
MyOpenable.open(1, 2).args.should.equal([1, 2])
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should pass the constructed object into the block' do
|
33
|
+
MyOpenable.open { |o| o.should.be openable }
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should return the last value in the block' do
|
37
|
+
MyOpenable.open { :value }.should.equal(:value)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should return the new object without a block' do
|
41
|
+
MyOpenable.open.should.be openable
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should call close after running the block' do
|
45
|
+
MyOpenable.open { |db| db.should.not.be.closed; db }.should.be.closed
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should not be closed when opened without a block' do
|
49
|
+
MyOpenable.open.should.not.be.closed
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,426 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-tokyo
|
4
|
+
#
|
5
|
+
# Fri Jul 17 15:37:16 JST 2009 #rubykaigi2009
|
6
|
+
#
|
7
|
+
|
8
|
+
shared 'an abstract structure' do
|
9
|
+
|
10
|
+
it 'should be empty initially' do
|
11
|
+
|
12
|
+
@db.size.should.equal(0)
|
13
|
+
@db['pillow'].should.be.nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should accept values' do
|
17
|
+
|
18
|
+
@db['pillow'] = 'Shonagon'
|
19
|
+
@db.size.should.equal(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should restitute values' do
|
23
|
+
|
24
|
+
@db['pillow'] = 'Shonagon'
|
25
|
+
@db['pillow'].should.equal('Shonagon')
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should delete values' do
|
29
|
+
|
30
|
+
@db['pillow'] = 'Shonagon'
|
31
|
+
@db.delete('pillow').should.equal('Shonagon')
|
32
|
+
@db.size.should.equal(0)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should accept and restitute \\0 strings' do
|
36
|
+
|
37
|
+
s = "toto#{0.chr}nada"
|
38
|
+
@db[s] = s
|
39
|
+
@db[s].should.equal(s)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should stringify keys and values' do
|
43
|
+
@db[123] = 456
|
44
|
+
@db["123".to_sym].should.equal("456")
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should reply to #keys and #values' do
|
48
|
+
|
49
|
+
keys = %w{ alpha bravo charly delta echo foxtrott }
|
50
|
+
keys.each_with_index { |k, i| @db[k] = i.to_s }
|
51
|
+
@db.keys.should.equal(keys)
|
52
|
+
@db.values.should.equal(%w{ 0 1 2 3 4 5 })
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should reply to #keys when there are keys containing \0' do
|
56
|
+
|
57
|
+
s = "toto#{0.chr}nada"
|
58
|
+
@db[s] = s
|
59
|
+
@db.keys.should.equal([ s ])
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should return a Ruby hash on merge' do
|
63
|
+
|
64
|
+
@db['a'] = 'A'
|
65
|
+
|
66
|
+
@db.merge({ 'b' => 'B', 'c' => 'C' }).should.equal(
|
67
|
+
{ 'a' => 'A', 'b' => 'B', 'c' => 'C' })
|
68
|
+
|
69
|
+
@db['b'].should.be.nil
|
70
|
+
|
71
|
+
@db.size.should.equal(1)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'should have more values in case of merge!' do
|
75
|
+
|
76
|
+
@db['a'] = 'A'
|
77
|
+
|
78
|
+
@db.merge!({ 'b' => 'B', 'c' => 'C' })
|
79
|
+
|
80
|
+
@db.size.should.equal(3)
|
81
|
+
@db['b'].should.equal('B')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
shared 'abstract structure #keys' do
|
86
|
+
|
87
|
+
it 'should return a Ruby Array by default' do
|
88
|
+
|
89
|
+
@db.keys.class.should.equal(::Array)
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should retrieve keys that contain \0' do
|
93
|
+
|
94
|
+
@db.keys.include?("toto#{0.chr}5").should.be.true
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should retrieve forward matching keys when key contains \0' do
|
98
|
+
|
99
|
+
@db.keys(:prefix => 'toto').should.equal([ "toto#{0.chr}5" ])
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should return a limited number of keys when :limit is set' do
|
103
|
+
|
104
|
+
@db.keys(:limit => 20).size.should.equal(20)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should delete_keys_with_prefix' do
|
108
|
+
|
109
|
+
@db.delete_keys_with_prefix('animal')
|
110
|
+
@db.size.should.equal(@n + 1)
|
111
|
+
@db.keys(:prefix => 'animal').size.should.equal(0)
|
112
|
+
end
|
113
|
+
|
114
|
+
unless @db.class.name.match(/^Rufus::Edo/)
|
115
|
+
|
116
|
+
it 'should return a Cabinet List when :native => true' do
|
117
|
+
|
118
|
+
l = @db.keys(:native => true)
|
119
|
+
l.class.should.equal(Rufus::Tokyo::List)
|
120
|
+
l.size.should.equal(2 * @n + 1)
|
121
|
+
l.free
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should retrieve forward matching keys when :prefix => "prefix-"' do
|
125
|
+
|
126
|
+
@db.keys(:prefix => 'person').size.should.equal(@n)
|
127
|
+
|
128
|
+
l = @db.keys(:prefix => 'animal', :native => true)
|
129
|
+
l.size.should.equal(@n)
|
130
|
+
l.free
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
shared 'abstract structure with transactions' do
|
136
|
+
|
137
|
+
#before do
|
138
|
+
# @db = Rufus::Tokyo::Cabinet.new('tmp/cabinet_spec.tch')
|
139
|
+
# @db.clear
|
140
|
+
#end
|
141
|
+
#after do
|
142
|
+
# @db.close
|
143
|
+
#end
|
144
|
+
|
145
|
+
it 'should correctly abort transactions' do
|
146
|
+
|
147
|
+
@db.transaction {
|
148
|
+
@db['pk0'] = 'value0'
|
149
|
+
@db.abort
|
150
|
+
}
|
151
|
+
@db.size.should.be.zero
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should rollback transactions with errors, and bubble exceptions' do
|
155
|
+
|
156
|
+
begin
|
157
|
+
@db.transaction {
|
158
|
+
@db['pk0'] = 'value0'
|
159
|
+
raise 'something goes wrong'
|
160
|
+
}
|
161
|
+
rescue RuntimeError
|
162
|
+
end
|
163
|
+
@db.size.should.be.zero
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should rollback transactions with Abort exceptions, and consume exceptions' do
|
167
|
+
|
168
|
+
@db.transaction {
|
169
|
+
@db['pk0'] = 'value0'
|
170
|
+
raise Rufus::Tokyo::Transactions::Abort
|
171
|
+
}
|
172
|
+
@db.size.should.be.zero
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'should commit successful transactions' do
|
176
|
+
|
177
|
+
@db.transaction do
|
178
|
+
@db['pk0'] = 'showanojidaietaminamishima'
|
179
|
+
end
|
180
|
+
@db['pk0'].should.equal('showanojidaietaminamishima')
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should abort low level transactions' do
|
184
|
+
|
185
|
+
@db.tranbegin
|
186
|
+
@db['pk0'] = 'shikataganai'
|
187
|
+
@db.tranabort
|
188
|
+
@db.size.should.be.zero
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'should commit low level transactions' do
|
192
|
+
|
193
|
+
@db.tranbegin
|
194
|
+
@db['pk0'] = 'shikataganai'
|
195
|
+
@db.trancommit
|
196
|
+
@db['pk0'].should.equal('shikataganai')
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
shared 'abstract structure #lget/lput/ldelete' do
|
201
|
+
|
202
|
+
it 'should get multiple values' do
|
203
|
+
|
204
|
+
@db.lget(%w{ 0 1 2 }).should.equal({"0"=>"val0", "1"=>"val1", "2"=>"val2"})
|
205
|
+
@db.mget(%w{ 0 1 2 }).should.equal({"0"=>"val0", "1"=>"val1", "2"=>"val2"})
|
206
|
+
@db.mget(*%w{ 0 1 2 }).should.equal({"0"=>"val0", "1"=>"val1", "2"=>"val2"})
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'should put multiple values' do
|
210
|
+
|
211
|
+
@db.lput('3' => 'val3', '4' => 'val4')
|
212
|
+
@db.lget(%w{ 2 3 }).should.equal({"2"=>"val2", "3"=>"val3"})
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'should delete multiple values' do
|
216
|
+
|
217
|
+
@db.ldelete(%w{ 2 3 })
|
218
|
+
@db.lget(%w{ 0 1 2 }).should.equal({"0"=>"val0", "1"=>"val1"})
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should delete multiple values' do
|
222
|
+
|
223
|
+
@db.ldelete(*%w{ 2 3 })
|
224
|
+
@db.lget(%w{ 0 1 2 }).should.equal({"0"=>"val0", "1"=>"val1"})
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
shared 'abstract structure #add{int|double}' do
|
229
|
+
|
230
|
+
it 'should increment (int)' do
|
231
|
+
|
232
|
+
@db.addint('counter', 1).should.equal(1)
|
233
|
+
@db.incr('counter', 1).should.equal(2)
|
234
|
+
@db.addint('counter', 2).should.equal(4)
|
235
|
+
@db.incr('counter').should.equal(5)
|
236
|
+
|
237
|
+
@db.counter_value('counter').should.equal(5)
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should fail gracefully if counter has already a [string] value (int)' do
|
241
|
+
|
242
|
+
@db['counter'] = 'a'
|
243
|
+
|
244
|
+
lambda { @db.addint('counter', 1) }.should.raise(
|
245
|
+
@db.class.name.match(/^Rufus::Edo/) ?
|
246
|
+
Rufus::Edo::EdoError : Rufus::Tokyo::TokyoError)
|
247
|
+
|
248
|
+
@db['counter'].should.equal('a')
|
249
|
+
end
|
250
|
+
|
251
|
+
it 'should increment (double)' do
|
252
|
+
|
253
|
+
@db.adddouble('counter', 1.0).should.equal(1.0)
|
254
|
+
@db.incr('counter', 1.5).should.equal(2.5)
|
255
|
+
@db.adddouble('counter', 2.2).should.equal(4.7)
|
256
|
+
|
257
|
+
@db.counter_value('counter').should.equal(4.7)
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'should fail gracefully if counter has already a [string] value (double)' do
|
261
|
+
|
262
|
+
@db['counter'] = 'a'
|
263
|
+
|
264
|
+
lambda {
|
265
|
+
@db.adddouble('counter', 1.0)
|
266
|
+
}.should.raise(
|
267
|
+
@db.class.name.match(/^Rufus::Edo/) ?
|
268
|
+
Rufus::Edo::EdoError : Rufus::Tokyo::TokyoError)
|
269
|
+
|
270
|
+
@db['counter'].should.equal('a')
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
shared 'abstract structure #putkeep' do
|
275
|
+
|
276
|
+
it 'should accept values' do
|
277
|
+
|
278
|
+
@db.putkeep('pillow', 'Shonagon')
|
279
|
+
@db.size.should.equal(1)
|
280
|
+
end
|
281
|
+
|
282
|
+
it 'should restitute values' do
|
283
|
+
|
284
|
+
@db.putkeep('pillow', 'Shonagon')
|
285
|
+
@db['pillow'].should.equal('Shonagon')
|
286
|
+
end
|
287
|
+
|
288
|
+
it 'should not overwrite values if already set' do
|
289
|
+
|
290
|
+
@db['pillow'] = 'Shonagon'
|
291
|
+
@db['pillow'].should.equal('Shonagon')
|
292
|
+
|
293
|
+
@db.putkeep('pillow', 'Ruby')
|
294
|
+
@db['pillow'].should.equal('Shonagon')
|
295
|
+
end
|
296
|
+
|
297
|
+
it 'should return true if not yet set' do
|
298
|
+
|
299
|
+
@db.putkeep('pillow', 'Shonagon').should.equal(true)
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'should return false if already set' do
|
303
|
+
|
304
|
+
@db['pillow'] = 'Shonagon'
|
305
|
+
@db.putkeep('pillow', 'Ruby').should.equal(false)
|
306
|
+
end
|
307
|
+
|
308
|
+
it 'should accept binary data \0' do
|
309
|
+
|
310
|
+
s = "Sei#{0.chr}Shonagon"
|
311
|
+
|
312
|
+
@db.putkeep(s, s).should.be.true
|
313
|
+
@db[s].should.equal(s)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
shared 'abstract structure #putcat' do
|
318
|
+
|
319
|
+
it 'should append' do
|
320
|
+
|
321
|
+
@db['heian'] = 'Shonagon'
|
322
|
+
@db.putcat('heian', ', Shikibu')
|
323
|
+
@db.putcat('heian', ', Michitsuna')
|
324
|
+
|
325
|
+
@db['heian'].should.equal('Shonagon, Shikibu, Michitsuna')
|
326
|
+
end
|
327
|
+
|
328
|
+
it 'should create when not present' do
|
329
|
+
|
330
|
+
@db.putcat('regent', 'Fujiwara no Michinaga')
|
331
|
+
|
332
|
+
@db['regent'].should.equal('Fujiwara no Michinaga')
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
shared 'tyrant with embedded lua' do
|
337
|
+
|
338
|
+
it 'should call lua extensions' do
|
339
|
+
|
340
|
+
@db['toto'] = '0'
|
341
|
+
3.times { @db.ext(:incr, 'toto', '1') }
|
342
|
+
@db.ext('incr', 'toto', 2) # lax
|
343
|
+
|
344
|
+
@db['toto'].should.equal('5')
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'should return nil when function is missing' do
|
348
|
+
|
349
|
+
@db.ext(:missing, 'nada', 'forever').should.equal(nil)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
shared 'an abstract structure flattening keys and values' do
|
354
|
+
|
355
|
+
it 'should to_s keys and values when #[]=' do
|
356
|
+
|
357
|
+
@db[:hello] = :world
|
358
|
+
@db['hello'].should.equal('world')
|
359
|
+
@db[:hello].should.equal('world')
|
360
|
+
@db.size.should.equal(1)
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'should to_s keys and values when #putkeep' do
|
364
|
+
|
365
|
+
@db.putkeep(:pillow, :shonagon)
|
366
|
+
@db[:pillow].should.equal('shonagon')
|
367
|
+
@db.size.should.equal(1)
|
368
|
+
end
|
369
|
+
|
370
|
+
it 'should to_s keys when #delete' do
|
371
|
+
|
372
|
+
@db['hello'] = 'world'
|
373
|
+
@db.delete(:hello).should.equal('world')
|
374
|
+
@db.size.should.equal(0)
|
375
|
+
end
|
376
|
+
|
377
|
+
it 'should to_s keys when #lget' do
|
378
|
+
|
379
|
+
writers = %w[ shikibu shonagon ]
|
380
|
+
writers.each { |s| @db[s] = s }
|
381
|
+
@db.lget(writers.collect { |w| w.to_sym }).keys.sort.should.equal(writers)
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'should to_s keys when #ldelete' do
|
385
|
+
|
386
|
+
writers = %w[ shonagon shikibu ]
|
387
|
+
writers.each { |s| @db[s] = s }
|
388
|
+
|
389
|
+
@db.ldelete(writers.collect { |w| w.to_sym })
|
390
|
+
|
391
|
+
@db.size.should.equal(0)
|
392
|
+
end
|
393
|
+
|
394
|
+
it 'should to_s keys when #incr' do
|
395
|
+
|
396
|
+
@db.incr(:genji_count, 1).should.equal(1)
|
397
|
+
@db.incr(:genji_count, 1).should.equal(2)
|
398
|
+
end
|
399
|
+
|
400
|
+
it 'should to_s keys and values when #merge!' do
|
401
|
+
|
402
|
+
@db.merge!(:genji => 1, :to_no_chujo => 2)
|
403
|
+
|
404
|
+
@db['genji'].should.equal('1')
|
405
|
+
@db['to_no_chujo'].should.equal('2')
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
shared 'an abstract structure with a default value' do
|
410
|
+
|
411
|
+
it 'should restitute the default value' do
|
412
|
+
|
413
|
+
@db['known'].should.equal('Ulysse')
|
414
|
+
@db['unknown'].should.equal('Nemo')
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
shared 'an abstract structure with a default_proc' do
|
419
|
+
|
420
|
+
it 'should restitute the value computed by the default_proc' do
|
421
|
+
|
422
|
+
@db['known'].should.equal('Ulysse')
|
423
|
+
@db['unknown'].should.equal('default:unknown')
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|