relaton 1.7.0 → 1.7.5

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 +228 -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 +3 -2
  8. data/lib/relaton/db.rb +237 -32
  9. data/lib/relaton/db_cache.rb +22 -6
  10. data/lib/relaton/processor.rb +11 -0
  11. data/lib/relaton/registry.rb +1 -1
  12. data/lib/relaton/version.rb +1 -1
  13. data/lib/relaton/workers_pool.rb +23 -0
  14. data/localcache/iec/iec_60050_102_2007.xml +58 -0
  15. data/localcache/iec/version +1 -0
  16. data/relaton.gemspec +8 -6
  17. data/spec/relaton/db_cache_spec.rb +1 -1
  18. data/spec/relaton/db_spec.rb +122 -0
  19. data/spec/relaton/processor_spec.rb +4 -0
  20. data/spec/relaton/regirtry_spec.rb +54 -44
  21. data/spec/relaton_spec.rb +120 -19
  22. data/spec/vcr_cassetes/19133_2005.yml +18 -18
  23. data/spec/vcr_cassetes/cc_dir_10005_2019.yml +7 -7
  24. data/spec/vcr_cassetes/cie_001_1980.yml +120 -0
  25. data/spec/vcr_cassetes/ecma_6.yml +94 -0
  26. data/spec/vcr_cassetes/fisp_140.yml +6 -6
  27. data/spec/vcr_cassetes/gb_t_20223_2006.yml +13 -9
  28. data/spec/vcr_cassetes/hist_cmbined_included.yml +105 -0
  29. data/spec/vcr_cassetes/iec_60050_102_2007.yml +283 -0
  30. data/spec/vcr_cassetes/iec_combined_included.yml +945 -0
  31. data/spec/vcr_cassetes/ieee_528_2019.yml +15 -15
  32. data/spec/vcr_cassetes/iho_b_11.yml +15 -15
  33. data/spec/vcr_cassetes/iso_111111119115_1.yml +4 -4
  34. data/spec/vcr_cassetes/iso_19115.yml +19 -19
  35. data/spec/vcr_cassetes/iso_19115_1.yml +17 -17
  36. data/spec/vcr_cassetes/iso_19115_1_2.yml +35 -35
  37. data/spec/vcr_cassetes/iso_awi_24229.yml +18 -18
  38. data/spec/vcr_cassetes/iso_combined_applied.yml +361 -0
  39. data/spec/vcr_cassetes/iso_combined_included.yml +361 -0
  40. data/spec/vcr_cassetes/itu_combined_included.yml +1296 -0
  41. data/spec/vcr_cassetes/ogc_19_025r1.yml +2484 -1901
  42. data/spec/vcr_cassetes/ogm_ami4ccm_1_0.yml +7 -7
  43. data/spec/vcr_cassetes/rfc_8341.yml +47 -15
  44. data/spec/vcr_cassetes/rfc_unsuccess.yml +70 -0
  45. data/spec/vcr_cassetes/sp_800_38b.yml +6 -6
  46. data/spec/vcr_cassetes/un_rtade_cefact_2004_32.yml +30 -30
  47. data/spec/vcr_cassetes/w3c_json_ld11.yml +12 -12
  48. metadata +62 -50
  49. data/.github/workflows/macos.yml +0 -34
  50. data/.github/workflows/ubuntu.yml +0 -32
  51. data/.github/workflows/windows.yml +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c04670d96d910f7279ae306322df75cc9939ce240c37fb237716f97877207029
4
- data.tar.gz: f25fc7f76f03fa90dcbe18c881b8781353e55dc9f867af5464cdcd0423d76be9
3
+ metadata.gz: a8c7a7a21ac269d14d0d4532e4a7ee8d28fa9446bf7c7b59e0ddb71b5a21b681
4
+ data.tar.gz: 31332da1783e054318a74808417dd8d3cc924a31f73cd7f35470b9d769c9aad8
5
5
  SHA512:
6
- metadata.gz: e858712ad2f9691936dfd5af9563896be74447eb4985cd1b56ede9a2e283fb6205f1ef791a9d4bc2921376e0346a8ac826ec1666abf3199f212d483bc007628e
7
- data.tar.gz: '08b9ada0c3c65394c8301c5bbc9b0cb025ba0cf94c64dd042aec313fbb124740a6f55e91a3d8a5e2e1952f79517130ffc28b0cd2fc4b5ca8106998723e74fb9c'
6
+ metadata.gz: 0a8cdaf3cad2830b90f27305a788a2710bcf542f47fa4a56a374cce17519626f9f5914c3c2f5ab37eb3488cfb6949ea55af3e6e9fd3ce3dce9e0aaf653be8e5f
7
+ data.tar.gz: 7b7d5e8e20cdc91c3e0d30ce0492d79c937a772b7d67c7041f04447210f3bf2045a3c95472d61a3bb7760e9d45b96e948979ba4b4ef4bbc497678cc270badf05
@@ -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
@@ -62,6 +62,13 @@ e.g. `get("ISO 19115-1", "2014", all_parts: true)` is transformed into a referen
62
62
 
63
63
  == Usage
64
64
 
65
+ === Create DB
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
+
65
72
  [source,ruby]
66
73
  ----
67
74
  require "relaton"
@@ -93,7 +100,47 @@ db = Relaton::Db.new("globalcache", "localcache")
93
100
  @local_db=#<Relaton::DbCache:0x007faabc8fa5c0 @dir="localcache", @ext="xml">,
94
101
  @local_db_name="localcache",
95
102
  ...
103
+ ----
104
+
105
+ === Modify DB
106
+
107
+ ==== Move DB
108
+
109
+ `Relaton::Db#mv(new_globalcache_dir, new_localcahe_dir)` moves DB directories to new location.
110
+
111
+ * `new_globalcahe_dir` - (String or nil) new globalcache location
112
+ * `new_localcahe_dir` - (String or nil) new localcache location
113
+
114
+ [source,ruby]
115
+ ----
116
+ db.mv("new_globalcache_dir", "new_localcahe_dir")
117
+ ----
118
+
119
+ ==== Clear DB
96
120
 
121
+ `Relaton::Db#clear` removes all entries form DB
122
+
123
+ === Fetch documens
124
+
125
+ ==== Fetch document by references
126
+
127
+ There are 3 fetching methods:
128
+
129
+ * `Relaton::Db#fetch(reference, year, options)` - fetches document from local cache or remote source.
130
+ * `Relaton::Db#fetch_db(reference, year, options)` - fetches document from local cache
131
+ * `Relaton::Db#fetch_async(reference, year, options, &block)` - fetches document asynchronously
132
+
133
+ Arguments:
134
+
135
+ * `reference` - (String) reference to fethc document
136
+ * `year` - (String or nil) year to filter relult (optional)
137
+ * `options` - (Hash) hash of options. Alloved options:
138
+ - `:all_parts` - (Boolean) should be `true` if all-parts reference is required
139
+ - `:keep_yer` - (Boolean) should be `true` if undated reference should return actual reference with year
140
+ - `:retries` - (Number) number of network retries. Default 1
141
+
142
+ [source,ruby]
143
+ ----
97
144
  x = db.fetch("IEEE 19011")
98
145
  [relaton-ieee] ("IEEE 19011") fetching...
99
146
  [relaton-ieee] WARNING: no match found online for IEEE 19011. The code must be exactly like it is on the standards website.
@@ -105,7 +152,7 @@ x = db.fetch("ISO 19011")
105
152
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d0ab2f00
106
153
  ...
107
154
 
108
- x = db.fetch("ISO 19011", "2011")
155
+ x = db.fetch("ISO 19011", "2011", retries: 3)
109
156
  [relaton-iso] ("ISO 19011") fetching...
110
157
  [relaton-iso] ("ISO 19011") found ISO 19011:2011
111
158
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d2593068
@@ -117,9 +164,185 @@ x = db.fetch("ISO 19115", nil, all_parts: true)
117
164
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d0ae8bf0
118
165
  ...
119
166
 
167
+ # Fetchig from local cache
168
+
169
+ x = db.fetch("ISO 19011")
170
+ => #<RelatonIsoBib::IsoBibliographicItem:0x007fde5f48a9f0
171
+ ...
172
+
173
+ x = db.fetch_db("ISO 5749")
174
+ => nil
175
+
176
+ # Fetching asynchronously
177
+
178
+ # prepare queue for results
179
+ results = Queue.new
180
+
181
+ # fetch document
182
+ db.fetch_async("ISO 19115") do |result|
183
+ results << { "ISO 19115" => result }
184
+ end
185
+ # fetch other documets the same way
186
+
187
+ # wait until documets fetching
188
+ while x = results.pop
189
+ # do thatever you need with result x
190
+ end
191
+ ----
192
+
193
+ ==== Fetch by URN
194
+
195
+ This functionality works only for IEC documents.
196
+
197
+ [source,ruby]
198
+ ----
199
+ x = db.fetch "urn:iec:std:iec:60050-102:2007:::"
200
+ [relaton-iec] ("IEC 60050-102") fetching...
201
+ [relaton-iec] ("IEC 60050-102") found IEC 60050-102:2007
202
+ => #<RelatonIec::IecBibliographicItem:0x007fbd6c3790e8
203
+ ...
204
+ ----
205
+
206
+ === Fetch combined documents
207
+
208
+ This functionality works only for ISO, IEC, ITU, and NIST documents.
209
+
210
+ ==== Fetch included documents
211
+ [source,ruby]
212
+ ----
213
+ bib = db.fetch "ISO 19115-1 + Amd 1"
214
+ [relaton-iso] ("ISO 19115-1") fetching...
215
+ [relaton-iso] ("ISO 19115-1") found ISO 19115-1:2014
216
+ [relaton-iso] ("ISO 19115-1/Amd 1") fetching...
217
+ [relaton-iso] ("ISO 19115-1/Amd 1") found ISO 19115-1:2014/Amd 1:2018
218
+ => #<RelatonIsoBib::IsoBibliographicItem:0x007f95a929a748
219
+
220
+ bib.docidentifier[0].id
221
+ => "ISO 19115-1 + Amd 1"
222
+
223
+ bib.relation[0].type
224
+ => "updates"
225
+
226
+ bib.relation[0].bibitem.docidentifier[0].id
227
+ => "ISO 19115-1"
228
+
229
+ bib.relation[1].type
230
+ => "derivedFrom"
231
+
232
+ bib.relation[1].bibitem.docidentifier[0].id
233
+ => "ISO 19115-1/Amd 1:2018"
234
+
235
+ bib.docidentifier[0].id
236
+ => "ISO 19115-1, Amd 1"
237
+
238
+ bib.relation[0].type
239
+ => "updates"
240
+
241
+ bib.relation[0].bibitem.docidentifier[0].id
242
+ => "ISO 19115-1"
243
+
244
+ bib.relation[1].type
245
+ => "complements"
246
+
247
+ bib.relation[1].description
248
+ => "amendment"
249
+
250
+ bib.relation[1].bibitem.docidentifier[0].id
251
+ => "ISO 19115-1/Amd 1:2018"
252
+ ----
253
+
254
+ ==== Fetch applied documents
255
+ [source,ruby]
256
+ ----
257
+ bib = db.fetch "ISO 19115-1, Amd 1"
258
+ => ["Chinese Standard", "GB/T 1.1"]
259
+ [relaton-iso] ("ISO 19115-1") fetching...
260
+ [relaton-iso] ("ISO 19115-1") found ISO 19115-1:2014
261
+ [relaton-iso] ("ISO 19115-1/Amd 1") fetching...
262
+ [relaton-iso] ("ISO 19115-1/Amd 1") found ISO 19115-1:2014/Amd 1:2018
263
+ => #<RelatonIsoBib::IsoBibliographicItem:0x007fb09b36d1b8
264
+ ...
265
+ ----
266
+
267
+ ==== Fetch all documents from cache
268
+
269
+ `Relaton::Db#fetch_all(text = nil, edition: nil, year: nil)` - fetches all document from local cache
270
+
271
+ * `text` - (String) filter entries by a text (optional)
272
+ * `edition` - (String) filter entries by an edition (optional)
273
+ * `year` - (Integer) filter entries by a year (optional)
274
+
275
+ [source,ruby]
276
+ ----
277
+ # query for all entries in a cahche
278
+
279
+ items = db.fetch_all
280
+ => [#<RelatonIec::IecBibliographicItem:0x007facda8fdc28
281
+ ...
282
+
283
+ items.size
284
+ => 6
285
+
286
+ # query for all entries in a cahche for a certain string
287
+
288
+ items = db.fetch_all("mathematical terminology")
289
+ => [#<RelatonIec::IecBibliographicItem:0x007ffeae5bd240
290
+ ...
291
+
292
+ items.size
293
+ => 1
294
+
295
+ items[0].docidentifier[0].id
296
+ => "IEC 60050-102:2007"
297
+
298
+ # query for all entries in a cahche for a certain string and edition
299
+
300
+ items = db.fetch_all("system", edition: "2")
301
+ => [#<RelatonIsoBib::IsoBibliographicItem:0x007ffebe2d1be8
302
+ ...
303
+
304
+ items.size
305
+ => 1
306
+
307
+ items[0].docidentifier[0].id
308
+ => "ISO 19011:2011"
309
+
310
+ # query for all entries in a cahche for a certain string and year
311
+
312
+ items = db.fetch_all("system", year: 2018)
313
+ => [#<RelatonIsoBib::IsoBibliographicItem:0x007ffeae645fa0
314
+ ...
315
+
316
+ items.size
317
+ => 1
318
+
319
+ items[0].docidentifier[0].id
320
+ => "ISO 19011 (all parts)"
321
+ ----
322
+
323
+ === Static DB
324
+
325
+ This gem has a static DB which is distributed with it. Now the static contains documents:
326
+ ----
327
+ ISO/IEC DIR 1 IEC SUP
328
+ ISO/IEC DIR 1 ISO SUP
329
+ ISO/IEC DIR 1
330
+ ISO/IEC DIR 2 IEC
331
+ ISO/IEC DIR 2 ISO
332
+ ISO/IEC DIR IEC SUP
333
+ ISO/IEC DIR 1 ISO SUP
334
+ ----
335
+
336
+ === Get document type
337
+ [source,ruby]
338
+ ----
120
339
  db.docid_type("CN(GB/T 1.1)")
121
340
  => ["Chinese Standard", "GB/T 1.1"]
341
+ ----
122
342
 
343
+ === Serializing
344
+ [source,ruby]
345
+ ----
123
346
  x.to_xml
124
347
  => "<bibitem id="ISO19115(allparts)" type="standard">
125
348
  ...
@@ -146,11 +369,14 @@ db.load_entry("ISO(ISO 19011)")
146
369
  => "<bibdata type="standard">
147
370
  ...
148
371
  <?bibdata>"
372
+ ----
149
373
 
374
+ === Entry manipulation
375
+ [source,ruby]
376
+ ----
150
377
  db.save_entry("ISO(ISO 19011)", nil)
151
378
  => nil
152
379
 
153
380
  db.load_entry("ISO(ISO 19011)")
154
381
  => nil
155
-
156
382
  ----
@@ -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,11 @@ 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(warning error)
19
+ @use_api = false # @TODO change to true when we start using api.relaton.org
19
20
  end
20
21
  end
21
22
 
data/lib/relaton/db.rb CHANGED
@@ -12,37 +12,112 @@ module Relaton
12
12
  @registry = Relaton::Registry.instance
13
13
  @db = open_cache_biblio(global_cache, type: :global)
14
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
15
+ @static_db = open_cache_biblio File.expand_path("../relaton/static_cache", __dir__)
16
+ @queues = {}
19
17
  end
20
18
 
19
+ # Move global and/or local caches to anothe dirs
20
+ # @param new_global_dir [String, nil]
21
+ # @param new_local_dir [String, nil]
22
+ def mv(new_global_dir, new_local_dir)
23
+ @db.mv new_global_dir
24
+ @local_db.mv new_local_dir
25
+ end
26
+
27
+ # Clear global and local databases
28
+ def clear
29
+ @db.clear
30
+ @local_db.clear
31
+ end
32
+
33
+ ##
21
34
  # The class of reference requested is determined by the prefix of the code:
22
35
  # GB Standard for gbbib, IETF for ietfbib, ISO for isobib, IEC or IEV for iecbib,
36
+ #
23
37
  # @param code [String] the ISO standard Code to look up (e.g. "ISO 9000")
24
38
  # @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,
39
+ #
40
+ # @param opts [Hash] options
41
+ # @option opts [Boolean] :all_parts If all-parts reference is required
42
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
43
+ # @option opts [Integer] :retries (1) Number of network retries
44
+ #
45
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
27
46
  # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
28
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem]
47
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
48
+ # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
49
+ # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
50
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
51
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
52
+ # RelatonW3c::W3cBibliographicItem
53
+ ##
29
54
  def fetch(code, year = nil, opts = {})
30
55
  stdclass = standard_class(code) || return
31
- check_bibliocache(code, year, opts, stdclass)
56
+ processor = @registry.processors[stdclass]
57
+ ref = processor.respond_to?(:urn_to_code) ? processor.urn_to_code(code)&.first : code
58
+ ref ||= code
59
+ result = combine_doc ref, year, opts, stdclass
60
+ result ||= check_bibliocache(ref, year, opts, stdclass)
61
+ result
62
+ end
63
+
64
+ # @see Relaton::Db#fetch
65
+ def fetch_db(code, year = nil, opts = {})
66
+ opts[:fetch_db] = true
67
+ fetch code, year, opts
68
+ end
69
+
70
+ # fetch all standards from DB
71
+ # @param test [String, nil]
72
+ # @param edition [String], nil
73
+ # @param year [Integer, nil]
74
+ # @return [Array]
75
+ def fetch_all(text = nil, edition: nil, year: nil)
76
+ result = @static_db.all { |file, yml| search_yml file, yml, text, edition, year }.compact
77
+ db = @db || @local_db
78
+ result += db.all { |file, xml| search_xml file, xml, text, edition, year }.compact if db
79
+ result
80
+ end
81
+
82
+ # Fetch asynchronously
83
+ def fetch_async(code, year = nil, opts = {}, &_block) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
84
+ stdclass = standard_class code
85
+ if stdclass
86
+ unless @queues[stdclass]
87
+ processor = @registry.processors[stdclass]
88
+ wp = WorkersPool.new(processor.threads) { |args| yield fetch *args }
89
+ @queues[stdclass] = { queue: Queue.new, workers_pool: wp }
90
+ Thread.new { process_queue @queues[stdclass] }
91
+ end
92
+ @queues[stdclass][:queue] << [code, year, opts]
93
+ else yield nil
94
+ end
32
95
  end
33
96
 
34
97
  # @param code [String]
35
98
  # @param year [String, NilClass]
36
99
  # @param stdclass [Symbol, NilClass]
100
+ #
37
101
  # @param opts [Hash]
102
+ # @option opts [Boolean] :all_parts If all-parts reference is required
103
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
104
+ # @option opts [Integer] :retries (1) Number of network retries
105
+ #
106
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
107
+ # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
108
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
109
+ # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
110
+ # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
111
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
112
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
113
+ # RelatonW3c::W3cBibliographicItem
38
114
  def fetch_std(code, year = nil, stdclass = nil, opts = {})
39
115
  std = nil
40
116
  @registry.processors.each do |name, processor|
41
117
  std = name if processor.prefix == stdclass
42
118
  end
43
- unless std
44
- std = standard_class(code) or return nil
45
- end
119
+ std = standard_class(code) or return nil unless std
120
+
46
121
  check_bibliocache(code, year, opts, std)
47
122
  end
48
123
 
@@ -86,27 +161,115 @@ module Relaton
86
161
 
87
162
  private
88
163
 
164
+ # @param file [String] file path
165
+ # @param yml [String] content in YAML format
166
+ # @param text [String, nil] text to serach
167
+ # @param edition [String, nil] edition to filter
168
+ # @param year [Integer, nil] year to filter
169
+ # @return [BibliographicItem, nil]
170
+ def search_yml(file, yml, text, edition, year)
171
+ item = search_edition_year(file, yml, edition, year)
172
+ return unless item
173
+
174
+ item if match_xml_text(item.to_xml(bibdata: true), text)
175
+ end
176
+
177
+ # @param file [String] file path
178
+ # @param xml [String] content in XML format
179
+ # @param text [String, nil] text to serach
180
+ # @param edition [String, nil] edition to filter
181
+ # @param year [Integer, nil] year to filter
182
+ # @return [BibliographicItem, nil]
183
+ def search_xml(file, xml, text, edition, year)
184
+ return unless text.nil? || match_xml_text(xml, text)
185
+
186
+ search_edition_year(file, xml, edition, year)
187
+ end
188
+
189
+ # @param file [String] file path
190
+ # @param content [String] content in XML or YAmL format
191
+ # @param edition [String, nil] edition to filter
192
+ # @param year [Integer, nil] year to filter
193
+ # @return [BibliographicItem, nil]
194
+ def search_edition_year(file, content, edition, year) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
195
+ processor = @registry.processors[standard_class(file.split("/")[-2])]
196
+ item = file.match?(/xml$/) ? processor.from_xml(content) : processor.hash_to_bib(YAML.safe_load(content))
197
+ item if (edition.nil? || item.edition == edition) &&
198
+ (year.nil? || item.date.detect { |d| d.type == "published" && d.on(:year) == year })
199
+ end
200
+
201
+ # @param xml [String] content in XML format
202
+ # @param text [String, nil] text to serach
203
+ # @return [Boolean]
204
+ def match_xml_text(xml, text)
205
+ %r{((?<attr>=((?<apstr>')|"))|>).*?#{text}.*?(?(<attr>)(?(<apstr>)'|")|<)}mi.match?(xml)
206
+ end
207
+
208
+ # @param code [String]
209
+ # @param year [String, nil]
210
+ # @param stdslass [String]
211
+ #
212
+ # @param opts [Hash] options
213
+ # @option opts [Boolean] :all_parts If all-parts reference is required
214
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
215
+ # @option opts [Integer] :retries (1) Number of network retries
216
+ #
217
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
218
+ # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
219
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
220
+ # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
221
+ # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
222
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
223
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
224
+ # RelatonW3c::W3cBibliographicItem
225
+ def combine_doc(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
226
+ if (refs = code.split " + ").size > 1
227
+ reltype = "derivedFrom"
228
+ reldesc = nil
229
+ elsif (refs = code.split ", ").size > 1
230
+ reltype = "complements"
231
+ reldesc = RelatonBib::FormattedString.new content: "amendment"
232
+ else return
233
+ end
234
+
235
+ doc = @registry.processors[stdclass].hash_to_bib docid: { id: code }
236
+ ref = refs[0]
237
+ updates = check_bibliocache(ref, year, opts, stdclass)
238
+ doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates, type: "updates") if updates
239
+ refs[1..-1].each_with_object(doc) do |c, d|
240
+ bib = check_bibliocache("#{ref}/#{c}", year, opts, stdclass)
241
+ if bib
242
+ d.relation << RelatonBib::DocumentRelation.new(type: reltype, description: reldesc, bibitem: bib)
243
+ end
244
+ end
245
+ end
246
+
89
247
  # @param code [String] code of standard
90
248
  # @return [Symbol] standard class name
91
249
  def standard_class(code)
92
250
  @registry.processors.each do |name, processor|
93
- return name if /^#{processor.prefix}/.match(code) ||
251
+ return name if /^(urn:)?#{processor.prefix}/i.match?(code) ||
94
252
  processor.defaultprefix.match(code)
95
253
  end
96
254
  allowed = @registry.processors.reduce([]) do |m, (_k, v)|
97
255
  m << v.prefix
98
256
  end
99
257
  warn <<~WARN
100
- #{code} does not have a recognised prefix: #{allowed.join(', ')}.
101
- See https://github.com/relaton/relaton/ for instructions on prefixing and wrapping document identifiers to disambiguate them.
102
- WARN
258
+ #{code} does not have a recognised prefix: #{allowed.join(', ')}.
259
+ See https://github.com/relaton/relaton/ for instructions on prefixing and wrapping document identifiers to disambiguate them.
260
+ WARN
103
261
  end
104
262
 
105
263
  # TODO: i18n
106
264
  # Fofmat ID
107
265
  # @param code [String]
108
266
  # @param year [String]
267
+ #
109
268
  # @param opts [Hash]
269
+ # @option opts [Boolean] :all_parts If all-parts reference is required
270
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
271
+ # @option opts [Integer] :retries (1) Number of network retries
272
+ #
110
273
  # @param stdClass [Symbol]
111
274
  # @return [Array<String>] docid and code
112
275
  def std_id(code, year, opts, stdclass)
@@ -129,23 +292,36 @@ module Relaton
129
292
 
130
293
  # @param entry [String] XML string
131
294
  # @param stdclass [Symbol]
132
- # @param id [String] docid
133
- # @return [NilClass, RelatonIsoBib::IsoBibliographicItem,
295
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
134
296
  # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
135
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem]
136
- def bib_retval(entry, stdclass, id)
137
- entry =~ /^not_found/ ? nil : @registry.processors[stdclass].from_xml(entry)
297
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
298
+ # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
299
+ # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
300
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
301
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
302
+ # RelatonW3c::W3cBibliographicItem
303
+ def bib_retval(entry, stdclass)
304
+ entry.nil? || entry.match?(/^not_found/) ? nil : @registry.processors[stdclass].from_xml(entry)
138
305
  end
139
306
 
140
307
  # @param code [String]
141
308
  # @param year [String]
309
+ #
142
310
  # @param opts [Hash]
311
+ # @option opts [Boolean] :all_parts If all-parts reference is required
312
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
313
+ # @option opts [Integer] :retries (1) Number of network retries
314
+ #
143
315
  # @param stdclass [Symbol]
144
- # @return [NilClass, RelatonIsoBib::IsoBibliographicItem,
316
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
145
317
  # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
318
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
146
319
  # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
147
320
  # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
148
- def check_bibliocache(code, year, opts, stdclass)
321
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
322
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
323
+ # RelatonW3c::W3cBibliographicItem
324
+ def check_bibliocache(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
149
325
  id, searchcode = std_id(code, year, opts, stdclass)
150
326
  yaml = @static_db[id]
151
327
  return @registry.processors[stdclass].hash_to_bib YAML.safe_load(yaml) if yaml
@@ -153,31 +329,41 @@ module Relaton
153
329
  db = @local_db || @db
154
330
  altdb = @local_db && @db ? @db : nil
155
331
  if db.nil?
332
+ return if opts[:fetch_db]
333
+
156
334
  bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
157
- return bib_retval(bibentry, stdclass, id)
335
+ return bib_retval(bibentry, stdclass)
158
336
  end
159
337
 
160
338
  db.delete(id) unless db.valid_entry?(id, year)
161
339
  if altdb
162
- # db[id] ||= altdb[id]
163
- db.clone_entry id, altdb
340
+ return bib_retval(altdb[id], stdclass) if opts[:fetch_db]
341
+
342
+ db.clone_entry id, altdb if altdb.valid_entry? id, year
164
343
  db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
165
344
  altdb.clone_entry(id, db) if !altdb.valid_entry?(id, year)
166
345
  else
346
+ return bib_retval(db[id], stdclass) if opts[:fetch_db]
347
+
167
348
  db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
168
349
  end
169
- bib_retval(db[id], stdclass, id)
350
+ bib_retval(db[id], stdclass)
170
351
  end
171
352
 
172
353
  # @param code [String]
173
354
  # @param year [String]
355
+ #
174
356
  # @param opts [Hash]
357
+ # @option opts [Boolean] :all_parts If all-parts reference is required
358
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
359
+ # @option opts [Integer] :retries (1) Number of network retries
360
+ #
175
361
  # @param stdclass [Symbol]
176
362
  # @param db [Relaton::DbCache,`NilClass]
177
363
  # @param id [String] docid
178
364
  # @return [String]
179
- def new_bib_entry(code, year, opts, stdclass, **args)
180
- bib = @registry.processors[stdclass].get(code, year, opts)
365
+ def new_bib_entry(code, year, opts, stdclass, **args) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
366
+ bib = net_retry(code, year, opts, stdclass, opts.fetch(:retries, 1))
181
367
  bib_id = bib&.docidentifier&.first&.id
182
368
 
183
369
  # when docid doesn't match bib's id then return a reference to bib's id
@@ -185,11 +371,19 @@ module Relaton
185
371
  bid = std_id(bib.docidentifier.first.id, nil, {}, stdclass).first
186
372
  args[:db][bid] ||= bib_entry bib
187
373
  "redirection #{bid}"
188
- else
189
- bib_entry bib
374
+ else bib_entry bib
190
375
  end
191
376
  end
192
377
 
378
+ # @raise [RelatonBib::RequestError]
379
+ def net_retry(code, year, opts, stdclass, retries)
380
+ @registry.processors[stdclass].get(code, year, opts)
381
+ rescue RelatonBib::RequestError => e
382
+ raise e unless retries > 1
383
+
384
+ net_retry(code, year, opts, stdclass, retries - 1)
385
+ end
386
+
193
387
  # @param bib [RelatonGb::GbBibliongraphicItem, RelatonIsoBib::IsoBibliographicItem,
194
388
  # RelatonIetf::IetfBibliographicItem, RelatonItu::ItuBibliographicItem,
195
389
  # RelatonNist::NistBibliongraphicItem, RelatonOgc::OgcBibliographicItem]
@@ -202,21 +396,32 @@ module Relaton
202
396
  end
203
397
  end
204
398
 
205
- # @param dir [String] DB directory
399
+ # @param dir [String, nil] DB directory
206
400
  # @param type [Symbol]
207
401
  # @return [Relaton::DbCache, NilClass]
208
402
  def open_cache_biblio(dir, type: :static)
209
403
  return nil if dir.nil?
210
404
 
211
405
  db = DbCache.new dir, type == :static ? "yml" : "xml"
406
+ return db if type == :static
212
407
 
213
408
  Dir["#{dir}/*/"].each do |fdir|
214
- next if type == :static || db.check_version?(fdir)
409
+ next if db.check_version?(fdir)
215
410
 
216
411
  FileUtils.rm_rf(Dir.glob(fdir + "/*"), secure: true)
412
+ db.set_version fdir
217
413
  warn "[relaton] cache #{fdir}: version is obsolete and cache is cleared."
218
414
  end
219
415
  db
220
416
  end
417
+
418
+ # @param qwp [Hash]
419
+ # @option qwp [Queue] :queue The queue of references to fetch
420
+ # @option qwp [Relaton::WorkersPool] :workers_pool The pool of workers
421
+ def process_queue(qwp)
422
+ while args = qwp[:queue].pop
423
+ qwp[:workers_pool] << args
424
+ end
425
+ end
221
426
  end
222
427
  end