relaton 1.8.pre3 → 1.9.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 +4 -4
- data/.github/workflows/rake.yml +1 -11
- data/lib/relaton/config.rb +2 -4
- data/lib/relaton/db.rb +55 -92
- data/lib/relaton/db_cache.rb +125 -38
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton.rb +0 -1
- data/relaton.gemspec +18 -22
- data/spec/relaton/db_cache_spec.rb +2 -2
- data/spec/relaton/db_spec.rb +0 -17
- data/spec/relaton/regirtry_spec.rb +1 -1
- data/spec/relaton_spec.rb +17 -51
- data/spec/spec_helper.rb +0 -4
- data/spec/vcr_cassetes/api_relaton_org.yml +14 -8
- data/spec/vcr_cassetes/api_relaton_org_unavailable.yml +56 -40
- data/spec/vcr_cassetes/async_fetch.yml +1302 -1302
- data/spec/vcr_cassetes/bsi_bs_en_iso_8848.yml +117 -114
- data/spec/vcr_cassetes/cc_dir_10005_2019.yml +16 -16
- data/spec/vcr_cassetes/cen_en_10160_1999.yml +30 -30
- data/spec/vcr_cassetes/cie_001_1980.yml +7 -7
- data/spec/vcr_cassetes/ecma_6.yml +7 -7
- data/spec/vcr_cassetes/fisp_140.yml +4 -4
- data/spec/vcr_cassetes/gb_t_20223_2006.yml +6 -6
- data/spec/vcr_cassetes/iec_60050_102_2007.yml +28 -28
- data/spec/vcr_cassetes/iec_combined_included.yml +88 -90
- data/spec/vcr_cassetes/ieee_528_2019.yml +18 -18
- data/spec/vcr_cassetes/iho_b_11.yml +7 -7
- data/spec/vcr_cassetes/iso_111111119115_1.yml +45 -26
- data/spec/vcr_cassetes/iso_19115_1.yml +55 -39
- data/spec/vcr_cassetes/iso_19115_1_2.yml +113 -81
- data/spec/vcr_cassetes/iso_19115_all_parts.yml +198 -0
- data/spec/vcr_cassetes/{19133_2005.yml → iso_19133_2005.yml} +57 -41
- data/spec/vcr_cassetes/iso_awi_14093.yml +62 -42
- data/spec/vcr_cassetes/iso_combined_applied.yml +112 -80
- data/spec/vcr_cassetes/iso_combined_included.yml +112 -80
- data/spec/vcr_cassetes/itu_combined_included.yml +161 -161
- data/spec/vcr_cassetes/ogc_19_025r1.yml +1168 -1160
- data/spec/vcr_cassetes/omg_ami4ccm_1_0.yml +4 -4
- data/spec/vcr_cassetes/rfc_8341.yml +7 -7
- data/spec/vcr_cassetes/sp_800_38b.yml +4 -4
- data/spec/vcr_cassetes/un_rtade_cefact_2004_32.yml +29 -29
- data/spec/vcr_cassetes/w3c_json_ld11.yml +12 -12
- metadata +42 -61
- data/lib/relaton/storage.rb +0 -186
- data/spec/relaton/storage_spec.rb +0 -130
- data/spec/vcr_cassetes/hist_cmbined_included.yml +0 -105
- data/spec/vcr_cassetes/iso_19115.yml +0 -182
- data/spec/vcr_cassetes/iso_iec_guide_2.yml +0 -232
- data/spec/vcr_cassetes/rfc_unsuccess.yml +0 -70
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9a47a3437f5f8afb131ea6cf2a0cf1714875f45e3bd3881c17bc8c7ab9cc2101
|
|
4
|
+
data.tar.gz: b2a25232edd0d71d5597c06c011362771326bdf3369272e9ca5c862b76947427
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2c99ab3fe479d11714a2848656076685057f9169d59d548530a60e8405d8be23d7f1a04b79744e6fbd112d4495e2cf5d1451d7e3f769fa0bb8844874281dee72
|
|
7
|
+
data.tar.gz: 48d30e142c8a611f97ebc9eb0aed6f3619ec2784e9856b1e659473b52c48fdae77c131c29241087c8a31e59623ed3830e383d75103fe42e18416a0a06c251c66
|
data/.github/workflows/rake.yml
CHANGED
|
@@ -16,19 +16,9 @@ jobs:
|
|
|
16
16
|
strategy:
|
|
17
17
|
fail-fast: false
|
|
18
18
|
matrix:
|
|
19
|
-
ruby: [ '2.7', '2.6', '2.5' ]
|
|
19
|
+
ruby: [ '3.0', '2.7', '2.6', '2.5' ]
|
|
20
20
|
os: [ ubuntu-latest, windows-latest, macos-latest ]
|
|
21
21
|
experimental: [ false ]
|
|
22
|
-
include:
|
|
23
|
-
- ruby: '3.0'
|
|
24
|
-
os: 'ubuntu-latest'
|
|
25
|
-
experimental: true
|
|
26
|
-
- ruby: '3.0'
|
|
27
|
-
os: 'windows-latest'
|
|
28
|
-
experimental: true
|
|
29
|
-
- ruby: '3.0'
|
|
30
|
-
os: 'macos-latest'
|
|
31
|
-
experimental: true
|
|
32
22
|
steps:
|
|
33
23
|
- uses: actions/checkout@v2
|
|
34
24
|
with:
|
data/lib/relaton/config.rb
CHANGED
|
@@ -12,15 +12,13 @@ module Relaton
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
class Configuration
|
|
15
|
-
attr_accessor :logs, :use_api
|
|
15
|
+
attr_accessor :logs, :use_api
|
|
16
16
|
|
|
17
17
|
def initialize
|
|
18
18
|
@logs = %i(info error) # allowed values: :info, :warning, :error, :debug
|
|
19
19
|
|
|
20
20
|
# @TODO change to true when we start using api.relaton.org
|
|
21
|
-
@use_api =
|
|
22
|
-
@api_mode = false
|
|
23
|
-
@api_host = "https://api.relaton.org/api/v1"
|
|
21
|
+
@use_api = false
|
|
24
22
|
end
|
|
25
23
|
end
|
|
26
24
|
|
data/lib/relaton/db.rb
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
+
require "yaml"
|
|
2
|
+
require_relative "registry"
|
|
3
|
+
require_relative "db_cache"
|
|
4
|
+
|
|
1
5
|
module Relaton
|
|
2
|
-
|
|
6
|
+
class RelatonError < StandardError; end
|
|
3
7
|
|
|
4
8
|
class Db
|
|
5
9
|
# @param global_cache [String] directory of global DB
|
|
6
10
|
# @param local_cache [String] directory of local DB
|
|
7
|
-
def initialize(global_cache, local_cache)
|
|
11
|
+
def initialize(global_cache, local_cache)
|
|
8
12
|
@registry = Relaton::Registry.instance
|
|
9
|
-
|
|
10
|
-
gpath = global_cache
|
|
11
|
-
lpath = local_cache
|
|
12
|
-
else
|
|
13
|
-
gpath = global_cache && File.expand_path(global_cache)
|
|
14
|
-
lpath = local_cache && File.expand_path(local_cache)
|
|
15
|
-
end
|
|
13
|
+
gpath = global_cache && File.expand_path(global_cache)
|
|
16
14
|
@db = open_cache_biblio(gpath, type: :global)
|
|
15
|
+
lpath = local_cache && File.expand_path(local_cache)
|
|
17
16
|
@local_db = open_cache_biblio(lpath, type: :local)
|
|
18
|
-
@static_db = open_cache_biblio File.expand_path
|
|
17
|
+
@static_db = open_cache_biblio File.expand_path("../relaton/static_cache",
|
|
18
|
+
__dir__)
|
|
19
19
|
@queues = {}
|
|
20
20
|
end
|
|
21
21
|
|
|
@@ -25,8 +25,10 @@ module Relaton
|
|
|
25
25
|
# @return [String, nil]
|
|
26
26
|
def mv(new_dir, type: :global)
|
|
27
27
|
case type
|
|
28
|
-
when :global
|
|
29
|
-
|
|
28
|
+
when :global
|
|
29
|
+
@db&.mv new_dir
|
|
30
|
+
when :local
|
|
31
|
+
@local_db&.mv new_dir
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
|
|
@@ -87,15 +89,19 @@ module Relaton
|
|
|
87
89
|
result = @static_db.all do |file, yml|
|
|
88
90
|
search_yml file, yml, text, edition, year
|
|
89
91
|
end.compact
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
db = @db || @local_db
|
|
93
|
+
if db
|
|
94
|
+
result += db.all do |file, xml|
|
|
95
|
+
search_xml file, xml, text, edition, year
|
|
96
|
+
end.compact
|
|
92
97
|
end
|
|
93
98
|
result
|
|
94
99
|
end
|
|
95
100
|
|
|
96
101
|
# Fetch asynchronously
|
|
97
102
|
def fetch_async(code, year = nil, opts = {}, &_block) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
98
|
-
|
|
103
|
+
stdclass = standard_class code
|
|
104
|
+
if stdclass
|
|
99
105
|
unless @queues[stdclass]
|
|
100
106
|
processor = @registry.processors[stdclass]
|
|
101
107
|
wp = WorkersPool.new(processor.threads) { |args| yield fetch(*args) }
|
|
@@ -167,43 +173,14 @@ module Relaton
|
|
|
167
173
|
def to_xml
|
|
168
174
|
db = @local_db || @db || return
|
|
169
175
|
Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
|
170
|
-
xml.documents
|
|
176
|
+
xml.documents do
|
|
177
|
+
xml.parent.add_child db.all.join(" ")
|
|
178
|
+
end
|
|
171
179
|
end.to_xml
|
|
172
180
|
end
|
|
173
181
|
|
|
174
182
|
private
|
|
175
183
|
|
|
176
|
-
#
|
|
177
|
-
# @param code [String]
|
|
178
|
-
# @param year [String]
|
|
179
|
-
#
|
|
180
|
-
# @param opts [Hash]
|
|
181
|
-
# @option opts [Boolean] :all_parts If all-parts reference is required
|
|
182
|
-
# @option opts [Boolean] :keep_year If undated reference should return
|
|
183
|
-
# actual reference with year
|
|
184
|
-
#
|
|
185
|
-
# @param stdclass [Symbol]
|
|
186
|
-
def fetch_api(code, year, opts, stdclass)
|
|
187
|
-
return unless Relaton.configuration.use_api
|
|
188
|
-
|
|
189
|
-
url = "#{Relaton.configuration.api_host}/document?#{params(code, year, opts)}"
|
|
190
|
-
rsp = Net::HTTP.get_response URI(url)
|
|
191
|
-
@registry.processors[stdclass].from_xml rsp.body if rsp.code == "200"
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
#
|
|
195
|
-
# Make string of parametrs
|
|
196
|
-
#
|
|
197
|
-
# @param [String] code
|
|
198
|
-
# @param [String] year
|
|
199
|
-
# @param [Hash] opts
|
|
200
|
-
#
|
|
201
|
-
# @return [String]
|
|
202
|
-
#
|
|
203
|
-
def params(code, year, opts)
|
|
204
|
-
opts.merge(code: code, year: year).map { |k, v| "#{k}=#{v}" }.join "&"
|
|
205
|
-
end
|
|
206
|
-
|
|
207
184
|
# @param file [String] file path
|
|
208
185
|
# @param yml [String] content in YAML format
|
|
209
186
|
# @param text [String, nil] text to serach
|
|
@@ -230,7 +207,7 @@ module Relaton
|
|
|
230
207
|
end
|
|
231
208
|
|
|
232
209
|
# @param file [String] file path
|
|
233
|
-
# @param content [String] content in XML or
|
|
210
|
+
# @param content [String] content in XML or YAmL format
|
|
234
211
|
# @param edition [String, nil] edition to filter
|
|
235
212
|
# @param year [Integer, nil] year to filter
|
|
236
213
|
# @return [BibliographicItem, nil]
|
|
@@ -243,14 +220,9 @@ module Relaton
|
|
|
243
220
|
item.date.detect { |d| d.type == "published" && d.on(:year).to_s == year.to_s })
|
|
244
221
|
end
|
|
245
222
|
|
|
246
|
-
#
|
|
247
|
-
# Look up text in the XML elements attributes and content
|
|
248
|
-
#
|
|
249
223
|
# @param xml [String] content in XML format
|
|
250
224
|
# @param text [String, nil] text to serach
|
|
251
|
-
#
|
|
252
225
|
# @return [Boolean]
|
|
253
|
-
#
|
|
254
226
|
def match_xml_text(xml, text)
|
|
255
227
|
%r{((?<attr>=((?<apstr>')|"))|>).*?#{text}.*?(?(<attr>)(?(<apstr>)'|")|<)}mi.match?(xml)
|
|
256
228
|
end
|
|
@@ -284,15 +256,19 @@ module Relaton
|
|
|
284
256
|
end
|
|
285
257
|
|
|
286
258
|
doc = @registry.processors[stdclass].hash_to_bib docid: { id: code }
|
|
287
|
-
|
|
259
|
+
ref = refs[0]
|
|
260
|
+
updates = check_bibliocache(ref, year, opts, stdclass)
|
|
288
261
|
if updates
|
|
289
|
-
doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates,
|
|
262
|
+
doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates,
|
|
263
|
+
type: "updates")
|
|
290
264
|
end
|
|
291
265
|
divider = stdclass == :relaton_itu ? " " : "/"
|
|
292
266
|
refs[1..-1].each_with_object(doc) do |c, d|
|
|
293
|
-
bib = check_bibliocache(
|
|
267
|
+
bib = check_bibliocache(ref + divider + c, year, opts, stdclass)
|
|
294
268
|
if bib
|
|
295
|
-
d.relation << RelatonBib::DocumentRelation.new(
|
|
269
|
+
d.relation << RelatonBib::DocumentRelation.new(
|
|
270
|
+
type: reltype, description: reldesc, bibitem: bib
|
|
271
|
+
)
|
|
296
272
|
end
|
|
297
273
|
end
|
|
298
274
|
end
|
|
@@ -304,7 +280,9 @@ module Relaton
|
|
|
304
280
|
return name if /^(urn:)?#{processor.prefix}/i.match?(code) ||
|
|
305
281
|
processor.defaultprefix.match(code)
|
|
306
282
|
end
|
|
307
|
-
allowed = @registry.processors.reduce([])
|
|
283
|
+
allowed = @registry.processors.reduce([]) do |m, (_k, v)|
|
|
284
|
+
m << v.prefix
|
|
285
|
+
end
|
|
308
286
|
Util.log <<~WARN, :info
|
|
309
287
|
[relaton] #{code} does not have a recognised prefix: #{allowed.join(', ')}.
|
|
310
288
|
See https://github.com/relaton/relaton/ for instructions on prefixing and wrapping document identifiers to disambiguate them.
|
|
@@ -353,8 +331,8 @@ module Relaton
|
|
|
353
331
|
# RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
|
|
354
332
|
# RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
|
|
355
333
|
def bib_retval(entry, stdclass)
|
|
356
|
-
|
|
357
|
-
|
|
334
|
+
if entry.nil? || entry.match?(/^not_found/) then nil
|
|
335
|
+
else @registry.processors[stdclass].from_xml(entry)
|
|
358
336
|
end
|
|
359
337
|
end
|
|
360
338
|
|
|
@@ -378,7 +356,8 @@ module Relaton
|
|
|
378
356
|
# RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
|
|
379
357
|
def check_bibliocache(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
380
358
|
id, searchcode = std_id(code, year, opts, stdclass)
|
|
381
|
-
|
|
359
|
+
yaml = @static_db[id]
|
|
360
|
+
if yaml
|
|
382
361
|
return @registry.processors[stdclass].hash_to_bib YAML.safe_load(yaml)
|
|
383
362
|
end
|
|
384
363
|
|
|
@@ -387,7 +366,8 @@ module Relaton
|
|
|
387
366
|
if db.nil?
|
|
388
367
|
return if opts[:fetch_db]
|
|
389
368
|
|
|
390
|
-
bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db,
|
|
369
|
+
bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db,
|
|
370
|
+
id: id)
|
|
391
371
|
return bib_retval(bibentry, stdclass)
|
|
392
372
|
end
|
|
393
373
|
|
|
@@ -396,17 +376,18 @@ module Relaton
|
|
|
396
376
|
return bib_retval(altdb[id], stdclass) if opts[:fetch_db]
|
|
397
377
|
|
|
398
378
|
db.clone_entry id, altdb if altdb.valid_entry? id, year
|
|
399
|
-
db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
|
|
379
|
+
db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
|
|
380
|
+
id: id)
|
|
400
381
|
altdb.clone_entry(id, db) if !altdb.valid_entry?(id, year)
|
|
401
382
|
else
|
|
402
383
|
return bib_retval(db[id], stdclass) if opts[:fetch_db]
|
|
403
384
|
|
|
404
|
-
db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
|
|
385
|
+
db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
|
|
386
|
+
id: id)
|
|
405
387
|
end
|
|
406
388
|
bib_retval(db[id], stdclass)
|
|
407
389
|
end
|
|
408
390
|
|
|
409
|
-
#
|
|
410
391
|
# @param code [String]
|
|
411
392
|
# @param year [String]
|
|
412
393
|
#
|
|
@@ -419,9 +400,7 @@ module Relaton
|
|
|
419
400
|
# @param stdclass [Symbol]
|
|
420
401
|
# @param db [Relaton::DbCache,`NilClass]
|
|
421
402
|
# @param id [String] docid
|
|
422
|
-
#
|
|
423
403
|
# @return [String]
|
|
424
|
-
#
|
|
425
404
|
def new_bib_entry(code, year, opts, stdclass, **args) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
|
|
426
405
|
bib = net_retry(code, year, opts, stdclass, opts.fetch(:retries, 1))
|
|
427
406
|
bib_id = bib&.docidentifier&.first&.id
|
|
@@ -436,27 +415,8 @@ module Relaton
|
|
|
436
415
|
end
|
|
437
416
|
end
|
|
438
417
|
|
|
439
|
-
#
|
|
440
|
-
# @param code [String]
|
|
441
|
-
# @param year [String]
|
|
442
|
-
#
|
|
443
|
-
# @param opts [Hash]
|
|
444
|
-
# @option opts [Boolean] :all_parts If all-parts reference is required
|
|
445
|
-
# @option opts [Boolean] :keep_year If undated reference should return
|
|
446
|
-
# actual reference with year
|
|
447
|
-
#
|
|
448
|
-
# @param stdclass [Symbol]
|
|
449
|
-
# @param retries [Integer] remain Number of network retries
|
|
450
|
-
#
|
|
451
418
|
# @raise [RelatonBib::RequestError]
|
|
452
|
-
# @return [RelatonBib::BibliographicItem]
|
|
453
|
-
#
|
|
454
419
|
def net_retry(code, year, opts, stdclass, retries)
|
|
455
|
-
doc = fetch_api code, year, opts, stdclass
|
|
456
|
-
return doc if doc
|
|
457
|
-
|
|
458
|
-
@registry.processors[stdclass].get(code, year, opts)
|
|
459
|
-
rescue Errno::ECONNREFUSED
|
|
460
420
|
@registry.processors[stdclass].get(code, year, opts)
|
|
461
421
|
rescue RelatonBib::RequestError => e
|
|
462
422
|
raise e unless retries > 1
|
|
@@ -474,7 +434,11 @@ module Relaton
|
|
|
474
434
|
# RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
|
|
475
435
|
# @return [String] XML or "not_found mm-dd-yyyy"
|
|
476
436
|
def bib_entry(bib)
|
|
477
|
-
bib.respond_to?
|
|
437
|
+
if bib.respond_to? :to_xml
|
|
438
|
+
bib.to_xml(bibdata: true)
|
|
439
|
+
else
|
|
440
|
+
"not_found #{Date.today}"
|
|
441
|
+
end
|
|
478
442
|
end
|
|
479
443
|
|
|
480
444
|
# @param dir [String, nil] DB directory
|
|
@@ -492,7 +456,8 @@ module Relaton
|
|
|
492
456
|
FileUtils.rm_rf(fdir, secure: true)
|
|
493
457
|
Util.log(
|
|
494
458
|
"[relaton] WARNING: cache #{fdir}: version is obsolete and cache is "\
|
|
495
|
-
"cleared.",
|
|
459
|
+
"cleared.",
|
|
460
|
+
:warning
|
|
496
461
|
)
|
|
497
462
|
end
|
|
498
463
|
db
|
|
@@ -525,13 +490,11 @@ module Relaton
|
|
|
525
490
|
end
|
|
526
491
|
|
|
527
492
|
def global_bibliocache_name
|
|
528
|
-
|
|
493
|
+
"#{Dir.home}/.relaton/cache"
|
|
529
494
|
end
|
|
530
495
|
|
|
531
496
|
def local_bibliocache_name(cachename)
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
cachename = "relaton" if cachename.empty?
|
|
497
|
+
cachename = "relaton" if cachename.nil? || cachename.empty?
|
|
535
498
|
"#{cachename}/cache"
|
|
536
499
|
end
|
|
537
500
|
end
|
data/lib/relaton/db_cache.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
require "fileutils"
|
|
2
2
|
require "timeout"
|
|
3
|
-
require "relaton/storage"
|
|
4
3
|
|
|
5
4
|
module Relaton
|
|
6
5
|
class DbCache
|
|
@@ -11,15 +10,16 @@ module Relaton
|
|
|
11
10
|
def initialize(dir, ext = "xml")
|
|
12
11
|
@dir = dir
|
|
13
12
|
@ext = ext
|
|
14
|
-
@
|
|
15
|
-
|
|
13
|
+
FileUtils::mkdir_p @dir
|
|
14
|
+
# file_version = "#{@dir}/version"
|
|
15
|
+
# set_version # unless File.exist? file_version
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
# Move caches to anothe dir
|
|
19
19
|
# @param new_dir [String, nil]
|
|
20
20
|
# @return [String, nil]
|
|
21
21
|
def mv(new_dir)
|
|
22
|
-
return unless new_dir && @ext == "xml"
|
|
22
|
+
return unless new_dir && @ext == "xml"
|
|
23
23
|
|
|
24
24
|
if File.exist? new_dir
|
|
25
25
|
warn "[relaton] WARNING: target directory exists \"#{new_dir}\""
|
|
@@ -32,9 +32,7 @@ module Relaton
|
|
|
32
32
|
|
|
33
33
|
# Clear database
|
|
34
34
|
def clear
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
FileUtils.rm_rf Dir.glob "#{dir}/*" if @ext == "xml" # if it's static DB
|
|
35
|
+
FileUtils.rm_rf Dir.glob "#{dir}/*" if @ext == "xml" # unless it's static DB
|
|
38
36
|
end
|
|
39
37
|
|
|
40
38
|
# Save item
|
|
@@ -45,10 +43,21 @@ module Relaton
|
|
|
45
43
|
delete key
|
|
46
44
|
return
|
|
47
45
|
end
|
|
48
|
-
|
|
49
|
-
prefix_dir = "#{@dir}/#{
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
|
|
47
|
+
prefix_dir = "#{@dir}/#{prefix(key)}"
|
|
48
|
+
FileUtils::mkdir_p prefix_dir unless Dir.exist? prefix_dir
|
|
49
|
+
set_version prefix_dir
|
|
50
|
+
file_safe_write "#{filename(key)}.#{ext(value)}", value
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @param value [String]
|
|
54
|
+
# @return [String]
|
|
55
|
+
def ext(value)
|
|
56
|
+
case value
|
|
57
|
+
when /^not_found/ then "notfound"
|
|
58
|
+
when /^redirection/ then "redirect"
|
|
59
|
+
else @ext
|
|
60
|
+
end
|
|
52
61
|
end
|
|
53
62
|
|
|
54
63
|
# Read item
|
|
@@ -77,7 +86,7 @@ module Relaton
|
|
|
77
86
|
value = self[key]
|
|
78
87
|
return unless value
|
|
79
88
|
|
|
80
|
-
if value.match?
|
|
89
|
+
if value.match? /^not_found/
|
|
81
90
|
value.match(/\d{4}-\d{2}-\d{2}/).to_s
|
|
82
91
|
else
|
|
83
92
|
doc = Nokogiri::XML value
|
|
@@ -87,21 +96,41 @@ module Relaton
|
|
|
87
96
|
|
|
88
97
|
# Returns all items
|
|
89
98
|
# @return [Array<String>]
|
|
90
|
-
def all
|
|
91
|
-
|
|
99
|
+
def all
|
|
100
|
+
Dir.glob("#{@dir}/**/*.{xml,yml,yaml}").sort.map do |f|
|
|
101
|
+
content = File.read(f, encoding: "utf-8")
|
|
102
|
+
block_given? ? yield(f, content) : content
|
|
103
|
+
end
|
|
92
104
|
end
|
|
93
105
|
|
|
94
106
|
# Delete item
|
|
95
107
|
# @param key [String]
|
|
96
108
|
def delete(key)
|
|
97
|
-
|
|
109
|
+
file = filename key
|
|
110
|
+
f = search_ext(file)
|
|
111
|
+
File.delete f if f
|
|
98
112
|
end
|
|
99
113
|
|
|
100
114
|
# Check if version of the DB match to the gem grammar hash.
|
|
101
115
|
# @param fdir [String] dir pathe to flover cache
|
|
102
|
-
# @return [
|
|
116
|
+
# @return [TrueClass, FalseClass]
|
|
103
117
|
def check_version?(fdir)
|
|
104
|
-
|
|
118
|
+
version_dir = fdir + "/version"
|
|
119
|
+
return false unless File.exist? version_dir
|
|
120
|
+
|
|
121
|
+
v = File.read version_dir, encoding: "utf-8"
|
|
122
|
+
v.strip == grammar_hash(fdir)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Set version of the DB to the gem grammar hash.
|
|
126
|
+
# @param fdir [String] dir pathe to flover cache
|
|
127
|
+
# @return [Relaton::DbCache]
|
|
128
|
+
def set_version(fdir)
|
|
129
|
+
file_version = "#{fdir}/version"
|
|
130
|
+
unless File.exist? file_version
|
|
131
|
+
file_safe_write file_version, grammar_hash(fdir)
|
|
132
|
+
end
|
|
133
|
+
self
|
|
105
134
|
end
|
|
106
135
|
|
|
107
136
|
# if cached reference is undated, expire it after 60 days
|
|
@@ -115,54 +144,112 @@ module Relaton
|
|
|
115
144
|
year || Date.today - date < 60
|
|
116
145
|
end
|
|
117
146
|
|
|
147
|
+
protected
|
|
148
|
+
|
|
149
|
+
# @param fdir [String] dir pathe to flover cache
|
|
150
|
+
# @return [String]
|
|
151
|
+
def grammar_hash(fdir)
|
|
152
|
+
type = fdir.split("/").last
|
|
153
|
+
Relaton::Registry.instance.by_type(type)&.grammar_hash
|
|
154
|
+
end
|
|
155
|
+
|
|
118
156
|
# Reads file by a key
|
|
119
157
|
#
|
|
120
158
|
# @param key [String]
|
|
121
159
|
# @return [String, NilClass]
|
|
122
160
|
def get(key)
|
|
123
|
-
|
|
161
|
+
file = filename key
|
|
162
|
+
return unless (f = search_ext(file))
|
|
163
|
+
|
|
164
|
+
File.read(f, encoding: "utf-8")
|
|
124
165
|
end
|
|
125
166
|
|
|
126
167
|
private
|
|
127
168
|
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
end
|
|
169
|
+
# Check if a file content is redirection
|
|
170
|
+
#
|
|
171
|
+
# @prarm value [String] file content
|
|
172
|
+
# @return [String, NilClass] redirection code or nil
|
|
173
|
+
def redirect?(value)
|
|
174
|
+
%r{redirection\s(?<code>.*)} =~ value
|
|
175
|
+
code
|
|
136
176
|
end
|
|
137
177
|
|
|
138
178
|
# Return item's file name
|
|
139
179
|
# @param key [String]
|
|
140
180
|
# @return [String]
|
|
141
181
|
def filename(key)
|
|
142
|
-
prefcode = key.downcase.match
|
|
182
|
+
prefcode = key.downcase.match /^(?<prefix>[^\(]+)\((?<code>[^\)]+)/
|
|
143
183
|
fn = if prefcode
|
|
144
|
-
"#{prefcode[:prefix]}/#{prefcode[:code].gsub(/[-:\s
|
|
145
|
-
.squeeze('_')}"
|
|
184
|
+
"#{prefcode[:prefix]}/#{prefcode[:code].gsub(/[-:\s\/\()]/, '_').squeeze('_')}"
|
|
146
185
|
else
|
|
147
186
|
key.gsub(/[-:\s]/, "_")
|
|
148
187
|
end
|
|
149
188
|
"#{@dir}/#{fn.sub(/(,|_$)/, '')}"
|
|
150
189
|
end
|
|
151
190
|
|
|
152
|
-
# Check if a file content is redirection
|
|
153
191
|
#
|
|
154
|
-
#
|
|
155
|
-
#
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
192
|
+
# Checks if there is file with xml or txt extension and return filename with
|
|
193
|
+
# the extension.
|
|
194
|
+
#
|
|
195
|
+
# @param file [String]
|
|
196
|
+
# @return [String, NilClass]
|
|
197
|
+
def search_ext(file)
|
|
198
|
+
if File.exist?("#{file}.#{@ext}")
|
|
199
|
+
"#{file}.#{@ext}"
|
|
200
|
+
elsif File.exist? "#{file}.notfound"
|
|
201
|
+
"#{file}.notfound"
|
|
202
|
+
elsif File.exist? "#{file}.redirect"
|
|
203
|
+
"#{file}.redirect"
|
|
204
|
+
end
|
|
159
205
|
end
|
|
160
206
|
|
|
161
207
|
# Return item's subdir
|
|
162
208
|
# @param key [String]
|
|
163
209
|
# @return [String]
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
210
|
+
def prefix(key)
|
|
211
|
+
key.downcase.match(/^[^\(]+(?=\()/).to_s
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# @param file [String]
|
|
215
|
+
# @content [String]
|
|
216
|
+
def file_safe_write(file, content)
|
|
217
|
+
File.open file, File::RDWR | File::CREAT, encoding: "UTF-8" do |f|
|
|
218
|
+
Timeout.timeout(10) { f.flock File::LOCK_EX }
|
|
219
|
+
f.write content
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
class << self
|
|
224
|
+
private
|
|
225
|
+
|
|
226
|
+
def global_bibliocache_name
|
|
227
|
+
"#{Dir.home}/.relaton/cache"
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def local_bibliocache_name(cachename)
|
|
231
|
+
return nil if cachename.nil?
|
|
232
|
+
|
|
233
|
+
cachename = "relaton" if cachename.empty?
|
|
234
|
+
"#{cachename}/cache"
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
public
|
|
238
|
+
|
|
239
|
+
# Initialse and return relaton instance, with local and global cache names
|
|
240
|
+
# local_cache: local cache name; none created if nil; "relaton" created
|
|
241
|
+
# if empty global_cache: boolean to create global_cache
|
|
242
|
+
# flush_caches: flush caches
|
|
243
|
+
def init_bib_caches(opts) # rubocop:disable Metrics/CyclomaticComplexity
|
|
244
|
+
globalname = global_bibliocache_name if opts[:global_cache]
|
|
245
|
+
localname = local_bibliocache_name(opts[:local_cache])
|
|
246
|
+
localname = "relaton" if localname&.empty?
|
|
247
|
+
if opts[:flush_caches]
|
|
248
|
+
FileUtils.rm_rf globalname unless globalname.nil?
|
|
249
|
+
FileUtils.rm_rf localname unless localname.nil?
|
|
250
|
+
end
|
|
251
|
+
Relaton::Db.new(globalname, localname)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
167
254
|
end
|
|
168
255
|
end
|