relaton-iec 1.14.1 → 1.14.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64b4e21a953edecfca9d2ccb0b9dde4e91f8d7e6ced8ce5be3c825142f5e853b
4
- data.tar.gz: c8478d74927f064b4c2711fbd916a1fb68ac1ee6ffa5ecde681c3374816ac024
3
+ metadata.gz: 4d00653dcd13da1fbfe251bd51366bcb0e038980a6a5598e8d06e90e93c25a5c
4
+ data.tar.gz: 1f70ddc26bc98c7a8da254e8eb7b31a28508c06763ebc3ab4de44dfc008b5465
5
5
  SHA512:
6
- metadata.gz: e65980c0a520d2244db616e3dcced3a97e0ca3c8c8aed4a9a856eeca4badd5cd0a8bd3748207b5e52c58154066a291e0797b3c8b2c67b4d2472418f050acde6d
7
- data.tar.gz: 22894e978223c56b60aab15c4a497982e8b783ab857dd20386a81485eb19b87283d7da5d903a11dd90fb91230fc576b2e5ce3b70a05cc57c664595376b829e98
6
+ metadata.gz: b4b1f3a22cfa10e630795cebe87ee63ef4e803f4ca276d1f94b37ab09e940d9abc430ab66fbd80e781c1dd8055dd948209f767449139d23bbc42ecbe4e4501cf
7
+ data.tar.gz: 9ad6a0084b3144ffde1c06237265ca2a6e73ae3762c4dc210ae199a70bdd931866f3db0dfdc1ebbbf17d3714942c33346dc9fb8ae1233910433ba6391bdd7281
data/Gemfile CHANGED
@@ -4,3 +4,9 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in relaton_iec.gemspec
6
6
  gemspec
7
+
8
+ gem "pry-byebug"
9
+ gem "ruby-jing"
10
+ gem "simplecov"
11
+ gem "vcr"
12
+ gem "webmock"
data/README.adoc CHANGED
@@ -47,25 +47,24 @@ hit_collection = RelatonIec::IecBibliography.search("60050")
47
47
  => <RelatonIec::HitCollection:0x007fe0d7126f28 @ref=60050 @fetched=false>
48
48
 
49
49
  hit_collection.first
50
- => <RelatonIec::Hit:0x007fe1068b4d10 @text="60050" @fetched="false" @fullIdentifier="" @title="IEC 60050-102:2007">
50
+ => <RelatonIec::Hit:0x000000000003e8 @text="60050" @fetched="false" @fullIdentifier="" @title="IEC 60050-05:1935">
51
51
 
52
52
  item = hit_collection[2].fetch
53
53
  => #<RelatonIec::IecBibliographicItem:0x007fe1171a06f8
54
54
  ...
55
55
 
56
56
  item.docidentifier
57
- => [#<RelatonBib::DocumentIdentifier:0x00007f876539d1b0 @id="IEC 60050-112:2010", @language=nil, @primary=true, @scope=nil, @script=nil, @type="IEC">,
58
- #<RelatonBib::DocumentIdentifier:0x00007f876539d070
59
- @id="urn:iec:std:iec:60050-112:2010:::en",
57
+ => [#<RelatonBib::DocumentIdentifier:0x00007ff1b52a2b60 @id="IEC 60050-07:1956", @language=nil, @primary=true, @scope=nil, @script=nil, @type="IEC">,
58
+ #<RelatonBib::DocumentIdentifier:0x00007ff1b52a2a98
59
+ @id="urn:iec:std:iec:60050-07:1956-01:::",
60
60
  @language=nil,
61
61
  @primary=nil,
62
62
  @scope=nil,
63
63
  @script=nil,
64
64
  @type="URN">]
65
- [6] pry(main)>
66
65
 
67
66
  item.docidentifier.detect { |di| di.type == "URN" }.id
68
- => "urn:iec:std:iec:60050-112:2010:::en"
67
+ => "urn:iec:std:iec:60050-07:1956-01:::"
69
68
  ----
70
69
 
71
70
  === Fetch document by keywords
@@ -79,8 +78,8 @@ item.docidentifier.detect { |di| di.type == "URN" }.id
79
78
  [source,ruby]
80
79
  ----
81
80
  item = RelatonIec::IecBibliography.get("IEC 60050-112:2010")
82
- [relaton-iec] ("IEC 60050-112") fetching...
83
- [relaton-iec] ("IEC 60050-112") found IEC 60050-112:2010
81
+ [relaton-iec] ("IEC 60050-112:2010") fetching...
82
+ [relaton-iec] ("IEC 60050-112:2010") found IEC 60050-112:2010
84
83
  => #<RelatonIec::IecBibliographicItem:0x00007f876525e8d0
85
84
  ...
86
85
 
@@ -104,15 +103,12 @@ item.docidentifier.first
104
103
 
105
104
  === Search for ISO/IEC Directives
106
105
 
107
- The ISO/IEC Directives are stored in a static cache in a relaton gem. It needs to use the relaton gem to fetch the ISO/IEC Directives. The following references are allowed to fetch:
106
+ The following references are allowed to fetch:
108
107
 
109
- - ISO/IEC DIR 1 - Procedures for the technical work
110
- - ISO/IEC DIR 1 IEC SUP - Procedures for the technical work Procedures specific to IEC
111
- - ISO/IEC DIR 1 ISO SUP - Consolidated ISO Supplement -- Procedures specific to ISO
112
- - ISO/IEC DIR 2 IEC - Principles and rules for the structure and drafting of ISO and IEC documents
113
- - ISO/IEC DIR 2 ISO - Principles and rules for the structure and drafting of ISO and IEC documents
114
- - ISO/IEC DIR IEC SUP - Procedures specific to IEC
115
- - ISO/IEC DIR JTC 1 SUP - Procedures specific to JTC 1
108
+ - `IEC 61360-4 DB` - IEC/SC 3D - Common Data Dictionary (CDD - V2.0015.0001)
109
+ - `ISO/IEC DIR 1 IEC SUP` - Procedures for the technical work - Procedures specific to IEC
110
+ - `ISO/IEC DIR 2 IEC` - Principles and rules for the structure and drafting of ISO and IEC documents
111
+ - 'ISO/IEC DIR IEC SUP' - Procedures specific to IEC
116
112
 
117
113
  === XML serialization
118
114
 
@@ -125,22 +121,22 @@ Possible options:
125
121
  ----
126
122
  item.to_xml
127
123
  => "<bibitem id="IEC60050-112-2010" type="standard" schema-version="v1.2.1">
128
- <fetched>2022-12-03</fetched>
129
- <title type="title-main" format="text/plain" language="en" script="Latn">International Electrotechnical Vocabulary (IEV)</title>
130
- <title type="title-part" format="text/plain" language="en" script="Latn">Part 112: Quantities and units</title>
124
+ <fetched>2023-03-01</fetched>
131
125
  <title type="main" format="text/plain" language="en" script="Latn">International Electrotechnical Vocabulary (IEV) - Part 112: Quantities and units</title>
126
+ <title type="main" format="text/plain" language="fr" script="Latn">Vocabulaire Electrotechnique International (IEV) - Partie 112: Grandeurs et unités</title>
127
+ <title type="main" format="text/plain" language="es" script="Latn">Versión Oficial En español - Vocabulario Electrotécnico Internacional. Parte 112: Magnitudes y unidades.</title>
132
128
  <uri type="src">https://webstore.iec.ch/publication/162</uri>
133
129
  ...
134
130
  </bibitem>"
135
131
 
136
132
  item.to_xml bibdata: true
137
133
  => "<bibdata type="standard" schema-version="v1.2.1">
138
- <fetched>2022-12-03</fetched>
139
- <title type="title-main" format="text/plain" language="en" script="Latn">International Electrotechnical Vocabulary (IEV)</title>
140
- <title type="title-part" format="text/plain" language="en" script="Latn">Part 112: Quantities and units</title>
134
+ <fetched>2023-03-01</fetched>
141
135
  <title type="main" format="text/plain" language="en" script="Latn">International Electrotechnical Vocabulary (IEV) - Part 112: Quantities and units</title>
136
+ <title type="main" format="text/plain" language="fr" script="Latn">Vocabulaire Electrotechnique International (IEV) - Partie 112: Grandeurs et unités</title>
137
+ <title type="main" format="text/plain" language="es" script="Latn">Versión Oficial En español - Vocabulario Electrotécnico Internacional. Parte 112: Magnitudes y unidades.</title>
142
138
  <uri type="src">https://webstore.iec.ch/publication/162</uri>
143
- <uri type="obp">/preview/info_iec60050-112%7Bed1.0%7Db.pdf</uri>
139
+ <uri type="obp">https://webstore.iec.ch/preview/info_iec60050-112{ed1.0}b.pdf</uri>
144
140
  ...
145
141
  <ext schema-version="v1.0.0">
146
142
  <doctype>international-standard</doctype>
@@ -163,8 +159,16 @@ Each IEC document has `src` type link and optional `obp` type link.
163
159
  [source,ruby]
164
160
  ----
165
161
  item.link
166
- => [#<RelatonBib::TypedUri:0x00007ffe9d9b6420 @content=#<Addressable::URI:0x80c URI:https://webstore.iec.ch/publication/162>, @type="src">,
167
- #<RelatonBib::TypedUri:0x00007ffe9d9af080 @content=#<Addressable::URI:0x820 URI:/preview/info_iec60050-112%7Bed1.0%7Db.pdf>, @type="obp">]
162
+ => [#<RelatonBib::TypedUri:0x00007ff1d50e9e20
163
+ @content=#<Addressable::URI:0x2260 URI:https://webstore.iec.ch/publication/162>,
164
+ @language=nil,
165
+ @script=nil,
166
+ @type="src">,
167
+ #<RelatonBib::TypedUri:0x00007ff1d50e9498
168
+ @content=#<Addressable::URI:0x2274 URI:https://webstore.iec.ch/preview/info_iec60050-112{ed1.0}b.pdf>,
169
+ @language=nil,
170
+ @script=nil,
171
+ @type="obp">]
168
172
  ----
169
173
 
170
174
  === Create bibliographic item from Hash
@@ -172,7 +176,8 @@ item.link
172
176
  [source,ruby]
173
177
  ----
174
178
  hash = YAML.load_file "spec/examples/hit.yaml"
175
- => {"id"=>"IEC61058-2-4-1995+AMD1-2003CSV",
179
+ => {"schema-version"=>"v1.2.1",
180
+ "id"=>"IEC61058-2-4-1995+AMD1-2003CSV",
176
181
  ...
177
182
 
178
183
  RelatonIec::IecBibliographicItem.from_hash hash
@@ -233,6 +238,28 @@ RelatonIec.urn_to_code "urn:iec:std:iec:60034-1:1969::csv:en-fr:plus:amd:1:1977:
233
238
  => ["IEC 60034-1:1969+AMD1:1977+AMD2:1979+AMD3:1980 CSV", "en-fr"]
234
239
  ----
235
240
 
241
+ === Fetch data
242
+
243
+ This gem uses the https://bitbucket.org/sdo-hapi/api-specifications/wiki/Guidelines[Harmonized API] as a data source. The following options are available:
244
+ - `iec-harmonized-all` - fetches all the documents using the API
245
+ - `iec-harmonized-latest` - fetches the latest documents using the API
246
+
247
+ The method `RelatonIec::DataFetcher.new(source, output: "data", format: "yaml").fetch` fetches IEC documents from the dataset and saves them to the `./data` folder in YAML format.
248
+ Arguments:
249
+
250
+ - `source` - data source. Possible values: `iec-harmonized-all`, `iec-harmonized-latest` (default `iec-harmonized-latest`).
251
+ - `output` - folder to save documents (default './data').
252
+ - `format` - the format in which the documents are saved. Possible formats are: `yaml`, `xml`, `bibxxml` (default `yaml`).
253
+
254
+ [source,ruby]
255
+ ----
256
+ RelatonIec::DataFetcher.new.fetch
257
+ Started at: 2022-06-23 09:36:55 +0200
258
+ Stopped at: 2022-06-23 09:36:58 +0200
259
+ Done in: 752 sec.
260
+ => nil
261
+ ----
262
+
236
263
  == Development
237
264
 
238
265
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,190 @@
1
+ module RelatonIec
2
+ class DataFetcher
3
+ ENTRYPOINT = "https://api.iec.ch/harmonized/publications?size=100&sortBy=urn&page=".freeze
4
+ CREDENTIAL = "https://api.iec.ch/oauth/client_credential/accesstoken?grant_type=client_credentials".freeze
5
+ LAST_CHANGE_FILE = "last_change.txt".freeze
6
+
7
+ #
8
+ # Initialize new instance.
9
+ #
10
+ # @param [String] source source name (iec-harmonized-all, iec-harmonized-latest)
11
+ # @param [String] output output directory
12
+ # @param [String] format format of output files (xml, bibxml, yaml)
13
+ #
14
+ def initialize(source = "iec-harmonised-latest", output: "data", format: "yaml")
15
+ @output = output
16
+ @format = format
17
+ @ext = format.sub(/^bib/, "")
18
+ @files = []
19
+ # @index = Index.new "index.yaml"
20
+ @last_change = File.read(LAST_CHANGE_FILE, encoding: "UTF-8") if File.exist? LAST_CHANGE_FILE
21
+ @last_change_max = @last_change.to_s
22
+ @all = source == "iec-harmonised-all"
23
+ end
24
+
25
+ def last_change_max(date)
26
+ @last_change_max = date if @last_change_max < date
27
+ end
28
+
29
+ def save_last_change
30
+ return if @last_change_max.empty?
31
+
32
+ File.write LAST_CHANGE_FILE, @last_change_max, encoding: "UTF-8"
33
+ end
34
+
35
+ #
36
+ # Fetch data from IEC.
37
+ #
38
+ def fetch # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
39
+ t1 = Time.now
40
+ puts "Started at: #{t1}"
41
+
42
+ if @all
43
+ FileUtils.rm_rf @output
44
+ end
45
+ FileUtils.mkdir_p @output
46
+ fetch_all
47
+ create_index
48
+ save_last_change
49
+
50
+ t2 = Time.now
51
+ puts "Stopped at: #{t2}"
52
+ puts "Done in: #{(t2 - t1).round} sec."
53
+ rescue StandardError => e
54
+ warn e.message
55
+ warn e.backtrace.join("\n")
56
+ end
57
+
58
+ def create_index
59
+ index = Relaton::Index.find_or_create :IEC, file: "index1.yaml"
60
+ index.remove_all
61
+ Dir["{#{@output},static}/*.yaml"].each do |file|
62
+ item = YAML.load_file file
63
+ id = item["docid"].detect { |i| i["primary"] }["id"]
64
+ index.add_or_update id, file
65
+ end
66
+ index.save
67
+ end
68
+
69
+ #
70
+ # Add static files to index.
71
+ #
72
+ # @return [void]
73
+ #
74
+ # def add_static_files_to_index
75
+ # Dir["static/*.yaml"].each do |file|
76
+ # pub = RelatonBib.parse_yaml File.read(file, encoding: "UTF-8")
77
+ # pubid = RelatonBib.array(pub["docid"]).detect { |id| id["primary"] }["id"]
78
+ # @index.add pubid, file
79
+ # end
80
+ # end
81
+
82
+ #
83
+ # Fetch documents from IEC API.
84
+ #
85
+ # @return [void]
86
+ #
87
+ def fetch_all # rubocop:disable Metrics/MethodLength
88
+ page = 0
89
+ next_page = true
90
+ while next_page
91
+ res = fetch_page_token page
92
+ unless res.code == "200"
93
+ warn "[relaton-iec] #{res.body}"
94
+ break
95
+ end
96
+ json = JSON.parse res.body
97
+ json["publication"].each { |pub| fetch_pub pub }
98
+ page += 1
99
+ next_page = res["link"]&.include? "rel=\"last\""
100
+ end
101
+ end
102
+
103
+ #
104
+ # Fetch page. If response code is 401, then get new access token and try
105
+ #
106
+ # @param [Integer] page page number
107
+ #
108
+ # @return [Net::HTTP::Response] response
109
+ #
110
+ def fetch_page_token(page)
111
+ res = fetch_page page
112
+ if res.code == "401"
113
+ @access_token = nil
114
+ res = fetch_page page
115
+ end
116
+ res
117
+ end
118
+
119
+ #
120
+ # Fetch page from IEC API.
121
+ #
122
+ # @param [Integer] page page number
123
+ #
124
+ # @return [Net::HTTP::Response] response
125
+ #
126
+ def fetch_page(page)
127
+ url = "#{ENTRYPOINT}#{page}"
128
+ if !@all && @last_change
129
+ url += "&lastChangeTimestampFrom=#{@last_change}"
130
+ end
131
+ uri = URI url
132
+ req = Net::HTTP::Get.new uri
133
+ req["Authorization"] = "Bearer #{access_token}"
134
+ Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
135
+ http.request req
136
+ end
137
+ end
138
+
139
+ #
140
+ # Get access token.
141
+ #
142
+ # @return [String] access token
143
+ #
144
+ def access_token # rubocop:disable Metrics/AbcSize
145
+ @access_token ||= begin
146
+ uri = URI CREDENTIAL
147
+ req = Net::HTTP::Get.new uri
148
+ req.basic_auth ENV.fetch("IEC_HAPI_PROJ_PUBS_KEY"), ENV.fetch("IEC_HAPI_PROJ_PUBS_SECRET")
149
+ res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
150
+ http.request req
151
+ end
152
+ JSON.parse(res.body)["access_token"]
153
+ end
154
+ end
155
+
156
+ #
157
+ # Fetch publication and save it to file.
158
+ #
159
+ # @param [Hash] pub publication
160
+ #
161
+ def fetch_pub(pub) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
162
+ bib = DataParser.new(pub).parse
163
+ did = bib.docidentifier.detect &:primary
164
+ file = File.join(@output, "#{did.id.downcase.gsub(/[:\s\/]/, '_')}.#{@ext}")
165
+ if @files.include? file then warn "File #{file} exists."
166
+ else
167
+ @files << file
168
+ # @index.add index_id(pub), file, pub["lastChangeTimestamp"]
169
+ end
170
+ last_change_max pub["lastChangeTimestamp"]
171
+ content = case @format
172
+ when "xml" then bib.to_xml bibdata: true
173
+ when "yaml", "yml" then bib.to_hash.to_yaml
174
+ when "bibxml" then bib.to_bibxml
175
+ end
176
+ File.write file, content, encoding: "UTF-8"
177
+ end
178
+
179
+ def index_id(pub)
180
+ /-(?<part>\d+)/ =~ pub["reference"]
181
+ title = pub.dig("title", 0, "value")
182
+ return pub["reference"] unless part && title
183
+
184
+ ids = title.scan(/(?<=-\sPart\s)#{part[0]}\d+(?=:)/).map do |m|
185
+ pub["reference"].sub(/-#{part}/, "-#{m}")
186
+ end
187
+ ids.size > 1 ? ids : pub["reference"]
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,289 @@
1
+ module RelatonIec
2
+ class DataParser
3
+ DOMAIN = "https://webstore.iec.ch"
4
+
5
+ ATTRS = %i[
6
+ docid structuredidentifier language script title doctype
7
+ ics date contributor editorialgroup abstract copyright link relation
8
+ ].freeze
9
+
10
+ ABBREVS = {
11
+ "ISO" => ["International Organization for Standardization", "www.iso.org"],
12
+ "IEC" => ["International Electrotechnical Commission", "www.iec.ch"],
13
+ "IEEE" => ["Institute of Electrical and Electronics Engineers", "www.ieee.org"],
14
+ "ASTM" => ["American Society of Testing Materials", "www.astm.org"],
15
+ "CISPR" => ["International special committee on radio interference", "www.iec.ch"],
16
+ }.freeze
17
+
18
+ #
19
+ # Initialize new instance.
20
+ #
21
+ # @param [Hash] pub document data
22
+ #
23
+ def initialize(pub)
24
+ @pub = pub
25
+ end
26
+
27
+ #
28
+ # Parse document.
29
+ #
30
+ # @return [RelatonIec::IecBibliographicItem] bib item
31
+ #
32
+ def parse # rubocop:disable Metrics/AbcSize
33
+ args = ATTRS.each_with_object({}) { |a, h| h[a] = send a }
34
+ args[:docstatus] = RelatonBib::DocumentStatus.new stage: @pub["status"]
35
+ args[:edition] = @pub["edition"]
36
+ args[:price_code] = @pub["priceInfo"]["priceCode"]
37
+ args[:place] = ["Geneva"]
38
+ IecBibliographicItem.new(**args)
39
+ end
40
+
41
+ #
42
+ # Parse document identifiers.
43
+ #
44
+ # @return [Array<RelatonBib::DocumentIdentifier>] document identifiers
45
+ #
46
+ def docid
47
+ ids = []
48
+ ids << RelatonBib::DocumentIdentifier.new(id: @pub["reference"], type: "IEC", primary: true)
49
+ urnid = "urn:#{@pub['urnAlt'][0]}"
50
+ ids << RelatonBib::DocumentIdentifier.new(id: urnid, type: "URN")
51
+ end
52
+
53
+ #
54
+ # Parse structured identifier.
55
+ #
56
+ # @return [RelatonIsoBib::StructuredIdentifier] structured identifier
57
+ #
58
+ def structuredidentifier
59
+ m = @pub["reference"].match(
60
+ /(?<=\s)(?<project>\w+)(?:-(?<part>\w*)(?:-(?<subpart>\w*))?)?/,
61
+ )
62
+ RelatonIsoBib::StructuredIdentifier.new(
63
+ project_number: m[:project], part: m[:part], subpart: m[:subpart],
64
+ type: "IEC", id: @pub["reference"]
65
+ )
66
+ end
67
+
68
+ #
69
+ # Parse languages.
70
+ #
71
+ # @return [Array<String>] languages
72
+ #
73
+ def language
74
+ @pub["title"].map { |t| t["lang"] }.uniq
75
+ end
76
+
77
+ #
78
+ # Parse scripts.
79
+ #
80
+ # @return [Array<String>] scripts
81
+ #
82
+ def script
83
+ language.each_with_object([]) do |l, s|
84
+ scr = lang_to_script l
85
+ s << scr if scr && !s.include?(scr)
86
+ end
87
+ end
88
+
89
+ #
90
+ # Detect script.
91
+ #
92
+ # @param [String] lang language
93
+ #
94
+ # @return [String] script
95
+ #
96
+ def lang_to_script(lang)
97
+ case lang
98
+ when "en", "fr", "es" then "Latn"
99
+ end
100
+ end
101
+
102
+ #
103
+ # Parse titles.
104
+ #
105
+ # @return [Array<RelatonBib::TypedTitleString>] titles
106
+ #
107
+ def title
108
+ @pub["title"].map do |t|
109
+ RelatonBib::TypedTitleString.new(
110
+ content: t["value"], language: t["lang"], script: lang_to_script(t["lang"]), type: "main",
111
+ )
112
+ end
113
+ end
114
+
115
+ #
116
+ # Parse editorial group.
117
+ #
118
+ # @return [Hash] editorial group
119
+ #
120
+ def editorialgroup
121
+ return unless @pub["committee"]
122
+
123
+ wg = @pub["committee"]["reference"]
124
+ {
125
+ technical_committee: [{
126
+ name: wg,
127
+ type: "technicalCommittee",
128
+ number: wg.match(/\d+/)&.to_s&.to_i,
129
+ }],
130
+ }
131
+ end
132
+
133
+ #
134
+ # Parse abstract.
135
+ #
136
+ # @return [Array<RelatonBib::FormattedString>] abstract
137
+ #
138
+ def abstract
139
+ @pub["abstract"]&.map do |a|
140
+ RelatonBib::FormattedString.new(
141
+ content: a["content"], language: a["lang"], script: lang_to_script(a["lang"]),
142
+ format: a["format"]
143
+ )
144
+ end
145
+ end
146
+
147
+ # @return [Array<Hash>]
148
+ def copyright # rubocop:disable Metrics/AbcSize
149
+ from = @pub["reference"].match(/(?<=:)\d{4}/).to_s
150
+ from = @pub["releaseDate"]&.match(/\d{4}/).to_s if from.empty?
151
+ return [] if from.nil? || from.empty?
152
+
153
+ abbreviation = @pub["reference"].match(/.*?(?=\s)/).to_s
154
+ owner = abbreviation.split("/").map do |abbrev|
155
+ name, url = ABBREVS[abbrev]
156
+ { name: name, abbreviation: abbrev, url: url }
157
+ end
158
+ [{ owner: owner, from: from }]
159
+ end
160
+
161
+ #
162
+ # Fetche ics.
163
+ #
164
+ # @return [Array<RelatonIsoBib::Ics>] ics
165
+ #
166
+ def ics
167
+ return [] unless @pub["classifications"]
168
+
169
+ @pub["classifications"].select { |c| c["type"] == "ICS" }.map do |c|
170
+ RelatonIsoBib::Ics.new(c["value"])
171
+ end
172
+ end
173
+
174
+ #
175
+ # Parse dates.
176
+ #
177
+ # @return [Array<RelatonBib::BibliographicDate>] dates
178
+ #
179
+ def date
180
+ {
181
+ "published" => "publicationDate",
182
+ "stable-until" => "stabilityDate",
183
+ "confirmed" => "confirmationDate",
184
+ "obsoleted" => "dateOfWithdrawal",
185
+ }.reduce([]) do |a, (k, v)|
186
+ next a unless @pub[v]
187
+
188
+ a << RelatonBib::BibliographicDate.new(type: k, on: @pub[v])
189
+ end
190
+ end
191
+
192
+ #
193
+ # Parse contributors.
194
+ #
195
+ # @return [Array<Hash>] contributors
196
+ #
197
+ def contributor
198
+ @pub["reference"].sub(/\s.*/, "").split("/").map do |abbrev|
199
+ name, url = ABBREVS[abbrev]
200
+ { entity: { name: name, url: url, abbreviation: abbrev },
201
+ role: [type: "publisher"] }
202
+ end
203
+ end
204
+
205
+ #
206
+ # Parse links.
207
+ #
208
+ # @return [Array<RelatonBib::TypedUri>] links
209
+ #
210
+ def link
211
+ url = "#{DOMAIN}/publication/#{urn_id}"
212
+ l = [RelatonBib::TypedUri.new(content: url, type: "src")]
213
+ RelatonBib.array(@pub["releaseItems"]).each_with_object(l) do |r, a|
214
+ next unless r["type"] == "PREVIEW"
215
+
216
+ url = "#{DOMAIN}/preview/#{r['contentRef']['fileName']}"
217
+ a << RelatonBib::TypedUri.new(content: url, type: "obp")
218
+ end
219
+ end
220
+
221
+ #
222
+ # Extract URN ID from URN.
223
+ #
224
+ # @return [String] URN ID
225
+ #
226
+ def urn_id
227
+ @pub["urn"].split(":").last
228
+ end
229
+
230
+ #
231
+ # Parse document type.
232
+ #
233
+ # @return [String] document type
234
+ #
235
+ def doctype
236
+ case @pub["stdType"]
237
+ when "IS" then "international-standard"
238
+ when "TR" then "technical-report"
239
+ when "TS" then "technical-specification"
240
+ when "PAS" then "publicly-available-specification"
241
+ when "SRD" then "system-reference-delivrabble"
242
+ else @pub["stdType"].downcase
243
+ end
244
+ end
245
+
246
+ #
247
+ # Parse relation.
248
+ #
249
+ # @return [Array<RelatonBib::DocumentRelation>] relation
250
+ #
251
+ def relation # rubocop:disable Metrics/MethodLength
252
+ try = 0
253
+ begin
254
+ uri = URI "#{DOMAIN}/webstore/webstore.nsf/AjaxRequestXML?" \
255
+ "Openagent&url=#{urn_id}"
256
+ resp = Net::HTTP.get_response uri
257
+ doc = Nokogiri::XML resp.body
258
+ create_relations doc
259
+ rescue StandardError => e
260
+ try += 1
261
+ try < 3 ? retry : raise(e)
262
+ end
263
+ end
264
+
265
+ #
266
+ # Create relations.
267
+ #
268
+ # @param [Nokogiri::XML::Document] doc XML document
269
+ #
270
+ # @return [Array<Hash>] relations
271
+ #
272
+ def create_relations(doc) # rubocop:disable Metrics/MethodLength
273
+ doc.xpath('//ROW[STATUS[.!="PREPARING" and .!="PUBLISHED"]]')
274
+ .map do |r|
275
+ r_type = r.at("STATUS").text.downcase
276
+ type = case r_type
277
+ when "revised", "replaced" then "updates"
278
+ when "withdrawn" then "obsoletes"
279
+ else r_type
280
+ end
281
+ ref = r.at("FULL_NAME").text
282
+ fref = RelatonBib::FormattedRef.new content: ref, format: "text/plain"
283
+ docid = RelatonBib::DocumentIdentifier.new(id: ref, type: "IEC", primary: true)
284
+ bibitem = IecBibliographicItem.new(formattedref: fref, docid: [docid])
285
+ RelatonBib::DocumentRelation.new type: type, bibitem: bibitem
286
+ end
287
+ end
288
+ end
289
+ end
@@ -3,16 +3,32 @@
3
3
  module RelatonIec
4
4
  # Hit.
5
5
  class Hit < RelatonBib::Hit
6
+ GHURL = "https://raw.githubusercontent.com/relaton/relaton-data-iec/main/"
7
+
6
8
  attr_writer :fetch
7
9
 
8
10
  # Parse page.
9
11
  # @return [RelatonIec::IecBibliographicItem]
10
12
  def fetch
11
- @fetch ||= Scrapper.parse_page @hit
13
+ @fetch ||= begin
14
+ url = "#{GHURL}#{hit[:file]}"
15
+ resp = Net::HTTP.get URI(url)
16
+ hash = YAML.safe_load resp
17
+ hash["fetched"] = Date.today.to_s
18
+ IecBibliographicItem.from_hash hash
19
+ end
12
20
  end
13
21
 
14
22
  def part
15
23
  @part ||= hit[:code].match(/(?<=-)[\w-]+/)&.to_s
16
24
  end
25
+
26
+ def inspect
27
+ "<#{self.class}:#{format('%<id>#.14x', id: object_id << 1)} " \
28
+ "@text=\"#{@hit_collection&.text}\" " \
29
+ "@fetched=\"#{!@fetch.nil?}\" " \
30
+ "@fullIdentifier=\"#{@fetch&.shortref(nil, no_year: true)}\" " \
31
+ "@title=\"#{@hit[:code]}\">"
32
+ end
17
33
  end
18
34
  end