relaton-etsi 2.0.0 → 2.1.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3f3b20d51d31465037d74aff3c4a88db51e16020d894b5cd6ae994c094ab3fe
4
- data.tar.gz: 38271ff60d1ccef3ca1976cb1b887e795151a36ccb3973dac253190d7765e3e3
3
+ metadata.gz: 637634d27039848b4e93c7aadfe70cf2b220d2e222a2a9feba7b5a9760e933f1
4
+ data.tar.gz: 20dd06bbbff7b1af33ff03523ac418a91b2f276588d998061bdc2536a8f42075
5
5
  SHA512:
6
- metadata.gz: 81e1ce86f16cd81aebae309f16761877014db6784743b7813a413ef0af82240595ad7779f095142f0822b3e2b376254112fb419aeba22e78d77f557f0f4e3749
7
- data.tar.gz: 3cc6f64e2833c524f6ab12fb582b22498093fc870b087b104635a0be04a574b895c0f767cef0f67ac8a583fc3cf70f5f92e5b653974bc8cac0652b7894ad10ce
6
+ metadata.gz: 2fdae3a2a629012007d6d05a0245e3569e6e3a5eb2c45547ca89e018d348e68dd5bd3fa29c703b06a8e2ca30f4c296455676862c4e55c9d4395b706ba9023844
7
+ data.tar.gz: 818a000c7d5d7755859f45685eb33ab59611de7b50c2edc712c947f850d9ba448cf2433e4a93fc7017c79de055da4a312a00a1aa6c3c28db2693f8a31093596b
data/CLAUDE.md CHANGED
@@ -66,4 +66,5 @@ Uses Lutaml for serialization:
66
66
 
67
67
  ## Testing
68
68
 
69
+ - **Index fixture:** `spec/fixtures/index-v1.zip` is pre-loaded into `Relaton::Index` pool in `before(:suite)` (configured in `spec/support/webmock.rb`). Run `rake spec:update_index` to refresh from relaton-data-etsi.
69
70
  Uses RSpec with VCR for HTTP interaction recording. VCR cassettes are in `spec/vcr_cassettes/`. When tests make new HTTP requests, VCR will record them.
data/README.adoc CHANGED
@@ -141,6 +141,8 @@ Relaton::Etsi uses the relaton-logger gem for logging. By default, it logs to ST
141
141
 
142
142
  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.
143
143
 
144
+ To update the index test fixture (used by tests), run `rake spec:update_index`. This downloads the latest `index-v1.zip` from the https://github.com/relaton/relaton-data-etsi[relaton-data-etsi] repository.
145
+
144
146
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
145
147
 
146
148
  == Contributing
data/Rakefile CHANGED
@@ -10,3 +10,25 @@ require "rubocop/rake_task"
10
10
  RuboCop::RakeTask.new
11
11
 
12
12
  task default: %i[spec]
13
+
14
+ namespace :spec do
15
+ desc "Download latest ETSI index fixture from relaton-data-etsi"
16
+ task :update_index do
17
+ require "net/http"
18
+ require "uri"
19
+
20
+ url = "https://raw.githubusercontent.com/relaton/relaton-data-etsi/data-v2/index-v1.zip"
21
+ dest = File.join(__dir__, "spec", "fixtures", "index-v1.zip")
22
+
23
+ puts "Downloading \#{url} ..."
24
+ uri = URI.parse(url)
25
+ response = Net::HTTP.get_response(uri)
26
+
27
+ if response.is_a?(Net::HTTPSuccess)
28
+ File.binwrite(dest, response.body)
29
+ puts "Updated \#{dest} (\#{response.body.bytesize} bytes)"
30
+ else
31
+ abort "Failed to download: HTTP \#{response.code}"
32
+ end
33
+ end
34
+ end
data/grammars/biblio.rng CHANGED
@@ -2015,15 +2015,11 @@ provided that it is not the entire bibliographic item that is so related</a:docu
2015
2015
  <a:documentation>A version of the bibliographic item (within an edition). Can be used for drafts</a:documentation>
2016
2016
  <element name="version">
2017
2017
  <optional>
2018
- <ref name="revision-date">
2019
- <a:documentation>The date at which the current version of the bibliographic item was produced</a:documentation>
2020
- </ref>
2021
- </optional>
2022
- <optional>
2023
- <ref name="draft">
2024
- <a:documentation>The identifier for the current draft of the bibliographic item</a:documentation>
2025
- </ref>
2018
+ <attribute name="type">
2019
+ <a:documentation>Versioning scheme, in case of multiple versioning schemes</a:documentation>
2020
+ </attribute>
2026
2021
  </optional>
2022
+ <text/>
2027
2023
  </element>
2028
2024
  </define>
2029
2025
  <define name="vedition">
@@ -3,6 +3,7 @@ require_relative "item"
3
3
  module Relaton
4
4
  module Etsi
5
5
  class Bibdata < Item
6
+ model ItemData
6
7
  include Bib::BibdataShared
7
8
  end
8
9
  end
@@ -3,6 +3,7 @@ require_relative "item"
3
3
  module Relaton
4
4
  module Etsi
5
5
  class Bibitem < Item
6
+ model ItemData
6
7
  include Bib::BibitemShared
7
8
  end
8
9
  end
@@ -1,6 +1,6 @@
1
1
  require "date"
2
+ require "json"
2
3
  require "mechanize"
3
- require "csv"
4
4
  require "relaton/core"
5
5
  require "relaton/index"
6
6
  require_relative "../etsi"
@@ -9,10 +9,12 @@ require_relative "data_parser"
9
9
  module Relaton
10
10
  module Etsi
11
11
  class DataFetcher < Core::DataFetcher
12
- SOURCEURL = "https://www.etsi.org/?option=com_standardssearch&view=data&format=csv&includeScope=1&" \
13
- "page=1&search=&title=1&etsiNumber=1&content=1&version=0&onApproval=1&published=1&withdrawn=1&" \
14
- "historical=1&isCurrent=1&superseded=1&startDate=1988-01-15&endDate=%<date>s&harmonized=0&" \
15
- "keyword=&TB=&stdType=&frequency=&mandate=&collection=&sort=1&x=%<timestamp>s".freeze
12
+ PAGE_SIZE = 50
13
+
14
+ SOURCEURL = "https://www.etsi.org/custom/standardssearch/data.php?format=json&includeScope=1&" \
15
+ "page=%<page>s&search=&title=1&etsiNumber=1&content=1&version=0&onApproval=1&published=1&" \
16
+ "withdrawn=1&historical=1&isCurrent=1&superseded=1&startDate=1988-01-15&endDate=%<date>s&" \
17
+ "harmonized=0&keyword=&TB=&stdType=&frequency=&mandate=&collection=&sort=1&x=%<timestamp>s".freeze
16
18
 
17
19
  def index
18
20
  @index ||= Relaton::Index.find_or_create :etsi, file: INDEX_FILE
@@ -28,18 +30,60 @@ module Relaton
28
30
  # @param [Object] _source unused, required by superclass interface
29
31
  #
30
32
  def fetch(_source = nil)
31
- time = Time.now
32
- date = time.to_date + 1
33
- timestamp = (time.to_f * 1000).to_i
34
- url = format(SOURCEURL, date: date, timestamp: timestamp)
35
- csv = fetch_with_retry(url)
36
- CSV.parse(csv, headers: true, col_sep: ";", skip_lines: /sep=;/).each do |row|
37
- save DataParser.new(row, @errors).parse
38
- end
33
+ first_page = fetch_page(1)
34
+ process_records(first_page)
35
+ fetch_remaining_pages(first_page)
39
36
  index.save
40
37
  report_errors
41
38
  end
42
39
 
40
+ def fetch_remaining_pages(first_page)
41
+ total = first_page.first ? first_page.first["total_count"].to_i : 0
42
+ total_pages = (total / PAGE_SIZE.to_f).ceil
43
+ (2..total_pages).each do |page|
44
+ records = fetch_page(page)
45
+ break if records.empty?
46
+
47
+ process_records(records)
48
+ end
49
+ end
50
+
51
+ def fetch_page(page)
52
+ date = Time.now.to_date + 1
53
+ timestamp = (Time.now.to_f * 1000).to_i
54
+ url = format(SOURCEURL, page: page, date: date, timestamp: timestamp)
55
+ JSON.parse(fetch_with_retry(url))
56
+ end
57
+
58
+ def process_records(records)
59
+ records.each do |record|
60
+ save DataParser.new(normalize(record), @errors).parse
61
+ end
62
+ end
63
+
64
+ def normalize(record)
65
+ {
66
+ "ETSI deliverable" => record["ETSI_DELIVERABLE"],
67
+ "title" => record["TITLE"],
68
+ "Details link" => "https://webapp.etsi.org/workprogram/Report_WorkItem.asp?WKI_ID=#{record['wki_id']}",
69
+ "PDF link" => "https://www.etsi.org/deliver/#{record['EDSpathname']}#{record['EDSPDFfilename']}",
70
+ "Status" => derive_status(record),
71
+ "Keywords" => record["Keywords"].to_s,
72
+ "Technical body" => record["TB"],
73
+ "Scope" => record["Scope"],
74
+ }
75
+ end
76
+
77
+ def derive_status(record)
78
+ return "Withdrawn" if record["ACTION_TYPE"] == "WD"
79
+
80
+ code = record["STATUS_CODE"].to_i
81
+ return "On Approval" if code < 12
82
+ return "Historical" if code == 13
83
+
84
+ "Published"
85
+ end
86
+
43
87
  NETWORK_ERRORS = [
44
88
  Mechanize::Error, Net::OpenTimeout, Net::ReadTimeout,
45
89
  SocketError, Errno::ECONNRESET
@@ -13,10 +13,8 @@ module Relaton
13
13
  end
14
14
 
15
15
  def parse
16
- args = ATTRS.each_with_object({}) do |attr, hash|
17
- hash[attr] = send(attr)
18
- end
19
- ItemData.new(**args)
16
+ args = ATTRS.to_h { |attr| [attr, send(attr)] }
17
+ ItemData.new(type: "standard", **args)
20
18
  end
21
19
 
22
20
  def pubid
@@ -3,7 +3,6 @@ require_relative "doctype"
3
3
  module Relaton
4
4
  module Etsi
5
5
  class Ext < Bib::Ext
6
- attribute :schema_version, method: :get_schema_version
7
6
  attribute :doctype, Doctype
8
7
  attribute :marker, :string, values: %w[Current Superseded]
9
8
  attribute :frequency, :string, collection: true
@@ -19,9 +18,14 @@ module Relaton
19
18
  map_element "custom-collection", to: :custom_collection
20
19
  end
21
20
 
22
- def get_schema_version
23
- Relaton.schema_versions["relaton-model-etsi"]
21
+ key_value do
22
+ map_element "marker", to: :marker
23
+ map_element "frequency", to: :frequency
24
+ map_element "mandate", to: :mandate
25
+ map_element "custom_collection", to: :custom_collection
24
26
  end
27
+
28
+ def get_schema_version = Relaton.schema_versions["relaton-model-etsi"]
25
29
  end
26
30
  end
27
31
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Relaton
4
4
  module Etsi
5
- VERSION = "2.0.0"
5
+ VERSION = "2.1.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,28 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relaton-etsi
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-05-04 00:00:00.000000000 Z
11
12
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: csv
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '3.0'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '3.0'
26
13
  - !ruby/object:Gem::Dependency
27
14
  name: mechanize
28
15
  requirement: !ruby/object:Gem::Requirement
@@ -43,14 +30,14 @@ dependencies:
43
30
  requirements:
44
31
  - - "~>"
45
32
  - !ruby/object:Gem::Version
46
- version: 2.0.0
33
+ version: 2.1.0
47
34
  type: :runtime
48
35
  prerelease: false
49
36
  version_requirements: !ruby/object:Gem::Requirement
50
37
  requirements:
51
38
  - - "~>"
52
39
  - !ruby/object:Gem::Version
53
- version: 2.0.0
40
+ version: 2.1.0
54
41
  - !ruby/object:Gem::Dependency
55
42
  name: relaton-core
56
43
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +106,7 @@ licenses:
119
106
  - BSD-2-Clause
120
107
  metadata:
121
108
  homepage_uri: https://github.com/relaton/relaton-etsi
109
+ post_install_message:
122
110
  rdoc_options: []
123
111
  require_paths:
124
112
  - lib
@@ -133,7 +121,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
121
  - !ruby/object:Gem::Version
134
122
  version: '0'
135
123
  requirements: []
136
- rubygems_version: 3.6.9
124
+ rubygems_version: 3.5.22
125
+ signing_key:
137
126
  specification_version: 4
138
127
  summary: 'Relaton::Etsi: retrieve ETSI Standards for bibliographic using the BibliographicItem
139
128
  model'