relaton 1.7.2 → 1.7.7

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 +46 -0
  3. data/docs/README.adoc +160 -2
  4. data/globalcache/iec/iec_60050_102_2007.xml +58 -0
  5. data/globalcache/iec/version +1 -0
  6. data/lib/relaton.rb +8 -7
  7. data/lib/relaton/config.rb +5 -2
  8. data/lib/relaton/db.rb +291 -63
  9. data/lib/relaton/db_cache.rb +25 -3
  10. data/lib/relaton/processor.rb +11 -0
  11. data/lib/relaton/registry.rb +1 -1
  12. data/lib/relaton/util.rb +1 -1
  13. data/lib/relaton/version.rb +1 -1
  14. data/lib/relaton/workers_pool.rb +23 -0
  15. data/relaton.gemspec +6 -5
  16. data/spec/relaton/config_spec.rb +1 -1
  17. data/spec/relaton/db_spec.rb +145 -0
  18. data/spec/relaton/processor_spec.rb +4 -0
  19. data/spec/relaton/regirtry_spec.rb +51 -45
  20. data/spec/relaton_spec.rb +37 -19
  21. data/spec/vcr_cassetes/19133_2005.yml +20 -20
  22. data/spec/vcr_cassetes/cc_dir_10005_2019.yml +10 -10
  23. data/spec/vcr_cassetes/cie_001_1980.yml +120 -0
  24. data/spec/vcr_cassetes/ecma_6.yml +132 -446
  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 +285 -0
  28. data/spec/vcr_cassetes/iec_combined_included.yml +78 -423
  29. data/spec/vcr_cassetes/ieee_528_2019.yml +20 -20
  30. data/spec/vcr_cassetes/iho_b_11.yml +15 -15
  31. data/spec/vcr_cassetes/iso_111111119115_1.yml +5 -5
  32. data/spec/vcr_cassetes/iso_19115.yml +21 -21
  33. data/spec/vcr_cassetes/iso_19115_1.yml +21 -21
  34. data/spec/vcr_cassetes/iso_19115_1_2.yml +42 -42
  35. data/spec/vcr_cassetes/iso_awi_24229.yml +21 -21
  36. data/spec/vcr_cassetes/iso_combined_applied.yml +42 -42
  37. data/spec/vcr_cassetes/iso_combined_included.yml +40 -40
  38. data/spec/vcr_cassetes/itu_combined_included.yml +165 -147
  39. data/spec/vcr_cassetes/ogc_19_025r1.yml +13044 -18
  40. data/spec/vcr_cassetes/ogm_ami4ccm_1_0.yml +7 -7
  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 +29 -29
  45. data/spec/vcr_cassetes/w3c_json_ld11.yml +12 -12
  46. metadata +29 -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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 47b3cd2f3a5066e5b9bd67b07f02f6811593210e53e16438e5e0ccf32275be11
4
- data.tar.gz: 677a08b28aff3139512ddc4f37ba0b7cc98f871f3faa80dad3e8fcd224771089
3
+ metadata.gz: 5814864d64a95c8d7cb4fbb094b2e789cf4f7b731ebc8a2e1f41a7cdbbce2115
4
+ data.tar.gz: 57319c212c34e9ff237b0f834eaad40f3d173dc3de784acd4a5ea804bc11ae01
5
5
  SHA512:
6
- metadata.gz: b9379dace67bfc0ac7793b261b9c94306b1425e3794a9b66228cba139b9229b3326a93800da954f26de5c23020cf816655c05af85c592297cbe0b513cddfaa28
7
- data.tar.gz: 4aaeca235b959c2ec05ce03660639acd65899fdf1af0e96e9ccb5bfa6b6d26a42b9dbb69f1168f7904d36bd29c958ab9cfec3c34a1dc9c107e11c811ec262db1
6
+ metadata.gz: '097fcda0d2884380cbb6b64bdcbc43f38215036921177e897c5962274885456a49a323ea4c02a7a548bfb696cba261d1aac0e7ad7dfc51abe698d9d117b715b5'
7
+ data.tar.gz: 0052e5b6696c790e7deb6d17dd7b12a2918b452f93101cda548c96316317988a061a6aabe8c1277fdc69c45f9bfa2f3af2ab6f862adee48efa0504641d3035c1
@@ -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,8 +102,47 @@ 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
 
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
145
+
102
146
  [source,ruby]
103
147
  ----
104
148
  x = db.fetch("IEEE 19011")
@@ -112,7 +156,7 @@ x = db.fetch("ISO 19011")
112
156
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d0ab2f00
113
157
  ...
114
158
 
115
- x = db.fetch("ISO 19011", "2011")
159
+ x = db.fetch("ISO 19011", "2011", retries: 3)
116
160
  [relaton-iso] ("ISO 19011") fetching...
117
161
  [relaton-iso] ("ISO 19011") found ISO 19011:2011
118
162
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d2593068
@@ -123,6 +167,44 @@ x = db.fetch("ISO 19115", nil, all_parts: true)
123
167
  [relaton-iso] ("ISO 19115") found ISO 19115 (all parts)
124
168
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d0ae8bf0
125
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
+ # fetch document
186
+ db.fetch_async("ISO 19115") do |result|
187
+ results << { "ISO 19115" => result }
188
+ end
189
+ # fetch other documets the same way
190
+
191
+ # wait until documets fetching
192
+ while x = results.pop
193
+ # do thatever you need with result x
194
+ end
195
+ ----
196
+
197
+ ==== Fetch by URN
198
+
199
+ This functionality works only for IEC documents.
200
+
201
+ [source,ruby]
202
+ ----
203
+ x = db.fetch "urn:iec:std:iec:60050-102:2007:::"
204
+ [relaton-iec] ("IEC 60050-102") fetching...
205
+ [relaton-iec] ("IEC 60050-102") found IEC 60050-102:2007
206
+ => #<RelatonIec::IecBibliographicItem:0x007fbd6c3790e8
207
+ ...
126
208
  ----
127
209
 
128
210
  === Fetch combined documents
@@ -177,6 +259,82 @@ bib.relation[1].bibitem.docidentifier[0].id
177
259
  [source,ruby]
178
260
  ----
179
261
  bib = db.fetch "ISO 19115-1, Amd 1"
262
+ => ["Chinese Standard", "GB/T 1.1"]
263
+ [relaton-iso] ("ISO 19115-1") fetching...
264
+ [relaton-iso] ("ISO 19115-1") found ISO 19115-1:2014
265
+ [relaton-iso] ("ISO 19115-1/Amd 1") fetching...
266
+ [relaton-iso] ("ISO 19115-1/Amd 1") found ISO 19115-1:2014/Amd 1:2018
267
+ => #<RelatonIsoBib::IsoBibliographicItem:0x007fb09b36d1b8
268
+ ...
269
+ ----
270
+
271
+ ==== Fetch all documents from cache
272
+
273
+ `Relaton::Db#fetch_all(text = nil, edition: nil, year: nil)` - fetches all document from local cache
274
+
275
+ * `text` - (String) filter entries by a text (optional)
276
+ * `edition` - (String) filter entries by an edition (optional)
277
+ * `year` - (Integer) filter entries by a year (optional)
278
+
279
+ [source,ruby]
280
+ ----
281
+ # query for all entries in a cahche
282
+
283
+ items = db.fetch_all
284
+ => [#<RelatonIec::IecBibliographicItem:0x007facda8fdc28
285
+ ...
286
+
287
+ items.size
288
+ => 6
289
+
290
+ # query for all entries in a cahche for a certain string
291
+
292
+ items = db.fetch_all("mathematical terminology")
293
+ => [#<RelatonIec::IecBibliographicItem:0x007ffeae5bd240
294
+ ...
295
+
296
+ items.size
297
+ => 1
298
+
299
+ items[0].docidentifier[0].id
300
+ => "IEC 60050-102:2007"
301
+
302
+ # query for all entries in a cahche for a certain string and edition
303
+
304
+ items = db.fetch_all("system", edition: "2")
305
+ => [#<RelatonIsoBib::IsoBibliographicItem:0x007ffebe2d1be8
306
+ ...
307
+
308
+ items.size
309
+ => 1
310
+
311
+ items[0].docidentifier[0].id
312
+ => "ISO 19011:2011"
313
+
314
+ # query for all entries in a cahche for a certain string and year
315
+
316
+ items = db.fetch_all("system", year: 2018)
317
+ => [#<RelatonIsoBib::IsoBibliographicItem:0x007ffeae645fa0
318
+ ...
319
+
320
+ items.size
321
+ => 1
322
+
323
+ items[0].docidentifier[0].id
324
+ => "ISO 19011 (all parts)"
325
+ ----
326
+
327
+ === Static DB
328
+
329
+ This gem has a static DB which is distributed with it. Now the static contains documents:
330
+ ----
331
+ ISO/IEC DIR 1 IEC SUP
332
+ ISO/IEC DIR 1 ISO SUP
333
+ ISO/IEC DIR 1
334
+ ISO/IEC DIR 2 IEC
335
+ ISO/IEC DIR 2 ISO
336
+ ISO/IEC DIR IEC SUP
337
+ ISO/IEC DIR 1 JTC SUP
180
338
  ----
181
339
 
182
340
  === Get document type
@@ -214,7 +372,7 @@ x.to_xml bibdata: true
214
372
  db.load_entry("ISO(ISO 19011)")
215
373
  => "<bibdata type="standard">
216
374
  ...
217
- <?bibdata>"
375
+ </bibdata>"
218
376
  ----
219
377
 
220
378
  === Entry manipulation
@@ -0,0 +1,58 @@
1
+ <bibdata type="standard">
2
+ <fetched>2021-02-03</fetched>
3
+ <title type="title-main" format="text/plain" language="en" script="Latn">International Electrotechnical Vocabulary (IEV)</title>
4
+ <title type="title-part" format="text/plain" language="en" script="Latn">Part 102: Mathematics -- General concepts and linear algebra</title>
5
+ <title type="main" format="text/plain" language="en" script="Latn">International Electrotechnical Vocabulary (IEV) - Part 102: Mathematics -- General concepts and linear algebra</title>
6
+ <uri type="src">https://webstore.iec.ch/publication/160</uri>
7
+ <uri type="obp">/preview/info_iec60050-102%7Bed1.0%7Db.pdf</uri>
8
+ <docidentifier type="IEC">IEC 60050-102:2007</docidentifier>
9
+ <docidentifier type="URN">urn:iec:std:iec:60050-102:2007:::en</docidentifier>
10
+ <date type="published">
11
+ <on>2007-08-27</on>
12
+ </date>
13
+ <contributor>
14
+ <role type="publisher"/>
15
+ <organization>
16
+ <name>International Electrotechnical Commission</name>
17
+ <abbreviation>IEC</abbreviation>
18
+ <uri>www.iec.ch</uri>
19
+ </organization>
20
+ </contributor>
21
+ <edition>1.0</edition>
22
+ <language>en</language>
23
+ <script>Latn</script>
24
+ <abstract format="text/plain" language="en" script="Latn">This part of IEC 60050 gives the general mathematical terminology used in the fields of electricity, electronics and telecommunications, together with basic concepts in linear algebra. It maintains a clear distinction between mathematical concepts and physical concepts, even if some terms are used in both cases. Another part will deal with functions.&#13;
25
+ It has the status of a horizontal standard in accordance with IEC Guide 108.</abstract>
26
+ <status>
27
+ <stage>60</stage>
28
+ <substage>60</substage>
29
+ </status>
30
+ <copyright>
31
+ <from>2007</from>
32
+ <owner>
33
+ <organization>
34
+ <name>International Electrotechnical Commission</name>
35
+ <abbreviation>IEC</abbreviation>
36
+ <uri>www.iec.ch</uri>
37
+ </organization>
38
+ </owner>
39
+ </copyright>
40
+ <place>Geneva</place>
41
+ <ext>
42
+ <doctype>international-standard</doctype>
43
+ <editorialgroup>
44
+ <technical-committee number="1" type="technicalCommittee">TC 1 - Terminology</technical-committee>
45
+ </editorialgroup>
46
+ <ics>
47
+ <code>01.040.07</code>
48
+ <text>Natural and applied sciences (Vocabularies)</text>
49
+ </ics>
50
+ <ics>
51
+ <code>07.020</code>
52
+ <text>Mathematics</text>
53
+ </ics>
54
+ <structuredidentifier type="IEC">
55
+ <project-number>60050</project-number>
56
+ </structuredidentifier>
57
+ </ext>
58
+ </bibdata>
@@ -0,0 +1 @@
1
+ 407d6f5afdc9ae9ea7abe6e84d27f40b
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,56 +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 [NilClass, RelatonIsoBib::IsoBibliographicItem,
27
- # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
28
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem]
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,
61
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
62
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
63
+ ##
29
64
  def fetch(code, year = nil, opts = {})
30
65
  stdclass = standard_class(code) || return
31
- cd = combine_doc code, year, opts, stdclass
32
- return cd if cd
66
+ processor = @registry.processors[stdclass]
67
+ ref = if processor.respond_to?(:urn_to_code)
68
+ processor.urn_to_code(code)&.first
69
+ else code
70
+ end
71
+ ref ||= code
72
+ result = combine_doc ref, year, opts, stdclass
73
+ result ||= check_bibliocache(ref, year, opts, stdclass)
74
+ result
75
+ end
33
76
 
34
- check_bibliocache(code, 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
35
81
  end
36
82
 
37
- def combine_doc(code, year, opts, stdclass)
38
- if (refs = code.split " + ").size > 1
39
- reltype = "derivedFrom"
40
- reldesc = nil
41
- elsif (refs = code.split ", ").size > 1
42
- reltype = "complements"
43
- reldesc = RelatonBib::FormattedString.new content: "amendment"
44
- 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
45
97
  end
98
+ result
99
+ end
46
100
 
47
- doc = @registry.processors[stdclass].hash_to_bib docid: { id: code }
48
- ref = refs[0]
49
- updates = check_bibliocache(ref, year, opts, stdclass)
50
- doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates, type: "updates") if updates
51
- refs[1..-1].each_with_object(doc) do |c, d|
52
- bib = check_bibliocache("#{ref}/#{c}", year, opts, stdclass)
53
- if bib
54
- 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] }
55
110
  end
111
+ @queues[stdclass][:queue] << [code, year, opts]
112
+ else yield nil
56
113
  end
57
114
  end
58
115
 
59
116
  # @param code [String]
60
117
  # @param year [String, NilClass]
61
118
  # @param stdclass [Symbol, NilClass]
119
+ #
62
120
  # @param opts [Hash]
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,
132
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
133
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
63
134
  def fetch_std(code, year = nil, stdclass = nil, opts = {})
64
135
  std = nil
65
136
  @registry.processors.each do |name, processor|
@@ -110,18 +181,109 @@ module Relaton
110
181
 
111
182
  private
112
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
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
+ refs[1..-1].each_with_object(doc) do |c, d|
266
+ bib = check_bibliocache("#{ref}/#{c}", year, opts, stdclass)
267
+ if bib
268
+ d.relation << RelatonBib::DocumentRelation.new(
269
+ type: reltype, description: reldesc, bibitem: bib
270
+ )
271
+ end
272
+ end
273
+ end
274
+
113
275
  # @param code [String] code of standard
114
276
  # @return [Symbol] standard class name
115
277
  def standard_class(code)
116
278
  @registry.processors.each do |name, processor|
117
- return name if /^#{processor.prefix}/.match(code) ||
279
+ return name if /^(urn:)?#{processor.prefix}/i.match?(code) ||
118
280
  processor.defaultprefix.match(code)
119
281
  end
120
282
  allowed = @registry.processors.reduce([]) do |m, (_k, v)|
121
283
  m << v.prefix
122
284
  end
123
- warn <<~WARN
124
- #{code} does not have a recognised prefix: #{allowed.join(', ')}.
285
+ Util.log <<~WARN, :info
286
+ [relaton] #{code} does not have a recognised prefix: #{allowed.join(', ')}.
125
287
  See https://github.com/relaton/relaton/ for instructions on prefixing and wrapping document identifiers to disambiguate them.
126
288
  WARN
127
289
  end
@@ -130,7 +292,13 @@ module Relaton
130
292
  # Fofmat ID
131
293
  # @param code [String]
132
294
  # @param year [String]
295
+ #
133
296
  # @param opts [Hash]
297
+ # @option opts [Boolean] :all_parts If all-parts reference is required
298
+ # @option opts [Boolean] :keep_year If undated reference should return
299
+ # actual reference with year
300
+ # @option opts [Integer] :retries (1) Number of network retries
301
+ #
134
302
  # @param stdClass [Symbol]
135
303
  # @return [Array<String>] docid and code
136
304
  def std_id(code, year, opts, stdclass)
@@ -153,70 +321,116 @@ module Relaton
153
321
 
154
322
  # @param entry [String] XML string
155
323
  # @param stdclass [Symbol]
156
- # @param id [String] docid
157
- # @return [NilClass, RelatonIsoBib::IsoBibliographicItem,
158
- # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
159
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem]
160
- def bib_retval(entry, stdclass, _id)
161
- entry.match?(/^not_found/) ? nil : @registry.processors[stdclass].from_xml(entry)
324
+ # @return [nil, RelatonBib::BibliographicItem,
325
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
326
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
327
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
328
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
329
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
330
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
331
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
332
+ def bib_retval(entry, stdclass)
333
+ if entry.nil? || entry.match?(/^not_found/) then nil
334
+ else @registry.processors[stdclass].from_xml(entry)
335
+ end
162
336
  end
163
337
 
164
338
  # @param code [String]
165
339
  # @param year [String]
340
+ #
166
341
  # @param opts [Hash]
342
+ # @option opts [Boolean] :all_parts If all-parts reference is required
343
+ # @option opts [Boolean] :keep_year If undated reference should return
344
+ # actual reference with year
345
+ # @option opts [Integer] :retries (1) Number of network retries
346
+ #
167
347
  # @param stdclass [Symbol]
168
- # @return [NilClass, RelatonIsoBib::IsoBibliographicItem,
169
- # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
170
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
171
- # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
348
+ # @return [nil, RelatonBib::BibliographicItem,
349
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
350
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
351
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
352
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
353
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
354
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
355
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
172
356
  def check_bibliocache(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
173
357
  id, searchcode = std_id(code, year, opts, stdclass)
174
358
  yaml = @static_db[id]
175
- return @registry.processors[stdclass].hash_to_bib YAML.safe_load(yaml) if yaml
359
+ if yaml
360
+ return @registry.processors[stdclass].hash_to_bib YAML.safe_load(yaml)
361
+ end
176
362
 
177
363
  db = @local_db || @db
178
364
  altdb = @local_db && @db ? @db : nil
179
365
  if db.nil?
180
- bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
181
- return bib_retval(bibentry, stdclass, id)
366
+ return if opts[:fetch_db]
367
+
368
+ bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db,
369
+ id: id)
370
+ return bib_retval(bibentry, stdclass)
182
371
  end
183
372
 
184
373
  db.delete(id) unless db.valid_entry?(id, year)
185
374
  if altdb
186
- # db[id] ||= altdb[id]
187
- db.clone_entry id, altdb
188
- db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
375
+ return bib_retval(altdb[id], stdclass) if opts[:fetch_db]
376
+
377
+ db.clone_entry id, altdb if altdb.valid_entry? id, year
378
+ db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
379
+ id: id)
189
380
  altdb.clone_entry(id, db) if !altdb.valid_entry?(id, year)
190
381
  else
191
- db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
382
+ return bib_retval(db[id], stdclass) if opts[:fetch_db]
383
+
384
+ db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db,
385
+ id: id)
192
386
  end
193
- bib_retval(db[id], stdclass, id)
387
+ bib_retval(db[id], stdclass)
194
388
  end
195
389
 
196
390
  # @param code [String]
197
391
  # @param year [String]
392
+ #
198
393
  # @param opts [Hash]
394
+ # @option opts [Boolean] :all_parts If all-parts reference is required
395
+ # @option opts [Boolean] :keep_year If undated reference should return
396
+ # actual reference with year
397
+ # @option opts [Integer] :retries (1) Number of network retries
398
+ #
199
399
  # @param stdclass [Symbol]
200
400
  # @param db [Relaton::DbCache,`NilClass]
201
401
  # @param id [String] docid
202
402
  # @return [String]
203
403
  def new_bib_entry(code, year, opts, stdclass, **args) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
204
- bib = @registry.processors[stdclass].get(code, year, opts)
404
+ bib = net_retry(code, year, opts, stdclass, opts.fetch(:retries, 1))
205
405
  bib_id = bib&.docidentifier&.first&.id
206
406
 
207
407
  # when docid doesn't match bib's id then return a reference to bib's id
208
- if args[:db] && args[:id] && bib_id && args[:id] !~ %r{#{Regexp.quote("(#{bib_id})")}}
408
+ if args[:db] && args[:id] &&
409
+ bib_id && args[:id] !~ %r{#{Regexp.quote("(#{bib_id})")}}
209
410
  bid = std_id(bib.docidentifier.first.id, nil, {}, stdclass).first
210
411
  args[:db][bid] ||= bib_entry bib
211
412
  "redirection #{bid}"
212
- else
213
- bib_entry bib
413
+ else bib_entry bib
214
414
  end
215
415
  end
216
416
 
217
- # @param bib [RelatonGb::GbBibliongraphicItem, RelatonIsoBib::IsoBibliographicItem,
218
- # RelatonIetf::IetfBibliographicItem, RelatonItu::ItuBibliographicItem,
219
- # RelatonNist::NistBibliongraphicItem, RelatonOgc::OgcBibliographicItem]
417
+ # @raise [RelatonBib::RequestError]
418
+ def net_retry(code, year, opts, stdclass, retries)
419
+ @registry.processors[stdclass].get(code, year, opts)
420
+ rescue RelatonBib::RequestError => e
421
+ raise e unless retries > 1
422
+
423
+ net_retry(code, year, opts, stdclass, retries - 1)
424
+ end
425
+
426
+ # @param bib [RelatonBib::BibliographicItem,
427
+ # RelatonIsoBib::IsoBibliographicItem, RelatonItu::ItuBibliographicItem,
428
+ # RelatonIetf::IetfBibliographicItem, RelatonIec::IecBibliographicItem,
429
+ # RelatonIeee::IeeeBibliographicItem, RelatonNist::NistBibliongraphicItem,
430
+ # RelatonGb::GbbibliographicItem, RelatonOgc::OgcBibliographicItem,
431
+ # RelatonCalconnect::CcBibliographicItem, RelatinUn::UnBibliographicItem,
432
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
433
+ # RelatonOmg::OmgBibliographicItem, RelatonW3c::W3cBibliographicItem]
220
434
  # @return [String] XML or "not_found mm-dd-yyyy"
221
435
  def bib_entry(bib)
222
436
  if bib.respond_to? :to_xml
@@ -226,21 +440,35 @@ module Relaton
226
440
  end
227
441
  end
228
442
 
229
- # @param dir [String] DB directory
443
+ # @param dir [String, nil] DB directory
230
444
  # @param type [Symbol]
231
445
  # @return [Relaton::DbCache, NilClass]
232
- def open_cache_biblio(dir, type: :static)
446
+ def open_cache_biblio(dir, type: :static) # rubocop:disable Metrics/MethodLength
233
447
  return nil if dir.nil?
234
448
 
235
449
  db = DbCache.new dir, type == :static ? "yml" : "xml"
450
+ return db if type == :static
236
451
 
237
452
  Dir["#{dir}/*/"].each do |fdir|
238
- next if type == :static || db.check_version?(fdir)
453
+ next if db.check_version?(fdir)
239
454
 
240
- FileUtils.rm_rf(Dir.glob(fdir + "/*"), secure: true)
241
- warn "[relaton] cache #{fdir}: version is obsolete and cache is cleared."
455
+ FileUtils.rm_rf(fdir, secure: true)
456
+ Util.log(
457
+ "[relaton] WARNING: cache #{fdir}: version is obsolete and cache is "\
458
+ "cleared.",
459
+ :warning
460
+ )
242
461
  end
243
462
  db
244
463
  end
464
+
465
+ # @param qwp [Hash]
466
+ # @option qwp [Queue] :queue The queue of references to fetch
467
+ # @option qwp [Relaton::WorkersPool] :workers_pool The pool of workers
468
+ def process_queue(qwp)
469
+ while args = qwp[:queue].pop
470
+ qwp[:workers_pool] << args
471
+ end
472
+ end
245
473
  end
246
474
  end