relaton 1.7.2 → 1.7.7

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 +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