carton_db 1.1.2 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/carton_db/datum.rb +14 -8
- data/lib/carton_db/escaping.rb +37 -34
- data/lib/carton_db/list_map_db/segment.rb +94 -0
- data/lib/carton_db/list_map_db/segment_group.rb +2 -0
- data/lib/carton_db/list_map_db.rb +29 -71
- data/lib/carton_db/set_map_db.rb +3 -0
- data/lib/carton_db/simple_map_db.rb +3 -0
- data/lib/carton_db/version.rb +3 -1
- data/lib/carton_db.rb +2 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0569eb04a7231087ac8ba262cc56330a1c61912
|
4
|
+
data.tar.gz: aaae82f45cfdeb14e4dea5110e9a09c3b062ab5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e07e734b21b74e9988654549060f615897fb9b5e57763a61d392bf58ef0ff46845ba43118c805766f9177a117d0c4f7d49d1fa52e13e8e2042f410dd385b18a3
|
7
|
+
data.tar.gz: 5c818326762c092a868e9abc642ce1baa3a1b9a2fbe38a17c7932f0ebbbde99a1e0a8d72cd7479a98e61a5c97cc1516968f92e9c655cb0e1758333f02a778b2d
|
data/lib/carton_db/datum.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
1
4
|
require 'digest'
|
2
5
|
|
3
6
|
module CartonDb
|
@@ -5,20 +8,22 @@ module CartonDb
|
|
5
8
|
module Datum
|
6
9
|
|
7
10
|
def self.for_plain(plain_text, auto_placeholder: false)
|
8
|
-
|
9
|
-
if auto_placeholder && plain_text.nil?
|
11
|
+
if auto_placeholder && (! plain_text) && plain_text.nil?
|
10
12
|
Datum::Placeholder
|
13
|
+
elsif plain_text.is_a?(Datum::Base)
|
14
|
+
plain_text
|
11
15
|
else
|
12
|
-
Datum::ForPlain.new(plain_text)
|
16
|
+
Datum::ForPlain.new(plain_text.to_s)
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
16
20
|
def self.for_escaped(escaped_text, auto_placeholder: false)
|
17
|
-
|
18
|
-
if auto_placeholder && escaped_text.nil?
|
21
|
+
if auto_placeholder && (! escaped_text) && escaped_text.nil?
|
19
22
|
Datum::Placeholder
|
23
|
+
elsif escaped_text.is_a?(Datum::Base)
|
24
|
+
escaped_text
|
20
25
|
else
|
21
|
-
Datum::ForEscaped.new(escaped_text)
|
26
|
+
Datum::ForEscaped.new(escaped_text.to_s)
|
22
27
|
end
|
23
28
|
end
|
24
29
|
|
@@ -58,8 +63,9 @@ module CartonDb
|
|
58
63
|
class ForPlain < Datum::Base
|
59
64
|
attr_reader :plain
|
60
65
|
|
66
|
+
|
61
67
|
def initialize(plain)
|
62
|
-
if plain.nil?
|
68
|
+
if (! plain) && plain.nil?
|
63
69
|
raise ArgumentError "A non-nil 'plain' value is required."
|
64
70
|
end
|
65
71
|
@plain = plain
|
@@ -90,7 +96,7 @@ module CartonDb
|
|
90
96
|
attr_reader :escaped
|
91
97
|
|
92
98
|
def initialize(escaped)
|
93
|
-
if escaped.nil?
|
99
|
+
if (! escaped) && escaped.nil?
|
94
100
|
raise ArgumentError "A non-nil 'escaped' value is required."
|
95
101
|
end
|
96
102
|
@escaped = escaped
|
data/lib/carton_db/escaping.rb
CHANGED
@@ -1,42 +1,45 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
1
4
|
module CartonDb
|
2
5
|
|
3
6
|
module Escaping
|
4
7
|
|
5
8
|
ESCAPING_MAP = {
|
6
|
-
"\u0000"
|
7
|
-
"\u0001"
|
8
|
-
"\u0002"
|
9
|
-
"\u0003"
|
10
|
-
"\u0004"
|
11
|
-
"\u0005"
|
12
|
-
"\u0006"
|
13
|
-
"\u0007"
|
14
|
-
"\u0008"
|
15
|
-
"\u0009"
|
16
|
-
"\u000A"
|
17
|
-
"\u000B"
|
18
|
-
"\u000C"
|
19
|
-
"\u000D"
|
20
|
-
"\u000E"
|
21
|
-
"\u000F"
|
22
|
-
"\u0010"
|
23
|
-
"\u0011"
|
24
|
-
"\u0012"
|
25
|
-
"\u0013"
|
26
|
-
"\u0014"
|
27
|
-
"\u0015"
|
28
|
-
"\u0016"
|
29
|
-
"\u0017"
|
30
|
-
"\u0018"
|
31
|
-
"\u0019"
|
32
|
-
"\u001A"
|
33
|
-
"\u001B"
|
34
|
-
"\u001C"
|
35
|
-
"\u001D"
|
36
|
-
"\u001E"
|
37
|
-
"\u001F"
|
38
|
-
"\u007F"
|
39
|
-
"\\"
|
9
|
+
"\u0000" => '\x00',
|
10
|
+
"\u0001" => '\x01',
|
11
|
+
"\u0002" => '\x02',
|
12
|
+
"\u0003" => '\x03',
|
13
|
+
"\u0004" => '\x04',
|
14
|
+
"\u0005" => '\x05',
|
15
|
+
"\u0006" => '\x06',
|
16
|
+
"\u0007" => '\a',
|
17
|
+
"\u0008" => '\b',
|
18
|
+
"\u0009" => '\t',
|
19
|
+
"\u000A" => '\n',
|
20
|
+
"\u000B" => '\v',
|
21
|
+
"\u000C" => '\f',
|
22
|
+
"\u000D" => '\r',
|
23
|
+
"\u000E" => '\x0E',
|
24
|
+
"\u000F" => '\x0F',
|
25
|
+
"\u0010" => '\x10',
|
26
|
+
"\u0011" => '\x11',
|
27
|
+
"\u0012" => '\x12',
|
28
|
+
"\u0013" => '\x13',
|
29
|
+
"\u0014" => '\x14',
|
30
|
+
"\u0015" => '\x15',
|
31
|
+
"\u0016" => '\x16',
|
32
|
+
"\u0017" => '\x17',
|
33
|
+
"\u0018" => '\x18',
|
34
|
+
"\u0019" => '\x19',
|
35
|
+
"\u001A" => '\x1A',
|
36
|
+
"\u001B" => '\x1B',
|
37
|
+
"\u001C" => '\x1C',
|
38
|
+
"\u001D" => '\x1D',
|
39
|
+
"\u001E" => '\x1E',
|
40
|
+
"\u001F" => '\x1F',
|
41
|
+
"\u007F" => '\x7F',
|
42
|
+
"\\" => "\\\\",
|
40
43
|
}.freeze
|
41
44
|
|
42
45
|
UNESCAPING_MAP = ESCAPING_MAP.invert.freeze
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'fileutils'
|
5
|
+
require 'set'
|
3
6
|
|
4
7
|
module CartonDb
|
5
8
|
class ListMapDb
|
@@ -58,6 +61,55 @@ module CartonDb
|
|
58
61
|
! content?
|
59
62
|
end
|
60
63
|
|
64
|
+
def key_count
|
65
|
+
return 0 if empty?
|
66
|
+
key_d_set.length
|
67
|
+
end
|
68
|
+
|
69
|
+
def touch_d(key_d, optimization)
|
70
|
+
if optimization == :small && content?
|
71
|
+
each_entry_element_line do |kd, _ed, _line|
|
72
|
+
return if kd == key_d
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
open_append do |io|
|
77
|
+
io << key_d.escaped << "\n"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def key_d_set
|
82
|
+
result = Set.new
|
83
|
+
each_entry_element_line do |kd, _ed, _line|
|
84
|
+
result << kd
|
85
|
+
end
|
86
|
+
result
|
87
|
+
end
|
88
|
+
|
89
|
+
def key_d?(key_d)
|
90
|
+
each_entry_element_line do |kd, _ed, _line|
|
91
|
+
return true if kd = key_d
|
92
|
+
end
|
93
|
+
false
|
94
|
+
end
|
95
|
+
|
96
|
+
def element_d?(key_d, element_d)
|
97
|
+
each_entry_element_line do |kd, ed, _line|
|
98
|
+
return true if kd == key_d && ed == element_d
|
99
|
+
end
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
103
|
+
def collect_content(key_d, collection_class)
|
104
|
+
result = nil
|
105
|
+
each_entry_element_line do |kd, ed, _line|
|
106
|
+
next unless kd == key_d
|
107
|
+
result ||= collection_class.new
|
108
|
+
result << ed.plain unless ed.placeholder?
|
109
|
+
end
|
110
|
+
result
|
111
|
+
end
|
112
|
+
|
61
113
|
def each_entry
|
62
114
|
entries = nil
|
63
115
|
each_entry_element_line do |key_d, elem_d, _line|
|
@@ -71,6 +123,13 @@ module CartonDb
|
|
71
123
|
end
|
72
124
|
end
|
73
125
|
|
126
|
+
def each_element_for_d(key_d)
|
127
|
+
each_entry_element_line do |kd, ed, _line|
|
128
|
+
next unless kd == key_d
|
129
|
+
yield ed
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
74
133
|
def each_first_element
|
75
134
|
first_entries = nil
|
76
135
|
each_entry_element_line do |key_d, elem_d, _line|
|
@@ -94,6 +153,41 @@ module CartonDb
|
|
94
153
|
end
|
95
154
|
end
|
96
155
|
|
156
|
+
def replace
|
157
|
+
replacement = self.class.new(
|
158
|
+
segment_group, "#{segment_filename}.txt"
|
159
|
+
)
|
160
|
+
begin
|
161
|
+
yield replacement
|
162
|
+
rescue StandardError
|
163
|
+
File.unlink replacement.filename
|
164
|
+
raise
|
165
|
+
end
|
166
|
+
File.unlink filename
|
167
|
+
File.rename replacement.filename, filename
|
168
|
+
end
|
169
|
+
|
170
|
+
def write_key_element_d(key_d, element_d)
|
171
|
+
open_append do |io|
|
172
|
+
io << "#{key_d.escaped}\t#{element_d.escaped}\n"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def write_key_d_elements(key_d, elements)
|
177
|
+
open_append do |io|
|
178
|
+
elements.each do |element|
|
179
|
+
element_d = CartonDb::Datum.for_plain(element)
|
180
|
+
io<< "#{key_d.escaped}\t#{element_d.escaped}\n"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def copy_entries_except(key_d, to_io)
|
186
|
+
each_entry_element_line do |kd, _ed, line|
|
187
|
+
to_io << line unless kd == key_d
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
97
191
|
def open_append
|
98
192
|
touch_dir
|
99
193
|
File.open filename, 'a', **FILE_ENCODING_OPTS do |io|
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
require 'forwardable'
|
3
5
|
require 'fileutils'
|
4
6
|
require 'carton_db/list_map_db/segment'
|
@@ -77,14 +79,7 @@ module CartonDb
|
|
77
79
|
def [](key)
|
78
80
|
key_d = CartonDb::Datum.for_plain(key)
|
79
81
|
segment = segment_containing(key_d)
|
80
|
-
|
81
|
-
ary = nil
|
82
|
-
segment.each_entry_element_line do |kd, ed, _line|
|
83
|
-
next ary unless kd == key_d
|
84
|
-
ary ||= []
|
85
|
-
ary << ed.plain unless ed.placeholder?
|
86
|
-
end
|
87
|
-
ary
|
82
|
+
segment.collect_content(key_d, Array)
|
88
83
|
end
|
89
84
|
|
90
85
|
# Returns true if an entry with the given key exists.
|
@@ -97,11 +92,7 @@ module CartonDb
|
|
97
92
|
def key?(key)
|
98
93
|
key_d = CartonDb::Datum.for_plain(key)
|
99
94
|
segment = segment_containing(key_d)
|
100
|
-
|
101
|
-
segment.each_entry_element_line do |kd, _ed, _line|
|
102
|
-
return true if kd = key_d
|
103
|
-
end
|
104
|
-
false
|
95
|
+
segment.key_d?(key_d)
|
105
96
|
end
|
106
97
|
|
107
98
|
# Returns trus if an entry with the given key exists and its
|
@@ -116,11 +107,7 @@ module CartonDb
|
|
116
107
|
key_d = CartonDb::Datum.for_plain(key)
|
117
108
|
element_d = CartonDb::Datum.for_plain(element)
|
118
109
|
segment = segment_containing(key_d)
|
119
|
-
|
120
|
-
segment.each_entry_element_line do |kd, ed, _line|
|
121
|
-
return true if kd == key_d && ed == element_d
|
122
|
-
end
|
123
|
-
false
|
110
|
+
segment.element_d?(key_d, element_d)
|
124
111
|
end
|
125
112
|
|
126
113
|
# Returns true if the map has no entries.
|
@@ -143,14 +130,8 @@ module CartonDb
|
|
143
130
|
# @return [Fixnum]
|
144
131
|
def count
|
145
132
|
key_count = 0
|
146
|
-
file_key_datum_set = Set.new
|
147
133
|
ListMapDb::Segment.each_in_db name do |segment|
|
148
|
-
|
149
|
-
file_key_datum_set.clear
|
150
|
-
segment.each_entry_element_line do |kd, _ed, _line|
|
151
|
-
file_key_datum_set << kd
|
152
|
-
end
|
153
|
-
key_count += file_key_datum_set.length
|
134
|
+
key_count += segment.key_count
|
154
135
|
end
|
155
136
|
key_count
|
156
137
|
end
|
@@ -177,16 +158,7 @@ module CartonDb
|
|
177
158
|
|
178
159
|
key_d = CartonDb::Datum.for_plain(key)
|
179
160
|
segment = segment_containing(key_d)
|
180
|
-
|
181
|
-
if optimization == :small && segment.content?
|
182
|
-
segment.each_entry_element_line do |kd, _ed, _line|
|
183
|
-
return if kd == key_d
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
segment.open_append do |io|
|
188
|
-
io << key_d.escaped << "\n"
|
189
|
-
end
|
161
|
+
segment.touch_d key_d, optimization
|
190
162
|
end
|
191
163
|
|
192
164
|
# Removes all entries from the database, leaving it empty.
|
@@ -245,16 +217,11 @@ module CartonDb
|
|
245
217
|
segment = segment_containing(key_d)
|
246
218
|
return if segment.empty?
|
247
219
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
segment.each_entry_element_line do |kd, _ed, line|
|
252
|
-
io << line unless kd == key_d
|
220
|
+
segment.replace do |replacement|
|
221
|
+
replacement.open_overwrite do |repl_io|
|
222
|
+
segment.copy_entries_except key_d, repl_io
|
253
223
|
end
|
254
224
|
end
|
255
|
-
|
256
|
-
File.unlink segment.filename
|
257
|
-
File.rename new_segment.filename, segment.filename
|
258
225
|
end
|
259
226
|
|
260
227
|
# Appends an element string to the content of an entry.
|
@@ -272,10 +239,7 @@ module CartonDb
|
|
272
239
|
key_d = CartonDb::Datum.for_plain(key)
|
273
240
|
element_d = CartonDb::Datum.for_plain(element)
|
274
241
|
segment = segment_containing(key_d)
|
275
|
-
|
276
|
-
segment.open_append do |io|
|
277
|
-
io << "#{key_d.escaped}\t#{element_d.escaped}\n"
|
278
|
-
end
|
242
|
+
segment.write_key_element_d key_d, element_d
|
279
243
|
end
|
280
244
|
|
281
245
|
# Appends any number of element strings to the content of an
|
@@ -313,12 +277,7 @@ module CartonDb
|
|
313
277
|
def concat_any_elements(key, elements)
|
314
278
|
key_d = CartonDb::Datum.for_plain(key)
|
315
279
|
segment = segment_containing(key_d)
|
316
|
-
segment.
|
317
|
-
elements.each do |element|
|
318
|
-
element_d = CartonDb::Datum.for_plain(element)
|
319
|
-
io<< "#{key_d.escaped}\t#{element_d.escaped}\n"
|
320
|
-
end
|
321
|
-
end
|
280
|
+
segment.write_key_d_elements key_d, elements
|
322
281
|
end
|
323
282
|
|
324
283
|
# Appends an element to the content of an entry if no
|
@@ -353,8 +312,7 @@ module CartonDb
|
|
353
312
|
CartonDb::Datum.for_plain(el)
|
354
313
|
}
|
355
314
|
segment = segment_containing(key_d)
|
356
|
-
segment.
|
357
|
-
next unless kd == key_d
|
315
|
+
segment.each_element_for_d key_d do |ed|
|
358
316
|
eds_idx = element_ds.index(ed)
|
359
317
|
element_ds.delete_at(eds_idx) if eds_idx
|
360
318
|
end
|
@@ -367,24 +325,14 @@ module CartonDb
|
|
367
325
|
attr_accessor :name
|
368
326
|
|
369
327
|
def replace_entry_in_file(segment, key_d, content)
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
element_count = 0
|
377
|
-
content.each do |element|
|
378
|
-
element_d = CartonDb::Datum.for_plain(element)
|
379
|
-
element_count += 1
|
380
|
-
nf_io.puts "#{key_d.escaped}\t#{element_d.escaped}"
|
381
|
-
end
|
382
|
-
if element_count.zero?
|
383
|
-
nf_io.puts key_d.escaped
|
328
|
+
segment.replace do |replacement|
|
329
|
+
replacement.open_overwrite do |repl_io|
|
330
|
+
segment.copy_entries_except key_d, repl_io
|
331
|
+
element_count = 0
|
332
|
+
count = write_key_elements(key_d, content, repl_io)
|
333
|
+
repl_io << "#{key_d.escaped}\n" if count.zero?
|
384
334
|
end
|
385
335
|
end
|
386
|
-
File.unlink segment.filename
|
387
|
-
File.rename new_segment.filename, segment.filename
|
388
336
|
end
|
389
337
|
|
390
338
|
def segment_containing(key)
|
@@ -399,6 +347,16 @@ module CartonDb
|
|
399
347
|
! occupied
|
400
348
|
end
|
401
349
|
|
350
|
+
def write_key_elements(key_d, elements, to_io)
|
351
|
+
count = 0
|
352
|
+
elements.each do |element|
|
353
|
+
element_d = CartonDb::Datum.for_plain(element)
|
354
|
+
count += 1
|
355
|
+
to_io << "#{key_d.escaped}\t#{element_d.escaped}\n"
|
356
|
+
end
|
357
|
+
count
|
358
|
+
end
|
359
|
+
|
402
360
|
end
|
403
361
|
|
404
362
|
end
|
data/lib/carton_db/set_map_db.rb
CHANGED
data/lib/carton_db/version.rb
CHANGED
data/lib/carton_db.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: carton_db
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Jorgensen
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|