relaton 1.7.3 → 1.7.8

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +46 -0
  3. data/docs/README.adoc +151 -3
  4. data/lib/relaton.rb +8 -7
  5. data/lib/relaton/config.rb +5 -2
  6. data/lib/relaton/db.rb +283 -92
  7. data/lib/relaton/db_cache.rb +25 -3
  8. data/lib/relaton/processor.rb +11 -0
  9. data/lib/relaton/registry.rb +1 -1
  10. data/lib/relaton/util.rb +1 -1
  11. data/lib/relaton/version.rb +1 -1
  12. data/lib/relaton/workers_pool.rb +21 -0
  13. data/relaton.gemspec +6 -4
  14. data/spec/relaton/config_spec.rb +1 -1
  15. data/spec/relaton/db_spec.rb +154 -0
  16. data/spec/relaton/processor_spec.rb +4 -0
  17. data/spec/relaton/regirtry_spec.rb +51 -45
  18. data/spec/relaton_spec.rb +26 -17
  19. data/spec/vcr_cassetes/19133_2005.yml +22 -22
  20. data/spec/vcr_cassetes/async_fetch.yml +4423 -0
  21. data/spec/vcr_cassetes/bsi_bs_en_iso_8848.yml +159 -0
  22. data/spec/vcr_cassetes/cc_dir_10005_2019.yml +14 -14
  23. data/spec/vcr_cassetes/cie_001_1980.yml +120 -0
  24. data/spec/vcr_cassetes/ecma_6.yml +134 -67
  25. data/spec/vcr_cassetes/fisp_140.yml +4 -4
  26. data/spec/vcr_cassetes/gb_t_20223_2006.yml +11 -11
  27. data/spec/vcr_cassetes/iec_60050_102_2007.yml +30 -26
  28. data/spec/vcr_cassetes/iec_combined_included.yml +71 -73
  29. data/spec/vcr_cassetes/ieee_528_2019.yml +41 -39
  30. data/spec/vcr_cassetes/iho_b_11.yml +11 -11
  31. data/spec/vcr_cassetes/iso_111111119115_1.yml +4 -4
  32. data/spec/vcr_cassetes/iso_19115.yml +23 -23
  33. data/spec/vcr_cassetes/iso_19115_1.yml +21 -21
  34. data/spec/vcr_cassetes/iso_19115_1_2.yml +43 -43
  35. data/spec/vcr_cassetes/iso_awi_24229.yml +20 -20
  36. data/spec/vcr_cassetes/iso_combined_applied.yml +41 -41
  37. data/spec/vcr_cassetes/iso_combined_included.yml +42 -42
  38. data/spec/vcr_cassetes/itu_combined_included.yml +219 -159
  39. data/spec/vcr_cassetes/ogc_19_025r1.yml +1520 -1124
  40. data/spec/vcr_cassetes/ogm_ami4ccm_1_0.yml +11 -23
  41. data/spec/vcr_cassetes/rfc_8341.yml +47 -15
  42. data/spec/vcr_cassetes/rfc_unsuccess.yml +70 -0
  43. data/spec/vcr_cassetes/sp_800_38b.yml +4 -4
  44. data/spec/vcr_cassetes/un_rtade_cefact_2004_32.yml +34 -36
  45. data/spec/vcr_cassetes/w3c_json_ld11.yml +12 -12
  46. metadata +40 -39
  47. data/.github/workflows/macos.yml +0 -34
  48. data/.github/workflows/ubuntu.yml +0 -32
  49. data/.github/workflows/windows.yml +0 -35
  50. data/localcache/iec/iec_60050_102_2007.xml +0 -58
  51. data/localcache/iec/version +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f957d5a962fa3529fb21f4289ff4dc648029497ec3bf209e084b85c49a336531
4
- data.tar.gz: 6e6ad879c1552c8396c8f365c4bdc9c088197424f695b68b0dbeec9cc272f1a4
3
+ metadata.gz: d0ff67d3ebeb9332a6aa18ad88e8b585478c29adb27ccda935ab9b8af4b34e2b
4
+ data.tar.gz: 9aefca4601eb5bd7c4491dafc41fcee87cbb7e5d7508ee05086cfa39122bfbef
5
5
  SHA512:
6
- metadata.gz: f87f3d11aae3e805fa2fe3d9875692c2004a7b7a51fc1235181f8a4a9b314cf0403e50a4134fb093edc0da2cdb42339a7fe4ee7024e25de92d7923bf5029ab35
7
- data.tar.gz: 2684a909260936e26f9a2b987c667e61d24e96c01f326bc008deaf9358f1dc349f216c239932ee5780325057bfb192426173d1e226c031880743ff4ce0ad4d12
6
+ metadata.gz: b69bf1fbbbc4258bd22304dda3d54b23bc8a8e2361aeff2f26487518236e6b46690d0a793dd076489749ae0dcd93a6c3da7bc1969d3e877149ad9722b9ed0e9e
7
+ data.tar.gz: '0682111008bcb648773cd0e90bb4f5a789007b5d5deca6aa2c5aa245b1f677a136eff936c6256b8e6bf76bcf4cb65f8371ba0cb5fe0c9ffe908e7d4640031342'
@@ -0,0 +1,46 @@
1
+ # Auto-generated by Cimas: Do not edit it manually!
2
+ # See https://github.com/metanorma/cimas
3
+ name: rake
4
+
5
+ on:
6
+ push:
7
+ branches: [ master, main ]
8
+ tags: [ v* ]
9
+ pull_request:
10
+
11
+ jobs:
12
+ rake:
13
+ name: Test on Ruby ${{ matrix.ruby }} ${{ matrix.os }}
14
+ runs-on: ${{ matrix.os }}
15
+ continue-on-error: ${{ matrix.experimental }}
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ ruby: [ '2.7', '2.6', '2.5', '2.4' ]
20
+ os: [ ubuntu-latest, windows-latest, macos-latest ]
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
+ steps:
33
+ - uses: actions/checkout@v2
34
+ with:
35
+ submodules: true
36
+
37
+ # https://github.com/ruby-debug/debase/issues/89#issuecomment-686827382
38
+ - if: matrix.os == 'macos-latest' && matrix.ruby == '2.5'
39
+ run: echo BUNDLE_BUILD__DEBASE="--with-cflags=\"-Wno-error=implicit-function-declaration\"" >> $GITHUB_ENV
40
+
41
+ - uses: ruby/setup-ruby@v1
42
+ with:
43
+ ruby-version: ${{ matrix.ruby }}
44
+ bundler-cache: true
45
+
46
+ - run: bundle exec rake
data/docs/README.adoc CHANGED
@@ -64,6 +64,11 @@ e.g. `get("ISO 19115-1", "2014", all_parts: true)` is transformed into a referen
64
64
 
65
65
  === Create DB
66
66
 
67
+ `Relaton::Db#new(globalcache, localcache)` creates new DB. Returns Relaton::Db instance.
68
+
69
+ * `globalcache` - (String or nil) path to globalcache directory
70
+ * `localcache` - (String or nil) path to localcache directory
71
+
67
72
  [source,ruby]
68
73
  ----
69
74
  require "relaton"
@@ -97,9 +102,46 @@ db = Relaton::Db.new("globalcache", "localcache")
97
102
  ...
98
103
  ----
99
104
 
105
+ === Modify DB
106
+
107
+ ==== Move DB
108
+
109
+ `Relaton::Db#mv(new_dir, type: :global)` moves DB directory to new location. Returns path to new directory if successful, or `nil` if target directiory exists.
110
+
111
+ * `new_dir` - (String) new cache location
112
+ * `type` - (Symbol) type of cache DB. Allowed values are: `:global`, `:local`. Default is `:global`.
113
+
114
+ [source,ruby]
115
+ ----
116
+ db.mv("new_global_dir")
117
+ => "new_global_dir"
118
+
119
+ db.mv("new_local_dir", type: :local)
120
+ => "new_local_dir"
121
+ ----
122
+
123
+ ==== Clear DB
124
+
125
+ `Relaton::Db#clear` removes all entries form DB
126
+
100
127
  === Fetch documens
101
128
 
102
- ==== Fetch by references
129
+ ==== Fetch document by references
130
+
131
+ There are 3 fetching methods:
132
+
133
+ * `Relaton::Db#fetch(reference, year, options)` - fetches document from local cache or remote source.
134
+ * `Relaton::Db#fetch_db(reference, year, options)` - fetches document from local cache
135
+ * `Relaton::Db#fetch_async(reference, year, options, &block)` - fetches document asynchronously
136
+
137
+ Arguments:
138
+
139
+ * `reference` - (String) reference to fethc document
140
+ * `year` - (String or nil) year to filter relult (optional)
141
+ * `options` - (Hash) hash of options. Alloved options:
142
+ - `:all_parts` - (Boolean) should be `true` if all-parts reference is required
143
+ - `:keep_yer` - (Boolean) should be `true` if undated reference should return actual reference with year
144
+ - `:retries` - (Number) number of network retries. Default 1
103
145
 
104
146
  [source,ruby]
105
147
  ----
@@ -114,7 +156,7 @@ x = db.fetch("ISO 19011")
114
156
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d0ab2f00
115
157
  ...
116
158
 
117
- x = db.fetch("ISO 19011", "2011")
159
+ x = db.fetch("ISO 19011", "2011", retries: 3)
118
160
  [relaton-iso] ("ISO 19011") fetching...
119
161
  [relaton-iso] ("ISO 19011") found ISO 19011:2011
120
162
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d2593068
@@ -125,6 +167,36 @@ x = db.fetch("ISO 19115", nil, all_parts: true)
125
167
  [relaton-iso] ("ISO 19115") found ISO 19115 (all parts)
126
168
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d0ae8bf0
127
169
  ...
170
+
171
+ # Fetchig from local cache
172
+
173
+ x = db.fetch("ISO 19011")
174
+ => #<RelatonIsoBib::IsoBibliographicItem:0x007fde5f48a9f0
175
+ ...
176
+
177
+ x = db.fetch_db("ISO 5749")
178
+ => nil
179
+
180
+ # Fetching asynchronously
181
+
182
+ # prepare queue for results
183
+ results = Queue.new
184
+
185
+ # references ot fetch
186
+ refs = ["ISO 19011", "ISO 19115"]
187
+
188
+ # fetch documents
189
+ refs.each do |ref|
190
+ db.fetch_async(ref) do |doc|
191
+ results << [ref, doc]
192
+ end
193
+ end
194
+
195
+ # wait until documets fetching
196
+ refs.size.times do
197
+ ref, doc = results.pop
198
+ # do thatever you need with result x
199
+ end
128
200
  ----
129
201
 
130
202
  ==== Fetch by URN
@@ -192,6 +264,82 @@ bib.relation[1].bibitem.docidentifier[0].id
192
264
  [source,ruby]
193
265
  ----
194
266
  bib = db.fetch "ISO 19115-1, Amd 1"
267
+ => ["Chinese Standard", "GB/T 1.1"]
268
+ [relaton-iso] ("ISO 19115-1") fetching...
269
+ [relaton-iso] ("ISO 19115-1") found ISO 19115-1:2014
270
+ [relaton-iso] ("ISO 19115-1/Amd 1") fetching...
271
+ [relaton-iso] ("ISO 19115-1/Amd 1") found ISO 19115-1:2014/Amd 1:2018
272
+ => #<RelatonIsoBib::IsoBibliographicItem:0x007fb09b36d1b8
273
+ ...
274
+ ----
275
+
276
+ ==== Fetch all documents from cache
277
+
278
+ `Relaton::Db#fetch_all(text = nil, edition: nil, year: nil)` - fetches all document from local cache
279
+
280
+ * `text` - (String) filter entries by a text (optional)
281
+ * `edition` - (String) filter entries by an edition (optional)
282
+ * `year` - (Integer) filter entries by a year (optional)
283
+
284
+ [source,ruby]
285
+ ----
286
+ # query for all entries in a cahche
287
+
288
+ items = db.fetch_all
289
+ => [#<RelatonIec::IecBibliographicItem:0x007facda8fdc28
290
+ ...
291
+
292
+ items.size
293
+ => 6
294
+
295
+ # query for all entries in a cahche for a certain string
296
+
297
+ items = db.fetch_all("mathematical terminology")
298
+ => [#<RelatonIec::IecBibliographicItem:0x007ffeae5bd240
299
+ ...
300
+
301
+ items.size
302
+ => 1
303
+
304
+ items[0].docidentifier[0].id
305
+ => "IEC 60050-102:2007"
306
+
307
+ # query for all entries in a cahche for a certain string and edition
308
+
309
+ items = db.fetch_all("system", edition: "2")
310
+ => [#<RelatonIsoBib::IsoBibliographicItem:0x007ffebe2d1be8
311
+ ...
312
+
313
+ items.size
314
+ => 1
315
+
316
+ items[0].docidentifier[0].id
317
+ => "ISO 19011:2011"
318
+
319
+ # query for all entries in a cahche for a certain string and year
320
+
321
+ items = db.fetch_all("system", year: 2018)
322
+ => [#<RelatonIsoBib::IsoBibliographicItem:0x007ffeae645fa0
323
+ ...
324
+
325
+ items.size
326
+ => 1
327
+
328
+ items[0].docidentifier[0].id
329
+ => "ISO 19011 (all parts)"
330
+ ----
331
+
332
+ === Static DB
333
+
334
+ This gem has a static DB which is distributed with it. Now the static contains documents:
335
+ ----
336
+ ISO/IEC DIR 1 IEC SUP
337
+ ISO/IEC DIR 1 ISO SUP
338
+ ISO/IEC DIR 1
339
+ ISO/IEC DIR 2 IEC
340
+ ISO/IEC DIR 2 ISO
341
+ ISO/IEC DIR IEC SUP
342
+ ISO/IEC DIR 1 JTC SUP
195
343
  ----
196
344
 
197
345
  === Get document type
@@ -229,7 +377,7 @@ x.to_xml bibdata: true
229
377
  db.load_entry("ISO(ISO 19011)")
230
378
  => "<bibdata type="standard">
231
379
  ...
232
- <?bibdata>"
380
+ </bibdata>"
233
381
  ----
234
382
 
235
383
  === Entry manipulation
data/lib/relaton.rb CHANGED
@@ -1,8 +1,9 @@
1
- require_relative "relaton/util"
2
- require_relative "relaton/config"
1
+ require "relaton/util"
2
+ require "relaton/config"
3
3
 
4
- require_relative "relaton/db"
5
- require_relative "relaton/db_cache"
6
- require_relative "relaton/version"
7
- require_relative "relaton/registry"
8
- require_relative "relaton/processor"
4
+ require "relaton/workers_pool"
5
+ require "relaton/db"
6
+ require "relaton/db_cache"
7
+ require "relaton/version"
8
+ require "relaton/registry"
9
+ require "relaton/processor"
@@ -12,10 +12,13 @@ module Relaton
12
12
  end
13
13
 
14
14
  class Configuration
15
- attr_accessor :logs
15
+ attr_accessor :logs, :use_api
16
16
 
17
17
  def initialize
18
- @logs = %i(warning error)
18
+ @logs = %i(info error)
19
+
20
+ # @TODO change to true when we start using api.relaton.org
21
+ @use_api = false
19
22
  end
20
23
  end
21
24
 
data/lib/relaton/db.rb CHANGED
@@ -10,83 +10,127 @@ module Relaton
10
10
  # @param local_cache [String] directory of local DB
11
11
  def initialize(global_cache, local_cache)
12
12
  @registry = Relaton::Registry.instance
13
- @db = open_cache_biblio(global_cache, type: :global)
14
- @local_db = open_cache_biblio(local_cache, type: :local)
15
- @db_name = global_cache
16
- @local_db_name = local_cache
17
- static_db_name = File.expand_path "../relaton/static_cache", __dir__
18
- @static_db = open_cache_biblio static_db_name
13
+ gpath = global_cache && File.expand_path(global_cache)
14
+ @db = open_cache_biblio(gpath, type: :global)
15
+ lpath = local_cache && File.expand_path(local_cache)
16
+ @local_db = open_cache_biblio(lpath, type: :local)
17
+ @static_db = open_cache_biblio File.expand_path("../relaton/static_cache",
18
+ __dir__)
19
+ @queues = {}
19
20
  end
20
21
 
22
+ # Move global or local caches to anothe dirs
23
+ # @param new_dir [String, nil]
24
+ # @param type: [Symbol]
25
+ # @return [String, nil]
26
+ def mv(new_dir, type: :global)
27
+ case type
28
+ when :global
29
+ @db&.mv new_dir
30
+ when :local
31
+ @local_db&.mv new_dir
32
+ end
33
+ end
34
+
35
+ # Clear global and local databases
36
+ def clear
37
+ @db&.clear
38
+ @local_db&.clear
39
+ end
40
+
41
+ ##
21
42
  # The class of reference requested is determined by the prefix of the code:
22
- # GB Standard for gbbib, IETF for ietfbib, ISO for isobib, IEC or IEV for iecbib,
43
+ # GB Standard for gbbib, IETF for ietfbib, ISO for isobib, IEC or IEV for
44
+ # iecbib,
45
+ #
23
46
  # @param code [String] the ISO standard Code to look up (e.g. "ISO 9000")
24
47
  # @param year [String] the year the standard was published (optional)
25
- # @param opts [Hash] options; restricted to :all_parts if all-parts reference is required
26
- # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
27
- # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
28
- # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
29
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
30
- # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
48
+ #
49
+ # @param opts [Hash] options
50
+ # @option opts [Boolean] :all_parts If all-parts reference is required
51
+ # @option opts [Boolean] :keep_year If undated reference should return
52
+ # actual reference with year
53
+ # @option opts [Integer] :retries (1) Number of network retries
54
+ #
55
+ # @return [nil, RelatonBib::BibliographicItem,
56
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
57
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
58
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
59
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
60
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
31
61
  # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
32
- # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
33
- # RelatonW3c::W3cBibliographicItem
62
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
63
+ ##
34
64
  def fetch(code, year = nil, opts = {})
35
65
  stdclass = standard_class(code) || return
36
66
  processor = @registry.processors[stdclass]
37
- ref = processor.respond_to?(:urn_to_code) ? processor.urn_to_code(code)&.first : code
67
+ ref = if processor.respond_to?(:urn_to_code)
68
+ processor.urn_to_code(code)&.first
69
+ else code
70
+ end
38
71
  ref ||= code
39
- cd = combine_doc ref, year, opts, stdclass
40
- return cd if cd
72
+ result = combine_doc ref, year, opts, stdclass
73
+ result ||= check_bibliocache(ref, year, opts, stdclass)
74
+ result
75
+ end
41
76
 
42
- check_bibliocache(ref, year, opts, stdclass)
77
+ # @see Relaton::Db#fetch
78
+ def fetch_db(code, year = nil, opts = {})
79
+ opts[:fetch_db] = true
80
+ fetch code, year, opts
43
81
  end
44
82
 
45
- # @param code [String]
46
- # @param year [String, nil]
47
- # @param stdslass [String]
48
- # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
49
- # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
50
- # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
51
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
52
- # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
53
- # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
54
- # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
55
- # RelatonW3c::W3cBibliographicItem
56
- def combine_doc(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
57
- if (refs = code.split " + ").size > 1
58
- reltype = "derivedFrom"
59
- reldesc = nil
60
- elsif (refs = code.split ", ").size > 1
61
- reltype = "complements"
62
- reldesc = RelatonBib::FormattedString.new content: "amendment"
63
- else return
83
+ # fetch all standards from DB
84
+ # @param test [String, nil]
85
+ # @param edition [String], nil
86
+ # @param year [Integer, nil]
87
+ # @return [Array]
88
+ def fetch_all(text = nil, edition: nil, year: nil)
89
+ result = @static_db.all do |file, yml|
90
+ search_yml file, yml, text, edition, year
91
+ 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
64
97
  end
98
+ result
99
+ end
65
100
 
66
- doc = @registry.processors[stdclass].hash_to_bib docid: { id: code }
67
- ref = refs[0]
68
- updates = check_bibliocache(ref, year, opts, stdclass)
69
- doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates, type: "updates") if updates
70
- refs[1..-1].each_with_object(doc) do |c, d|
71
- bib = check_bibliocache("#{ref}/#{c}", year, opts, stdclass)
72
- if bib
73
- d.relation << RelatonBib::DocumentRelation.new(type: reltype, description: reldesc, bibitem: bib)
101
+ # Fetch asynchronously
102
+ def fetch_async(code, year = nil, opts = {}, &_block) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
103
+ stdclass = standard_class code
104
+ if stdclass
105
+ unless @queues[stdclass]
106
+ processor = @registry.processors[stdclass]
107
+ wp = WorkersPool.new(processor.threads) { |args| yield fetch *args }
108
+ @queues[stdclass] = { queue: Queue.new, workers_pool: wp }
109
+ Thread.new { process_queue @queues[stdclass] }
74
110
  end
111
+ @queues[stdclass][:queue] << [code, year, opts]
112
+ else yield nil
75
113
  end
76
114
  end
77
115
 
78
116
  # @param code [String]
79
117
  # @param year [String, NilClass]
80
118
  # @param stdclass [Symbol, NilClass]
119
+ #
81
120
  # @param opts [Hash]
82
- # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
83
- # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
84
- # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
85
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
86
- # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
121
+ # @option opts [Boolean] :all_parts If all-parts reference is required
122
+ # @option opts [Boolean] :keep_year If undated reference should return
123
+ # actual reference with year
124
+ # @option opts [Integer] :retries (1) Number of network retries
125
+ #
126
+ # @return [nil, RelatonBib::BibliographicItem,
127
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
128
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
129
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
130
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
131
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
87
132
  # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
88
- # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
89
- # RelatonW3c::W3cBibliographicItem
133
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
90
134
  def fetch_std(code, year = nil, stdclass = nil, opts = {})
91
135
  std = nil
92
136
  @registry.processors.each do |name, processor|
@@ -137,6 +181,98 @@ module Relaton
137
181
 
138
182
  private
139
183
 
184
+ # @param file [String] file path
185
+ # @param yml [String] content in YAML format
186
+ # @param text [String, nil] text to serach
187
+ # @param edition [String, nil] edition to filter
188
+ # @param year [Integer, nil] year to filter
189
+ # @return [BibliographicItem, nil]
190
+ def search_yml(file, yml, text, edition, year)
191
+ item = search_edition_year(file, yml, edition, year)
192
+ return unless item
193
+
194
+ item if match_xml_text(item.to_xml(bibdata: true), text)
195
+ end
196
+
197
+ # @param file [String] file path
198
+ # @param xml [String] content in XML format
199
+ # @param text [String, nil] text to serach
200
+ # @param edition [String, nil] edition to filter
201
+ # @param year [Integer, nil] year to filter
202
+ # @return [BibliographicItem, nil]
203
+ def search_xml(file, xml, text, edition, year)
204
+ return unless text.nil? || match_xml_text(xml, text)
205
+
206
+ search_edition_year(file, xml, edition, year)
207
+ end
208
+
209
+ # @param file [String] file path
210
+ # @param content [String] content in XML or YAmL format
211
+ # @param edition [String, nil] edition to filter
212
+ # @param year [Integer, nil] year to filter
213
+ # @return [BibliographicItem, nil]
214
+ def search_edition_year(file, content, edition, year) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
215
+ processor = @registry.processors[standard_class(file.split("/")[-2])]
216
+ item = if file.match?(/xml$/) then processor.from_xml(content)
217
+ else processor.hash_to_bib(YAML.safe_load(content))
218
+ end
219
+ item if (edition.nil? || item.edition == edition) && (year.nil? ||
220
+ item.date.detect { |d| d.type == "published" && d.on(:year).to_s == year.to_s })
221
+ end
222
+
223
+ # @param xml [String] content in XML format
224
+ # @param text [String, nil] text to serach
225
+ # @return [Boolean]
226
+ def match_xml_text(xml, text)
227
+ %r{((?<attr>=((?<apstr>')|"))|>).*?#{text}.*?(?(<attr>)(?(<apstr>)'|")|<)}mi.match?(xml)
228
+ end
229
+
230
+ # @param code [String]
231
+ # @param year [String, nil]
232
+ # @param stdslass [String]
233
+ #
234
+ # @param opts [Hash] options
235
+ # @option opts [Boolean] :all_parts If all-parts reference is required
236
+ # @option opts [Boolean] :keep_year If undated reference should return
237
+ # actual reference with year
238
+ # @option opts [Integer] :retries (1) Number of network retries
239
+ #
240
+ # @return [nil, RelatonBib::BibliographicItem,
241
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
242
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
243
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
244
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
245
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
246
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
247
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
248
+ def combine_doc(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
249
+ if (refs = code.split " + ").size > 1
250
+ reltype = "derivedFrom"
251
+ reldesc = nil
252
+ elsif (refs = code.split ", ").size > 1
253
+ reltype = "complements"
254
+ reldesc = RelatonBib::FormattedString.new content: "amendment"
255
+ else return
256
+ end
257
+
258
+ doc = @registry.processors[stdclass].hash_to_bib docid: { id: code }
259
+ ref = refs[0]
260
+ updates = check_bibliocache(ref, year, opts, stdclass)
261
+ if updates
262
+ doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates,
263
+ type: "updates")
264
+ end
265
+ divider = stdclass == :relaton_itu ? " " : "/"
266
+ refs[1..-1].each_with_object(doc) do |c, d|
267
+ bib = check_bibliocache(ref + divider + c, year, opts, stdclass)
268
+ if bib
269
+ d.relation << RelatonBib::DocumentRelation.new(
270
+ type: reltype, description: reldesc, bibitem: bib
271
+ )
272
+ end
273
+ end
274
+ end
275
+
140
276
  # @param code [String] code of standard
141
277
  # @return [Symbol] standard class name
142
278
  def standard_class(code)
@@ -147,8 +283,8 @@ module Relaton
147
283
  allowed = @registry.processors.reduce([]) do |m, (_k, v)|
148
284
  m << v.prefix
149
285
  end
150
- warn <<~WARN
151
- #{code} does not have a recognised prefix: #{allowed.join(', ')}.
286
+ Util.log <<~WARN, :info
287
+ [relaton] #{code} does not have a recognised prefix: #{allowed.join(', ')}.
152
288
  See https://github.com/relaton/relaton/ for instructions on prefixing and wrapping document identifiers to disambiguate them.
153
289
  WARN
154
290
  end
@@ -157,7 +293,13 @@ module Relaton
157
293
  # Fofmat ID
158
294
  # @param code [String]
159
295
  # @param year [String]
296
+ #
160
297
  # @param opts [Hash]
298
+ # @option opts [Boolean] :all_parts If all-parts reference is required
299
+ # @option opts [Boolean] :keep_year If undated reference should return
300
+ # actual reference with year
301
+ # @option opts [Integer] :retries (1) Number of network retries
302
+ #
161
303
  # @param stdClass [Symbol]
162
304
  # @return [Array<String>] docid and code
163
305
  def std_id(code, year, opts, stdclass)
@@ -180,79 +322,116 @@ module Relaton
180
322
 
181
323
  # @param entry [String] XML string
182
324
  # @param stdclass [Symbol]
183
- # @param id [String] docid
184
- # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
185
- # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
186
- # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
187
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
188
- # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
325
+ # @return [nil, RelatonBib::BibliographicItem,
326
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
327
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
328
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
329
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
330
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
189
331
  # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
190
- # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
191
- # RelatonW3c::W3cBibliographicItem
192
- def bib_retval(entry, stdclass, _id)
193
- entry.match?(/^not_found/) ? nil : @registry.processors[stdclass].from_xml(entry)
332
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
333
+ def bib_retval(entry, stdclass)
334
+ if entry.nil? || entry.match?(/^not_found/) then nil
335
+ else @registry.processors[stdclass].from_xml(entry)
336
+ end
194
337
  end
195
338
 
196
339
  # @param code [String]
197
340
  # @param year [String]
341
+ #
198
342
  # @param opts [Hash]
343
+ # @option opts [Boolean] :all_parts If all-parts reference is required
344
+ # @option opts [Boolean] :keep_year If undated reference should return
345
+ # actual reference with year
346
+ # @option opts [Integer] :retries (1) Number of network retries
347
+ #
199
348
  # @param stdclass [Symbol]
200
- # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
201
- # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
202
- # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
203
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
204
- # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
349
+ # @return [nil, RelatonBib::BibliographicItem,
350
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
351
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
352
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
353
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
354
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
205
355
  # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
206
- # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
207
- # RelatonW3c::W3cBibliographicItem
356
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
208
357
  def check_bibliocache(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
209
358
  id, searchcode = std_id(code, year, opts, stdclass)
210
359
  yaml = @static_db[id]
211
- return @registry.processors[stdclass].hash_to_bib YAML.safe_load(yaml) if yaml
360
+ if yaml
361
+ return @registry.processors[stdclass].hash_to_bib YAML.safe_load(yaml)
362
+ end
212
363
 
213
364
  db = @local_db || @db
214
365
  altdb = @local_db && @db ? @db : nil
215
366
  if db.nil?
216
- bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
217
- return bib_retval(bibentry, stdclass, id)
367
+ return if opts[:fetch_db]
368
+
369
+ bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db,
370
+ id: id)
371
+ return bib_retval(bibentry, stdclass)
218
372
  end
219
373
 
220
374
  db.delete(id) unless db.valid_entry?(id, year)
221
375
  if altdb
222
- # db[id] ||= altdb[id]
223
- db.clone_entry id, altdb
224
- db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
376
+ return bib_retval(altdb[id], stdclass) if opts[:fetch_db]
377
+
378
+ 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)
225
381
  altdb.clone_entry(id, db) if !altdb.valid_entry?(id, year)
226
382
  else
227
- db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
383
+ return bib_retval(db[id], stdclass) if opts[:fetch_db]
384
+
385
+ db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
386
+ id: id)
228
387
  end
229
- bib_retval(db[id], stdclass, id)
388
+ bib_retval(db[id], stdclass)
230
389
  end
231
390
 
232
391
  # @param code [String]
233
392
  # @param year [String]
393
+ #
234
394
  # @param opts [Hash]
395
+ # @option opts [Boolean] :all_parts If all-parts reference is required
396
+ # @option opts [Boolean] :keep_year If undated reference should return
397
+ # actual reference with year
398
+ # @option opts [Integer] :retries (1) Number of network retries
399
+ #
235
400
  # @param stdclass [Symbol]
236
401
  # @param db [Relaton::DbCache,`NilClass]
237
402
  # @param id [String] docid
238
403
  # @return [String]
239
404
  def new_bib_entry(code, year, opts, stdclass, **args) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
240
- bib = @registry.processors[stdclass].get(code, year, opts)
405
+ bib = net_retry(code, year, opts, stdclass, opts.fetch(:retries, 1))
241
406
  bib_id = bib&.docidentifier&.first&.id
242
407
 
243
408
  # when docid doesn't match bib's id then return a reference to bib's id
244
- if args[:db] && args[:id] && bib_id && args[:id] !~ %r{#{Regexp.quote("(#{bib_id})")}}
409
+ if args[:db] && args[:id] &&
410
+ bib_id && args[:id] !~ %r{#{Regexp.quote("(#{bib_id})")}}
245
411
  bid = std_id(bib.docidentifier.first.id, nil, {}, stdclass).first
246
412
  args[:db][bid] ||= bib_entry bib
247
413
  "redirection #{bid}"
248
- else
249
- bib_entry bib
414
+ else bib_entry bib
250
415
  end
251
416
  end
252
417
 
253
- # @param bib [RelatonGb::GbBibliongraphicItem, RelatonIsoBib::IsoBibliographicItem,
254
- # RelatonIetf::IetfBibliographicItem, RelatonItu::ItuBibliographicItem,
255
- # RelatonNist::NistBibliongraphicItem, RelatonOgc::OgcBibliographicItem]
418
+ # @raise [RelatonBib::RequestError]
419
+ def net_retry(code, year, opts, stdclass, retries)
420
+ @registry.processors[stdclass].get(code, year, opts)
421
+ rescue RelatonBib::RequestError => e
422
+ raise e unless retries > 1
423
+
424
+ net_retry(code, year, opts, stdclass, retries - 1)
425
+ end
426
+
427
+ # @param bib [RelatonBib::BibliographicItem,
428
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
429
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
430
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
431
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
432
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
433
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
434
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
256
435
  # @return [String] XML or "not_found mm-dd-yyyy"
257
436
  def bib_entry(bib)
258
437
  if bib.respond_to? :to_xml
@@ -262,21 +441,33 @@ module Relaton
262
441
  end
263
442
  end
264
443
 
265
- # @param dir [String] DB directory
444
+ # @param dir [String, nil] DB directory
266
445
  # @param type [Symbol]
267
446
  # @return [Relaton::DbCache, NilClass]
268
- def open_cache_biblio(dir, type: :static)
447
+ def open_cache_biblio(dir, type: :static) # rubocop:disable Metrics/MethodLength
269
448
  return nil if dir.nil?
270
449
 
271
450
  db = DbCache.new dir, type == :static ? "yml" : "xml"
451
+ return db if type == :static
272
452
 
273
453
  Dir["#{dir}/*/"].each do |fdir|
274
- next if type == :static || db.check_version?(fdir)
454
+ next if db.check_version?(fdir)
275
455
 
276
- FileUtils.rm_rf(Dir.glob(fdir + "/*"), secure: true)
277
- warn "[relaton] cache #{fdir}: version is obsolete and cache is cleared."
456
+ FileUtils.rm_rf(fdir, secure: true)
457
+ Util.log(
458
+ "[relaton] WARNING: cache #{fdir}: version is obsolete and cache is "\
459
+ "cleared.",
460
+ :warning
461
+ )
278
462
  end
279
463
  db
280
464
  end
465
+
466
+ # @param qwp [Hash]
467
+ # @option qwp [Queue] :queue The queue of references to fetch
468
+ # @option qwp [Relaton::WorkersPool] :workers_pool The pool of workers
469
+ def process_queue(qwp)
470
+ while args = qwp[:queue].pop; qwp[:workers_pool] << args end
471
+ end
281
472
  end
282
473
  end