relaton 3.0.0.pre.alpha.14 → 3.0.0.pre.alpha.16
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.
- checksums.yaml +4 -4
- data/lib/relaton/3gpp/bibliography.rb +7 -2
- data/lib/relaton/3gpp.rb +4 -0
- data/lib/relaton/adobe/bibliography.rb +5 -2
- data/lib/relaton/adobe.rb +4 -0
- data/lib/relaton/bib/model/item_shared.rb +5 -1
- data/lib/relaton/bib/model/localized_string.rb +10 -0
- data/lib/relaton/bib/model/relation.rb +1 -1
- data/lib/relaton/bipm/bibliography.rb +5 -1
- data/lib/relaton/bipm.rb +4 -0
- data/lib/relaton/calconnect/hit_collection.rb +7 -2
- data/lib/relaton/calconnect.rb +4 -0
- data/lib/relaton/ccsds/hit_collection.rb +5 -1
- data/lib/relaton/ccsds.rb +4 -0
- data/lib/relaton/cie/scrapper.rb +5 -1
- data/lib/relaton/cie.rb +4 -0
- data/lib/relaton/db/cache.rb +10 -5
- data/lib/relaton/db/registry.rb +1 -1
- data/lib/relaton/easc/bibliography.rb +5 -2
- data/lib/relaton/easc.rb +4 -0
- data/lib/relaton/ecma/bibliography.rb +5 -1
- data/lib/relaton/ecma.rb +4 -0
- data/lib/relaton/etsi/bibliography.rb +5 -1
- data/lib/relaton/etsi.rb +4 -0
- data/lib/relaton/evs/bibliography.rb +138 -0
- data/lib/relaton/evs/hit.rb +32 -0
- data/lib/relaton/evs/hit_collection.rb +73 -0
- data/lib/relaton/evs/item_data.rb +7 -0
- data/lib/relaton/evs/model/bibdata.rb +8 -0
- data/lib/relaton/evs/model/bibitem.rb +8 -0
- data/lib/relaton/evs/model/docidentifier.rb +79 -0
- data/lib/relaton/evs/model/ext.rb +12 -0
- data/lib/relaton/evs/model/item.rb +14 -0
- data/lib/relaton/evs/model/structured_identifier.rb +9 -0
- data/lib/relaton/evs/processor.rb +50 -0
- data/lib/relaton/evs/scraper.rb +212 -0
- data/lib/relaton/evs/util.rb +8 -0
- data/lib/relaton/evs.rb +27 -0
- data/lib/relaton/gost/bibliography.rb +5 -2
- data/lib/relaton/gost.rb +4 -0
- data/lib/relaton/iala/bibliography.rb +5 -2
- data/lib/relaton/iala.rb +4 -0
- data/lib/relaton/iana/bibliography.rb +5 -2
- data/lib/relaton/iana.rb +4 -0
- data/lib/relaton/iec/hit_collection.rb +7 -2
- data/lib/relaton/iec.rb +4 -0
- data/lib/relaton/ieee/bibliography.rb +5 -1
- data/lib/relaton/ieee.rb +4 -0
- data/lib/relaton/ietf/scraper.rb +7 -2
- data/lib/relaton/ietf.rb +4 -0
- data/lib/relaton/iho/bibliography.rb +5 -2
- data/lib/relaton/iho/processor.rb +3 -0
- data/lib/relaton/iho.rb +4 -0
- data/lib/relaton/iso/hit_collection.rb +7 -2
- data/lib/relaton/iso.rb +4 -0
- data/lib/relaton/itu/hit_collection.rb +7 -2
- data/lib/relaton/itu/model/ext.rb +10 -0
- data/lib/relaton/itu.rb +4 -0
- data/lib/relaton/jcgm/bibliography.rb +5 -2
- data/lib/relaton/jcgm.rb +4 -0
- data/lib/relaton/nist/hit_collection.rb +20 -1
- data/lib/relaton/oasis/bibliography.rb +5 -2
- data/lib/relaton/oasis.rb +4 -0
- data/lib/relaton/ogc/hit_collection.rb +7 -2
- data/lib/relaton/ogc.rb +4 -0
- data/lib/relaton/oiml/bibliography.rb +5 -2
- data/lib/relaton/oiml.rb +4 -0
- data/lib/relaton/omg/bibliography.rb +40 -2
- data/lib/relaton/omg/scraper.rb +14 -2
- data/lib/relaton/omg.rb +11 -0
- data/lib/relaton/version.rb +1 -1
- data/lib/relaton/xsf/hit_collection.rb +5 -2
- data/lib/relaton/xsf.rb +4 -0
- data/lib/relaton.rb +1 -0
- metadata +20 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 83f6b8e1b62e766d9b4fa8f46d68a8d505c4e1534fbe2049f18b36e7cbea29cf
|
|
4
|
+
data.tar.gz: 7813140bb28511c6396616c40f17ccba333cceccaae64c5e75b2bd8808807ca1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fbc94c74748bc1e096c03a475bfbe33b9c59438453a788d14e287924b6e0b0eded53d87e9c083effc1814dc4f5b3952e3f7db455271e17f7537de531fe5571b3
|
|
7
|
+
data.tar.gz: ac81371be2a1c5ca84a49b979098e3a14b15e75442dc1f7f11a43800239148d3e3691d4c6d26e436bead9fc0f9983c9471051a46850950a45e7817e3d196cfae
|
|
@@ -123,10 +123,15 @@ module Relaton
|
|
|
123
123
|
# deserialize the rows into identifiers, sort them by `id.root.number`,
|
|
124
124
|
# and let `Type#search` bsearch. Without it the rows stay raw hashes,
|
|
125
125
|
# `FileIO#sorted` stays false, and every lookup scans all 88,464 of them.
|
|
126
|
+
#
|
|
127
|
+
# The machine index on the Pages site (relaton#206, the W3C pilot's
|
|
128
|
+
# contract): a parsed query reads only its own shard. A Pages failure
|
|
129
|
+
# raises `Relaton::RequestError`; the whole-index zip on the same site
|
|
130
|
+
# serves only the retry on a miss.
|
|
131
|
+
#
|
|
126
132
|
def index
|
|
127
133
|
Relaton::Index.find_or_create(
|
|
128
|
-
"3GPP",
|
|
129
|
-
pubid_class: ::Pubid::Tgpp::Identifier
|
|
134
|
+
"3GPP", pages_url: PAGES_URL, pubid_class: ::Pubid::Tgpp::Identifier
|
|
130
135
|
)
|
|
131
136
|
end
|
|
132
137
|
|
data/lib/relaton/3gpp.rb
CHANGED
|
@@ -16,6 +16,10 @@ require_relative "3gpp/bibliography"
|
|
|
16
16
|
module Relaton
|
|
17
17
|
module ThreeGpp
|
|
18
18
|
INDEXFILE = "index-v2".freeze
|
|
19
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
20
|
+
# manifest + per-shard rows read by Bibliography's index; the zip stays
|
|
21
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
22
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-3gpp/"
|
|
19
23
|
|
|
20
24
|
# Returns hash of XML reammar
|
|
21
25
|
# @return [String]
|
|
@@ -70,10 +70,13 @@ module Relaton
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def index
|
|
73
|
+
# The machine index on the Pages site (relaton#206): a parsed query
|
|
74
|
+
# reads only its own shard; a Pages failure raises
|
|
75
|
+
# `Relaton::RequestError`; the whole-index zip on the same site
|
|
76
|
+
# serves only the retry on a miss.
|
|
73
77
|
Relaton::Index.find_or_create(
|
|
74
78
|
:adobe,
|
|
75
|
-
|
|
76
|
-
file: "#{INDEXFILE}.yaml",
|
|
79
|
+
pages_url: PAGES_URL,
|
|
77
80
|
pubid_class: ::Pubid::Adobe::Identifier,
|
|
78
81
|
)
|
|
79
82
|
end
|
data/lib/relaton/adobe.rb
CHANGED
|
@@ -13,6 +13,10 @@ require "relaton/version"
|
|
|
13
13
|
module Relaton
|
|
14
14
|
module Adobe
|
|
15
15
|
INDEXFILE = "index-v2".freeze
|
|
16
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
17
|
+
# manifest + per-shard rows read by the consumer's index; the zip stays
|
|
18
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
19
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-adobe/"
|
|
16
20
|
|
|
17
21
|
class Error < StandardError; end
|
|
18
22
|
|
|
@@ -12,7 +12,11 @@ module Relaton
|
|
|
12
12
|
graphic_work music patent inbook incollection inproceedings journal website
|
|
13
13
|
webresource dataset archival social_media alert message convesation misc
|
|
14
14
|
]
|
|
15
|
-
|
|
15
|
+
# Lenient ingest: some upstream corpus documents carry more than one
|
|
16
|
+
# <formattedref> in a bibitem; keep the first instead of failing the
|
|
17
|
+
# whole ingest (lutaml-model#971, the singular_tolerance option in
|
|
18
|
+
# 0.8.112).
|
|
19
|
+
attribute :formattedref, Formattedref, singular_tolerance: :first
|
|
16
20
|
attribute :title, Title, collection: true, initialize_empty: true
|
|
17
21
|
attribute :source, Uri, collection: true, initialize_empty: true
|
|
18
22
|
attribute :docidentifier, Docidentifier, collection: true, initialize_empty: true
|
|
@@ -32,6 +32,16 @@ module Relaton
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
# Cast at the assignment layer (lutaml-model#972): a bare scalar
|
|
36
|
+
# assigned to a singular custom-typed attribute (e.g. a relation's
|
|
37
|
+
# description) is wrapped here, so the serializer's type validation
|
|
38
|
+
# sees an instance instead of raising IncorrectModelError.
|
|
39
|
+
def self.cast(value)
|
|
40
|
+
return value if value.is_a?(self)
|
|
41
|
+
|
|
42
|
+
new(content: value.to_s)
|
|
43
|
+
end
|
|
44
|
+
|
|
35
45
|
attribute :content, :string
|
|
36
46
|
prepend ContentSanitization
|
|
37
47
|
|
|
@@ -16,7 +16,7 @@ module Relaton
|
|
|
16
16
|
hasReview commentaryOf hasCommentary related hasComplement complementOf
|
|
17
17
|
obsoletes obsoletedBy cites isCitedIn
|
|
18
18
|
]
|
|
19
|
-
attribute :description, LocalizedMarkedUpString
|
|
19
|
+
attribute :description, LocalizedMarkedUpString, singular_tolerance: :first
|
|
20
20
|
attribute :bibitem, ItemBase
|
|
21
21
|
choice(min: 1, max: 1) do
|
|
22
22
|
attribute :locality, Locality, collection: true, initialize_empty: true
|
|
@@ -215,8 +215,12 @@ module Relaton::Bipm
|
|
|
215
215
|
end
|
|
216
216
|
|
|
217
217
|
def index
|
|
218
|
+
# The machine index on the Pages site (relaton#206): a parsed query
|
|
219
|
+
# reads only its own shard; a Pages failure raises
|
|
220
|
+
# `Relaton::RequestError`; the whole-index zip on the same site
|
|
221
|
+
# serves only the retry on a miss.
|
|
218
222
|
Relaton::Index.find_or_create(
|
|
219
|
-
:bipm,
|
|
223
|
+
:bipm, pages_url: PAGES_URL,
|
|
220
224
|
pubid_class: ::Pubid::Bipm::Identifier
|
|
221
225
|
)
|
|
222
226
|
end
|
data/lib/relaton/bipm.rb
CHANGED
|
@@ -23,6 +23,10 @@ module Relaton
|
|
|
23
23
|
# by `relaton-data-bipm`'s crawler (using the retained `Relaton::Bipm::Id`),
|
|
24
24
|
# but this flavor no longer reads or writes it.
|
|
25
25
|
INDEXFILE = "index-v2".freeze
|
|
26
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
27
|
+
# manifest + per-shard rows read by the consumer's index; the zip stays
|
|
28
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
29
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-bipm/"
|
|
26
30
|
|
|
27
31
|
# Returns hash of gems versions used to generate the data model.
|
|
28
32
|
# @return [String]
|
|
@@ -12,9 +12,14 @@ module Relaton::Calconnect
|
|
|
12
12
|
private
|
|
13
13
|
|
|
14
14
|
# @return [Relaton::Index::Type]
|
|
15
|
+
#
|
|
16
|
+
# The machine index on the Pages site (relaton#206, the W3C pilot's
|
|
17
|
+
# contract): a parsed query reads only its own shard. A Pages failure
|
|
18
|
+
# raises `Relaton::RequestError`; the whole-index zip on the same site
|
|
19
|
+
# serves only the retry on a miss.
|
|
20
|
+
#
|
|
15
21
|
def index
|
|
16
|
-
Relaton::Index.find_or_create :CC,
|
|
17
|
-
file: "#{INDEXFILE}.yaml",
|
|
22
|
+
Relaton::Index.find_or_create :CC, pages_url: PAGES_URL,
|
|
18
23
|
pubid_class: ::Pubid::Calconnect::Identifier
|
|
19
24
|
end
|
|
20
25
|
|
data/lib/relaton/calconnect.rb
CHANGED
|
@@ -23,6 +23,10 @@ module Relaton
|
|
|
23
23
|
# `relaton-data-calconnect`'s crawler derives the legacy `index-v1` from
|
|
24
24
|
# these rows for released consumers, so it is not produced or read here.
|
|
25
25
|
INDEXFILE = "index-v2".freeze
|
|
26
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
27
|
+
# manifest + per-shard rows read by HitCollection's index; the zip stays
|
|
28
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
29
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-calconnect/"
|
|
26
30
|
|
|
27
31
|
# Returns hash of XML reammar
|
|
28
32
|
# @return [String]
|
|
@@ -20,8 +20,12 @@ module Relaton
|
|
|
20
20
|
# Pubid index (index-v2): `:id` deserializes to a Pubid::Ccsds::Identifier
|
|
21
21
|
# via pubid_class, so search narrows by number with binary search.
|
|
22
22
|
def index
|
|
23
|
+
# The machine index on the Pages site (relaton#206): a parsed query
|
|
24
|
+
# reads only its own shard; a Pages failure raises
|
|
25
|
+
# `Relaton::RequestError`; the whole-index zip on the same site
|
|
26
|
+
# serves only the retry on a miss.
|
|
23
27
|
@index ||= Relaton::Index.find_or_create(
|
|
24
|
-
:ccsds,
|
|
28
|
+
:ccsds, pages_url: PAGES_URL, pubid_class: Pubid::Ccsds::Identifier
|
|
25
29
|
)
|
|
26
30
|
end
|
|
27
31
|
|
data/lib/relaton/ccsds.rb
CHANGED
|
@@ -19,6 +19,10 @@ module Relaton
|
|
|
19
19
|
# index-v1 (pubid-v1 hash, for the released gem line) is rebuilt separately
|
|
20
20
|
# by the data repo's build_index_v1.rb.
|
|
21
21
|
INDEXFILE = "index-v2"
|
|
22
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
23
|
+
# manifest + per-shard rows read by the consumer's index; the zip stays
|
|
24
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
25
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-ccsds/"
|
|
22
26
|
|
|
23
27
|
class Error < StandardError; end
|
|
24
28
|
# Your code goes here...
|
data/lib/relaton/cie/scrapper.rb
CHANGED
|
@@ -15,7 +15,11 @@ module Relaton
|
|
|
15
15
|
# "... is not a recognized standards identifier". Partial refs
|
|
16
16
|
# (`CIE 001`, `CIE 15`) parse, so nothing valid is lost.
|
|
17
17
|
pubid = to_pubid ref
|
|
18
|
-
index
|
|
18
|
+
# The machine index on the Pages site (relaton#206): a parsed query
|
|
19
|
+
# reads only its own shard; a Pages failure raises
|
|
20
|
+
# `Relaton::RequestError`; the whole-index zip on the same site
|
|
21
|
+
# serves only the retry on a miss.
|
|
22
|
+
index = Index.find_or_create :cie, pages_url: PAGES_URL,
|
|
19
23
|
pubid_class: ::Pubid::Cie::Identifier
|
|
20
24
|
# Pass the parsed pubid (not the raw String) so index-v2 narrows
|
|
21
25
|
# candidates by number via binary search before the block runs; the
|
data/lib/relaton/cie.rb
CHANGED
|
@@ -16,6 +16,10 @@ require_relative "cie/scrapper"
|
|
|
16
16
|
module Relaton
|
|
17
17
|
module Cie
|
|
18
18
|
INDEXFILE = "index-v2".freeze
|
|
19
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
20
|
+
# manifest + per-shard rows read by the consumer's index; the zip stays
|
|
21
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
22
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-cie/"
|
|
19
23
|
|
|
20
24
|
# Returns hash of XML reammar
|
|
21
25
|
# @return [String]
|
data/lib/relaton/db/cache.rb
CHANGED
|
@@ -3,7 +3,6 @@ require "digest"
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "date"
|
|
5
5
|
require "lutaml/store"
|
|
6
|
-
require "nokogiri"
|
|
7
6
|
require_relative "cache_entry"
|
|
8
7
|
|
|
9
8
|
module Relaton
|
|
@@ -335,12 +334,18 @@ module Relaton
|
|
|
335
334
|
|
|
336
335
|
# The wrapped string key of an old-layout document: its own primary
|
|
337
336
|
# docidentifier under its flavor prefix, resolved through the same
|
|
338
|
-
# `wrapped_key` path a string cache read takes.
|
|
337
|
+
# `wrapped_key` path a string cache read takes. A value no parser reads
|
|
338
|
+
# is no document — the legacy cache predates this gem's own writes —
|
|
339
|
+
# not a crash.
|
|
339
340
|
def old_layout_key(path, value)
|
|
340
341
|
flavor = path.split("/").first or return
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
342
|
+
root = begin
|
|
343
|
+
Moxml.new.parse(value, readonly: true).root
|
|
344
|
+
rescue Moxml::ParseError
|
|
345
|
+
nil
|
|
346
|
+
end or return
|
|
347
|
+
id = root.at_xpath("./docidentifier[@primary = 'true']") ||
|
|
348
|
+
root.at_xpath("./docidentifier") or return
|
|
344
349
|
|
|
345
350
|
"#{flavor.upcase}(#{id.text.strip})"
|
|
346
351
|
end
|
data/lib/relaton/db/registry.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Relaton
|
|
|
13
13
|
relaton/oasis relaton/doi relaton/jis relaton/xsf
|
|
14
14
|
relaton/ccsds relaton/etsi relaton/isbn relaton/plateau
|
|
15
15
|
relaton/oiml relaton/jcgm relaton/easc relaton/gost relaton/adobe
|
|
16
|
-
relaton/iala
|
|
16
|
+
relaton/iala relaton/evs
|
|
17
17
|
].freeze
|
|
18
18
|
|
|
19
19
|
include Singleton
|
|
@@ -68,10 +68,13 @@ module Relaton
|
|
|
68
68
|
private
|
|
69
69
|
|
|
70
70
|
def index
|
|
71
|
+
# The machine index on the Pages site (relaton#206): a parsed query
|
|
72
|
+
# reads only its own shard; a Pages failure raises
|
|
73
|
+
# `Relaton::RequestError`; the whole-index zip on the same site
|
|
74
|
+
# serves only the retry on a miss.
|
|
71
75
|
Relaton::Index.find_or_create(
|
|
72
76
|
:easc,
|
|
73
|
-
|
|
74
|
-
file: "#{INDEXFILE}.yaml",
|
|
77
|
+
pages_url: PAGES_URL,
|
|
75
78
|
pubid_class: ::Pubid::Easc::Identifier,
|
|
76
79
|
)
|
|
77
80
|
end
|
data/lib/relaton/easc.rb
CHANGED
|
@@ -13,6 +13,10 @@ require "pubid"
|
|
|
13
13
|
module Relaton
|
|
14
14
|
module Easc
|
|
15
15
|
INDEXFILE = "index-v2".freeze
|
|
16
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
17
|
+
# manifest + per-shard rows read by the consumer's index; the zip stays
|
|
18
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
19
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-easc/"
|
|
16
20
|
|
|
17
21
|
class Error < StandardError; end
|
|
18
22
|
|
|
@@ -11,8 +11,12 @@ module Relaton
|
|
|
11
11
|
class << self
|
|
12
12
|
# @return [Relaton::Index::Type]
|
|
13
13
|
def index
|
|
14
|
+
# The machine index on the Pages site (relaton#206): a parsed query
|
|
15
|
+
# reads only its own shard; a Pages failure raises
|
|
16
|
+
# `Relaton::RequestError`; the whole-index zip on the same site
|
|
17
|
+
# serves only the retry on a miss.
|
|
14
18
|
Relaton::Index.find_or_create(
|
|
15
|
-
:ECMA,
|
|
19
|
+
:ECMA, pages_url: PAGES_URL,
|
|
16
20
|
pubid_class: ::Pubid::Ecma::Identifier
|
|
17
21
|
)
|
|
18
22
|
end
|
data/lib/relaton/ecma.rb
CHANGED
|
@@ -20,6 +20,10 @@ module Relaton
|
|
|
20
20
|
# `relaton-data-ecma`'s crawler derives the legacy `index-v1` from these
|
|
21
21
|
# rows for released consumers, so it is not produced or read here.
|
|
22
22
|
INDEXFILE = "index-v2".freeze
|
|
23
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
24
|
+
# manifest + per-shard rows read by the consumer's index; the zip stays
|
|
25
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
26
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-ecma/"
|
|
23
27
|
|
|
24
28
|
# Returns hash of XML reammar
|
|
25
29
|
# @return [String]
|
|
@@ -16,7 +16,11 @@ module Relaton
|
|
|
16
16
|
# A parsed pubid comes from Relaton::Db (relaton#205); it is only read.
|
|
17
17
|
pubid = ref.is_a?(String) ? ::Pubid::Etsi.parse(ref) : ref
|
|
18
18
|
|
|
19
|
-
index
|
|
19
|
+
# The machine index on the Pages site (relaton#206): a parsed query
|
|
20
|
+
# reads only its own shard; a Pages failure raises
|
|
21
|
+
# `Relaton::RequestError`; the whole-index zip on the same site
|
|
22
|
+
# serves only the retry on a miss.
|
|
23
|
+
index = Relaton::Index.find_or_create :etsi, pages_url: PAGES_URL,
|
|
20
24
|
pubid_class: ::Pubid::Etsi::Identifier
|
|
21
25
|
row = best_match(index, pubid)
|
|
22
26
|
return unless row
|
data/lib/relaton/etsi.rb
CHANGED
|
@@ -14,6 +14,10 @@ require_relative "etsi/bibliography"
|
|
|
14
14
|
module Relaton
|
|
15
15
|
module Etsi
|
|
16
16
|
INDEXFILE = "index-v2".freeze
|
|
17
|
+
# The machine index on the data repo's Pages site (relaton#206) —
|
|
18
|
+
# manifest + per-shard rows read by the consumer's index; the zip stays
|
|
19
|
+
# on the Pages site for the whole-index retry on a miss.
|
|
20
|
+
PAGES_URL = "https://relaton.github.io/relaton-data-etsi/"
|
|
17
21
|
|
|
18
22
|
# Returns hash of gem versions used to generate data model.
|
|
19
23
|
# @return [String]
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Evs
|
|
5
|
+
# Class methods for search Estonian standards.
|
|
6
|
+
class Bibliography
|
|
7
|
+
class << self
|
|
8
|
+
# @param ref [String] the printed reference
|
|
9
|
+
# @return [Relaton::Evs::HitCollection]
|
|
10
|
+
def search(ref, year = nil)
|
|
11
|
+
HitCollection.new(ref, year).search
|
|
12
|
+
rescue Net::ReadTimeout, Net::OpenTimeout => e
|
|
13
|
+
raise Relaton::RequestError, e.message
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
# Parses a printed EVS reference.
|
|
18
|
+
#
|
|
19
|
+
# Deliberately does NOT rescue. An unrecognized query reference must
|
|
20
|
+
# raise, so that relaton-cli can print `"…" is not a recognized
|
|
21
|
+
# standards identifier`; returning nil would make "malformed" look
|
|
22
|
+
# like "not found". Only the DATA side rescues — see `Hit#pubid`.
|
|
23
|
+
#
|
|
24
|
+
# @param ref [String] a printed reference, e.g. "EVS-EN 18216:2026"
|
|
25
|
+
#
|
|
26
|
+
# @return [Pubid::Evs::Identifier]
|
|
27
|
+
# @raise [Pubid::Errors::ParseError]
|
|
28
|
+
#
|
|
29
|
+
def parse(ref)
|
|
30
|
+
::Pubid::Evs.parse ref
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# @param ref [String, Pubid::Evs::Identifier] the EVS standard
|
|
35
|
+
# reference to look up, or its parse from Relaton::Db (relaton#205)
|
|
36
|
+
# @param year [String] the year the standard was published (optional)
|
|
37
|
+
# @param opts [Hash] options
|
|
38
|
+
# @option opts [Boolean] :keep_year don't update reference
|
|
39
|
+
#
|
|
40
|
+
# @return [Relaton::Evs::ItemData, nil]
|
|
41
|
+
#
|
|
42
|
+
def get(ref, year = nil, opts = {})
|
|
43
|
+
# An empty string is no reference, not a malformed one, so it stays a
|
|
44
|
+
# plain nil rather than a parse failure. Mirrors the guard
|
|
45
|
+
# HitCollection#search already carries.
|
|
46
|
+
return if ref.nil? || (ref.is_a?(String) && ref.strip.empty?)
|
|
47
|
+
|
|
48
|
+
# `Relaton::Db` hands `get` the parse it routed and keyed the cache
|
|
49
|
+
# with; it must reach `bib_get` unmutated.
|
|
50
|
+
query = ref.is_a?(String) ? parse(ref) : ref
|
|
51
|
+
year ||= publication_year query
|
|
52
|
+
|
|
53
|
+
bib_get ref.to_s, year, opts, query
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
#
|
|
59
|
+
# `#root` is the accessor that answers for every form: a national
|
|
60
|
+
# adoption keeps the origin standard's number and year behind its
|
|
61
|
+
# `base` chain, and a direct adoption or plain Estonian standard is
|
|
62
|
+
# its own root.
|
|
63
|
+
#
|
|
64
|
+
# @param id [Pubid::Evs::Identifier]
|
|
65
|
+
#
|
|
66
|
+
# @return [String, nil]
|
|
67
|
+
#
|
|
68
|
+
def publication_year(id)
|
|
69
|
+
id.root.year&.to_s
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# A component is absent from a reference when excluding it changes
|
|
73
|
+
# nothing.
|
|
74
|
+
#
|
|
75
|
+
# @return [Boolean]
|
|
76
|
+
def absent?(id, *keys)
|
|
77
|
+
id.exclude(*keys) == id
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def fetch_ref_err(ref, year, missed_years)
|
|
81
|
+
unless missed_years.empty?
|
|
82
|
+
Util.info "There was no match for `#{year}`, though there " \
|
|
83
|
+
"were matches found for `#{missed_years.join('`, `')}`.",
|
|
84
|
+
key: ref
|
|
85
|
+
end
|
|
86
|
+
nil
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# Selects the catalogue hits that denote the same document as the
|
|
91
|
+
# query. The selection is pubid's subset match `query === hit.pubid`:
|
|
92
|
+
# a year the query omits matches any value, and the class must be
|
|
93
|
+
# identical, so a base reference never answers with its own
|
|
94
|
+
# amendment's record.
|
|
95
|
+
#
|
|
96
|
+
# @param ref [String] the printed reference, as the catalogue URL
|
|
97
|
+
# wants it
|
|
98
|
+
# @param query [Pubid::Evs::Identifier]
|
|
99
|
+
#
|
|
100
|
+
# @return [Relaton::Evs::HitCollection]
|
|
101
|
+
#
|
|
102
|
+
def search_filter(ref, query)
|
|
103
|
+
search(ref).select! { |hit| hit.pubid && query === hit.pubid }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Fetch the matching hit, keeping the year filter for error reporting.
|
|
107
|
+
def isobib_results_filter(result, year)
|
|
108
|
+
missed_years = []
|
|
109
|
+
result.each do |r|
|
|
110
|
+
pyear = r.pubid && publication_year(r.pubid)
|
|
111
|
+
if !year || year == pyear
|
|
112
|
+
ret = r.item
|
|
113
|
+
return { ret: ret } if ret
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
missed_years << pyear
|
|
117
|
+
end
|
|
118
|
+
{ years: missed_years }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def bib_get(ref, year, opts, query)
|
|
122
|
+
key = year && absent?(query, :year) ? "#{ref}:#{year}" : ref
|
|
123
|
+
Util.info "Fetching from www.evs.ee ...", key: key
|
|
124
|
+
result = search_filter(ref, query)
|
|
125
|
+
ret = isobib_results_filter(result, year)
|
|
126
|
+
if ret[:ret]
|
|
127
|
+
bib = year || opts[:keep_year] ? ret[:ret] : ret[:ret].to_most_recent_reference
|
|
128
|
+
Util.info "Found: `#{bib.docidentifier.first&.content}`", key: key
|
|
129
|
+
bib
|
|
130
|
+
else
|
|
131
|
+
Util.info "Not found.", key: key
|
|
132
|
+
fetch_ref_err(ref, year, ret[:years])
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Evs
|
|
5
|
+
# Hit.
|
|
6
|
+
class Hit < Relaton::Core::Hit
|
|
7
|
+
attr_writer :item
|
|
8
|
+
|
|
9
|
+
# Parse page.
|
|
10
|
+
# @return [Relaton::Evs::ItemData]
|
|
11
|
+
def item
|
|
12
|
+
@fetch ||= Scraper.parse_page self
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# The hit's code parsed with pubid, memoized because the filter, the
|
|
16
|
+
# sort and the scraper all read it. `nil` when pubid cannot parse the
|
|
17
|
+
# code: the catalogue also hosts documents outside the EVS grammar
|
|
18
|
+
# (a bare `EN` or `ISO` record linked as a base document), and one such
|
|
19
|
+
# row must not abort the search. (A malformed *query* raises; see
|
|
20
|
+
# `Bibliography.parse`.)
|
|
21
|
+
#
|
|
22
|
+
# @return [Pubid::Evs::Identifier, nil]
|
|
23
|
+
def pubid
|
|
24
|
+
return @pubid if defined?(@pubid)
|
|
25
|
+
|
|
26
|
+
@pubid = Bibliography.parse hit[:code]
|
|
27
|
+
rescue StandardError
|
|
28
|
+
@pubid = nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Relaton
|
|
4
|
+
module Evs
|
|
5
|
+
# Page of hit collection.
|
|
6
|
+
class HitCollection < Relaton::Core::HitCollection
|
|
7
|
+
DOMAIN = "https://www.evs.ee"
|
|
8
|
+
|
|
9
|
+
def search
|
|
10
|
+
@array = hits
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def agent
|
|
15
|
+
@agent ||= Mechanize.new.tap { |a| a.user_agent_alias = "Mac Safari" }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def select!(&block)
|
|
19
|
+
@array.select!(&block)
|
|
20
|
+
self
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
#
|
|
26
|
+
# The catalogue URL is the printed reference slugified
|
|
27
|
+
# (`EVS-EN 18216:2026` -> /en/evs-en-18216-2026), so the search is a
|
|
28
|
+
# direct probe: the product page exists iff the reference denotes a
|
|
29
|
+
# published document. A miss redirects to /page-not-found, which is no
|
|
30
|
+
# hit. A reference carrying the `et` language code probes the Estonian
|
|
31
|
+
# locale, which serves the Estonian-language product.
|
|
32
|
+
#
|
|
33
|
+
# @return [Array<Relaton::Evs::Hit>]
|
|
34
|
+
#
|
|
35
|
+
def hits
|
|
36
|
+
page = agent.get url
|
|
37
|
+
return [] if page.uri.to_s.include? "page-not-found"
|
|
38
|
+
|
|
39
|
+
[Hit.new({ code: code, url: page.uri.to_s }, self)]
|
|
40
|
+
rescue Mechanize::ResponseCodeError
|
|
41
|
+
[]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def url
|
|
45
|
+
"#{DOMAIN}/#{locale}/#{slug}"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def locale
|
|
49
|
+
query_pubid&.language == "et" ? "et" : "en"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# The hit's code is the reference as queried, minus the "(all parts)"
|
|
53
|
+
# marker: `Hit#pubid` parses it back, and the filter `query === hit.pubid`
|
|
54
|
+
# needs the language code ON the hit for a language-carrying query to
|
|
55
|
+
# match its own record. The slug derivation strips the language code
|
|
56
|
+
# separately — the catalogue URL does not carry it.
|
|
57
|
+
def code
|
|
58
|
+
ref.to_s.sub(/\s+\(all parts\)\z/, "")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def slug
|
|
62
|
+
code.sub(/\s+(et-en|et|en)\z/, "")
|
|
63
|
+
.downcase.gsub(/[^a-z0-9]+/, "-").gsub(/\A-+|-+\z/, "")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def query_pubid
|
|
67
|
+
Bibliography.parse code
|
|
68
|
+
rescue StandardError
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|