relaton-3gpp 1.9.0

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,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