db-struct 0.1.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.
- checksums.yaml +7 -0
- data/README.md +125 -0
- data/Rakefile +35 -0
- data/db-struct.gemspec +37 -0
- data/doc/DBStruct/BogoHash.html +1384 -0
- data/doc/DBStruct/ErrorHelpers.html +288 -0
- data/doc/DBStruct/Failure.html +139 -0
- data/doc/DBStruct/FieldError.html +143 -0
- data/doc/DBStruct/MissingRowError.html +143 -0
- data/doc/DBStruct/TypeError.html +143 -0
- data/doc/DBStruct.html +1652 -0
- data/doc/_index.html +189 -0
- data/doc/class_list.html +54 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +503 -0
- data/doc/file.README.html +187 -0
- data/doc/file_list.html +59 -0
- data/doc/frames.html +22 -0
- data/doc/index.html +187 -0
- data/doc/js/app.js +344 -0
- data/doc/js/full_list.js +242 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +342 -0
- data/doc/top-level-namespace.html +110 -0
- data/gem.deps.rb +7 -0
- data/lib/dbstruct.rb +29 -0
- data/lib/internal/bogohash.rb +226 -0
- data/lib/internal/dbstruct_base.rb +144 -0
- data/lib/internal/dbstruct_class.rb +301 -0
- data/lib/internal/error.rb +44 -0
- data/lib/internal/util.rb +11 -0
- data/spec/dbstruct_spec.rb +452 -0
- data/spec/spec_helper.rb +48 -0
- metadata +138 -0
@@ -0,0 +1,452 @@
|
|
1
|
+
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'dbstruct'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
BOOK1_ITEMS = {title: "The Summoning of Dragons",
|
9
|
+
author: "Tubal de Malachite",
|
10
|
+
date: Time.new(1989, 11, 1),
|
11
|
+
edition: 1}
|
12
|
+
|
13
|
+
BOOK2_ITEMS = {title: "Howe To Kille Insects",
|
14
|
+
author: "Humptulip",
|
15
|
+
date: Time.new(1985, 8, 1), # guess
|
16
|
+
edition: 1}
|
17
|
+
|
18
|
+
BOOK3_ITEMS = {title: "Diseases of the Dragon",
|
19
|
+
author: "Lady Sybil Ramkin",
|
20
|
+
date: Time.new(1989, 11, 1),
|
21
|
+
edition: 1}
|
22
|
+
|
23
|
+
|
24
|
+
def make_post_items(fora, users, count)
|
25
|
+
posts = []
|
26
|
+
mc = 0
|
27
|
+
for f in fora
|
28
|
+
for u in users
|
29
|
+
(1..count).each do
|
30
|
+
mc += 1
|
31
|
+
posts << {
|
32
|
+
forum: f,
|
33
|
+
user: u,
|
34
|
+
|
35
|
+
subject: "subject number #{mc}",
|
36
|
+
date: Time.now,
|
37
|
+
contents: "message text #{mc}",
|
38
|
+
}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
return posts
|
44
|
+
end
|
45
|
+
|
46
|
+
def make_posts(fora, users, count) =
|
47
|
+
make_post_items(fora, users, count)
|
48
|
+
.map{|pi| Posts.new(**pi)}
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
|
53
|
+
POSTS_ITEMS = proc{
|
54
|
+
fora = %w{forum1 forum2 forum3}
|
55
|
+
users = %w{u1 u2 u3}
|
56
|
+
|
57
|
+
make_post_items(fora, users, 1)
|
58
|
+
}.call
|
59
|
+
|
60
|
+
|
61
|
+
describe DBStruct do
|
62
|
+
before(:all) do
|
63
|
+
@tmpdir = TmpDir.dir
|
64
|
+
|
65
|
+
dbfile = TmpDir.filepath("db.sqlite3")
|
66
|
+
@db = jruby? ?
|
67
|
+
Sequel.connect("jdbc:sqlite:#{dbfile}") :
|
68
|
+
Sequel.sqlite(dbfile)
|
69
|
+
#puts "Created #{dbfile}"
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
after(:all) do
|
74
|
+
TmpDir.cleanup!
|
75
|
+
end
|
76
|
+
|
77
|
+
it "lets you define dbstruct types" do
|
78
|
+
Book = DBStruct.with(@db, :books) do
|
79
|
+
field :title, String
|
80
|
+
field :author, String
|
81
|
+
field :date, Time
|
82
|
+
field :edition, Integer
|
83
|
+
|
84
|
+
def foo(x) = x+x
|
85
|
+
end
|
86
|
+
|
87
|
+
expect( Book.items.size ) .to eq 0
|
88
|
+
end
|
89
|
+
|
90
|
+
book1 = nil
|
91
|
+
it "lets you create an instance" do
|
92
|
+
book1 = Book.new(**BOOK1_ITEMS)
|
93
|
+
expect( Book.items.size ) .to eq 1
|
94
|
+
|
95
|
+
BOOK1_ITEMS.each{|k, v| expect( book1.send(k) ) .to eq v }
|
96
|
+
expect( book1.to_h ) .to eq BOOK1_ITEMS
|
97
|
+
|
98
|
+
b1a = Book.items[book1.rowid]
|
99
|
+
expect( b1a ) .to eq book1
|
100
|
+
expect( b1a.to_h ) .to eq BOOK1_ITEMS
|
101
|
+
|
102
|
+
b1b = Book.items.values.first
|
103
|
+
expect( b1b ) .to eq book1
|
104
|
+
end
|
105
|
+
|
106
|
+
it "lets you define and call methods" do
|
107
|
+
expect( book1.foo(2) ) .to eq 4
|
108
|
+
end
|
109
|
+
|
110
|
+
book2 = nil
|
111
|
+
it "lets you create multiple instances" do
|
112
|
+
book2 = Book.new(**BOOK2_ITEMS)
|
113
|
+
expect( Book.items.size ) .to eq 2
|
114
|
+
|
115
|
+
expect( book2 ) .to_not eq book1
|
116
|
+
expect( book2.to_a ) .to_not eq BOOK1_ITEMS
|
117
|
+
|
118
|
+
Book.items.values.each{|item|
|
119
|
+
expect( Book.items[item.rowid] ) .to eq item
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
it "lets you change field values" do
|
124
|
+
book2.edition = 3
|
125
|
+
|
126
|
+
expect( book2.edition ) .to eq 3
|
127
|
+
expect( Book.items[book2.rowid].edition ) .to eq 3
|
128
|
+
|
129
|
+
b2a = Book.items.each
|
130
|
+
.map{|rowid, book| book}
|
131
|
+
.find{|book| book.title == BOOK2_ITEMS[:title]}
|
132
|
+
expect( b2a.edition ) .to eq 3
|
133
|
+
|
134
|
+
book2.edition = BOOK2_ITEMS[:edition]
|
135
|
+
expect( book2.edition ) .to eq BOOK2_ITEMS[:edition]
|
136
|
+
end
|
137
|
+
|
138
|
+
it "has various struct-like conversions" do
|
139
|
+
expect( book2.to_h ) .to eq BOOK2_ITEMS
|
140
|
+
expect( book2.to_a.to_h) .to eq BOOK2_ITEMS
|
141
|
+
|
142
|
+
BOOK2_ITEMS.each{|k, v|
|
143
|
+
expect( book2[k] ) .to eq v
|
144
|
+
}
|
145
|
+
|
146
|
+
book2[:edition] = 42
|
147
|
+
expect( book2.edition ) .to eq 42
|
148
|
+
book2.edition = BOOK2_ITEMS[:edition]
|
149
|
+
end
|
150
|
+
|
151
|
+
it "lets you categorize along group values" do
|
152
|
+
Posts = DBStruct.with(@db, :posts) do
|
153
|
+
group :forum, String
|
154
|
+
group :user, String
|
155
|
+
|
156
|
+
field :subject, String
|
157
|
+
field :date, Time
|
158
|
+
field :contents, String
|
159
|
+
end
|
160
|
+
|
161
|
+
fora = []
|
162
|
+
users = []
|
163
|
+
posts = []
|
164
|
+
POSTS_ITEMS.each{|post|
|
165
|
+
posts << Posts.new(**post)
|
166
|
+
fora << post[:forum]
|
167
|
+
users << post[:user]
|
168
|
+
}
|
169
|
+
users.uniq!
|
170
|
+
fora.uniq!
|
171
|
+
|
172
|
+
expect( Posts.items.size ) .to eq posts.size
|
173
|
+
expect( Posts.items.values.to_set ) .to eq posts.to_set
|
174
|
+
|
175
|
+
# There should be exactly one post per forum/user
|
176
|
+
for forum in fora
|
177
|
+
for user in users
|
178
|
+
i = Posts.items(forum, user)
|
179
|
+
expect( i.size ) .to eq 1
|
180
|
+
|
181
|
+
p = i.values.first
|
182
|
+
expect( p.forum ) .to eq forum
|
183
|
+
expect( p.user ) .to eq user
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# nil is the wildcard when selecting across groups. Let's test
|
188
|
+
# those.
|
189
|
+
all = []
|
190
|
+
for forum in fora
|
191
|
+
i = Posts.items(forum)
|
192
|
+
expected = posts.select{|ii| ii.forum == forum}.to_set
|
193
|
+
expect( i.values.to_set ) .to eq expected
|
194
|
+
all += i.values
|
195
|
+
end
|
196
|
+
expect( all.uniq.size ) .to eq all.size
|
197
|
+
expect( all.to_set ) .to eq posts.to_set
|
198
|
+
|
199
|
+
all = []
|
200
|
+
for user in users
|
201
|
+
i = Posts.items(nil, user)
|
202
|
+
expected = posts.select{|ii| ii.user == user}.to_set
|
203
|
+
expect( i.values.to_set ) .to eq expected
|
204
|
+
all += i.values
|
205
|
+
end
|
206
|
+
expect( all.uniq.size ) .to eq all.size
|
207
|
+
expect( all.to_set ) .to eq posts.to_set
|
208
|
+
end
|
209
|
+
|
210
|
+
it "lets you create custom BogoStructs around Sequel queries" do
|
211
|
+
q1 = Posts.where(user: %w{u1 u3}, forum: "f2")
|
212
|
+
ex1 = POSTS_ITEMS.select{|i|
|
213
|
+
%w{u1 u3}.include?i[:user] && i[:forum] == "f2"
|
214
|
+
}
|
215
|
+
expect( q1.values.uniq ) .to eq q1.values
|
216
|
+
expect( q1.values.size ) .to eq ex1.size
|
217
|
+
|
218
|
+
q1.values.each{|item|
|
219
|
+
expect( item.forum ) .to eq "f2"
|
220
|
+
expect( %w{u1 u3} ) .to include(item.user)
|
221
|
+
}
|
222
|
+
end
|
223
|
+
|
224
|
+
it "and it lets you chain them together, possibly using blocks" do
|
225
|
+
q1 = Posts.where(user: %w{u1 u3}).where{forum == "f2"}
|
226
|
+
ex1 = POSTS_ITEMS.select{|i|
|
227
|
+
%w{u1 u3}.include?i[:user] && i[:forum] == "f2"
|
228
|
+
}
|
229
|
+
expect( q1.values.uniq ) .to eq q1.values
|
230
|
+
expect( q1.values.size ) .to eq ex1.size
|
231
|
+
|
232
|
+
q1.values.each{|item|
|
233
|
+
expect( item.forum ) .to eq "f2"
|
234
|
+
expect( %w{u1 u3} ) .to include(item.user)
|
235
|
+
}
|
236
|
+
end
|
237
|
+
|
238
|
+
book3 = nil
|
239
|
+
book4 = nil
|
240
|
+
it "allows uninitialized fields in new items" do
|
241
|
+
book3 = Book.new
|
242
|
+
expect( book3.to_a.size ) .to eq 4
|
243
|
+
|
244
|
+
expect( book3.title ) .to eq nil
|
245
|
+
expect( book3.author ) .to eq nil
|
246
|
+
expect( book3.date ) .to eq nil
|
247
|
+
expect( book3.edition ) .to eq nil
|
248
|
+
|
249
|
+
book3.title = BOOK3_ITEMS[:title]
|
250
|
+
book3.author = BOOK3_ITEMS[:author]
|
251
|
+
book3.date = BOOK3_ITEMS[:date]
|
252
|
+
book3.edition = BOOK3_ITEMS[:edition]
|
253
|
+
|
254
|
+
expect( book3.to_h ) .to eq BOOK3_ITEMS
|
255
|
+
|
256
|
+
book4 = Book.new(title: "The Unknown Book")
|
257
|
+
expect( book4.title ) .to eq "The Unknown Book"
|
258
|
+
expect( book4.author ) .to eq nil
|
259
|
+
expect( book4.date ) .to eq nil
|
260
|
+
expect( book4.edition ) .to eq nil
|
261
|
+
end
|
262
|
+
|
263
|
+
it "fails if you attempt to set an unknown field." do
|
264
|
+
expect{ Book.new(title: "bad book", badness: 42) }
|
265
|
+
.to raise_error DBStruct::FieldError
|
266
|
+
|
267
|
+
expect{ book1.floop = 42 }
|
268
|
+
.to raise_error NoMethodError
|
269
|
+
|
270
|
+
expect{ book1[:floop] = 42 }
|
271
|
+
.to raise_error DBStruct::FieldError
|
272
|
+
end
|
273
|
+
|
274
|
+
it "ensures field values are of the expected type" do
|
275
|
+
expect{ book1.title = Time.now }
|
276
|
+
.to raise_error DBStruct::TypeError
|
277
|
+
expect{ book1.edition = "42" }
|
278
|
+
.to raise_error DBStruct::TypeError
|
279
|
+
expect{ book1.edition = Time.now }
|
280
|
+
.to raise_error DBStruct::TypeError
|
281
|
+
|
282
|
+
expect( book1.to_h ) .to eq BOOK1_ITEMS
|
283
|
+
end
|
284
|
+
|
285
|
+
book5 = nil
|
286
|
+
it "always allows null as a type" do
|
287
|
+
book1.title = nil
|
288
|
+
expect( book1.title ) .to eq nil
|
289
|
+
book1.title = BOOK1_ITEMS[:title]
|
290
|
+
expect( book1.to_h ) .to eq BOOK1_ITEMS
|
291
|
+
|
292
|
+
book5 = Book.new(title: "An Anonymous Book",
|
293
|
+
author: nil)
|
294
|
+
expect( book5.title ) .to eq "An Anonymous Book"
|
295
|
+
expect( book5.author ) .to eq nil
|
296
|
+
expect( book5.date ) .to eq nil
|
297
|
+
expect( book5.edition ) .to eq nil
|
298
|
+
end
|
299
|
+
|
300
|
+
it "supports block enumeration over tables" do
|
301
|
+
expect( Book.items.size ) .to be > 1 # consistency check
|
302
|
+
|
303
|
+
kv = []
|
304
|
+
Book.items.each{|k,v| kv.push [k,v]}
|
305
|
+
expect( kv.size ) .to eq Book.items.size
|
306
|
+
|
307
|
+
kv.each{|k,v|
|
308
|
+
expect( Book.items[k] ) .to eq v
|
309
|
+
}
|
310
|
+
|
311
|
+
# Test each_key
|
312
|
+
keys = []
|
313
|
+
Book.items.each_key{|rowid|
|
314
|
+
expect( Book.items[rowid].rowid ) .to eq rowid
|
315
|
+
keys.push(rowid)
|
316
|
+
}
|
317
|
+
expect( keys.size ) .to eq kv.size
|
318
|
+
expect( keys.to_set ) .to eq Book.items.keys.to_set
|
319
|
+
expect( keys.to_set ) .to eq kv.map{|k,v| k}.to_set
|
320
|
+
|
321
|
+
# Test each_value
|
322
|
+
values = []
|
323
|
+
Book.items.each_value{|row|
|
324
|
+
expect( Book.items[row.rowid] ) .to eq row
|
325
|
+
values.push(row)
|
326
|
+
}
|
327
|
+
expect( values.size ) .to eq keys.size
|
328
|
+
expect( values.to_set ) .to eq Book.items.values.to_set
|
329
|
+
expect( values.to_set ) .to eq kv.map{|k,v| v}.to_set
|
330
|
+
end
|
331
|
+
|
332
|
+
it "provides enumerators as well" do
|
333
|
+
e = Book.items.each
|
334
|
+
expect( e.class ) .to eq Enumerator
|
335
|
+
expect( e.to_a.to_set ) .to eq Book.items.to_a.to_set
|
336
|
+
|
337
|
+
expect( Book.items.each_key.to_a.to_set ) .to eq Book.items.keys.to_set
|
338
|
+
expect( Book.items.each_value.to_a.to_set ) .to eq Book.items.values.to_set
|
339
|
+
end
|
340
|
+
|
341
|
+
it "includes Enumerable" do
|
342
|
+
# Just call a couple of methods to ensure that they work. We
|
343
|
+
# assume the rest will work correctly.
|
344
|
+
expect( Book.items.any?{true} ) .to be true
|
345
|
+
expect( Book.items.select{true} ) .to eq Book.items.to_a
|
346
|
+
end
|
347
|
+
|
348
|
+
it "fails gracefully when given an invalid row ID" do
|
349
|
+
# Invalid wrt the entire
|
350
|
+
maxrow = Posts.items.keys.max
|
351
|
+
expect( Posts.items[maxrow + 1] ) .to eq nil
|
352
|
+
|
353
|
+
# Garbage row Ids should also return nil
|
354
|
+
expect( Posts.items[ ["garbage!!!"] ] ) .to eq nil
|
355
|
+
|
356
|
+
# Invalid key but not part of the current group. Note that
|
357
|
+
# changes in the order of Post creation above could break this; we
|
358
|
+
# assume that there is at least one row-id that is larger than the
|
359
|
+
# largest row-id in this group. If not, the following test will
|
360
|
+
# fail.
|
361
|
+
grp = Posts.items("forum1", "u1")
|
362
|
+
maxrow_grp = grp.keys.max
|
363
|
+
expect( maxrow_grp ) .to be < maxrow
|
364
|
+
|
365
|
+
outside_row = maxrow_grp + 1
|
366
|
+
expect( grp[outside_row] ) .to eq nil
|
367
|
+
expect( Posts.items[outside_row] ) .not_to eq nil
|
368
|
+
|
369
|
+
# Ditto for `where`; we abuse it to select by row-id; this may or
|
370
|
+
# may not be supported.
|
371
|
+
grp2 = Posts.where{_id < maxrow - 3}
|
372
|
+
expect( grp2[maxrow - 1] ) .to eq nil
|
373
|
+
end
|
374
|
+
|
375
|
+
it "supports row deletion but only in its group of items" do
|
376
|
+
fx = %w{xforum1 xforum2}
|
377
|
+
ux = %w{alice bob charlene}
|
378
|
+
|
379
|
+
xposts = make_posts(fx, ux, 2)
|
380
|
+
xposts.each{|r| expect( Posts.items[r.rowid] ) .to eq r }
|
381
|
+
|
382
|
+
f1 = Posts.items("xforum1")
|
383
|
+
f2 = Posts.items("xforum2")
|
384
|
+
|
385
|
+
d1 = f1.keys.first
|
386
|
+
|
387
|
+
# Can't delete an item not in the current group
|
388
|
+
expect( f2.delete(d1) ) .to eq nil
|
389
|
+
expect( f2[d1] ) .to eq nil
|
390
|
+
|
391
|
+
# row objects can tell you if the underlying row exists
|
392
|
+
target = f1[d1]
|
393
|
+
expect( target.present? ) .to be true
|
394
|
+
expect( target.deleted? ) .to be false
|
395
|
+
|
396
|
+
# Deletion returns the value and removes it from the database
|
397
|
+
expect( f1[d1] ) .to eq target
|
398
|
+
expect( f1.delete(d1) ) .to eq target
|
399
|
+
expect( f1[d1] ) .to eq nil
|
400
|
+
expect( Posts.items[d1] ) .to eq nil
|
401
|
+
|
402
|
+
# And the lingering row object should handle this gracefully
|
403
|
+
expect( target.present? ) .to be false
|
404
|
+
expect( target.deleted? ) .to be true
|
405
|
+
expect{ target.user }
|
406
|
+
.to raise_error DBStruct::MissingRowError
|
407
|
+
end
|
408
|
+
|
409
|
+
it "supports 'delete_if'" do
|
410
|
+
c = Posts.items("xforum1").size
|
411
|
+
Posts.items.delete_if{|k, v|
|
412
|
+
next false unless v.forum == "xforum1"
|
413
|
+
c -= 1
|
414
|
+
true
|
415
|
+
}
|
416
|
+
expect( Posts.items("xforum1").size ) .to eq 0
|
417
|
+
expect( c ) .to eq 0
|
418
|
+
end
|
419
|
+
|
420
|
+
it "supports clearing per group" do
|
421
|
+
c = Posts.items("xforum2").size
|
422
|
+
expect( c ) .to be > 0
|
423
|
+
|
424
|
+
Posts.items("xforum2").clear
|
425
|
+
expect( Posts.items("xforum2").size ) .to eq 0
|
426
|
+
end
|
427
|
+
|
428
|
+
it "can deal with any Ruby type Sequel can handle" do
|
429
|
+
BigTbl = DBStruct.with(@db, :bigtbl) do
|
430
|
+
field :i1, Integer
|
431
|
+
field :s1, String
|
432
|
+
field :fn1, Fixnum
|
433
|
+
field :bn1, Bignum
|
434
|
+
field :f1, Float
|
435
|
+
field :bd1, BigDecimal
|
436
|
+
field :dt1, Date
|
437
|
+
field :dtt1, DateTime
|
438
|
+
field :tm1, Time
|
439
|
+
field :nm1, Numeric
|
440
|
+
field :b1, TrueClass
|
441
|
+
field :b2, FalseClass
|
442
|
+
end
|
443
|
+
|
444
|
+
b1 = BigTbl.new
|
445
|
+
|
446
|
+
# TrueClass and FalseClass are shorthand for either boolean
|
447
|
+
b1.b2 = true
|
448
|
+
b1.b1 = false
|
449
|
+
end
|
450
|
+
|
451
|
+
|
452
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
SpecDir = File.realpath( File.dirname(__FILE__) )
|
5
|
+
|
6
|
+
$: << File.join(SpecDir, '..', 'lib')
|
7
|
+
$: << File.join(SpecDir, '..', 'src')
|
8
|
+
|
9
|
+
def jruby?
|
10
|
+
return RUBY_PLATFORM == "java"
|
11
|
+
end
|
12
|
+
|
13
|
+
module TmpDir
|
14
|
+
@root = File.join( File.dirname(__FILE__), "tmpdata")
|
15
|
+
@tmpdir = File.join(@root, SecureRandom.uuid)
|
16
|
+
@count = 0
|
17
|
+
|
18
|
+
def self.dir
|
19
|
+
FileUtils.mkdir_p(@tmpdir) unless File.directory?(@tmpdir)
|
20
|
+
return @tmpdir
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.filepath(name, versioned: false)
|
24
|
+
self.dir # ensure @tmpdir exists
|
25
|
+
|
26
|
+
filepath = File.join(@tmpdir, name)
|
27
|
+
if versioned
|
28
|
+
while File.exist?(filepath)
|
29
|
+
@count += 1
|
30
|
+
|
31
|
+
nameparts = name.split('.')
|
32
|
+
suffix = nameparts.pop if nameparts.size > 1
|
33
|
+
nameparts.push @count.to_s
|
34
|
+
nameparts.push suffix if suffix
|
35
|
+
|
36
|
+
newname = nameparts.join(".")
|
37
|
+
filepath = File.join(@tmpdir, newname)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
return filepath
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.cleanup!
|
45
|
+
return unless File.directory?(@root)
|
46
|
+
FileUtils.rm_rf(@root)
|
47
|
+
end
|
48
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: db-struct
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Reuter
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-09-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: 5.76.0
|
19
|
+
name: sequel
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.76.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3.10'
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 3.10.0
|
36
|
+
name: rspec
|
37
|
+
type: :development
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '3.10'
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.10.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - "~>"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 0.9.25
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 0.9.25
|
56
|
+
name: yard
|
57
|
+
type: :development
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - "~>"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.9.25
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 0.9.25
|
67
|
+
description: |2
|
68
|
+
DBStruct is a class that, like Struct, provides a convenient way
|
69
|
+
to create subclasses with named fields that can be accessed via
|
70
|
+
the usual Ruby setters and getters. Unlike Struct, their contents
|
71
|
+
are stored in a SQLite3 database.
|
72
|
+
|
73
|
+
In addition, each subclass also provides access to the database
|
74
|
+
via an interface that closely mimics a Ruby Hash, including
|
75
|
+
support for enumeration.
|
76
|
+
email: chris@remove-this-part.blit.ca
|
77
|
+
executables: []
|
78
|
+
extensions: []
|
79
|
+
extra_rdoc_files: []
|
80
|
+
files:
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- db-struct.gemspec
|
84
|
+
- doc/DBStruct.html
|
85
|
+
- doc/DBStruct/BogoHash.html
|
86
|
+
- doc/DBStruct/ErrorHelpers.html
|
87
|
+
- doc/DBStruct/Failure.html
|
88
|
+
- doc/DBStruct/FieldError.html
|
89
|
+
- doc/DBStruct/MissingRowError.html
|
90
|
+
- doc/DBStruct/TypeError.html
|
91
|
+
- doc/_index.html
|
92
|
+
- doc/class_list.html
|
93
|
+
- doc/css/common.css
|
94
|
+
- doc/css/full_list.css
|
95
|
+
- doc/css/style.css
|
96
|
+
- doc/file.README.html
|
97
|
+
- doc/file_list.html
|
98
|
+
- doc/frames.html
|
99
|
+
- doc/index.html
|
100
|
+
- doc/js/app.js
|
101
|
+
- doc/js/full_list.js
|
102
|
+
- doc/js/jquery.js
|
103
|
+
- doc/method_list.html
|
104
|
+
- doc/top-level-namespace.html
|
105
|
+
- gem.deps.rb
|
106
|
+
- lib/dbstruct.rb
|
107
|
+
- lib/internal/bogohash.rb
|
108
|
+
- lib/internal/dbstruct_base.rb
|
109
|
+
- lib/internal/dbstruct_class.rb
|
110
|
+
- lib/internal/error.rb
|
111
|
+
- lib/internal/util.rb
|
112
|
+
- spec/dbstruct_spec.rb
|
113
|
+
- spec/spec_helper.rb
|
114
|
+
homepage: https://codeberg.org/suetanvil/db-struct
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 3.0.0
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements:
|
133
|
+
- Sequel
|
134
|
+
rubygems_version: 3.3.26
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Persistant storage of sets of structured records.
|
138
|
+
test_files: []
|