relaton-3gpp 1.9.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.
data/grammars/reqt.rng ADDED
@@ -0,0 +1,205 @@
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
+ <zeroOrMore>
68
+ <ref name="subject"/>
69
+ </zeroOrMore>
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
+ <ref name="component"/>
84
+ </choice>
85
+ </zeroOrMore>
86
+ <optional>
87
+ <ref name="reqt_references"/>
88
+ </optional>
89
+ <zeroOrMore>
90
+ <choice>
91
+ <ref name="requirement"/>
92
+ <ref name="recommendation"/>
93
+ <ref name="permission"/>
94
+ </choice>
95
+ </zeroOrMore>
96
+ </define>
97
+ <define name="reqtitle">
98
+ <element name="title">
99
+ <ref name="FormattedString"/>
100
+ </element>
101
+ </define>
102
+ <define name="label">
103
+ <element name="label">
104
+ <text/>
105
+ </element>
106
+ </define>
107
+ <define name="subject">
108
+ <element name="subject">
109
+ <oneOrMore>
110
+ <ref name="TextElement"/>
111
+ </oneOrMore>
112
+ </element>
113
+ </define>
114
+ <define name="reqinherit">
115
+ <element name="inherit">
116
+ <oneOrMore>
117
+ <ref name="TextElement"/>
118
+ </oneOrMore>
119
+ </element>
120
+ </define>
121
+ <define name="measurementtarget">
122
+ <element name="measurement-target">
123
+ <ref name="RequirementSubpart"/>
124
+ </element>
125
+ </define>
126
+ <define name="specification">
127
+ <element name="specification">
128
+ <ref name="RequirementSubpart"/>
129
+ </element>
130
+ </define>
131
+ <define name="verification">
132
+ <element name="verification">
133
+ <ref name="RequirementSubpart"/>
134
+ </element>
135
+ </define>
136
+ <define name="import">
137
+ <element name="import">
138
+ <ref name="RequirementSubpart"/>
139
+ </element>
140
+ </define>
141
+ <define name="description">
142
+ <element name="description">
143
+ <ref name="RequirementSubpart"/>
144
+ </element>
145
+ </define>
146
+ <define name="component">
147
+ <element name="component">
148
+ <attribute name="class"/>
149
+ <ref name="RequirementSubpart"/>
150
+ </element>
151
+ </define>
152
+ <define name="reqt_references">
153
+ <element name="references">
154
+ <oneOrMore>
155
+ <ref name="bibitem"/>
156
+ </oneOrMore>
157
+ </element>
158
+ </define>
159
+ <define name="RequirementSubpart">
160
+ <optional>
161
+ <attribute name="type"/>
162
+ </optional>
163
+ <optional>
164
+ <attribute name="exclude">
165
+ <data type="boolean"/>
166
+ </attribute>
167
+ </optional>
168
+ <optional>
169
+ <attribute name="keep-with-next">
170
+ <data type="boolean"/>
171
+ </attribute>
172
+ </optional>
173
+ <optional>
174
+ <attribute name="keep-lines-together">
175
+ <data type="boolean"/>
176
+ </attribute>
177
+ </optional>
178
+ <oneOrMore>
179
+ <ref name="BasicBlock"/>
180
+ </oneOrMore>
181
+ </define>
182
+ <define name="ObligationType">
183
+ <choice>
184
+ <value>requirement</value>
185
+ <value>recommendation</value>
186
+ <value>permission</value>
187
+ </choice>
188
+ </define>
189
+ <define name="classification">
190
+ <element name="classification">
191
+ <ref name="classification_tag"/>
192
+ <ref name="classification_value"/>
193
+ </element>
194
+ </define>
195
+ <define name="classification_tag">
196
+ <element name="tag">
197
+ <text/>
198
+ </element>
199
+ </define>
200
+ <define name="classification_value">
201
+ <element name="value">
202
+ <text/>
203
+ </element>
204
+ </define>
205
+ </grammar>
@@ -0,0 +1,74 @@
1
+ module Relaton3gpp
2
+ class BibliographicItem < RelatonBib::BibliographicItem
3
+ DOCTYPES = %w[TR TS].freeze
4
+ DOCSUBTYPES = %w[spec release].freeze
5
+ RADIOTECHNOLOGIES = %w[2G 3G LTE 5G].freeze
6
+
7
+ #
8
+ # Initialize bibliographic item.
9
+ #
10
+ # @param [String] radiotechnology
11
+ # @param [Boolean] common_ims_spec
12
+ # @param [Relaton3gpp::Release] release
13
+ #
14
+ def initialize(**args) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
15
+ @radiotechnology = args.delete(:radiotechnology)
16
+ if @radiotechnology && !RADIOTECHNOLOGIES.include?(@radiotechnology)
17
+ warn "[relaton-3gpp] Unknown radiotechnology type: #{@radiotechnology}"
18
+ warn "[relaton-3gpp] Possible radiotechnology types: #{RADIOTECHNOLOGIES.join ' '}"
19
+ end
20
+ @common_ims_spec = args.delete(:common_ims_spec)
21
+ @release = args.delete(:release)
22
+ if args[:doctype].nil? then warn "[relaton-3gpp] doctype is missing"
23
+ elsif !DOCTYPES.include?(args[:doctype])
24
+ warn "[relaton-3gpp] Unknown doctype: #{args[:doctype]}"
25
+ warn "[relaton-3gpp] Possible doctypes: #{DOCTYPES.join ' '}"
26
+ end
27
+ if args[:docsubtype] && !DOCSUBTYPES.include?(args[:docsubtype])
28
+ warn "[relaton-3gpp] Unknown docsubtype: #{args[:docsubtype]}"
29
+ warn "[relaton-3gpp] Possible docsubtypes: #{DOCSUBTYPES.join ' '}"
30
+ end
31
+ super(**args)
32
+ end
33
+
34
+ # @param opts [Hash]
35
+ # @option opts [Nokogiri::XML::Builder] :builder XML builder
36
+ # @option opts [Boolean] :bibdata
37
+ # @option opts [String] :lang language
38
+ # @return [String] XML
39
+ def to_xml(**opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
40
+ super do |b|
41
+ if block_given? then yield b
42
+ elsif opts[:bibdata] && has_ext_attrs?
43
+ b.ext do
44
+ b.doctype doctype if doctype
45
+ b.subdoctype subdoctype if subdoctype
46
+ editorialgroup&.to_xml b
47
+ ics.each { |i| i.to_xml b }
48
+ b.radiotechnology @radiotechnology if @radiotechnology
49
+ b.send "common-ims-spec", @common_ims_spec if @common_ims_spec
50
+ @release&.to_xml b if @release
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ def has_ext_attrs? # rubocop:disable Metrics/CyclomaticComplexity
57
+ doctype || subdoctype || editorialgroup || ics.any? || @radiotechnology ||
58
+ @common_ims_spec || @release
59
+ end
60
+
61
+ #
62
+ # Convert to hash.
63
+ #
64
+ # @return [Hash
65
+ #
66
+ def to_hash
67
+ hash = super
68
+ hash["radiotechnology"] = @radiotechnology if @radiotechnology
69
+ hash["common-ims-spec"] = @common_ims_spec if @common_ims_spec
70
+ hash["release"] = @release.to_hash if @release
71
+ hash
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Relaton3gpp
4
+ # Methods for search IANA standards.
5
+ module Bibliography
6
+ # SOURCE = "http://xml2rfc.tools.ietf.org/public/rfc/bibxml-3gpp-new/"
7
+ SOURCE = "https://raw.githubusercontent.com/relaton/relaton-data-3gpp/main/data/"
8
+
9
+ # @param text [String]
10
+ # @return [RelatonBib::BibliographicItem]
11
+ def search(text) # rubocop:disable Metrics/MethodLength
12
+ file = text.sub(/^3GPP\s/, "").gsub(/[\s,:\/]/, "_").squeeze("_").upcase
13
+ url = "#{SOURCE}#{file}.yaml"
14
+ resp = Net::HTTP.get_response URI(url)
15
+ return unless resp.code == "200"
16
+
17
+ hash = YAML.safe_load resp.body
18
+ bib_hash = Relaton3gpp::HashConverter.hash_to_bib(hash)
19
+ Relaton3gpp::BibliographicItem.new(**bib_hash)
20
+ rescue SocketError, Timeout::Error, Errno::EINVAL, Errno::ECONNRESET,
21
+ EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
22
+ Net::ProtocolError, Errno::ETIMEDOUT => e
23
+ raise RelatonBib::RequestError, e.message
24
+ end
25
+
26
+ # @param ref [String] the W3C standard Code to look up
27
+ # @param year [String, NilClass] not used
28
+ # @param opts [Hash] options
29
+ # @return [RelatonBib::BibliographicItem]
30
+ def get(ref, _year = nil, _opts = {})
31
+ warn "[relaton-3gpp] (\"#{ref}\") fetching..."
32
+ result = search(ref)
33
+ unless result
34
+ warn "[relaton-3gpp] (\"#{ref}\") not found"
35
+ return
36
+ end
37
+
38
+ warn "[relaton-3gpp] (\"#{ref}\") found #{result.docidentifier[0].id}"
39
+ result
40
+ end
41
+
42
+ extend Bibliography
43
+ end
44
+ end
@@ -0,0 +1,135 @@
1
+ require "fileutils"
2
+ require "net/ftp"
3
+ require "zip"
4
+ require "mdb"
5
+
6
+ module Relaton3gpp
7
+ class DataFetcher
8
+ CURRENT = "current.yaml".freeze
9
+ #
10
+ # Data fetcher initializer
11
+ #
12
+ # @param [String] output directory to save files
13
+ # @param [String] format format of output files (xml, yaml, bibxml)
14
+ #
15
+ def initialize(output, format)
16
+ @output = output
17
+ @format = format
18
+ @ext = format.sub(/^bib/, "")
19
+ @files = []
20
+ end
21
+
22
+ #
23
+ # Initialize fetcher and run fetch
24
+ #
25
+ # @param [Strin] output directory to save files, default: "data"
26
+ # @param [Strin] format format of output files (xml, yaml, bibxml), default: yaml
27
+ #
28
+ def self.fetch(output: "data", format: "yaml")
29
+ t1 = Time.now
30
+ puts "Started at: #{t1}"
31
+ FileUtils.mkdir_p output unless Dir.exist? output
32
+ new(output, format).fetch
33
+ t2 = Time.now
34
+ puts "Stopped at: #{t2}"
35
+ puts "Done in: #{(t2 - t1).round} sec."
36
+ end
37
+
38
+ #
39
+ # Parse documents
40
+ #
41
+ def fetch # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
42
+ file = get_file
43
+ return unless file
44
+
45
+ Zip::File.open(file) do |zip_file|
46
+ enntry = zip_file.glob("status_smg_3GPP.mdb").first
47
+ File.open("status_smg_3GPP.mdb", "wb") do |f|
48
+ f.write enntry.get_input_stream.read
49
+ end
50
+ end
51
+ dbs = Mdb.open "status_smg_3GPP.mdb"
52
+ specs = dbs["Specs_GSM+3G"]
53
+ specrels = dbs["Specs_GSM+3G_release-info"]
54
+ releases = dbs["Releases"]
55
+ dbs["2001-04-25_schedule"].each do |row|
56
+ fetch_doc row, specs, specrels, releases
57
+ end
58
+ File.write CURRENT, @current.to_yaml, encoding: "UTF-8"
59
+ end
60
+
61
+ #
62
+ # Get file from FTP
63
+ #
64
+ # @return [String] file name
65
+ #
66
+ def get_file # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
67
+ @current = YAML.load_file CURRENT if File.exist? CURRENT
68
+ @current ||= {}
69
+ ftp = Net::FTP.new("www.3gpp.org")
70
+ ftp.resume = true
71
+ ftp.login
72
+ ftp.chdir "/Information/Databases/Spec_Status/"
73
+ d, t, _, file = ftp.list("*.zip").first.split
74
+ dt = DateTime.strptime("#{d} #{t}", "%m-%d-%y %I:%M%p")
75
+ return if file == @current["file"] && dt == DateTime.parse(@current["date"])
76
+
77
+ ftp.getbinaryfile file
78
+ @current["file"] = file
79
+ @current["date"] = dt.to_s
80
+ file
81
+ end
82
+
83
+ #
84
+ # Fetch document
85
+ #
86
+ # @param [Hash] row row from mdb
87
+ # @param [Mdb] dbs mdb
88
+ #
89
+ # @return [Relaton3gpp::BibliographicItem, nil] bibliographic item
90
+ #
91
+ def fetch_doc(row, specs, specrels, releases)
92
+ doc = Parser.parse row, specs, specrels, releases
93
+ save_doc doc
94
+ rescue StandardError => e
95
+ warn "Error: #{e.message}"
96
+ warn "PubID: #{row[:spec]}:#{row[:release]}/#{row[:MAJOR_VERSION_NB]}."\
97
+ "#{row[:TECHNICAL_VERSION_NB]}.#{row[:EDITORIAL_VERSION_NB]}"
98
+ warn e.backtrace[0..5].join("\n")
99
+ end
100
+
101
+ #
102
+ # Save document to file
103
+ #
104
+ # @param [RelatonW3c::W3cBibliographicItem, nil] bib bibliographic item
105
+ #
106
+ def save_doc(bib) # rubocop:disable Metrics/MethodLength
107
+ return unless bib
108
+
109
+ c = case @format
110
+ when "xml" then bib.to_xml(bibdata: true)
111
+ when "yaml" then bib.to_hash.to_yaml
112
+ else bib.send("to_#{@format}")
113
+ end
114
+ file = file_name(bib)
115
+ if @files.include? file
116
+ warn "File #{file} already exists. Document: #{bib.docnumber}"
117
+ else
118
+ @files << file
119
+ end
120
+ File.write file, c, encoding: "UTF-8"
121
+ end
122
+
123
+ #
124
+ # Generate file name
125
+ #
126
+ # @param [RelatonW3c::W3cBibliographicItem] bib bibliographic item
127
+ #
128
+ # @return [String] file name
129
+ #
130
+ def file_name(bib)
131
+ name = bib.docnumber.gsub(/[\s,:\/]/, "_").squeeze("_").upcase
132
+ File.join @output, "#{name}.#{@ext}"
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,21 @@
1
+ module Relaton3gpp
2
+ class HashConverter < RelatonBib::HashConverter
3
+ class << self
4
+ def hash_to_bib(args, nested = false)
5
+ hash = super
6
+ release_hash_to_bib(hash)
7
+ hash
8
+ end
9
+
10
+ def release_hash_to_bib(hash)
11
+ hash[:release] &&= Release.new(**hash[:release])
12
+ end
13
+
14
+ # @param item_hash [Hash]
15
+ # @return [RelatonBib::BibliographicItem]
16
+ def bib_item(item_hash)
17
+ BibliographicItem.new(**item_hash)
18
+ end
19
+ end
20
+ end
21
+ end