relaton 3.0.0.pre.alpha.7 → 3.0.0.pre.alpha.9
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 +4 -4
- data/lib/relaton/bib/model/ics.rb +38 -4
- data/lib/relaton/index/config.rb +11 -1
- data/lib/relaton/index/file_io.rb +146 -2
- data/lib/relaton/index/sqlite_backend.rb +99 -0
- data/lib/relaton/index/type.rb +15 -4
- data/lib/relaton/index.rb +3 -1
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton.rb +10 -10
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2c1a04ce086b4f13d9ec8c448b4254cd3f4bc0399d0d1b4892e2201f45717f4c
|
|
4
|
+
data.tar.gz: f5a8286c7313b4f47a131290923ad2d23082cd51fb492f20555d859f38375cfd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 63355667dfc69e951fd03842f8b3769dae41ffce420b4deb21349dac2a035db489b17c808d9c6b8c478f324c15715c1d6cbc7d00422f47f46d649443ea9f3a63
|
|
7
|
+
data.tar.gz: bbe9885dd3811d1004a2048dd0dd88846ded2075ca21f26fe7b32f5286d63f5a014b83f0fd681bd9db61400f54bc3fabc9ec4998d791bcac578be07cfe290645
|
|
@@ -29,8 +29,7 @@ module Relaton
|
|
|
29
29
|
return unless val.is_a?(String) && !val.empty?
|
|
30
30
|
return if @text.is_a?(String) && !@text.empty?
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
self.text = description if description
|
|
32
|
+
populate_text_from_isoics
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
# When the deserializer reaches the end of the XML element and
|
|
@@ -38,9 +37,44 @@ module Relaton
|
|
|
38
37
|
# to mark the attribute as default-valued (suppressing serialization).
|
|
39
38
|
# Refuse that mark if we've already populated text from Isoics so the
|
|
40
39
|
# value survives round-trip. See #112.
|
|
40
|
+
# lutaml-model 0.8.92 (lutaml/lutaml-model#922): assignments made
|
|
41
|
+
# inside `code=` while from_xml is still mid-element do not register
|
|
42
|
+
# as explicit values. Populate once deserialization has finished.
|
|
43
|
+
def self.from_xml(node)
|
|
44
|
+
ics = super
|
|
45
|
+
# lutaml-model 0.8.92 (#922): a value assigned through a custom
|
|
46
|
+
# writer's `super` mid-deserialization is left default-suppressed.
|
|
47
|
+
# Register code as explicitly set, then populate text.
|
|
48
|
+
ics.value_set_for(:code) if ics.code.is_a?(String) && !ics.code.empty?
|
|
49
|
+
ics.populate_text_from_isoics
|
|
50
|
+
ics
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def populate_text_from_isoics
|
|
54
|
+
code.is_a?(String) && !code.empty? or return
|
|
55
|
+
@text.is_a?(String) && !@text.empty? and return
|
|
56
|
+
|
|
57
|
+
description = Isoics.fetch(code)&.description
|
|
58
|
+
self.text = description if description
|
|
59
|
+
end
|
|
60
|
+
|
|
41
61
|
def using_default_for(attribute_name)
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
# lutaml-model 0.8.92 (#922) leaves values assigned through a
|
|
63
|
+
# custom writer's `super` default-suppressed. code, when present,
|
|
64
|
+
# is always explicit; text absent from the XML is filled from
|
|
65
|
+
# Isoics here — the element end — and emitted.
|
|
66
|
+
if attribute_name == :code
|
|
67
|
+
return value_set_for(:code) if @code.is_a?(String) && !@code.empty?
|
|
68
|
+
|
|
69
|
+
return super
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
return if attribute_name == :text && @text.is_a?(String) && !@text.empty?
|
|
73
|
+
|
|
74
|
+
if attribute_name == :text
|
|
75
|
+
populate_text_from_isoics
|
|
76
|
+
return value_set_for(:text) unless @text.nil? || @text.empty?
|
|
77
|
+
end
|
|
44
78
|
|
|
45
79
|
super
|
|
46
80
|
end
|
data/lib/relaton/index/config.rb
CHANGED
|
@@ -4,7 +4,8 @@ module Relaton
|
|
|
4
4
|
# Configuration class for Relaton::Index
|
|
5
5
|
#
|
|
6
6
|
class Config
|
|
7
|
-
attr_reader :storage, :storage_dir, :filename, :build_sidecar_in_child
|
|
7
|
+
attr_reader :storage, :storage_dir, :filename, :build_sidecar_in_child,
|
|
8
|
+
:sqlite_index
|
|
8
9
|
|
|
9
10
|
#
|
|
10
11
|
# Set default values
|
|
@@ -14,6 +15,7 @@ module Relaton
|
|
|
14
15
|
@storage_dir = Dir.home
|
|
15
16
|
@filename = "index.yaml"
|
|
16
17
|
@build_sidecar_in_child = true
|
|
18
|
+
@sqlite_index = true
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
# Build the sidecar in a forked child when available, so the one-time
|
|
@@ -23,6 +25,14 @@ module Relaton
|
|
|
23
25
|
@build_sidecar_in_child = flag
|
|
24
26
|
end
|
|
25
27
|
|
|
28
|
+
# Materialize a downloaded index into SQLite so a search answers from
|
|
29
|
+
# a bucket query and the process never holds the whole index
|
|
30
|
+
# (relaton#242 phase 2). Set to false to keep the raw-row sidecar path
|
|
31
|
+
# only.
|
|
32
|
+
def sqlite_index=(flag)
|
|
33
|
+
@sqlite_index = flag
|
|
34
|
+
end
|
|
35
|
+
|
|
26
36
|
#
|
|
27
37
|
# Set storage
|
|
28
38
|
#
|
|
@@ -275,6 +275,8 @@ module Relaton
|
|
|
275
275
|
end
|
|
276
276
|
end.to_yaml
|
|
277
277
|
Index.config.storage.write file, yaml
|
|
278
|
+
delete_sidecar
|
|
279
|
+
delete_sqlite
|
|
278
280
|
end
|
|
279
281
|
|
|
280
282
|
def sort_structured_index(index)
|
|
@@ -293,14 +295,15 @@ module Relaton
|
|
|
293
295
|
def remove
|
|
294
296
|
Index.config.storage.remove file
|
|
295
297
|
delete_sidecar
|
|
298
|
+
delete_sqlite
|
|
296
299
|
[]
|
|
297
300
|
end
|
|
298
301
|
|
|
299
302
|
#
|
|
300
303
|
# Raw-row read for the lazy search path (relaton#242 stopgap): returns
|
|
301
304
|
# precomputed root-number sort keys and the rows as plain hashes — no
|
|
302
|
-
# pubid objects. A Marshal sidecar next to the yaml holds
|
|
303
|
-
#
|
|
305
|
+
# pubid objects. A Marshal sidecar next to the yaml holds them so
|
|
306
|
+
# repeat loads skip the YAML parse and the one-time full
|
|
304
307
|
# materialization; the sidecar is rebuilt whenever the yaml is newer.
|
|
305
308
|
#
|
|
306
309
|
# @return [Array<Array<String>, Array<Hash>] sort keys and raw rows
|
|
@@ -316,6 +319,147 @@ module Relaton
|
|
|
316
319
|
end
|
|
317
320
|
end
|
|
318
321
|
|
|
322
|
+
# ── SQLite backend (relaton#242 phase 2) ──
|
|
323
|
+
#
|
|
324
|
+
# The downloaded index is materialized once into a SQLite database
|
|
325
|
+
# keyed by the narrowing number. A search answers from a bucket query,
|
|
326
|
+
# so the process holds O(bucket) rows instead of the whole index. The
|
|
327
|
+
# build is pure hash transforms (no pubid objects), run in a forked
|
|
328
|
+
# child so even the one-time YAML parse never lands in this process.
|
|
329
|
+
|
|
330
|
+
def sqlite_ready?
|
|
331
|
+
url.is_a?(String) && Index.config.sqlite_index != false &&
|
|
332
|
+
File.file?(sqlite_db_path) && sqlite_fresh?
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# Ensure the db exists and is current (24 h TTL, schema-versioned).
|
|
336
|
+
def ensure_sqlite
|
|
337
|
+
return false unless url.is_a?(String)
|
|
338
|
+
return true if sqlite_ready?
|
|
339
|
+
|
|
340
|
+
with_file_lock do
|
|
341
|
+
build_sqlite unless sqlite_ready?
|
|
342
|
+
end
|
|
343
|
+
sqlite_ready?
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def sqlite_bucket(number)
|
|
347
|
+
sqlite_backend.bucket(number)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def sqlite_count
|
|
351
|
+
sqlite_backend.count
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def close_sqlite
|
|
355
|
+
@sqlite_backend&.close
|
|
356
|
+
@sqlite_backend = nil
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
def delete_sqlite
|
|
360
|
+
close_sqlite
|
|
361
|
+
File.delete(sqlite_db_path) if File.file?(sqlite_db_path)
|
|
362
|
+
rescue Errno::EACCES
|
|
363
|
+
nil
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def sqlite_db_path
|
|
367
|
+
"#{path_to_local_file}.db"
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
private
|
|
371
|
+
|
|
372
|
+
def sqlite_backend
|
|
373
|
+
@sqlite_backend ||= SqliteBackend.new(sqlite_db_path, pubid_class: @pubid_class)
|
|
374
|
+
end
|
|
375
|
+
|
|
376
|
+
def sqlite_fresh?
|
|
377
|
+
ctime = Index.config.storage.ctime(sqlite_db_path)
|
|
378
|
+
backend = sqlite_backend
|
|
379
|
+
ctime && ctime > Time.now - 86400 && !backend.stale_schema?
|
|
380
|
+
rescue SQLite3::SQLException
|
|
381
|
+
false
|
|
382
|
+
ensure
|
|
383
|
+
backend&.close
|
|
384
|
+
@sqlite_backend = nil
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# The build downloads the published zip, converts its rows to
|
|
388
|
+
# `[number, sort_key, id_json, file]` tuples by hash transforms alone,
|
|
389
|
+
# and writes the db — in a forked child where the YAML parse's memory
|
|
390
|
+
# dies with the process.
|
|
391
|
+
def build_sqlite
|
|
392
|
+
# The whole build — download, YAML parse, db write — runs in a
|
|
393
|
+
# forked child where available: the parse's ~300 MB (per flavor,
|
|
394
|
+
# larger for IETF) dies with the child, and the serving process
|
|
395
|
+
# never allocates it.
|
|
396
|
+
if Process.respond_to?(:fork) && !ENV["RELATON_NO_FORK"]
|
|
397
|
+
pid = Process.fork do
|
|
398
|
+
tuples = download_tuples
|
|
399
|
+
write_sqlite(tuples) if tuples
|
|
400
|
+
exit!(0)
|
|
401
|
+
end
|
|
402
|
+
Process.wait(pid)
|
|
403
|
+
true
|
|
404
|
+
else
|
|
405
|
+
tuples = download_tuples
|
|
406
|
+
return false unless tuples
|
|
407
|
+
|
|
408
|
+
write_sqlite(tuples)
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def write_sqlite(tuples)
|
|
413
|
+
File.dirname(sqlite_db_path).then { |d| require "fileutils"; FileUtils.mkdir_p(d) }
|
|
414
|
+
backend = SqliteBackend.new(sqlite_db_path, pubid_class: @pubid_class)
|
|
415
|
+
backend.build(tuples.each)
|
|
416
|
+
backend.close
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# Enumerate `[number, sort_key, id_hash, file]` from the published zip.
|
|
420
|
+
# The root number — the base document's, walking `base` nesting — is
|
|
421
|
+
# computed on the raw hash; no pubid object is ever built.
|
|
422
|
+
def download_tuples
|
|
423
|
+
body = Net::HTTP.get(URI.parse(url))
|
|
424
|
+
# rubyzip may mutate the buffer it is handed; a StringIO over a copy
|
|
425
|
+
# keeps the response body intact for any later reader of it.
|
|
426
|
+
yaml = nil
|
|
427
|
+
Zip::File.open_buffer(StringIO.new(body.dup)) do |zip|
|
|
428
|
+
stream = zip.entries.first.get_input_stream
|
|
429
|
+
yaml = stream.read
|
|
430
|
+
end
|
|
431
|
+
yaml = yaml.read unless yaml.is_a?(String)
|
|
432
|
+
Util.info "Downloaded index from `#{url}` for sqlite materialization", progname
|
|
433
|
+
raw = YAML.safe_load(yaml, permitted_classes: [Symbol])
|
|
434
|
+
return nil unless check_format(raw)
|
|
435
|
+
|
|
436
|
+
Enumerator.new do |y|
|
|
437
|
+
raw.each do |r|
|
|
438
|
+
number = raw_root_number(r[:id]).to_s
|
|
439
|
+
y << [number, number, r[:id], r[:file]]
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
rescue Psych::SyntaxError, SocketError, OpenURI::HTTPError, Errno::ECONNRESET,
|
|
443
|
+
OpenSSL::SSL::SSLError => e
|
|
444
|
+
Util.info "SQLite index build failed (#{e.message}); falling back", progname
|
|
445
|
+
nil
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
# `#root` as a hash walk: a supplement nests its origin under `base`,
|
|
449
|
+
# and the flattened to_hash puts the supplement's own components first.
|
|
450
|
+
# Accepts string and symbol keys — a YAML round-trip with permitted
|
|
451
|
+
# Symbol may give either.
|
|
452
|
+
def raw_root_number(id_hash)
|
|
453
|
+
return nil unless id_hash.is_a?(Hash)
|
|
454
|
+
|
|
455
|
+
base = id_hash["base"] || id_hash[:base]
|
|
456
|
+
return raw_root_number(base) if base
|
|
457
|
+
|
|
458
|
+
id_hash["number"] || id_hash[:number]
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
public
|
|
462
|
+
|
|
319
463
|
# Deserialize raw rows into pubid rows. Only the caller knows which
|
|
320
464
|
# slice it needs, so materialization happens here rather than at load.
|
|
321
465
|
#
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "sqlite3"
|
|
4
|
+
|
|
5
|
+
module Relaton
|
|
6
|
+
module Index
|
|
7
|
+
#
|
|
8
|
+
# The SQLite materialization of one flavor index (relaton#242 phase 2).
|
|
9
|
+
#
|
|
10
|
+
# A downloaded index zip is built once into a local database whose rows
|
|
11
|
+
# are `(number, sort_key, id_json, file)` with an index on `number` — the
|
|
12
|
+
# narrowing key. A search materializes only its bucket; the whole index
|
|
13
|
+
# is never resident. WAL journaling lets one build and concurrent readers
|
|
14
|
+
# share the file across processes.
|
|
15
|
+
#
|
|
16
|
+
class SqliteBackend
|
|
17
|
+
SCHEMA_VERSION = "1"
|
|
18
|
+
|
|
19
|
+
def initialize(db_path, pubid_class: nil)
|
|
20
|
+
@db_path = db_path
|
|
21
|
+
@pubid_class = pubid_class
|
|
22
|
+
@db = SQLite3::Database.new(db_path)
|
|
23
|
+
@db.busy_timeout = 30_000
|
|
24
|
+
@db.results_as_hash = false
|
|
25
|
+
@db.execute("PRAGMA journal_mode=WAL")
|
|
26
|
+
@db.execute("PRAGMA synchronous=NORMAL")
|
|
27
|
+
create_schema
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Build from an enumerator of `[number, sort_key, id_hash, file]`
|
|
31
|
+
# tuples. Callers hand the child process's enumerator here; the tuples
|
|
32
|
+
# are written inside one transaction.
|
|
33
|
+
def build(rows_enum)
|
|
34
|
+
@db.transaction do
|
|
35
|
+
@db.execute("DELETE FROM index_rows")
|
|
36
|
+
@db.prepare("INSERT INTO index_rows (number, sort_key, id_json, file) VALUES (?, ?, ?, ?)") do |stmt|
|
|
37
|
+
rows_enum.each { |(number, sort_key, id_hash, file)| stmt.execute(number, sort_key, JSON.generate(id_hash), file) }
|
|
38
|
+
end
|
|
39
|
+
meta_set("schema_version", SCHEMA_VERSION)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# The bucket for a narrowing key: raw rows, ordered as written.
|
|
44
|
+
def bucket(number)
|
|
45
|
+
rows = []
|
|
46
|
+
@db.execute("SELECT id_json, file FROM index_rows WHERE number = ? ORDER BY rowid", [number]) do |row|
|
|
47
|
+
rows << { id: JSON.parse(row[0]), file: row[1] }
|
|
48
|
+
end
|
|
49
|
+
rows
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def each_row
|
|
53
|
+
@db.execute("SELECT id_json, file FROM index_rows ORDER BY rowid") do |row|
|
|
54
|
+
yield({ id: JSON.parse(row[0]), file: row[1] })
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def count
|
|
59
|
+
@db.get_first_value("SELECT COUNT(*) FROM index_rows").to_i
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def stale_schema?
|
|
63
|
+
meta_get("schema_version") != SCHEMA_VERSION
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def close
|
|
67
|
+
@db.close
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def create_schema
|
|
73
|
+
@db.execute(<<~SQL)
|
|
74
|
+
CREATE TABLE IF NOT EXISTS index_rows (
|
|
75
|
+
number TEXT NOT NULL,
|
|
76
|
+
sort_key TEXT NOT NULL,
|
|
77
|
+
id_json TEXT NOT NULL,
|
|
78
|
+
file TEXT NOT NULL
|
|
79
|
+
)
|
|
80
|
+
SQL
|
|
81
|
+
@db.execute("CREATE INDEX IF NOT EXISTS idx_index_rows_number ON index_rows (number)")
|
|
82
|
+
@db.execute(<<~SQL)
|
|
83
|
+
CREATE TABLE IF NOT EXISTS index_meta (
|
|
84
|
+
key TEXT PRIMARY KEY,
|
|
85
|
+
value TEXT NOT NULL
|
|
86
|
+
)
|
|
87
|
+
SQL
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def meta_set(key, value)
|
|
91
|
+
@db.execute("INSERT OR REPLACE INTO index_meta (key, value) VALUES (?, ?)", [key, value])
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def meta_get(key)
|
|
95
|
+
@db.get_first_value("SELECT value FROM index_meta WHERE key = ?", [key])
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
data/lib/relaton/index/type.rb
CHANGED
|
@@ -228,17 +228,28 @@ module Relaton
|
|
|
228
228
|
# never refreshed, so the shards stay the fresher answer.
|
|
229
229
|
return @source.rows(id) if @source && id && !id.is_a?(String)
|
|
230
230
|
|
|
231
|
-
# The
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
# Load first: a pubid-backed load is what settles @file_io.sorted.
|
|
231
|
+
# The SQLite backend answers a parsed query with a bucket query:
|
|
232
|
+
# O(bucket) rows ever resident, no sidecar load at all. Falls back
|
|
233
|
+
# to the raw-row path when the backend cannot build or is disabled.
|
|
235
234
|
if id && !id.is_a?(String) && @file_io.pubid_class
|
|
235
|
+
begin
|
|
236
|
+
return sqlite_candidates(id) if @file_io.ensure_sqlite
|
|
237
|
+
rescue SQLite3::SQLException
|
|
238
|
+
nil # fall back to the sidecar path below
|
|
239
|
+
end
|
|
240
|
+
|
|
236
241
|
raw_index
|
|
237
242
|
return candidates_by_number(id) if @file_io.sorted
|
|
238
243
|
end
|
|
239
244
|
index
|
|
240
245
|
end
|
|
241
246
|
|
|
247
|
+
def sqlite_candidates(id)
|
|
248
|
+
target = id.root.number.to_s
|
|
249
|
+
rows = @file_io.sqlite_bucket(target)
|
|
250
|
+
@file_io.materialize(rows)
|
|
251
|
+
end
|
|
252
|
+
|
|
242
253
|
# Narrowing key: the base *document's* number as a string. `#root` walks a
|
|
243
254
|
# supplement/amendment/corrigendum's `.base` chain to the origin (and
|
|
244
255
|
# returns self for a base document), so a document and all its wrappers
|
data/lib/relaton/index.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "yaml"
|
|
4
4
|
require "zip"
|
|
5
|
+
require "open-uri"
|
|
5
6
|
require "relaton/logger"
|
|
6
7
|
|
|
7
8
|
require_relative "version"
|
|
@@ -10,9 +11,10 @@ require_relative "index/file_storage"
|
|
|
10
11
|
require_relative "index/config"
|
|
11
12
|
require_relative "index/util"
|
|
12
13
|
require_relative "index/pool"
|
|
13
|
-
require_relative "index/type"
|
|
14
14
|
require_relative "index/file_io"
|
|
15
15
|
require_relative "index/shard_source"
|
|
16
|
+
require_relative "index/sqlite_backend"
|
|
17
|
+
require_relative "index/type"
|
|
16
18
|
|
|
17
19
|
module Relaton
|
|
18
20
|
module Index
|
data/lib/relaton/version.rb
CHANGED
data/lib/relaton.rb
CHANGED
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
require "relaton/version"
|
|
8
8
|
require "moxml"
|
|
9
9
|
|
|
10
|
-
# YAML through
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
require "
|
|
10
|
+
# YAML through stdlib Psych. The former yeptris drop-in rebind
|
|
11
|
+
# (require "yeptris/psych/drop_in") replaced ::Psych for the WHOLE
|
|
12
|
+
# host process: every gem that later loaded YAML — glossarist/iev's
|
|
13
|
+
# ISO 639 table, metanorma-cli's collections, anything psych-lenient
|
|
14
|
+
# — silently changed engine, and yeptris 0.6.28.4 diverges from psych
|
|
15
|
+
# (block-scalar headers at column 1, permitted_classes ignored; see
|
|
16
|
+
# yeptris-ruby#258). A library must never rebind global constants;
|
|
17
|
+
# the namespaced Yeptris::Psych API remains the opt-in path for hosts
|
|
18
|
+
# that want it.
|
|
19
|
+
require "yaml"
|
|
20
20
|
|
|
21
21
|
module Relaton
|
|
22
22
|
autoload :Logger, "relaton/logger"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: relaton
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0.0.pre.alpha.
|
|
4
|
+
version: 3.0.0.pre.alpha.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -94,6 +94,20 @@ dependencies:
|
|
|
94
94
|
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
96
|
version: '1.0'
|
|
97
|
+
- !ruby/object:Gem::Dependency
|
|
98
|
+
name: sqlite3
|
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
|
100
|
+
requirements:
|
|
101
|
+
- - "~>"
|
|
102
|
+
- !ruby/object:Gem::Version
|
|
103
|
+
version: '1.7'
|
|
104
|
+
type: :runtime
|
|
105
|
+
prerelease: false
|
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - "~>"
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '1.7'
|
|
97
111
|
- !ruby/object:Gem::Dependency
|
|
98
112
|
name: csv
|
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -933,6 +947,7 @@ files:
|
|
|
933
947
|
- lib/relaton/index/file_storage.rb
|
|
934
948
|
- lib/relaton/index/pool.rb
|
|
935
949
|
- lib/relaton/index/shard_source.rb
|
|
950
|
+
- lib/relaton/index/sqlite_backend.rb
|
|
936
951
|
- lib/relaton/index/type.rb
|
|
937
952
|
- lib/relaton/index/util.rb
|
|
938
953
|
- lib/relaton/isbn.rb
|