kyoto_record 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/kyoto_record.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "kyoto_record"
3
- s.version = "0.0.1"
3
+ s.version = "0.0.2"
4
4
  s.summary = "Persist your classes in Kyoto Cabinet."
5
5
  s.description = "\"KyotoRecord\": Kyoto Cabinet wrapper for Ruby binding. Scannable. Indexable. A programming interface made for babies."
6
6
  s.homepage = "http://github.com/thirdreplicator/kyoto_record"
data/kyoto_record.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # kyoto_record.rb
1
2
  require 'kyotocabinet'
2
3
 
3
4
  module KyotoRecord
@@ -9,6 +10,8 @@ module KyotoRecord
9
10
  module Cabinet
10
11
  include KyotoCabinet
11
12
 
13
+ DATA_DIR = File.dirname(__FILE__) + '/data'
14
+
12
15
  def find(id)
13
16
  value = @db.get(id)
14
17
  if value
@@ -18,6 +21,16 @@ module KyotoRecord
18
21
  end
19
22
  end
20
23
 
24
+ def delete(id)
25
+ @db.remove(id)
26
+ end
27
+
28
+ def delete_all
29
+ scan(1, 1/0.0) do |obj|
30
+ obj.delete
31
+ end
32
+ end
33
+
21
34
  def scan(start_key=nil, limit=1/0.0, &block)
22
35
  cur = @db.cursor
23
36
  i = 0
@@ -52,16 +65,16 @@ module KyotoRecord
52
65
  end
53
66
 
54
67
  # Utilities
55
- def open_db(base_name)
56
- Dir.mkdir('data') if !Dir.exists?('data')
68
+ def open_db
69
+ Dir.mkdir(DATA_DIR) if !Dir.exists?(DATA_DIR)
57
70
  db = DB::new
58
- unless db.open("./data/#{base_name}.kch", DB::OWRITER | DB::OCREATE)
71
+ unless db.open(data_file, DB::OWRITER | DB::OCREATE)
59
72
  STDERR.printf("open error: %s\n", db.error)
60
73
  end
61
74
  db
62
75
  end
63
76
 
64
- def close_db(base_name)
77
+ def close_db
65
78
  unless @db.close
66
79
  STDERR.printf("close error: %s\n", db.error)
67
80
  end
@@ -70,9 +83,9 @@ module KyotoRecord
70
83
  # Utilities
71
84
 
72
85
  def set(k,v)
73
- @db.set(k, Marshal.dump(v))
86
+ set_error(k,v) unless @db.set(k, Marshal.dump(v))
74
87
  end
75
-
88
+
76
89
  def get(k)
77
90
  val = @db.get(k)
78
91
  Marshal.load(val) if val
@@ -97,6 +110,16 @@ module KyotoRecord
97
110
  def class_name
98
111
  @class_name ||= self.to_s
99
112
  end
113
+
114
+ def data_file
115
+ "#{DATA_DIR}/#{@base_name}.kch"
116
+ end
117
+
118
+ def set_error(k,v)
119
+ STDERR.printf("set error for (k,v)=(%s, %s): %s\n", k, v, @db.error)
120
+ raise @db.error
121
+ end
122
+
100
123
  end # Cabinet
101
124
 
102
125
  # Reuse the Cabinet module to make indexes of attributes.
@@ -112,7 +135,7 @@ module KyotoRecord
112
135
  @klass = klass
113
136
  @attr = attribute
114
137
  @base_name = klass.to_s + "_" + attribute.to_s
115
- @db = open_db(@base_name)
138
+ @db = open_db
116
139
  end
117
140
  end # class Index
118
141
 
@@ -121,35 +144,33 @@ module KyotoRecord
121
144
  include Cabinet
122
145
 
123
146
  def attr_kyoto( *attrs )
124
- @db = open_db(class_name)
147
+ @base_name = class_name
148
+ @db = open_db
125
149
 
126
150
  @attrs ||= {}
127
151
  @indices ||= {}
128
152
 
129
- # Don't redefine it if it was already defined.
130
- if !self.respond_to?(:id)
131
- # a general setter
132
- define_method :set_attr do |k, v|
133
- @values[k] = v
153
+ # a general setter
154
+ define_method :set_attr do |k, v|
155
+ @values[k] = v
156
+ end
157
+
158
+ # a general getter
159
+ define_method :get_attr do |k|
160
+ @values[k]
161
+ end
162
+
163
+ def define_getter_and_setter(attr)
164
+ define_method :"#{attr}".to_s do
165
+ @values[attr]
134
166
  end
135
167
 
136
- # a general getter
137
- define_method :get_attr do |k|
138
- @values[k]
139
- end
140
-
141
- def define_getter_and_setter(attr)
142
- define_method :"#{attr}".to_s do
143
- @values[attr]
144
- end
145
-
146
- define_method :"#{attr}=".to_s do |val|
147
- set_attr(attr, val)
148
- end
149
- end
168
+ define_method :"#{attr}=".to_s do |val|
169
+ set_attr(attr, val)
170
+ end
171
+ end
150
172
 
151
- define_getter_and_setter(:id)
152
- end # if
173
+ define_getter_and_setter(:id)
153
174
 
154
175
  # In case multiple attributes were passed in, let's loop over each one.
155
176
  attrs.each do |attr|
@@ -189,14 +210,23 @@ EOM
189
210
  def save
190
211
  if !id
191
212
  # TODO: use KyotoCabinet::DB#increment
192
- id = self.class.last_id + 1
213
+ self.id = self.class.last_id + 1
193
214
  self.class.last_id = id
194
215
  end
195
-
216
+
196
217
  write_indices(id)
197
218
  write_to_kyoto(id, self)
198
219
  end
199
220
 
221
+ def update(attr, value)
222
+ @values[attr] = value
223
+ save
224
+ end
225
+
226
+ def delete
227
+ self.class.delete(self.id)
228
+ end
229
+
200
230
  def write_indices(id)
201
231
  self.class.indices.each do |attr, index|
202
232
  index.set(@values[attr], id)
@@ -204,14 +234,11 @@ EOM
204
234
  end
205
235
 
206
236
  def write_to_kyoto(k, v)
207
- set_error(k,v) unless self.class.set(k, v)
237
+ self.class.set(k, v)
208
238
  end
209
239
 
210
240
  private
211
241
 
212
- def set_error(k,v)
213
- STDERR.printf("set error for (k,v)=(%s, %s): %s\n", k, v, kc.error)
214
- end
215
242
 
216
243
  end
217
244
 
data/kyoto_record_spec.rb CHANGED
@@ -19,13 +19,20 @@ describe 'KyotoRecord module' do
19
19
  File.exist?('./data/A.kch').should be_true
20
20
  end
21
21
 
22
- it "should retrieve 3 if 3 was saved into a kyoto attribute" do
22
+ it "find should return an instance of the enhanced user-defined class" do
23
23
  @a = A.new
24
24
  @a.x = 3
25
25
  @a.save
26
26
  A.find(1).should be_an_instance_of(A)
27
27
  end
28
28
 
29
+ it "should have an id after being saved." do
30
+ @a = A.new
31
+ @a.x = 3
32
+ @a.save
33
+ @a.id.should == 1
34
+ end
35
+
29
36
  it "should retrieve 3 if 3 was saved into a kyoto attribute" do
30
37
  @a = A.new
31
38
  @a.x = 3
@@ -47,6 +54,21 @@ describe 'KyotoRecord module' do
47
54
  A.find(1).x.should be_an_instance_of( Time )
48
55
  end
49
56
 
57
+ it "should be able to save 2 different objects using the same variable" do
58
+ a = A.new
59
+ a.x = "David"
60
+ a.save
61
+
62
+ a = A.new
63
+ a.x = "Bob"
64
+ a.save
65
+
66
+ A.find(1).x.should == "David"
67
+ A.find(1).id.should == 1
68
+ A.find(2).x.should == "Bob"
69
+ A.find(2).id.should == 2
70
+ end
71
+
50
72
  it "should have a last_id of nil if nothing has been saved yet." do
51
73
  A.last_id.should == 0
52
74
  end
@@ -108,7 +130,7 @@ describe 'KyotoRecord module' do
108
130
 
109
131
  describe "Iterating over the records." do
110
132
  before(:each) do
111
- # Insert 100 records
133
+ # Insert some records
112
134
  10.times do |i|
113
135
  a = A.new
114
136
  a.x = i+1
@@ -148,6 +170,7 @@ describe 'KyotoRecord module' do
148
170
  word.should == "56"
149
171
  end
150
172
  end
173
+
151
174
  describe "Indexing of attributes." do
152
175
  before(:each) do
153
176
  class A
@@ -170,6 +193,110 @@ describe 'KyotoRecord module' do
170
193
  A.find_by_username("David").username.should == "David"
171
194
  end
172
195
  end
196
+ describe "DELETE functionality" do
197
+ it "should be able to delete records by key (class utility function)" do
198
+ a = A.new
199
+ a.username = "David"
200
+ a.save
201
+ A.find(1).should_not be_nil
202
+ A.delete(1)
203
+ A.find(1).should be_nil
204
+ end
205
+
206
+ it "should be able to delete records by key (instance method)" do
207
+ a = A.new
208
+ a.username = "David"
209
+ a.save
210
+ A.find(1).should_not be_nil
211
+ a.delete
212
+ A.find(1).should be_nil
213
+ end
214
+ end
215
+
216
+ describe "UPDATE functionality" do
217
+ it "should be able to update just by saving over the existing one." do
218
+ a = A.new
219
+ a.username = "David"
220
+ a.save
221
+
222
+ # Loop him up.
223
+ a1 = A.find(1)
224
+ a1.username.should == "David"
225
+
226
+ # Modify him.
227
+ a1.username = "Bob"
228
+ a1.save
229
+
230
+ # Make sure he changed.
231
+ A.find(1).username.should == "Bob"
232
+ end
233
+
234
+ it "should be able to update with a instance method." do
235
+ a = A.new
236
+ a.username = "David"
237
+ a.save
238
+
239
+ A.find(1).update(:username, "Bob")
240
+ A.find(1).username.should == "Bob"
241
+ end
242
+
243
+ it "should be able to batch update by scanning over a range of ids." do
244
+ 10.times do |i|
245
+ a = A.new
246
+ a.username = i+1
247
+ a.save
248
+ end
249
+
250
+ A.scan(1,5) do |a|
251
+ a.update(:username, "Anonymous")
252
+ end
253
+
254
+ A.find(1).username.should == "Anonymous"
255
+ A.find(3).username.should == "Anonymous"
256
+ A.find(5).username.should == "Anonymous"
257
+ A.find(6).username.should == 6
258
+ A.find(7).username.should == 7
259
+ A.find(10).username.should == 10
260
+ end
261
+ end
262
+
263
+ describe "DROP the whole database" do
264
+ it "should be able to drop the whole database." do
265
+ a = A.new
266
+ a.username = "David"
267
+ a.save
268
+
269
+ a = A.new
270
+ a.username = "Bob"
271
+ a.save
272
+
273
+ A.find(1).username.should == "David"
274
+ A.find(2).username.should == "Bob"
275
+
276
+ A.delete_all
277
+
278
+ A.find(1).should be_nil
279
+ A.find(2).should be_nil
280
+ end
281
+
282
+ it "should be able to add more items after the database was dropped." do
283
+ a = A.new
284
+ a.username = "David"
285
+ a.save
286
+
287
+ A.find(1).username.should == "David"
288
+
289
+ A.delete_all
290
+
291
+ b = A.new
292
+ b.username = "Duck"
293
+ b.id.should be_nil
294
+ b.save
295
+
296
+ b.id.should == 2
297
+ A.find(2).should_not be_nil
298
+ end
299
+ end
173
300
 
174
301
  describe "Auxilliary functions" do
175
302
  it "should be able to know it's own name as a string" do
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: kyoto_record
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.0.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - David Beckwith
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-02 00:00:00 -08:00
13
+ date: 2011-03-05 00:00:00 -08:00
14
14
  default_executable:
15
15
  dependencies: []
16
16