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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +1 -11
  3. data/lib/relaton/config.rb +2 -4
  4. data/lib/relaton/db.rb +55 -92
  5. data/lib/relaton/db_cache.rb +125 -38
  6. data/lib/relaton/version.rb +1 -1
  7. data/lib/relaton.rb +0 -1
  8. data/relaton.gemspec +18 -22
  9. data/spec/relaton/db_cache_spec.rb +2 -2
  10. data/spec/relaton/db_spec.rb +0 -17
  11. data/spec/relaton/regirtry_spec.rb +1 -1
  12. data/spec/relaton_spec.rb +17 -51
  13. data/spec/spec_helper.rb +0 -4
  14. data/spec/vcr_cassetes/api_relaton_org.yml +14 -8
  15. data/spec/vcr_cassetes/api_relaton_org_unavailable.yml +56 -40
  16. data/spec/vcr_cassetes/async_fetch.yml +1302 -1302
  17. data/spec/vcr_cassetes/bsi_bs_en_iso_8848.yml +117 -114
  18. data/spec/vcr_cassetes/cc_dir_10005_2019.yml +16 -16
  19. data/spec/vcr_cassetes/cen_en_10160_1999.yml +30 -30
  20. data/spec/vcr_cassetes/cie_001_1980.yml +7 -7
  21. data/spec/vcr_cassetes/ecma_6.yml +7 -7
  22. data/spec/vcr_cassetes/fisp_140.yml +4 -4
  23. data/spec/vcr_cassetes/gb_t_20223_2006.yml +6 -6
  24. data/spec/vcr_cassetes/iec_60050_102_2007.yml +28 -28
  25. data/spec/vcr_cassetes/iec_combined_included.yml +88 -90
  26. data/spec/vcr_cassetes/ieee_528_2019.yml +18 -18
  27. data/spec/vcr_cassetes/iho_b_11.yml +7 -7
  28. data/spec/vcr_cassetes/iso_111111119115_1.yml +45 -26
  29. data/spec/vcr_cassetes/iso_19115_1.yml +55 -39
  30. data/spec/vcr_cassetes/iso_19115_1_2.yml +113 -81
  31. data/spec/vcr_cassetes/iso_19115_all_parts.yml +198 -0
  32. data/spec/vcr_cassetes/{19133_2005.yml → iso_19133_2005.yml} +57 -41
  33. data/spec/vcr_cassetes/iso_awi_14093.yml +62 -42
  34. data/spec/vcr_cassetes/iso_combined_applied.yml +112 -80
  35. data/spec/vcr_cassetes/iso_combined_included.yml +112 -80
  36. data/spec/vcr_cassetes/itu_combined_included.yml +161 -161
  37. data/spec/vcr_cassetes/ogc_19_025r1.yml +1168 -1160
  38. data/spec/vcr_cassetes/omg_ami4ccm_1_0.yml +4 -4
  39. data/spec/vcr_cassetes/rfc_8341.yml +7 -7
  40. data/spec/vcr_cassetes/sp_800_38b.yml +4 -4
  41. data/spec/vcr_cassetes/un_rtade_cefact_2004_32.yml +29 -29
  42. data/spec/vcr_cassetes/w3c_json_ld11.yml +12 -12
  43. metadata +42 -61
  44. data/lib/relaton/storage.rb +0 -186
  45. data/spec/relaton/storage_spec.rb +0 -130
  46. data/spec/vcr_cassetes/hist_cmbined_included.yml +0 -105
  47. data/spec/vcr_cassetes/iso_19115.yml +0 -182
  48. data/spec/vcr_cassetes/iso_iec_guide_2.yml +0 -232
  49. data/spec/vcr_cassetes/rfc_unsuccess.yml +0 -70
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d954779afa85cdbe30b00b6780f4fe2ea261839da0f82855dca6e63fe8be77d
4
- data.tar.gz: e7549980e5771e74412291428b8010ad4d6a7720526b98169b97dac82539e909
3
+ metadata.gz: 9a47a3437f5f8afb131ea6cf2a0cf1714875f45e3bd3881c17bc8c7ab9cc2101
4
+ data.tar.gz: b2a25232edd0d71d5597c06c011362771326bdf3369272e9ca5c862b76947427
5
5
  SHA512:
6
- metadata.gz: 466c2e7c24c972df07bf9548b0dac26ec0eb2c03d7c8716abba50cc7a95f83dd58c903b3b99a99fbddcb3afa1d68518c93082acee68034ec3d3230e10d4f0b25
7
- data.tar.gz: 3f4fb6fd8750375862ae109d8d50654372fa3d8e1b6b8eb966e827a026cd4c99f1790a68068c6785a93c6a2c459b6c1506a1768aef881025fa12914cffd0708b
6
+ metadata.gz: 2c99ab3fe479d11714a2848656076685057f9169d59d548530a60e8405d8be23d7f1a04b79744e6fbd112d4495e2cf5d1451d7e3f769fa0bb8844874281dee72
7
+ data.tar.gz: 48d30e142c8a611f97ebc9eb0aed6f3619ec2784e9856b1e659473b52c48fdae77c131c29241087c8a31e59623ed3830e383d75103fe42e18416a0a06c251c66
@@ -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:
@@ -12,15 +12,13 @@ module Relaton
12
12
  end
13
13
 
14
14
  class Configuration
15
- attr_accessor :logs, :use_api, :api_host, :api_mode
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 = true
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
- # class RelatonError < StandardError; end
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) # rubocop:disable Metrics/MethodLength
11
+ def initialize(global_cache, local_cache)
8
12
  @registry = Relaton::Registry.instance
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
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 "../relaton/static_cache", __dir__
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 then @db&.mv new_dir
29
- when :local then @local_db&.mv new_dir
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
- if (db = @db || @local_db)
91
- result += db.all { |f, x| search_xml f, x, text, edition, year }.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
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
- if (stdclass = standard_class code)
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 { xml.parent.add_child db.all.join(" ") }
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 YAML format
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
- updates = check_bibliocache(refs[0], year, opts, stdclass)
259
+ ref = refs[0]
260
+ updates = check_bibliocache(ref, year, opts, stdclass)
288
261
  if updates
289
- doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates, type: "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(refs[0] + divider + c, year, opts, stdclass)
267
+ bib = check_bibliocache(ref + divider + c, year, opts, stdclass)
294
268
  if bib
295
- d.relation << RelatonBib::DocumentRelation.new(type: reltype, description: reldesc, bibitem: bib)
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([]) { |m, (_k, v)| m << v.prefix }
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
- unless entry.nil? || entry.match?(/^not_found/)
357
- @registry.processors[stdclass].from_xml(entry)
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
- if (yaml = @static_db[id])
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, id: id)
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, id: id)
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, id: id)
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?(:to_xml) ? bib.to_xml(bibdata: true) : "not_found #{Date.today}"
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.", :warning
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
- Relaton.configuration.api_mode ? "cache" : "#{Dir.home}/.relaton/cache"
493
+ "#{Dir.home}/.relaton/cache"
529
494
  end
530
495
 
531
496
  def local_bibliocache_name(cachename)
532
- return nil if Relaton.configuration.api_mode || cachename.nil?
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
@@ -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
- @storage = Storage.instance
15
- FileUtils::mkdir_p @dir unless Relaton.configuration.api_mode
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" && !Relaton.configuration.api_mode
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
- return if Relaton.configuration.api_mode
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
- /^(?<pref>[^(]+)(?=\()/ =~ key.downcase
49
- prefix_dir = "#{@dir}/#{pref}"
50
- file = "#{filename(key)}.#{ext(value)}"
51
- @storage.save prefix_dir, file, value
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?(/^not_found/)
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(&block)
91
- @storage.all(@dir, &block)
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
- @storage.delete filename(key)
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 [Boolean]
116
+ # @return [TrueClass, FalseClass]
103
117
  def check_version?(fdir)
104
- @storage.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
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
- @storage.get filename(key), static: @ext == "yml"
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
- # @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
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(/^(?<prefix>[^(]+)\((?<code>[^)]+)/)
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
- # @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
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
- # def prefix(key)
165
- # key.downcase.match(/^[^(]+(?=\()/).to_s
166
- # end
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