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.
- checksums.yaml +7 -0
- data/.github/workflows/rake.yml +36 -0
- data/.gitignore +13 -0
- data/.rspec +3 -0
- data/.rubocop.yml +12 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +21 -0
- data/README.adoc +170 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/rspec +29 -0
- data/bin/setup +8 -0
- data/grammars/3gpp.rng +105 -0
- data/grammars/basicdoc.rng +1131 -0
- data/grammars/biblio.rng +1236 -0
- data/grammars/isodoc.rng +2519 -0
- data/grammars/reqt.rng +205 -0
- data/lib/relaton_3gpp/bibliographic_item.rb +74 -0
- data/lib/relaton_3gpp/bibliography.rb +44 -0
- data/lib/relaton_3gpp/data_fetcher.rb +135 -0
- data/lib/relaton_3gpp/hash_converter.rb +21 -0
- data/lib/relaton_3gpp/parser.rb +244 -0
- data/lib/relaton_3gpp/processor.rb +54 -0
- data/lib/relaton_3gpp/release.rb +65 -0
- data/lib/relaton_3gpp/version.rb +5 -0
- data/lib/relaton_3gpp/xml_parser.rb +58 -0
- data/lib/relaton_3gpp.rb +25 -0
- data/relaton_3gpp.gemspec +50 -0
- metadata +225 -0
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
|