relaton-itu 2.1.2 → 2.2.0.pre.alpha.1
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/CLAUDE.md +0 -22
- data/Gemfile +8 -0
- data/lib/relaton/itu/hit_collection.rb +79 -89
- data/lib/relaton/itu/radio_regulations_parser.rb +1 -2
- data/lib/relaton/itu/scraper.rb +0 -14
- data/lib/relaton/itu/version.rb +1 -1
- data/relaton-itu.gemspec +4 -4
- metadata +9 -10
- data/.rubocop.yml +0 -12
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1c4821cc8b6a9ce8a01c25c40b1f45d719d86fd0d0c0573fe4043a12b17ff9cb
|
|
4
|
+
data.tar.gz: 5eecc3cf067f12aacda1765adb5dcaf442617c2d30acd79b18739b98697a37b2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b49648210b4649382889aa44a46dfb3b2ee28833bd35f82946e052e0dc7731404a5e03a8f6076735f55676b4dd6a248a6c73014dcae7655bf8e2d14ae62be7c0
|
|
7
|
+
data.tar.gz: 3dfc18dd9e59e79295f532c27a37c540b0f3a4c8515c6373b8b9823edf568fc5fb39707c24361aa399e9f940afd3701aaa59dacf027a607c527d4a4996510550
|
data/CLAUDE.md
CHANGED
|
@@ -45,28 +45,6 @@ All model classes use `Lutaml::Model::Serializable` for XML/YAML serialization:
|
|
|
45
45
|
- **`DataParserR`** — module that parses ITU-R JSON search API results into `ItemData` instances (sets `flavor: "itu"` on all parsed documents)
|
|
46
46
|
- Sources: recommendations (JSON index), questions, reports, handbooks, resolutions (HTML indices)
|
|
47
47
|
|
|
48
|
-
### Runtime lookup (`HitCollection#search`)
|
|
49
|
-
|
|
50
|
-
`Bibliography.get`/`search` routes by reference in `HitCollection#search`:
|
|
51
|
-
|
|
52
|
-
- **ITU-T Recommendations** (`request_recommendation`) — discovery is a two-stage HTTP flow against
|
|
53
|
-
`www.itu.int`. The `RunSearch` Deep Search endpoint was removed/WAF-blocked (issue #88), so
|
|
54
|
-
discovery now GETs the public `ITU-T/recommendations/rec.aspx?rec={code}` page, extracts the
|
|
55
|
-
record handle (`11.1002/1000/{idrec}`), and calls the `mws/api/recommendations/getRecEditions`
|
|
56
|
-
API to build one `Hit` per edition (each `hit[:url]` is a `handle.itu.int/.../{idrec}-en` URL so
|
|
57
|
-
`Scraper#idrec` re-parses it). Year/edition filtering stays in `Bibliography#search_filter` /
|
|
58
|
-
`#isobib_results_filter`. Full metadata is fetched by `RecommendationParser` (the `mws/api/*`
|
|
59
|
-
endpoints), unchanged.
|
|
60
|
-
- **ITU-R RR & Operational Bulletins** (`request_publication`) — resolved to their predictable
|
|
61
|
-
`/pub/{pubid}` landing page (`R-REG-RR-{year}`, `T-SP-OB.{num}-{year}`) and scraped by
|
|
62
|
-
`RadioRegulationsParser`. A redirect to `notfound.aspx` (or a 404) yields no hit.
|
|
63
|
-
- **ITU-R (other)** (`request_document`) — reads the pre-built `relaton-data-itu-r` GitHub dataset
|
|
64
|
-
via `Relaton::Index`; does not hit `www.itu.int`.
|
|
65
|
-
|
|
66
|
-
Note: `DataFetcher` (the offline ITU-R harvester) still POSTs to the removed `RunSearch` endpoint,
|
|
67
|
-
so a dataset *refresh* is currently broken — a follow-up should migrate it (and, longer term, ITU-T)
|
|
68
|
-
to a relaton-data dataset.
|
|
69
|
-
|
|
70
48
|
### Processor
|
|
71
49
|
|
|
72
50
|
`Relaton::Itu::Processor` extends `Relaton::Core::Processor` and is the entry point for the Relaton plugin system. Provides `get`, `fetch_data`, `from_xml`, `hash_to_bib`, `grammar_hash`, and `remove_index_file`.
|
data/Gemfile
CHANGED
|
@@ -5,6 +5,14 @@ source "https://rubygems.org"
|
|
|
5
5
|
# Specify your gem's dependencies in relaton_itu.gemspec
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
|
+
# Use local monorepo sibling gems where available.
|
|
9
|
+
Dir["../*/"].each do |dir|
|
|
10
|
+
name = File.basename(dir)
|
|
11
|
+
next if name == File.basename(__dir__)
|
|
12
|
+
next unless File.exist?(File.join(dir, "#{name}.gemspec"))
|
|
13
|
+
gem name, path: dir
|
|
14
|
+
end
|
|
15
|
+
|
|
8
16
|
|
|
9
17
|
gem "equivalent-xml", "~> 0.6"
|
|
10
18
|
gem "pry-byebug"
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "cgi"
|
|
4
|
-
require "json"
|
|
5
3
|
require_relative "hit"
|
|
6
4
|
|
|
7
5
|
module Relaton
|
|
@@ -10,16 +8,11 @@ module Relaton
|
|
|
10
8
|
class HitCollection < Relaton::Core::HitCollection
|
|
11
9
|
DOMAIN = "https://www.itu.int"
|
|
12
10
|
GH_ITU_R = "https://raw.githubusercontent.com/relaton/relaton-data-itu-r/refs/heads/v2/"
|
|
13
|
-
REC_URL = "#{DOMAIN}/ITU-T/recommendations/rec.aspx?rec=%<rec>s&lang=en".freeze
|
|
14
|
-
RECEDITIONS_URL = "#{DOMAIN}/mws/api/recommendations/getRecEditions?idrec=%<idrec>s&lang=en".freeze
|
|
15
|
-
HANDLE_URL = "http://handle.itu.int/11.1002/1000/%<idrec>s-en".freeze
|
|
16
11
|
|
|
17
12
|
def search
|
|
18
13
|
case ref.to_ref
|
|
19
|
-
when
|
|
20
|
-
|
|
21
|
-
when /^ITU-T/
|
|
22
|
-
request_recommendation
|
|
14
|
+
when /^(ITU-T|ITU-R\sRR)/
|
|
15
|
+
request_search
|
|
23
16
|
when /^ITU-R\s/
|
|
24
17
|
request_document
|
|
25
18
|
end
|
|
@@ -34,87 +27,12 @@ module Relaton
|
|
|
34
27
|
|
|
35
28
|
private
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
# page (which exposes the record's handle/idrec) and the getRecEditions API.
|
|
39
|
-
# One hit is built per edition, mirroring the multi-result shape the old
|
|
40
|
-
# RunSearch endpoint used to return, so year filtering keeps working.
|
|
41
|
-
def request_recommendation
|
|
30
|
+
def request_search
|
|
42
31
|
Util.info "Fetching from www.itu.int ...", key: ref.to_s
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
@array =
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# @return [String, nil] the record's idrec, or nil when the code is unknown
|
|
50
|
-
def fetch_idrec
|
|
51
|
-
url = format(REC_URL, rec: CGI.escape(rec_query))
|
|
52
|
-
agent.get(url).body[%r{11\.1002/1000/(\d+)}, 1]
|
|
53
|
-
rescue Mechanize::ResponseCodeError => e
|
|
54
|
-
raise unless e.response_code == "404" # unknown code => treat as not found
|
|
55
|
-
|
|
56
|
-
nil
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
# @return [String] the `rec=` value for the rec.aspx lookup
|
|
60
|
-
def rec_query
|
|
61
|
-
ref.suppl ? "#{ref.code} Suppl. #{ref.suppl}" : ref.code
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# @param idrec [String]
|
|
65
|
-
# @return [Array<Hash>] editions of the recommendation
|
|
66
|
-
def editions(idrec)
|
|
67
|
-
JSON.parse agent.get(format(RECEDITIONS_URL, idrec: idrec)).body
|
|
68
|
-
rescue JSON::ParserError
|
|
69
|
-
[]
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# @param edition [Hash] a getRecEditions entry
|
|
73
|
-
# @return [Relaton::Itu::Hit]
|
|
74
|
-
def recommendation_hit(edition)
|
|
75
|
-
Hit.new({
|
|
76
|
-
code: "ITU-T #{edition['rec_name']}",
|
|
77
|
-
title: edition["title"],
|
|
78
|
-
url: format(HANDLE_URL, idrec: edition["idrec"]),
|
|
79
|
-
type: "recommendation",
|
|
80
|
-
}, self)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# Resolve an ITU-R Radio Regulation or Operational Bulletin to its stable
|
|
84
|
-
# /pub landing page, whose id is derivable from the reference.
|
|
85
|
-
def request_publication
|
|
86
|
-
Util.info "Fetching from www.itu.int ...", key: ref.to_s
|
|
87
|
-
return @array = [] unless ref.year
|
|
88
|
-
|
|
89
|
-
url = "#{DOMAIN}/pub/#{publication_id}"
|
|
90
|
-
page = fetch_publication_page url
|
|
91
|
-
return @array = [] if page.nil? || page.uri.to_s.match?(/notfound/i)
|
|
92
|
-
|
|
93
|
-
hit = Hit.new({ code: publication_code, title: nil, url: url, type: "publication" }, self)
|
|
94
|
-
@array = [hit]
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# @return [Mechanize::Page, nil] nil when the publication does not exist
|
|
98
|
-
def fetch_publication_page(url)
|
|
99
|
-
agent.get url
|
|
100
|
-
rescue Mechanize::ResponseCodeError => e
|
|
101
|
-
raise unless e.response_code == "404" # unknown publication => not found
|
|
102
|
-
|
|
103
|
-
nil
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# @return [String] the /pub identifier for RR or OB
|
|
107
|
-
def publication_id
|
|
108
|
-
if ref.code == "RR"
|
|
109
|
-
"R-REG-RR-#{ref.year}"
|
|
110
|
-
else # Operational Bulletin, e.g. OB.1096
|
|
111
|
-
"T-SP-OB.#{ref.code[/\d+/]}-#{ref.year}"
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# @return [String] the docidentifier-friendly code (year only, no month)
|
|
116
|
-
def publication_code
|
|
117
|
-
"#{ref.prefix}-#{ref.sector} #{ref.code} (#{ref.year})"
|
|
32
|
+
url = "#{DOMAIN}/net4/ITU-T/search/GlobalSearch/RunSearch"
|
|
33
|
+
data = { json: params.to_json }
|
|
34
|
+
resp = agent.post url, data
|
|
35
|
+
@array = hits JSON.parse(resp.body)
|
|
118
36
|
end
|
|
119
37
|
|
|
120
38
|
def request_document # rubocop:todo Metrics/MethodLength, Metrics/AbcSize
|
|
@@ -132,6 +50,78 @@ module Relaton
|
|
|
132
50
|
hit.item = item
|
|
133
51
|
@array = [hit]
|
|
134
52
|
end
|
|
53
|
+
|
|
54
|
+
# @return [String]
|
|
55
|
+
def group
|
|
56
|
+
@group ||= case ref.to_ref
|
|
57
|
+
when %r{OB|Operational Bulletin}, %r{^ITU-R\sRR}
|
|
58
|
+
"Publications"
|
|
59
|
+
when %r{^ITU-T} then "Recommendations"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @return [Hash]
|
|
64
|
+
def params # rubocop:disable Metrics/MethodLength
|
|
65
|
+
input = ref.dup
|
|
66
|
+
input.year = nil
|
|
67
|
+
{
|
|
68
|
+
"Input" => input.to_s,
|
|
69
|
+
"Start" => 0,
|
|
70
|
+
"Rows" => 20,
|
|
71
|
+
"SortBy" => "RELEVANCE",
|
|
72
|
+
"ExactPhrase" => false,
|
|
73
|
+
"CollectionName" => "General",
|
|
74
|
+
"CollectionGroup" => group,
|
|
75
|
+
"Sector" => ref.to_ref.match(/(?<=^ITU-)\w/).to_s.downcase,
|
|
76
|
+
"Criterias" => [{
|
|
77
|
+
"Name" => "Search in",
|
|
78
|
+
"Criterias" => [
|
|
79
|
+
{
|
|
80
|
+
"Selected" => false,
|
|
81
|
+
"Value" => "",
|
|
82
|
+
"Label" => "Name",
|
|
83
|
+
"Target" => "/name_s",
|
|
84
|
+
"TypeName" => "CHECKBOX",
|
|
85
|
+
"GetCriteriaType" => 0,
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"Selected" => false,
|
|
89
|
+
"Value" => "",
|
|
90
|
+
"Label" => "Short description",
|
|
91
|
+
"Target" => "/short_description_s",
|
|
92
|
+
"TypeName" => "CHECKBOX",
|
|
93
|
+
"GetCriteriaType" => 0,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"Selected" => false,
|
|
97
|
+
"Value" => "",
|
|
98
|
+
"Label" => "File content",
|
|
99
|
+
"Target" => "/file",
|
|
100
|
+
"TypeName" => "CHECKBOX",
|
|
101
|
+
"GetCriteriaType" => 0,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
"ShowCheckbox" => true,
|
|
105
|
+
"Selected" => false,
|
|
106
|
+
}],
|
|
107
|
+
"Topics" => "",
|
|
108
|
+
"ClientData" => {},
|
|
109
|
+
"Language" => "en",
|
|
110
|
+
"SearchType" => "All",
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# @param data [Hash]
|
|
115
|
+
# @return [Array<Relaton::Itu::Hit>]
|
|
116
|
+
def hits(data)
|
|
117
|
+
data["results"].map do |h|
|
|
118
|
+
code = h["Media"]["Name"]
|
|
119
|
+
title = h["Title"]
|
|
120
|
+
url = "#{DOMAIN}#{h['Redirection']}"
|
|
121
|
+
type = h["Collection"]["Group"].downcase[0...-1]
|
|
122
|
+
Hit.new({ code: code, title: title, url: url, type: type }, self)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
135
125
|
end
|
|
136
126
|
end
|
|
137
127
|
end
|
data/lib/relaton/itu/scraper.rb
CHANGED
|
@@ -91,24 +91,10 @@ module Relaton
|
|
|
91
91
|
@docid ||= begin
|
|
92
92
|
docids = hit.hit[:code].to_s.split(" | ").map { |c| createdocid(c) }
|
|
93
93
|
docids << createdocid(doc["rec_name"]) if docids.empty?
|
|
94
|
-
iso = iso_docid
|
|
95
|
-
docids << iso if iso
|
|
96
94
|
docids
|
|
97
95
|
end
|
|
98
96
|
end
|
|
99
97
|
|
|
100
|
-
# The equivalent ISO/IEC identifier used to come from the search result's
|
|
101
|
-
# media name; it is now re-sourced from the recommendation header's
|
|
102
|
-
# `iso_number` field (e.g. "Equivalent standard: ISO/IEC 17788:2014 (Common)").
|
|
103
|
-
# @return [Relaton::Bib::Docidentifier, nil]
|
|
104
|
-
def iso_docid
|
|
105
|
-
return unless idrec # only recommendations carry an idrec / iso_number
|
|
106
|
-
|
|
107
|
-
num = parser.doc && parser.doc["iso_number"]
|
|
108
|
-
id = num && num[%r{ISO(?:/IEC)?(?:/IEEE)?\s+\d[\d-]*}]
|
|
109
|
-
createdocid(id) if id
|
|
110
|
-
end
|
|
111
|
-
|
|
112
98
|
# @param text [String]
|
|
113
99
|
# @return [Relaton::Bib::Docidentifier]
|
|
114
100
|
def createdocid(text) # rubocop:disable Metrics/MethodLength
|
data/lib/relaton/itu/version.rb
CHANGED
data/relaton-itu.gemspec
CHANGED
|
@@ -23,11 +23,11 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
spec.bindir = "exe"
|
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
25
25
|
spec.require_paths = ["lib"]
|
|
26
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 3.
|
|
26
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.3.0")
|
|
27
27
|
|
|
28
28
|
spec.add_dependency "mechanize", "~> 2.10"
|
|
29
29
|
spec.add_dependency "parslet", "~> 2.0.0"
|
|
30
|
-
spec.add_dependency "relaton-bib", "~> 2.
|
|
31
|
-
spec.add_dependency "relaton-core", "~>
|
|
32
|
-
spec.add_dependency "relaton-index", "~>
|
|
30
|
+
spec.add_dependency "relaton-bib", "~> 2.2.0.pre.alpha.1"
|
|
31
|
+
spec.add_dependency "relaton-core", "~> 2.2.0.pre.alpha.1"
|
|
32
|
+
spec.add_dependency "relaton-index", "~> 2.2.0.pre.alpha.1"
|
|
33
33
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: relaton-itu
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1
|
|
4
|
+
version: 2.2.0.pre.alpha.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: mechanize
|
|
@@ -44,42 +44,42 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 2.
|
|
47
|
+
version: 2.2.0.pre.alpha.1
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 2.
|
|
54
|
+
version: 2.2.0.pre.alpha.1
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: relaton-core
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
61
|
+
version: 2.2.0.pre.alpha.1
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
68
|
+
version: 2.2.0.pre.alpha.1
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: relaton-index
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
75
|
+
version: 2.2.0.pre.alpha.1
|
|
76
76
|
type: :runtime
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
82
|
+
version: 2.2.0.pre.alpha.1
|
|
83
83
|
description: 'Relaton::Itu: retrieve ITU Standards for bibliographic use using the
|
|
84
84
|
BibliographicItem model'
|
|
85
85
|
email:
|
|
@@ -92,7 +92,6 @@ files:
|
|
|
92
92
|
- ".github/workflows/release.yml"
|
|
93
93
|
- ".gitignore"
|
|
94
94
|
- ".rspec"
|
|
95
|
-
- ".rubocop.yml"
|
|
96
95
|
- CLAUDE.md
|
|
97
96
|
- Gemfile
|
|
98
97
|
- LICENSE.txt
|
|
@@ -141,7 +140,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
141
140
|
requirements:
|
|
142
141
|
- - ">="
|
|
143
142
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: 3.
|
|
143
|
+
version: 3.3.0
|
|
145
144
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
145
|
requirements:
|
|
147
146
|
- - ">="
|
data/.rubocop.yml
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# This project follows the Ribose OSS style guide.
|
|
2
|
-
# https://github.com/riboseinc/oss-guides
|
|
3
|
-
# All project-specific additions and overrides should be specified in this file.
|
|
4
|
-
|
|
5
|
-
require: rubocop-rails
|
|
6
|
-
|
|
7
|
-
inherit_from:
|
|
8
|
-
- https://raw.githubusercontent.com/riboseinc/oss-guides/master/ci/rubocop.yml
|
|
9
|
-
AllCops:
|
|
10
|
-
TargetRubyVersion: 3.2
|
|
11
|
-
Rails:
|
|
12
|
-
Enabled: false
|