relaton 1.7.9 → 1.8.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +1 -1
  3. data/.rubocop.yml +1 -1
  4. data/lib/relaton.rb +3 -0
  5. data/lib/relaton/config.rb +4 -2
  6. data/lib/relaton/db.rb +106 -52
  7. data/lib/relaton/db_cache.rb +38 -125
  8. data/lib/relaton/registry.rb +1 -0
  9. data/lib/relaton/storage.rb +186 -0
  10. data/lib/relaton/version.rb +1 -1
  11. data/relaton.gemspec +23 -19
  12. data/spec/relaton/db_cache_spec.rb +2 -2
  13. data/spec/relaton/db_spec.rb +17 -0
  14. data/spec/relaton/regirtry_spec.rb +9 -1
  15. data/spec/relaton/storage_spec.rb +130 -0
  16. data/spec/relaton_spec.rb +48 -7
  17. data/spec/spec_helper.rb +4 -0
  18. data/spec/vcr_cassetes/19133_2005.yml +17 -17
  19. data/spec/vcr_cassetes/api_relaton_org.yml +33 -0
  20. data/spec/vcr_cassetes/api_relaton_org_unavailable.yml +182 -0
  21. data/spec/vcr_cassetes/async_fetch.yml +2037 -1606
  22. data/spec/vcr_cassetes/bsi_bs_en_iso_8848.yml +17 -17
  23. data/spec/vcr_cassetes/cc_dir_10005_2019.yml +10 -10
  24. data/spec/vcr_cassetes/cen_en_10160_1999.yml +249 -0
  25. data/spec/vcr_cassetes/cie_001_1980.yml +7 -7
  26. data/spec/vcr_cassetes/ecma_6.yml +7 -7
  27. data/spec/vcr_cassetes/fisp_140.yml +4 -4
  28. data/spec/vcr_cassetes/gb_t_20223_2006.yml +9 -9
  29. data/spec/vcr_cassetes/iec_60050_102_2007.yml +23 -23
  30. data/spec/vcr_cassetes/iec_combined_included.yml +81 -79
  31. data/spec/vcr_cassetes/ieee_528_2019.yml +38 -38
  32. data/spec/vcr_cassetes/iho_b_11.yml +7 -7
  33. data/spec/vcr_cassetes/iso_111111119115_1.yml +3 -3
  34. data/spec/vcr_cassetes/iso_19115.yml +19 -19
  35. data/spec/vcr_cassetes/iso_19115_1.yml +18 -18
  36. data/spec/vcr_cassetes/iso_19115_1_2.yml +35 -35
  37. data/spec/vcr_cassetes/iso_awi_14093.yml +182 -0
  38. data/spec/vcr_cassetes/iso_combined_applied.yml +38 -38
  39. data/spec/vcr_cassetes/iso_combined_included.yml +34 -34
  40. data/spec/vcr_cassetes/itu_combined_included.yml +456 -459
  41. data/spec/vcr_cassetes/ogc_19_025r1.yml +1222 -1163
  42. data/spec/vcr_cassetes/omg_ami4ccm_1_0.yml +43 -0
  43. data/spec/vcr_cassetes/rfc_8341.yml +7 -7
  44. data/spec/vcr_cassetes/sp_800_38b.yml +4 -4
  45. data/spec/vcr_cassetes/un_rtade_cefact_2004_32.yml +29 -29
  46. data/spec/vcr_cassetes/w3c_json_ld11.yml +17 -17
  47. metadata +107 -46
  48. data/spec/vcr_cassetes/iso_awi_24229.yml +0 -182
  49. data/spec/vcr_cassetes/ogm_ami4ccm_1_0.yml +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1b14a266fd6fd230fc37d8e2e6843bd48c37019136dc6006a27a89668ecf7af2
4
- data.tar.gz: 3eb6ba9aaa798ab5b763328712e4051184ff2c9de1659791198ca8a7a21726c7
3
+ metadata.gz: 7613bdf8be768f76e3e24d8727210075cd8ad8d4e24924ec5d19d28473cd933f
4
+ data.tar.gz: 1332d1463afd07385d3aacb917a2f621b572e802b25ec64d5d5f87781b6c6ef6
5
5
  SHA512:
6
- metadata.gz: 13a0f6f87426975dbf87e9eefd69d3f519e3a178452039eb9d036725e4c7bdd676ebe0d228a07b3512d296b6d4153cc1e88c72589baa702fb8ac1de717204783
7
- data.tar.gz: e748db6725c7d027b38e1140dc60d74cdea86304f2380d9251cc9d07f143d0536e4b7e1bb63dea35ddd464e2969e08c03f6cde10a426f19e0a8959ecf7a6281f
6
+ metadata.gz: dd636d5da683476ff6abf8a0c686bd9b7112cbbbda7c19f96249b75a6ecb8a4cb4c5764eeead68e949003b8f460574b50fabbcbe2f838ff9f104cb52adda45ba
7
+ data.tar.gz: 75ec0ed77c187b48baef584702b10cd5add0938325a19a40eac6e0217c86b7f769f30ad2561c612ab4fd2c0905c03e8c94797c92ce28a034215cf88bfc8d5f09
@@ -16,7 +16,7 @@ jobs:
16
16
  strategy:
17
17
  fail-fast: false
18
18
  matrix:
19
- ruby: [ '2.7', '2.6', '2.5', '2.4' ]
19
+ ruby: [ '2.7', '2.6', '2.5' ]
20
20
  os: [ ubuntu-latest, windows-latest, macos-latest ]
21
21
  experimental: [ false ]
22
22
  include:
data/.rubocop.yml CHANGED
@@ -5,6 +5,6 @@
5
5
  inherit_from:
6
6
  - https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
7
7
  AllCops:
8
- TargetRubyVersion: 2.4
8
+ TargetRubyVersion: 2.5
9
9
  Rails:
10
10
  Enabled: false
data/lib/relaton.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "relaton/util"
2
2
  require "relaton/config"
3
+ require "yaml"
3
4
 
4
5
  require "relaton/workers_pool"
5
6
  require "relaton/db"
@@ -7,3 +8,5 @@ require "relaton/db_cache"
7
8
  require "relaton/version"
8
9
  require "relaton/registry"
9
10
  require "relaton/processor"
11
+ require "relaton/registry"
12
+ require "relaton/db_cache"
@@ -12,13 +12,15 @@ module Relaton
12
12
  end
13
13
 
14
14
  class Configuration
15
- attr_accessor :logs, :use_api
15
+ attr_accessor :logs, :use_api, :api_host, :api_mode
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 = false
21
+ @use_api = true
22
+ @api_mode = false
23
+ @api_host = nil # "http://0.0.0.0:9292"
22
24
  end
23
25
  end
24
26
 
data/lib/relaton/db.rb CHANGED
@@ -1,7 +1,3 @@
1
- require "yaml"
2
- require_relative "registry"
3
- require_relative "db_cache"
4
-
5
1
  module Relaton
6
2
  class RelatonError < StandardError; end
7
3
 
@@ -10,12 +6,16 @@ module Relaton
10
6
  # @param local_cache [String] directory of local DB
11
7
  def initialize(global_cache, local_cache)
12
8
  @registry = Relaton::Registry.instance
13
- gpath = global_cache && File.expand_path(global_cache)
9
+ if Relaton.configuration.api_mode
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
14
16
  @db = open_cache_biblio(gpath, type: :global)
15
- lpath = local_cache && File.expand_path(local_cache)
16
17
  @local_db = open_cache_biblio(lpath, type: :local)
17
- @static_db = open_cache_biblio File.expand_path("../relaton/static_cache",
18
- __dir__)
18
+ @static_db = open_cache_biblio File.expand_path "../relaton/static_cache", __dir__
19
19
  @queues = {}
20
20
  end
21
21
 
@@ -25,10 +25,8 @@ module Relaton
25
25
  # @return [String, nil]
26
26
  def mv(new_dir, type: :global)
27
27
  case type
28
- when :global
29
- @db&.mv new_dir
30
- when :local
31
- @local_db&.mv new_dir
28
+ when :global then @db&.mv new_dir
29
+ when :local then @local_db&.mv new_dir
32
30
  end
33
31
  end
34
32
 
@@ -89,22 +87,18 @@ module Relaton
89
87
  result = @static_db.all do |file, yml|
90
88
  search_yml file, yml, text, edition, year
91
89
  end.compact
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
90
+ if (db = @db || @local_db)
91
+ result += db.all { |f, x| search_xml f, x, text, edition, year }.compact
97
92
  end
98
93
  result
99
94
  end
100
95
 
101
96
  # Fetch asynchronously
102
97
  def fetch_async(code, year = nil, opts = {}, &_block) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
103
- stdclass = standard_class code
104
- if stdclass
98
+ if (stdclass = standard_class code)
105
99
  unless @queues[stdclass]
106
100
  processor = @registry.processors[stdclass]
107
- wp = WorkersPool.new(processor.threads) { |args| yield fetch *args }
101
+ wp = WorkersPool.new(processor.threads) { |args| yield fetch(*args) }
108
102
  @queues[stdclass] = { queue: Queue.new, workers_pool: wp }
109
103
  Thread.new { process_queue @queues[stdclass] }
110
104
  end
@@ -173,14 +167,31 @@ module Relaton
173
167
  def to_xml
174
168
  db = @local_db || @db || return
175
169
  Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
176
- xml.documents do
177
- xml.parent.add_child db.all.join(" ")
178
- end
170
+ xml.documents { xml.parent.add_child db.all.join(" ") }
179
171
  end.to_xml
180
172
  end
181
173
 
182
174
  private
183
175
 
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
+ params = opts.merge(code: code, year: year).map { |k, v| "#{k}=#{v}" }.join "&"
190
+ url = "#{Relaton.configuration.api_host}/api/v1/fetch?#{params}"
191
+ rsp = Net::HTTP.get_response URI(url)
192
+ @registry.processors[stdclass].from_xml rsp.body if rsp.code == "200"
193
+ end
194
+
184
195
  # @param file [String] file path
185
196
  # @param yml [String] content in YAML format
186
197
  # @param text [String, nil] text to serach
@@ -207,7 +218,7 @@ module Relaton
207
218
  end
208
219
 
209
220
  # @param file [String] file path
210
- # @param content [String] content in XML or YAmL format
221
+ # @param content [String] content in XML or YAML format
211
222
  # @param edition [String, nil] edition to filter
212
223
  # @param year [Integer, nil] year to filter
213
224
  # @return [BibliographicItem, nil]
@@ -220,9 +231,14 @@ module Relaton
220
231
  item.date.detect { |d| d.type == "published" && d.on(:year).to_s == year.to_s })
221
232
  end
222
233
 
234
+ #
235
+ # Look up text in the XML elements attributes and content
236
+ #
223
237
  # @param xml [String] content in XML format
224
238
  # @param text [String, nil] text to serach
239
+ #
225
240
  # @return [Boolean]
241
+ #
226
242
  def match_xml_text(xml, text)
227
243
  %r{((?<attr>=((?<apstr>')|"))|>).*?#{text}.*?(?(<attr>)(?(<apstr>)'|")|<)}mi.match?(xml)
228
244
  end
@@ -256,19 +272,15 @@ module Relaton
256
272
  end
257
273
 
258
274
  doc = @registry.processors[stdclass].hash_to_bib docid: { id: code }
259
- ref = refs[0]
260
- updates = check_bibliocache(ref, year, opts, stdclass)
275
+ updates = check_bibliocache(refs[0], year, opts, stdclass)
261
276
  if updates
262
- doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates,
263
- type: "updates")
277
+ doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates, type: "updates")
264
278
  end
265
279
  divider = stdclass == :relaton_itu ? " " : "/"
266
280
  refs[1..-1].each_with_object(doc) do |c, d|
267
- bib = check_bibliocache(ref + divider + c, year, opts, stdclass)
281
+ bib = check_bibliocache(refs[0] + divider + c, year, opts, stdclass)
268
282
  if bib
269
- d.relation << RelatonBib::DocumentRelation.new(
270
- type: reltype, description: reldesc, bibitem: bib
271
- )
283
+ d.relation << RelatonBib::DocumentRelation.new(type: reltype, description: reldesc, bibitem: bib)
272
284
  end
273
285
  end
274
286
  end
@@ -280,9 +292,7 @@ module Relaton
280
292
  return name if /^(urn:)?#{processor.prefix}/i.match?(code) ||
281
293
  processor.defaultprefix.match(code)
282
294
  end
283
- allowed = @registry.processors.reduce([]) do |m, (_k, v)|
284
- m << v.prefix
285
- end
295
+ allowed = @registry.processors.reduce([]) { |m, (_k, v)| m << v.prefix }
286
296
  Util.log <<~WARN, :info
287
297
  [relaton] #{code} does not have a recognised prefix: #{allowed.join(', ')}.
288
298
  See https://github.com/relaton/relaton/ for instructions on prefixing and wrapping document identifiers to disambiguate them.
@@ -331,8 +341,8 @@ module Relaton
331
341
  # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
332
342
  # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
333
343
  def bib_retval(entry, stdclass)
334
- if entry.nil? || entry.match?(/^not_found/) then nil
335
- else @registry.processors[stdclass].from_xml(entry)
344
+ unless entry.nil? || entry.match?(/^not_found/)
345
+ @registry.processors[stdclass].from_xml(entry)
336
346
  end
337
347
  end
338
348
 
@@ -356,8 +366,7 @@ module Relaton
356
366
  # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
357
367
  def check_bibliocache(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
358
368
  id, searchcode = std_id(code, year, opts, stdclass)
359
- yaml = @static_db[id]
360
- if yaml
369
+ if (yaml = @static_db[id])
361
370
  return @registry.processors[stdclass].hash_to_bib YAML.safe_load(yaml)
362
371
  end
363
372
 
@@ -366,8 +375,7 @@ module Relaton
366
375
  if db.nil?
367
376
  return if opts[:fetch_db]
368
377
 
369
- bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db,
370
- id: id)
378
+ bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
371
379
  return bib_retval(bibentry, stdclass)
372
380
  end
373
381
 
@@ -376,18 +384,17 @@ module Relaton
376
384
  return bib_retval(altdb[id], stdclass) if opts[:fetch_db]
377
385
 
378
386
  db.clone_entry id, altdb if altdb.valid_entry? id, year
379
- db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
380
- id: id)
387
+ db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
381
388
  altdb.clone_entry(id, db) if !altdb.valid_entry?(id, year)
382
389
  else
383
390
  return bib_retval(db[id], stdclass) if opts[:fetch_db]
384
391
 
385
- db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
386
- id: id)
392
+ db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
387
393
  end
388
394
  bib_retval(db[id], stdclass)
389
395
  end
390
396
 
397
+ #
391
398
  # @param code [String]
392
399
  # @param year [String]
393
400
  #
@@ -400,7 +407,9 @@ module Relaton
400
407
  # @param stdclass [Symbol]
401
408
  # @param db [Relaton::DbCache,`NilClass]
402
409
  # @param id [String] docid
410
+ #
403
411
  # @return [String]
412
+ #
404
413
  def new_bib_entry(code, year, opts, stdclass, **args) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
405
414
  bib = net_retry(code, year, opts, stdclass, opts.fetch(:retries, 1))
406
415
  bib_id = bib&.docidentifier&.first&.id
@@ -415,8 +424,27 @@ module Relaton
415
424
  end
416
425
  end
417
426
 
427
+ #
428
+ # @param code [String]
429
+ # @param year [String]
430
+ #
431
+ # @param opts [Hash]
432
+ # @option opts [Boolean] :all_parts If all-parts reference is required
433
+ # @option opts [Boolean] :keep_year If undated reference should return
434
+ # actual reference with year
435
+ #
436
+ # @param stdclass [Symbol]
437
+ # @param retries [Integer] remain Number of network retries
438
+ #
418
439
  # @raise [RelatonBib::RequestError]
440
+ # @return [RelatonBib::BibliographicItem]
441
+ #
419
442
  def net_retry(code, year, opts, stdclass, retries)
443
+ doc = fetch_api code, year, opts, stdclass
444
+ return doc if doc
445
+
446
+ @registry.processors[stdclass].get(code, year, opts)
447
+ rescue Errno::ECONNREFUSED
420
448
  @registry.processors[stdclass].get(code, year, opts)
421
449
  rescue RelatonBib::RequestError => e
422
450
  raise e unless retries > 1
@@ -434,11 +462,7 @@ module Relaton
434
462
  # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
435
463
  # @return [String] XML or "not_found mm-dd-yyyy"
436
464
  def bib_entry(bib)
437
- if bib.respond_to? :to_xml
438
- bib.to_xml(bibdata: true)
439
- else
440
- "not_found #{Date.today}"
441
- end
465
+ bib.respond_to?(:to_xml) ? bib.to_xml(bibdata: true) : "not_found #{Date.today}"
442
466
  end
443
467
 
444
468
  # @param dir [String, nil] DB directory
@@ -456,8 +480,7 @@ module Relaton
456
480
  FileUtils.rm_rf(fdir, secure: true)
457
481
  Util.log(
458
482
  "[relaton] WARNING: cache #{fdir}: version is obsolete and cache is "\
459
- "cleared.",
460
- :warning
483
+ "cleared.", :warning
461
484
  )
462
485
  end
463
486
  db
@@ -469,5 +492,36 @@ module Relaton
469
492
  def process_queue(qwp)
470
493
  while args = qwp[:queue].pop; qwp[:workers_pool] << args end
471
494
  end
495
+
496
+ class << self
497
+ # Initialse and return relaton instance, with local and global cache names
498
+ # local_cache: local cache name; none created if nil; "relaton" created
499
+ # if empty global_cache: boolean to create global_cache
500
+ # flush_caches: flush caches
501
+ def init_bib_caches(**opts) # rubocop:disable Metrics/CyclomaticComplexity
502
+ globalname = global_bibliocache_name if opts[:global_cache]
503
+ localname = local_bibliocache_name(opts[:local_cache])
504
+ flush_caches globalname, localname if opts[:flush_caches]
505
+ Relaton::Db.new(globalname, localname)
506
+ end
507
+
508
+ private
509
+
510
+ def flush_caches(gcache, lcache)
511
+ FileUtils.rm_rf gcache unless gcache.nil?
512
+ FileUtils.rm_rf lcache unless lcache.nil?
513
+ end
514
+
515
+ def global_bibliocache_name
516
+ Relaton.configuration.api_mode ? "cache" : "#{Dir.home}/.relaton/cache"
517
+ end
518
+
519
+ def local_bibliocache_name(cachename)
520
+ return nil if Relaton.configuration.api_mode || cachename.nil?
521
+
522
+ cachename = "relaton" if cachename.empty?
523
+ "#{cachename}/cache"
524
+ end
525
+ end
472
526
  end
473
527
  end
@@ -1,5 +1,6 @@
1
1
  require "fileutils"
2
2
  require "timeout"
3
+ require "relaton/storage"
3
4
 
4
5
  module Relaton
5
6
  class DbCache
@@ -10,16 +11,15 @@ module Relaton
10
11
  def initialize(dir, ext = "xml")
11
12
  @dir = dir
12
13
  @ext = ext
13
- FileUtils::mkdir_p @dir
14
- # file_version = "#{@dir}/version"
15
- # set_version # unless File.exist? file_version
14
+ @storage = Storage.instance
15
+ FileUtils::mkdir_p @dir unless Relaton.configuration.api_mode
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" && !Relaton.configuration.api_mode
23
23
 
24
24
  if File.exist? new_dir
25
25
  warn "[relaton] WARNING: target directory exists \"#{new_dir}\""
@@ -32,7 +32,9 @@ module Relaton
32
32
 
33
33
  # Clear database
34
34
  def clear
35
- FileUtils.rm_rf Dir.glob "#{dir}/*" if @ext == "xml" # unless it's static DB
35
+ return if Relaton.configuration.api_mode
36
+
37
+ FileUtils.rm_rf Dir.glob "#{dir}/*" if @ext == "xml" # if it's static DB
36
38
  end
37
39
 
38
40
  # Save item
@@ -43,21 +45,10 @@ module Relaton
43
45
  delete key
44
46
  return
45
47
  end
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
48
+ /^(?<pref>[^(]+)(?=\()/ =~ key.downcase
49
+ prefix_dir = "#{@dir}/#{pref}"
50
+ file = "#{filename(key)}.#{ext(value)}"
51
+ @storage.save prefix_dir, file, value
61
52
  end
62
53
 
63
54
  # Read item
@@ -86,7 +77,7 @@ module Relaton
86
77
  value = self[key]
87
78
  return unless value
88
79
 
89
- if value.match? /^not_found/
80
+ if value.match?(/^not_found/)
90
81
  value.match(/\d{4}-\d{2}-\d{2}/).to_s
91
82
  else
92
83
  doc = Nokogiri::XML value
@@ -96,41 +87,21 @@ module Relaton
96
87
 
97
88
  # Returns all items
98
89
  # @return [Array<String>]
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
90
+ def all(&block)
91
+ @storage.all(@dir, &block)
104
92
  end
105
93
 
106
94
  # Delete item
107
95
  # @param key [String]
108
96
  def delete(key)
109
- file = filename key
110
- f = search_ext(file)
111
- File.delete f if f
97
+ @storage.delete filename(key)
112
98
  end
113
99
 
114
100
  # Check if version of the DB match to the gem grammar hash.
115
101
  # @param fdir [String] dir pathe to flover cache
116
- # @return [TrueClass, FalseClass]
102
+ # @return [Boolean]
117
103
  def check_version?(fdir)
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
104
+ @storage.check_version? fdir
134
105
  end
135
106
 
136
107
  # if cached reference is undated, expire it after 60 days
@@ -144,112 +115,54 @@ module Relaton
144
115
  year || Date.today - date < 60
145
116
  end
146
117
 
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
-
156
118
  # Reads file by a key
157
119
  #
158
120
  # @param key [String]
159
121
  # @return [String, NilClass]
160
122
  def get(key)
161
- file = filename key
162
- return unless (f = search_ext(file))
163
-
164
- File.read(f, encoding: "utf-8")
123
+ @storage.get filename(key), static: @ext == "yml"
165
124
  end
166
125
 
167
126
  private
168
127
 
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
128
+ # @param value [String]
129
+ # @return [String]
130
+ def ext(value)
131
+ case value
132
+ when /^not_found/ then "notfound"
133
+ when /^redirection/ then "redirect"
134
+ else @ext
135
+ end
176
136
  end
177
137
 
178
138
  # Return item's file name
179
139
  # @param key [String]
180
140
  # @return [String]
181
141
  def filename(key)
182
- prefcode = key.downcase.match /^(?<prefix>[^\(]+)\((?<code>[^\)]+)/
142
+ prefcode = key.downcase.match(/^(?<prefix>[^(]+)\((?<code>[^)]+)/)
183
143
  fn = if prefcode
184
- "#{prefcode[:prefix]}/#{prefcode[:code].gsub(/[-:\s\/\()]/, '_').squeeze('_')}"
144
+ "#{prefcode[:prefix]}/#{prefcode[:code].gsub(/[-:\s\/()]/, '_')
145
+ .squeeze('_')}"
185
146
  else
186
147
  key.gsub(/[-:\s]/, "_")
187
148
  end
188
149
  "#{@dir}/#{fn.sub(/(,|_$)/, '')}"
189
150
  end
190
151
 
152
+ # Check if a file content is redirection
191
153
  #
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
154
+ # @prarm value [String] file content
155
+ # @return [String, NilClass] redirection code or nil
156
+ def redirect?(value)
157
+ %r{redirection\s(?<code>.*)} =~ value
158
+ code
205
159
  end
206
160
 
207
161
  # Return item's subdir
208
162
  # @param key [String]
209
163
  # @return [String]
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
164
+ # def prefix(key)
165
+ # key.downcase.match(/^[^(]+(?=\()/).to_s
166
+ # end
254
167
  end
255
168
  end