relaton 1.6.0 → 1.7.pre7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +46 -0
  3. data/docs/README.adoc +233 -3
  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 +247 -35
  9. data/lib/relaton/db_cache.rb +38 -7
  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/relaton.gemspec +18 -16
  15. data/spec/relaton/db_cache_spec.rb +26 -1
  16. data/spec/relaton/db_spec.rb +145 -0
  17. data/spec/relaton/processor_spec.rb +4 -0
  18. data/spec/relaton/regirtry_spec.rb +54 -44
  19. data/spec/relaton_spec.rb +121 -20
  20. data/spec/vcr_cassetes/19133_2005.yml +22 -22
  21. data/spec/vcr_cassetes/cc_dir_10005_2019.yml +10 -10
  22. data/spec/vcr_cassetes/cie_001_1980.yml +120 -0
  23. data/spec/vcr_cassetes/ecma_6.yml +159 -0
  24. data/spec/vcr_cassetes/fisp_140.yml +6 -6
  25. data/spec/vcr_cassetes/gb_t_20223_2006.yml +15 -11
  26. data/spec/vcr_cassetes/hist_cmbined_included.yml +105 -0
  27. data/spec/vcr_cassetes/iec_60050_102_2007.yml +285 -0
  28. data/spec/vcr_cassetes/iec_combined_included.yml +945 -0
  29. data/spec/vcr_cassetes/ieee_528_2019.yml +14 -14
  30. data/spec/vcr_cassetes/iho_b_11.yml +15 -15
  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 +22 -22
  34. data/spec/vcr_cassetes/iso_19115_1_2.yml +44 -44
  35. data/spec/vcr_cassetes/iso_awi_24229.yml +21 -21
  36. data/spec/vcr_cassetes/iso_combined_applied.yml +361 -0
  37. data/spec/vcr_cassetes/iso_combined_included.yml +361 -0
  38. data/spec/vcr_cassetes/itu_combined_included.yml +1296 -0
  39. data/spec/vcr_cassetes/ogc_19_025r1.yml +2569 -1910
  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 +6 -6
  44. data/spec/vcr_cassetes/un_rtade_cefact_2004_32.yml +31 -31
  45. data/spec/vcr_cassetes/w3c_json_ld11.yml +18 -12
  46. metadata +81 -71
  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: ed7e272fcfcf43938fe37532ceebde987f4f096e55d5dcd06a99a09302fd66f4
4
- data.tar.gz: 3a01eeed34f2f1817c05675d54287f68f312048ff40f450f1783dbac6beddba6
3
+ metadata.gz: 669c9390b4e3b0a3be1a928f3a13db65cff18d9e36d1ee434662ebccab367402
4
+ data.tar.gz: 9d285c4d6e00df82eb38baff1a191d8a4527456d689556312db1bef74c1fc364
5
5
  SHA512:
6
- metadata.gz: f35b5b2e317af3ff9a7f0a77dbe54e54796e314513518c9d538298a12ab21fda6fa0aff7020e5b1ea6d87ab7e6608e4b792f7ed5229e3b45f2aba409c04a2c5d
7
- data.tar.gz: cc97d7bfda217e408afc66ca06d31c9c1b2a9a165976116efd841dce8f59d696e29cb92a2a0940db594f2792fa563c5d13372102938d4e2151386021d909fe3f
6
+ metadata.gz: f0489929bc69ac678f9a3b5b2f4a73961102d72e9f0917807a422dbf495d3319b94e84c11cdfb46fc9cc423a523f04af20a1bacdd6964988e9deb2a87676470a
7
+ data.tar.gz: 792fa2b3c0cf6f95362ff7039c867ec57766fe691fb75dd71e0413b77c3982b3bfdf7ee57748ae4de9aaea18b2e76a1f0c3ae67eb9c01a81ec594865e4a20531
@@ -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,51 @@ 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_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
+ ----
96
122
 
123
+ ==== Clear DB
124
+
125
+ `Relaton::Db#clear` removes all entries form DB
126
+
127
+ === Fetch documens
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
+
146
+ [source,ruby]
147
+ ----
97
148
  x = db.fetch("IEEE 19011")
98
149
  [relaton-ieee] ("IEEE 19011") fetching...
99
150
  [relaton-ieee] WARNING: no match found online for IEEE 19011. The code must be exactly like it is on the standards website.
@@ -105,7 +156,7 @@ x = db.fetch("ISO 19011")
105
156
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d0ab2f00
106
157
  ...
107
158
 
108
- x = db.fetch("ISO 19011", "2011")
159
+ x = db.fetch("ISO 19011", "2011", retries: 3)
109
160
  [relaton-iso] ("ISO 19011") fetching...
110
161
  [relaton-iso] ("ISO 19011") found ISO 19011:2011
111
162
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d2593068
@@ -117,9 +168,185 @@ x = db.fetch("ISO 19115", nil, all_parts: true)
117
168
  => #<RelatonIsoBib::IsoBibliographicItem:0x007fb1d0ae8bf0
118
169
  ...
119
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
+ ...
208
+ ----
209
+
210
+ === Fetch combined documents
211
+
212
+ This functionality works only for ISO, IEC, ITU, and NIST documents.
213
+
214
+ ==== Fetch included documents
215
+ [source,ruby]
216
+ ----
217
+ bib = db.fetch "ISO 19115-1 + Amd 1"
218
+ [relaton-iso] ("ISO 19115-1") fetching...
219
+ [relaton-iso] ("ISO 19115-1") found ISO 19115-1:2014
220
+ [relaton-iso] ("ISO 19115-1/Amd 1") fetching...
221
+ [relaton-iso] ("ISO 19115-1/Amd 1") found ISO 19115-1:2014/Amd 1:2018
222
+ => #<RelatonIsoBib::IsoBibliographicItem:0x007f95a929a748
223
+
224
+ bib.docidentifier[0].id
225
+ => "ISO 19115-1 + Amd 1"
226
+
227
+ bib.relation[0].type
228
+ => "updates"
229
+
230
+ bib.relation[0].bibitem.docidentifier[0].id
231
+ => "ISO 19115-1"
232
+
233
+ bib.relation[1].type
234
+ => "derivedFrom"
235
+
236
+ bib.relation[1].bibitem.docidentifier[0].id
237
+ => "ISO 19115-1/Amd 1:2018"
238
+
239
+ bib.docidentifier[0].id
240
+ => "ISO 19115-1, Amd 1"
241
+
242
+ bib.relation[0].type
243
+ => "updates"
244
+
245
+ bib.relation[0].bibitem.docidentifier[0].id
246
+ => "ISO 19115-1"
247
+
248
+ bib.relation[1].type
249
+ => "complements"
250
+
251
+ bib.relation[1].description
252
+ => "amendment"
253
+
254
+ bib.relation[1].bibitem.docidentifier[0].id
255
+ => "ISO 19115-1/Amd 1:2018"
256
+ ----
257
+
258
+ ==== Fetch applied documents
259
+ [source,ruby]
260
+ ----
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
338
+ ----
339
+
340
+ === Get document type
341
+ [source,ruby]
342
+ ----
120
343
  db.docid_type("CN(GB/T 1.1)")
121
344
  => ["Chinese Standard", "GB/T 1.1"]
345
+ ----
122
346
 
347
+ === Serializing
348
+ [source,ruby]
349
+ ----
123
350
  x.to_xml
124
351
  => "<bibitem id="ISO19115(allparts)" type="standard">
125
352
  ...
@@ -145,12 +372,15 @@ x.to_xml bibdata: true
145
372
  db.load_entry("ISO(ISO 19011)")
146
373
  => "<bibdata type="standard">
147
374
  ...
148
- <?bibdata>"
375
+ </bibdata>"
376
+ ----
149
377
 
378
+ === Entry manipulation
379
+ [source,ruby]
380
+ ----
150
381
  db.save_entry("ISO(ISO 19011)", nil)
151
382
  => nil
152
383
 
153
384
  db.load_entry("ISO(ISO 19011)")
154
385
  => nil
155
-
156
386
  ----
@@ -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
@@ -10,39 +10,121 @@ 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", __dir__)
18
+ @queues = {}
19
19
  end
20
20
 
21
+ # Move global or local caches to anothe dirs
22
+ # @param new_dir [String, nil]
23
+ # @param type: [Symbol]
24
+ # @return [String, nil]
25
+ def mv(new_dir, type: :global)
26
+ case type
27
+ when :global
28
+ @db&.mv new_dir
29
+ when :local
30
+ @local_db&.mv new_dir
31
+ end
32
+ end
33
+
34
+ # Clear global and local databases
35
+ def clear
36
+ @db&.clear
37
+ @local_db&.clear
38
+ end
39
+
40
+ ##
21
41
  # The class of reference requested is determined by the prefix of the code:
22
42
  # GB Standard for gbbib, IETF for ietfbib, ISO for isobib, IEC or IEV for iecbib,
43
+ #
23
44
  # @param code [String] the ISO standard Code to look up (e.g. "ISO 9000")
24
45
  # @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,
46
+ #
47
+ # @param opts [Hash] options
48
+ # @option opts [Boolean] :all_parts If all-parts reference is required
49
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
50
+ # @option opts [Integer] :retries (1) Number of network retries
51
+ #
52
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
27
53
  # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
28
- # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem]
54
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
55
+ # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
56
+ # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
57
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
58
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
59
+ # RelatonW3c::W3cBibliographicItem
60
+ ##
29
61
  def fetch(code, year = nil, opts = {})
30
62
  stdclass = standard_class(code) || return
31
- check_bibliocache(code, year, opts, stdclass)
63
+ processor = @registry.processors[stdclass]
64
+ ref = processor.respond_to?(:urn_to_code) ? processor.urn_to_code(code)&.first : code
65
+ ref ||= code
66
+ result = combine_doc ref, year, opts, stdclass
67
+ result ||= check_bibliocache(ref, year, opts, stdclass)
68
+ result
69
+ end
70
+
71
+ # @see Relaton::Db#fetch
72
+ def fetch_db(code, year = nil, opts = {})
73
+ opts[:fetch_db] = true
74
+ fetch code, year, opts
75
+ end
76
+
77
+ # fetch all standards from DB
78
+ # @param test [String, nil]
79
+ # @param edition [String], nil
80
+ # @param year [Integer, nil]
81
+ # @return [Array]
82
+ def fetch_all(text = nil, edition: nil, year: nil)
83
+ result = @static_db.all { |file, yml| search_yml file, yml, text, edition, year }.compact
84
+ db = @db || @local_db
85
+ result += db.all { |file, xml| search_xml file, xml, text, edition, year }.compact if db
86
+ result
87
+ end
88
+
89
+ # Fetch asynchronously
90
+ def fetch_async(code, year = nil, opts = {}, &_block) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
91
+ stdclass = standard_class code
92
+ if stdclass
93
+ unless @queues[stdclass]
94
+ processor = @registry.processors[stdclass]
95
+ wp = WorkersPool.new(processor.threads) { |args| yield fetch *args }
96
+ @queues[stdclass] = { queue: Queue.new, workers_pool: wp }
97
+ Thread.new { process_queue @queues[stdclass] }
98
+ end
99
+ @queues[stdclass][:queue] << [code, year, opts]
100
+ else yield nil
101
+ end
32
102
  end
33
103
 
34
104
  # @param code [String]
35
105
  # @param year [String, NilClass]
36
106
  # @param stdclass [Symbol, NilClass]
107
+ #
37
108
  # @param opts [Hash]
109
+ # @option opts [Boolean] :all_parts If all-parts reference is required
110
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
111
+ # @option opts [Integer] :retries (1) Number of network retries
112
+ #
113
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
114
+ # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
115
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
116
+ # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
117
+ # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
118
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
119
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
120
+ # RelatonW3c::W3cBibliographicItem
38
121
  def fetch_std(code, year = nil, stdclass = nil, opts = {})
39
122
  std = nil
40
123
  @registry.processors.each do |name, processor|
41
124
  std = name if processor.prefix == stdclass
42
125
  end
43
- unless std
44
- std = standard_class(code) or return nil
45
- end
126
+ std = standard_class(code) or return nil unless std
127
+
46
128
  check_bibliocache(code, year, opts, std)
47
129
  end
48
130
 
@@ -86,27 +168,115 @@ module Relaton
86
168
 
87
169
  private
88
170
 
171
+ # @param file [String] file path
172
+ # @param yml [String] content in YAML format
173
+ # @param text [String, nil] text to serach
174
+ # @param edition [String, nil] edition to filter
175
+ # @param year [Integer, nil] year to filter
176
+ # @return [BibliographicItem, nil]
177
+ def search_yml(file, yml, text, edition, year)
178
+ item = search_edition_year(file, yml, edition, year)
179
+ return unless item
180
+
181
+ item if match_xml_text(item.to_xml(bibdata: true), text)
182
+ end
183
+
184
+ # @param file [String] file path
185
+ # @param xml [String] content in XML 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_xml(file, xml, text, edition, year)
191
+ return unless text.nil? || match_xml_text(xml, text)
192
+
193
+ search_edition_year(file, xml, edition, year)
194
+ end
195
+
196
+ # @param file [String] file path
197
+ # @param content [String] content in XML or YAmL format
198
+ # @param edition [String, nil] edition to filter
199
+ # @param year [Integer, nil] year to filter
200
+ # @return [BibliographicItem, nil]
201
+ def search_edition_year(file, content, edition, year) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
202
+ processor = @registry.processors[standard_class(file.split("/")[-2])]
203
+ item = file.match?(/xml$/) ? processor.from_xml(content) : processor.hash_to_bib(YAML.safe_load(content))
204
+ item if (edition.nil? || item.edition == edition) &&
205
+ (year.nil? || item.date.detect { |d| d.type == "published" && d.on(:year).to_s == year.to_s })
206
+ end
207
+
208
+ # @param xml [String] content in XML format
209
+ # @param text [String, nil] text to serach
210
+ # @return [Boolean]
211
+ def match_xml_text(xml, text)
212
+ %r{((?<attr>=((?<apstr>')|"))|>).*?#{text}.*?(?(<attr>)(?(<apstr>)'|")|<)}mi.match?(xml)
213
+ end
214
+
215
+ # @param code [String]
216
+ # @param year [String, nil]
217
+ # @param stdslass [String]
218
+ #
219
+ # @param opts [Hash] options
220
+ # @option opts [Boolean] :all_parts If all-parts reference is required
221
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
222
+ # @option opts [Integer] :retries (1) Number of network retries
223
+ #
224
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
225
+ # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
226
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
227
+ # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
228
+ # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
229
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
230
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
231
+ # RelatonW3c::W3cBibliographicItem
232
+ def combine_doc(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
233
+ if (refs = code.split " + ").size > 1
234
+ reltype = "derivedFrom"
235
+ reldesc = nil
236
+ elsif (refs = code.split ", ").size > 1
237
+ reltype = "complements"
238
+ reldesc = RelatonBib::FormattedString.new content: "amendment"
239
+ else return
240
+ end
241
+
242
+ doc = @registry.processors[stdclass].hash_to_bib docid: { id: code }
243
+ ref = refs[0]
244
+ updates = check_bibliocache(ref, year, opts, stdclass)
245
+ doc.relation << RelatonBib::DocumentRelation.new(bibitem: updates, type: "updates") if updates
246
+ refs[1..-1].each_with_object(doc) do |c, d|
247
+ bib = check_bibliocache("#{ref}/#{c}", year, opts, stdclass)
248
+ if bib
249
+ d.relation << RelatonBib::DocumentRelation.new(type: reltype, description: reldesc, bibitem: bib)
250
+ end
251
+ end
252
+ end
253
+
89
254
  # @param code [String] code of standard
90
255
  # @return [Symbol] standard class name
91
256
  def standard_class(code)
92
257
  @registry.processors.each do |name, processor|
93
- return name if /^#{processor.prefix}/.match(code) ||
258
+ return name if /^(urn:)?#{processor.prefix}/i.match?(code) ||
94
259
  processor.defaultprefix.match(code)
95
260
  end
96
261
  allowed = @registry.processors.reduce([]) do |m, (_k, v)|
97
262
  m << v.prefix
98
263
  end
99
264
  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
265
+ #{code} does not have a recognised prefix: #{allowed.join(', ')}.
266
+ See https://github.com/relaton/relaton/ for instructions on prefixing and wrapping document identifiers to disambiguate them.
267
+ WARN
103
268
  end
104
269
 
105
270
  # TODO: i18n
106
271
  # Fofmat ID
107
272
  # @param code [String]
108
273
  # @param year [String]
274
+ #
109
275
  # @param opts [Hash]
276
+ # @option opts [Boolean] :all_parts If all-parts reference is required
277
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
278
+ # @option opts [Integer] :retries (1) Number of network retries
279
+ #
110
280
  # @param stdClass [Symbol]
111
281
  # @return [Array<String>] docid and code
112
282
  def std_id(code, year, opts, stdclass)
@@ -129,23 +299,36 @@ module Relaton
129
299
 
130
300
  # @param entry [String] XML string
131
301
  # @param stdclass [Symbol]
132
- # @param id [String] docid
133
- # @return [NilClass, RelatonIsoBib::IsoBibliographicItem,
302
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
134
303
  # 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)
304
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
305
+ # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
306
+ # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
307
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
308
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
309
+ # RelatonW3c::W3cBibliographicItem
310
+ def bib_retval(entry, stdclass)
311
+ entry.nil? || entry.match?(/^not_found/) ? nil : @registry.processors[stdclass].from_xml(entry)
138
312
  end
139
313
 
140
314
  # @param code [String]
141
315
  # @param year [String]
316
+ #
142
317
  # @param opts [Hash]
318
+ # @option opts [Boolean] :all_parts If all-parts reference is required
319
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
320
+ # @option opts [Integer] :retries (1) Number of network retries
321
+ #
143
322
  # @param stdclass [Symbol]
144
- # @return [NilClass, RelatonIsoBib::IsoBibliographicItem,
323
+ # @return [nil, RelatonBib::BibliographicItem, RelatonIsoBib::IsoBibliographicItem,
145
324
  # RelatonItu::ItuBibliographicItem, RelatonIetf::IetfBibliographicItem,
325
+ # RelatonIec::IecBibliographicItem, RelatonIeee::IeeeBibliographicItem,
146
326
  # RelatonNist::NistBibliongraphicItem, RelatonGb::GbbibliographicItem,
147
327
  # RelatonOgc::OgcBibliographicItem, RelatonCalconnect::CcBibliographicItem]
148
- def check_bibliocache(code, year, opts, stdclass)
328
+ # RelatonBipm::BipmBibliographicItem, RelatonIho::IhoBibliographicItem,
329
+ # RelatonOmg::OmgBibliographicItem RelatinUn::UnBibliographicItem,
330
+ # RelatonW3c::W3cBibliographicItem
331
+ def check_bibliocache(code, year, opts, stdclass) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
149
332
  id, searchcode = std_id(code, year, opts, stdclass)
150
333
  yaml = @static_db[id]
151
334
  return @registry.processors[stdclass].hash_to_bib YAML.safe_load(yaml) if yaml
@@ -153,31 +336,41 @@ module Relaton
153
336
  db = @local_db || @db
154
337
  altdb = @local_db && @db ? @db : nil
155
338
  if db.nil?
339
+ return if opts[:fetch_db]
340
+
156
341
  bibentry = new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
157
- return bib_retval(bibentry, stdclass, id)
342
+ return bib_retval(bibentry, stdclass)
158
343
  end
159
344
 
160
345
  db.delete(id) unless db.valid_entry?(id, year)
161
346
  if altdb
162
- # db[id] ||= altdb[id]
163
- db.clone_entry id, altdb
347
+ return bib_retval(altdb[id], stdclass) if opts[:fetch_db]
348
+
349
+ db.clone_entry id, altdb if altdb.valid_entry? id, year
164
350
  db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
165
351
  altdb.clone_entry(id, db) if !altdb.valid_entry?(id, year)
166
352
  else
353
+ return bib_retval(db[id], stdclass) if opts[:fetch_db]
354
+
167
355
  db[id] ||= new_bib_entry(searchcode, year, opts, stdclass, db: db, id: id)
168
356
  end
169
- bib_retval(db[id], stdclass, id)
357
+ bib_retval(db[id], stdclass)
170
358
  end
171
359
 
172
360
  # @param code [String]
173
361
  # @param year [String]
362
+ #
174
363
  # @param opts [Hash]
364
+ # @option opts [Boolean] :all_parts If all-parts reference is required
365
+ # @option opts [Boolean] :keep_year If undated reference should return actual reference with year
366
+ # @option opts [Integer] :retries (1) Number of network retries
367
+ #
175
368
  # @param stdclass [Symbol]
176
369
  # @param db [Relaton::DbCache,`NilClass]
177
370
  # @param id [String] docid
178
371
  # @return [String]
179
- def new_bib_entry(code, year, opts, stdclass, **args)
180
- bib = @registry.processors[stdclass].get(code, year, opts)
372
+ def new_bib_entry(code, year, opts, stdclass, **args) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
373
+ bib = net_retry(code, year, opts, stdclass, opts.fetch(:retries, 1))
181
374
  bib_id = bib&.docidentifier&.first&.id
182
375
 
183
376
  # when docid doesn't match bib's id then return a reference to bib's id
@@ -185,11 +378,19 @@ module Relaton
185
378
  bid = std_id(bib.docidentifier.first.id, nil, {}, stdclass).first
186
379
  args[:db][bid] ||= bib_entry bib
187
380
  "redirection #{bid}"
188
- else
189
- bib_entry bib
381
+ else bib_entry bib
190
382
  end
191
383
  end
192
384
 
385
+ # @raise [RelatonBib::RequestError]
386
+ def net_retry(code, year, opts, stdclass, retries)
387
+ @registry.processors[stdclass].get(code, year, opts)
388
+ rescue RelatonBib::RequestError => e
389
+ raise e unless retries > 1
390
+
391
+ net_retry(code, year, opts, stdclass, retries - 1)
392
+ end
393
+
193
394
  # @param bib [RelatonGb::GbBibliongraphicItem, RelatonIsoBib::IsoBibliographicItem,
194
395
  # RelatonIetf::IetfBibliographicItem, RelatonItu::ItuBibliographicItem,
195
396
  # RelatonNist::NistBibliongraphicItem, RelatonOgc::OgcBibliographicItem]
@@ -202,21 +403,32 @@ module Relaton
202
403
  end
203
404
  end
204
405
 
205
- # @param dir [String] DB directory
406
+ # @param dir [String, nil] DB directory
206
407
  # @param type [Symbol]
207
408
  # @return [Relaton::DbCache, NilClass]
208
409
  def open_cache_biblio(dir, type: :static)
209
410
  return nil if dir.nil?
210
411
 
211
412
  db = DbCache.new dir, type == :static ? "yml" : "xml"
413
+ return db if type == :static
212
414
 
213
415
  Dir["#{dir}/*/"].each do |fdir|
214
- next if type == :static || db.check_version?(fdir)
416
+ next if db.check_version?(fdir)
215
417
 
216
- FileUtils.rm_rf(Dir.glob(fdir + "/*"), secure: true)
418
+ FileUtils.rm_rf(fdir, secure: true)
419
+ # db.set_version fdir
217
420
  warn "[relaton] cache #{fdir}: version is obsolete and cache is cleared."
218
421
  end
219
422
  db
220
423
  end
424
+
425
+ # @param qwp [Hash]
426
+ # @option qwp [Queue] :queue The queue of references to fetch
427
+ # @option qwp [Relaton::WorkersPool] :workers_pool The pool of workers
428
+ def process_queue(qwp)
429
+ while args = qwp[:queue].pop
430
+ qwp[:workers_pool] << args
431
+ end
432
+ end
221
433
  end
222
434
  end