-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdatabase.rb
101 lines (85 loc) · 2.05 KB
/
database.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
class Database
LEN_ID = 8
LEN_TITLE = 512
LEN_AUTHOR = 128
LEN_ISBN = 16
LEN_STATUS = 16
OFFSET_ID = 0
OFFSET_TITLE = OFFSET_ID + LEN_ID
OFFSET_AUTHOR = OFFSET_TITLE + LEN_TITLE
OFFSET_ISBN = OFFSET_AUTHOR + LEN_AUTHOR
OFFSET_STATUS = OFFSET_ISBN + LEN_ISBN
LENGTH = LEN_ID + LEN_TITLE + LEN_AUTHOR + LEN_ISBN + LEN_STATUS
EMPTY_STRING = "\x00"*LENGTH
attr_accessor :keyMap, :offset, :datastore
def initialize (datastore_name)
@keyMap = Hash.new
@offset = 0
@datastore = File.open(datastore_name, "a+b")
loop{
@datastore.seek(@offset)
b = @datastore.read(LEN_ID)
break unless b
key = b.unpack("A*").first
@keyMap[key] = @offset
@offset += LENGTH
}
@offset = 0
if block_given?
yield self
self.close
end
end
def add(book)
@keyMap[book.id] = @datastore.pos
@datastore.write(to_byte(book))
end
def find(key)
return nil unless @keyMap.include?(key)
@offset = @keyMap[key]
@datastore.seek(@offset)
bytes = @datastore.read(LENGTH)
to_entry(bytes)
end
def list
@keyMap.keys.collect{ |key| find(key) }
end
def to_byte(book)
bytes = "\x00"*LENGTH
offset = 0
write = proc{ |str,len|
bytes[offset, str.bytesize] = str.unpack("a*").first
offset += len
}
write[book.id, LEN_ID]
write[book.title, LEN_TITLE]
write[book.author, LEN_AUTHOR]
write[book.isbn, LEN_ISBN]
write[book.status.to_s, LEN_STATUS]
bytes
end
def to_entry(bytes)
reader = StringIO.new(bytes, "r")
offset = 0
readString = proc{ |len|
begin
data = reader.read(len)
data.unpack("A*").first.force_encoding("utf-8")
rescue
""
ensure
offset += len
end
}
book = Book.new
book.id = readString[LEN_ID]
book.title = readString[LEN_TITLE]
book.author = readString[LEN_AUTHOR]
book.isbn = readString[LEN_ISBN]
book.status = CirculationStatus.const_get(readString[LEN_STATUS])
book
end
def close
@datastore.close
end
end