relaton-iana 1.9.2

Sign up to get free protection for your applications and to get access to all the features.
data/grammars/reqt.rng ADDED
@@ -0,0 +1,194 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <grammar xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
3
+ <!--
4
+ Presupposes isodoc.rnc, is included in it
5
+ include "isodoc.rnc" { }
6
+ -->
7
+ <define name="requirement">
8
+ <element name="requirement">
9
+ <ref name="RequirementType"/>
10
+ </element>
11
+ </define>
12
+ <define name="recommendation">
13
+ <element name="recommendation">
14
+ <ref name="RequirementType"/>
15
+ </element>
16
+ </define>
17
+ <define name="permission">
18
+ <element name="permission">
19
+ <ref name="RequirementType"/>
20
+ </element>
21
+ </define>
22
+ <define name="RequirementType">
23
+ <optional>
24
+ <attribute name="obligation">
25
+ <ref name="ObligationType"/>
26
+ </attribute>
27
+ </optional>
28
+ <optional>
29
+ <attribute name="unnumbered">
30
+ <data type="boolean"/>
31
+ </attribute>
32
+ </optional>
33
+ <optional>
34
+ <attribute name="number"/>
35
+ </optional>
36
+ <optional>
37
+ <attribute name="subsequence"/>
38
+ </optional>
39
+ <optional>
40
+ <attribute name="keep-with-next">
41
+ <data type="boolean"/>
42
+ </attribute>
43
+ </optional>
44
+ <optional>
45
+ <attribute name="keep-lines-together">
46
+ <data type="boolean"/>
47
+ </attribute>
48
+ </optional>
49
+ <attribute name="id">
50
+ <data type="ID"/>
51
+ </attribute>
52
+ <optional>
53
+ <attribute name="filename"/>
54
+ </optional>
55
+ <optional>
56
+ <attribute name="model"/>
57
+ </optional>
58
+ <optional>
59
+ <attribute name="type"/>
60
+ </optional>
61
+ <optional>
62
+ <ref name="reqtitle"/>
63
+ </optional>
64
+ <optional>
65
+ <ref name="label"/>
66
+ </optional>
67
+ <optional>
68
+ <ref name="subject"/>
69
+ </optional>
70
+ <zeroOrMore>
71
+ <ref name="reqinherit"/>
72
+ </zeroOrMore>
73
+ <zeroOrMore>
74
+ <ref name="classification"/>
75
+ </zeroOrMore>
76
+ <zeroOrMore>
77
+ <choice>
78
+ <ref name="measurementtarget"/>
79
+ <ref name="specification"/>
80
+ <ref name="verification"/>
81
+ <ref name="import"/>
82
+ <ref name="description"/>
83
+ </choice>
84
+ </zeroOrMore>
85
+ <optional>
86
+ <ref name="reqt_references"/>
87
+ </optional>
88
+ <zeroOrMore>
89
+ <choice>
90
+ <ref name="requirement"/>
91
+ <ref name="recommendation"/>
92
+ <ref name="permission"/>
93
+ </choice>
94
+ </zeroOrMore>
95
+ </define>
96
+ <define name="reqtitle">
97
+ <element name="title">
98
+ <ref name="FormattedString"/>
99
+ </element>
100
+ </define>
101
+ <define name="label">
102
+ <element name="label">
103
+ <text/>
104
+ </element>
105
+ </define>
106
+ <define name="subject">
107
+ <element name="subject">
108
+ <text/>
109
+ </element>
110
+ </define>
111
+ <define name="reqinherit">
112
+ <element name="inherit">
113
+ <text/>
114
+ </element>
115
+ </define>
116
+ <define name="measurementtarget">
117
+ <element name="measurement-target">
118
+ <ref name="RequirementSubpart"/>
119
+ </element>
120
+ </define>
121
+ <define name="specification">
122
+ <element name="specification">
123
+ <ref name="RequirementSubpart"/>
124
+ </element>
125
+ </define>
126
+ <define name="verification">
127
+ <element name="verification">
128
+ <ref name="RequirementSubpart"/>
129
+ </element>
130
+ </define>
131
+ <define name="import">
132
+ <element name="import">
133
+ <ref name="RequirementSubpart"/>
134
+ </element>
135
+ </define>
136
+ <define name="description">
137
+ <element name="description">
138
+ <ref name="RequirementSubpart"/>
139
+ </element>
140
+ </define>
141
+ <define name="reqt_references">
142
+ <element name="references">
143
+ <oneOrMore>
144
+ <ref name="bibitem"/>
145
+ </oneOrMore>
146
+ </element>
147
+ </define>
148
+ <define name="RequirementSubpart">
149
+ <optional>
150
+ <attribute name="type"/>
151
+ </optional>
152
+ <optional>
153
+ <attribute name="exclude">
154
+ <data type="boolean"/>
155
+ </attribute>
156
+ </optional>
157
+ <optional>
158
+ <attribute name="keep-with-next">
159
+ <data type="boolean"/>
160
+ </attribute>
161
+ </optional>
162
+ <optional>
163
+ <attribute name="keep-lines-together">
164
+ <data type="boolean"/>
165
+ </attribute>
166
+ </optional>
167
+ <oneOrMore>
168
+ <ref name="BasicBlock"/>
169
+ </oneOrMore>
170
+ </define>
171
+ <define name="ObligationType">
172
+ <choice>
173
+ <value>requirement</value>
174
+ <value>recommendation</value>
175
+ <value>permission</value>
176
+ </choice>
177
+ </define>
178
+ <define name="classification">
179
+ <element name="classification">
180
+ <ref name="classification_tag"/>
181
+ <ref name="classification_value"/>
182
+ </element>
183
+ </define>
184
+ <define name="classification_tag">
185
+ <element name="tag">
186
+ <text/>
187
+ </element>
188
+ </define>
189
+ <define name="classification_value">
190
+ <element name="value">
191
+ <text/>
192
+ </element>
193
+ </define>
194
+ </grammar>
@@ -0,0 +1,115 @@
1
+ module RelatonIana
2
+ class DataFetcher
3
+ SOURCE = "https://raw.githubusercontent.com/ietf-ribose/iana-registries/main/"
4
+
5
+ #
6
+ # Data fetcher initializer
7
+ #
8
+ # @param [String] output directory to save files
9
+ # @param [String] format format of output files (xml, yaml, bibxml)
10
+ #
11
+ def initialize(output, format)
12
+ @output = output
13
+ @format = format
14
+ @ext = format.sub(/^bib/, "")
15
+ @files = []
16
+ end
17
+
18
+ #
19
+ # Initialize fetcher and run fetch
20
+ #
21
+ # @param [Strin] output directory to save files, default: "data"
22
+ # @param [Strin] format format of output files (xml, yaml, bibxml), default: yaml
23
+ #
24
+ def self.fetch(output: "data", format: "yaml")
25
+ t1 = Time.now
26
+ puts "Started at: #{t1}"
27
+ FileUtils.mkdir_p output unless Dir.exist? output
28
+ new(output, format).fetch
29
+ t2 = Time.now
30
+ puts "Stopped at: #{t2}"
31
+ puts "Done in: #{(t2 - t1).round} sec."
32
+ end
33
+
34
+ #
35
+ # Parse documents
36
+ #
37
+ def fetch(page = 1) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
38
+ params = {
39
+ q: "repo:ietf-ribose/iana-registries extension:xml",
40
+ page: page, per_page: 100
41
+ }
42
+ if ENV["GITHUB_TOKEN"]
43
+ headers = { "Authorization" => "token #{ENV['GITHUB_TOKEN']}" }
44
+ end
45
+ attempt = 0
46
+ json = {}
47
+ until attempt > 3 || json["items"]
48
+ if attempt.positive?
49
+ warn "Rate limit is reached. Retrying in 30 sec."
50
+ sleep 30
51
+ end
52
+ attempt += 1
53
+ resp = Faraday.get "https://api.github.com/search/code", params, headers
54
+ json = JSON.parse resp.body
55
+ end
56
+ raise StandardError, json["message"] if json["message"]
57
+
58
+ json["items"].each do |item|
59
+ fetch_doc URI.join(SOURCE, item["path"]).to_s
60
+ end
61
+ fetch(page + 1) if (json["total_count"] - (page * 100)).positive?
62
+ end
63
+
64
+ def fetch_doc(url) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
65
+ resp = Net::HTTP.get_response URI(url)
66
+ if resp.code == "200"
67
+ return unless resp.body.include? "<registry"
68
+
69
+ xml = Nokogiri::XML(resp.body)
70
+ registry = xml.at("/xmlns:registry")
71
+ doc = Parser.parse registry
72
+ save_doc doc
73
+ registry.xpath("./xmlns:registry").each do |r|
74
+ save_doc Parser.parse(r, doc)
75
+ end
76
+ end
77
+ rescue StandardError => e
78
+ warn "Error: #{e.message}. URL: #{url}"
79
+ end
80
+
81
+ #
82
+ # Save document to file
83
+ #
84
+ # @param [RelatonW3c::W3cBibliographicItem, nil] bib bibliographic item
85
+ #
86
+ def save_doc(bib) # rubocop:disable Metrics/MethodLength
87
+ return unless bib
88
+
89
+ c = case @format
90
+ when "xml" then bib.to_xml(bibdata: true)
91
+ when "yaml" then bib.to_hash.to_yaml
92
+ else bib.send("to_#{@format}")
93
+ end
94
+ file = file_name(bib)
95
+ if @files.include? file
96
+ warn "File #{file} already exists. Document: #{bib.docnumber}"
97
+ else
98
+ @files << file
99
+ end
100
+ File.write file, c, encoding: "UTF-8"
101
+ end
102
+
103
+ #
104
+ # Generate file name
105
+ #
106
+ # @param [RelatonW3c::W3cBibliographicItem] bib bibliographic item
107
+ #
108
+ # @return [String] file name
109
+ #
110
+ def file_name(bib)
111
+ name = bib.docnumber.gsub(/[\s,:\/]/, "_").squeeze("_")
112
+ File.join @output, "#{name}.#{@ext}"
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,5 @@
1
+ module RelatonIana
2
+ # IANA Bibliographic Item
3
+ class IanaBibliographicItem < RelatonBib::BibliographicItem
4
+ end
5
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RelatonIana
4
+ # Methods for search IANA standards.
5
+ module IanaBibliography
6
+ SOURCE = "https://raw.githubusercontent.com/relaton/relaton-data-iana/main/data/"
7
+
8
+ # @param text [String]
9
+ # @return [RelatonBib::BibliographicItem]
10
+ def search(text) # rubocop:disable Metrics/MethodLength
11
+ file = text.sub(/^IANA\s/, "").gsub(/[\s,:\/]/, "_")
12
+ url = "#{SOURCE}#{file}.yaml"
13
+ resp = Net::HTTP.get_response URI(url)
14
+ hash = YAML.safe_load resp.body
15
+ RelatonBib::BibliographicItem.from_hash hash
16
+ rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
17
+ EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
18
+ Net::ProtocolError, Errno::ETIMEDOUT => e
19
+ raise RelatonBib::RequestError, e.message
20
+ end
21
+
22
+ # @param ref [String] the W3C standard Code to look up
23
+ # @param year [String, NilClass] not used
24
+ # @param opts [Hash] options
25
+ # @return [RelatonBib::BibliographicItem]
26
+ def get(ref, _year = nil, _opts = {})
27
+ warn "[relaton-iana] (\"#{ref}\") fetching..."
28
+ result = search(ref)
29
+ return unless result
30
+
31
+ warn "[relaton-iana] (\"#{ref}\") found #{result.docidentifier[0].id}"
32
+ result
33
+ end
34
+
35
+ extend IanaBibliography
36
+ end
37
+ end
@@ -0,0 +1,119 @@
1
+ module RelatonIana
2
+ class Parser
3
+ #
4
+ # Document parser initalization
5
+ #
6
+ # @param [Nokogiri::XML::Element] xml
7
+ #
8
+ def initialize(xml, rootdoc)
9
+ @xml = xml
10
+ @rootdoc = rootdoc
11
+ end
12
+
13
+ #
14
+ # Initialize document parser and run it
15
+ #
16
+ # @param [Nokogiri::XML::Element] xml
17
+ #
18
+ # @return [RelatonBib:BibliographicItem, nil] bibliographic item
19
+ #
20
+ def self.parse(xml, rootdoc = nil)
21
+ new(xml, rootdoc).parse
22
+ end
23
+
24
+ #
25
+ # Parse document
26
+ #
27
+ # @return [RelatonBib:BibliographicItem, nil] bibliographic item
28
+ #
29
+ def parse # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
30
+ return unless @xml
31
+
32
+ RelatonBib::BibliographicItem.new(
33
+ type: "standard",
34
+ fetched: Date.today.to_s,
35
+ language: ["en"],
36
+ script: ["Latn"],
37
+ title: parse_title,
38
+ link: parse_link,
39
+ docid: parse_docid,
40
+ docnumber: docnumber,
41
+ date: parse_date,
42
+ contributor: contributor,
43
+ )
44
+ end
45
+
46
+ #
47
+ # Parse title
48
+ #
49
+ # @return [RelatonBib::TypedTitleStringCollection] title
50
+ #
51
+ def parse_title
52
+ content = @xml.at("./xmlns:title")&.text || @xml[:id]
53
+ t = RelatonBib::TypedTitleString.new content: content
54
+ RelatonBib::TypedTitleStringCollection.new [t]
55
+ end
56
+
57
+ #
58
+ # Parse link
59
+ #
60
+ # @return [Array<RelatonBib::TypedUri>] link
61
+ #
62
+ def parse_link
63
+ if @rootdoc then @rootdoc.link
64
+ else
65
+ uri = URI.join @xml.namespace.href.sub(/(?<=[^\/])$/, "/"), @xml[:id]
66
+ [RelatonBib::TypedUri.new(type: "src", content: uri.to_s)]
67
+ end
68
+ end
69
+
70
+ #
71
+ # Parse docidentifier
72
+ #
73
+ # @return [Arra<RelatonBib::DocumentIdentifier>] docidentifier
74
+ #
75
+ def parse_docid
76
+ [RelatonBib::DocumentIdentifier.new(type: "IANA", id: pub_id)]
77
+ end
78
+
79
+ #
80
+ # Generate PubID
81
+ #
82
+ # @return [String] PubID
83
+ #
84
+ def pub_id
85
+ "IANA #{docnumber}"
86
+ end
87
+
88
+ def docnumber
89
+ dn = ""
90
+ dn += "#{@rootdoc.docnumber}/" if @rootdoc
91
+ dn + @xml["id"]
92
+ end
93
+
94
+ #
95
+ # Parse date
96
+ #
97
+ # @return [Array<RelatonBib::BibliographicDate>] date
98
+ #
99
+ def parse_date
100
+ d = @xml.xpath("./xmlns:created|./xmlns:published|./xmlns:updated").map do |d|
101
+ RelatonBib::BibliographicDate.new(type: d.name, on: d.text)
102
+ end
103
+ d.none? && @rootdoc ? @rootdoc.date : d
104
+ end
105
+
106
+ #
107
+ # Create contributor
108
+ #
109
+ # @return [Array<RelatonBib::Contribution>] contributor
110
+ #
111
+ def contributor
112
+ org = RelatonBib::Organization.new(
113
+ name: "Internet Assigned Numbers Authority", abbreviation: "IANA",
114
+ )
115
+ role = { type: "publisher" }
116
+ [RelatonBib::ContributionInfo.new(entity: org, role: [role])]
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,54 @@
1
+ require "relaton/processor"
2
+
3
+ module RelatonIana
4
+ class Processor < Relaton::Processor
5
+ attr_reader :idtype
6
+
7
+ def initialize # rubocop:disable Lint/MissingSuper
8
+ @short = :relaton_iana
9
+ @prefix = "IANA"
10
+ @defaultprefix = %r{^IANA\s}
11
+ @idtype = "IANA"
12
+ @datasets = %w[iana-registries]
13
+ end
14
+
15
+ # @param code [String]
16
+ # @param date [String, NilClass] year
17
+ # @param opts [Hash]
18
+ # @return [RelatonBib::BibliographicItem]
19
+ def get(code, date, opts)
20
+ ::RelatonIana::IanaBibliography.get(code, date, opts)
21
+ end
22
+
23
+ #
24
+ # Fetch all the documents from https://github.com/ietf-ribose/iana-registries
25
+ #
26
+ # @param [String] _source source name
27
+ # @param [Hash] opts
28
+ # @option opts [String] :output directory to output documents
29
+ # @option opts [String] :format
30
+ #
31
+ def fetch_data(_source, opts)
32
+ DataFetcher.fetch(**opts)
33
+ end
34
+
35
+ # @param xml [String]
36
+ # @return [RelatonBib::BibliographicItem]
37
+ def from_xml(xml)
38
+ ::RelatonBib::XMLParser.from_xml xml
39
+ end
40
+
41
+ # @param hash [Hash]
42
+ # @return [RelatonIana::BibliographicItem]
43
+ def hash_to_bib(hash)
44
+ item_hash = ::RelatonBib::HashConverter.hash_to_bib(hash)
45
+ ::RelatonWBib::BibliographicItem.new(**item_hash)
46
+ end
47
+
48
+ # Returns hash of XML grammar
49
+ # @return [String]
50
+ def grammar_hash
51
+ @grammar_hash ||= ::RelatonIana.grammar_hash
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RelatonIana
4
+ VERSION = "1.9.2"
5
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require "relaton_bib"
5
+ require_relative "relaton_iana/version"
6
+ require_relative "relaton_iana/iana_bibliography"
7
+ require_relative "relaton_iana/parser"
8
+ require_relative "relaton_iana/data_fetcher"
9
+
10
+ module RelatonIana
11
+ class Error < StandardError; end
12
+
13
+ # Returns hash of XML reammar
14
+ # @return [String]
15
+ def self.grammar_hash
16
+ gem_path = File.expand_path "..", __dir__
17
+ grammars_path = File.join gem_path, "grammars", "*"
18
+ grammars = Dir[grammars_path].sort.map { |gp| File.read gp }.join
19
+ Digest::MD5.hexdigest grammars
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/relaton_iana/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "relaton-iana"
7
+ spec.version = RelatonIana::VERSION
8
+ spec.authors = ["Ribose Inc."]
9
+ spec.email = ["open.source@ribose.com"]
10
+
11
+ spec.summary = "RelatonIana: Ruby XMLDOC impementation."
12
+ spec.description = "RelatonIana: Ruby XMLDOC impementation."
13
+ spec.homepage = "https://github.com/relaton/relaton-iana"
14
+ spec.license = "BSD-2-Clause"
15
+ spec.required_ruby_version = ">= 2.5.0"
16
+
17
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'https://mygemserver.com'"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
21
+ # spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
27
+ end
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_development_dependency "equivalent-xml", "~> 0.6"
33
+ spec.add_development_dependency "rubocop"
34
+ spec.add_development_dependency "rubocop-performance"
35
+ spec.add_development_dependency "rubocop-rails"
36
+ spec.add_development_dependency "ruby-jing"
37
+ spec.add_development_dependency "simplecov"
38
+ spec.add_development_dependency "vcr"
39
+ spec.add_development_dependency "webmock"
40
+
41
+ spec.add_dependency "faraday", "~> 1.8.0"
42
+ spec.add_dependency "relaton-bib", "~> 1.9.0"
43
+
44
+ # Uncomment to register a new dependency of your gem
45
+ # spec.add_dependency "example-gem", "~> 1.0"
46
+
47
+ # For more information and examples about making a new gem, checkout our
48
+ # guide at: https://bundler.io/guides/creating_gem.html
49
+ end