relaton-ieee 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/macos.yml +38 -0
- data/.github/workflows/ubuntu.yml +38 -0
- data/.github/workflows/windows.yml +41 -0
- data/.gitignore +14 -0
- data/.rspec +3 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.adoc +172 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/rspec +29 -0
- data/bin/setup +8 -0
- data/grammars/basicdoc.rng +986 -0
- data/grammars/biblio.rng +1237 -0
- data/grammars/isodoc.rng +1077 -0
- data/grammars/reqt.rng +165 -0
- data/lib/relaton_ieee.rb +25 -0
- data/lib/relaton_ieee/committee.rb +33 -0
- data/lib/relaton_ieee/hash_converter.rb +29 -0
- data/lib/relaton_ieee/hit.rb +9 -0
- data/lib/relaton_ieee/hit_collection.rb +34 -0
- data/lib/relaton_ieee/ieee_bibliographic_item.rb +31 -0
- data/lib/relaton_ieee/ieee_bibliography.rb +72 -0
- data/lib/relaton_ieee/processor.rb +41 -0
- data/lib/relaton_ieee/scrapper.rb +154 -0
- data/lib/relaton_ieee/version.rb +3 -0
- data/lib/relaton_ieee/xml_parser.rb +29 -0
- data/relaton_ieee.gemspec +47 -0
- metadata +216 -0
data/grammars/reqt.rng
ADDED
@@ -0,0 +1,165 @@
|
|
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="subsequence"/>
|
35
|
+
</optional>
|
36
|
+
<attribute name="id">
|
37
|
+
<data type="ID"/>
|
38
|
+
</attribute>
|
39
|
+
<optional>
|
40
|
+
<attribute name="filename"/>
|
41
|
+
</optional>
|
42
|
+
<optional>
|
43
|
+
<ref name="reqtitle"/>
|
44
|
+
</optional>
|
45
|
+
<optional>
|
46
|
+
<ref name="label"/>
|
47
|
+
</optional>
|
48
|
+
<optional>
|
49
|
+
<ref name="subject"/>
|
50
|
+
</optional>
|
51
|
+
<optional>
|
52
|
+
<ref name="reqinherit"/>
|
53
|
+
</optional>
|
54
|
+
<zeroOrMore>
|
55
|
+
<ref name="classification"/>
|
56
|
+
</zeroOrMore>
|
57
|
+
<zeroOrMore>
|
58
|
+
<choice>
|
59
|
+
<ref name="measurementtarget"/>
|
60
|
+
<ref name="specification"/>
|
61
|
+
<ref name="verification"/>
|
62
|
+
<ref name="import"/>
|
63
|
+
<ref name="description"/>
|
64
|
+
</choice>
|
65
|
+
</zeroOrMore>
|
66
|
+
<optional>
|
67
|
+
<ref name="reqt_references"/>
|
68
|
+
</optional>
|
69
|
+
<zeroOrMore>
|
70
|
+
<choice>
|
71
|
+
<ref name="requirement"/>
|
72
|
+
<ref name="recommendation"/>
|
73
|
+
<ref name="permission"/>
|
74
|
+
</choice>
|
75
|
+
</zeroOrMore>
|
76
|
+
</define>
|
77
|
+
<define name="reqtitle">
|
78
|
+
<element name="title">
|
79
|
+
<ref name="FormattedString"/>
|
80
|
+
</element>
|
81
|
+
</define>
|
82
|
+
<define name="label">
|
83
|
+
<element name="label">
|
84
|
+
<text/>
|
85
|
+
</element>
|
86
|
+
</define>
|
87
|
+
<define name="subject">
|
88
|
+
<element name="subject">
|
89
|
+
<text/>
|
90
|
+
</element>
|
91
|
+
</define>
|
92
|
+
<define name="reqinherit">
|
93
|
+
<element name="inherit">
|
94
|
+
<text/>
|
95
|
+
</element>
|
96
|
+
</define>
|
97
|
+
<define name="measurementtarget">
|
98
|
+
<element name="measurement-target">
|
99
|
+
<ref name="RequirementSubpart"/>
|
100
|
+
</element>
|
101
|
+
</define>
|
102
|
+
<define name="specification">
|
103
|
+
<element name="specification">
|
104
|
+
<ref name="RequirementSubpart"/>
|
105
|
+
</element>
|
106
|
+
</define>
|
107
|
+
<define name="verification">
|
108
|
+
<element name="verification">
|
109
|
+
<ref name="RequirementSubpart"/>
|
110
|
+
</element>
|
111
|
+
</define>
|
112
|
+
<define name="import">
|
113
|
+
<element name="import">
|
114
|
+
<ref name="RequirementSubpart"/>
|
115
|
+
</element>
|
116
|
+
</define>
|
117
|
+
<define name="description">
|
118
|
+
<element name="description">
|
119
|
+
<ref name="RequirementSubpart"/>
|
120
|
+
</element>
|
121
|
+
</define>
|
122
|
+
<define name="reqt_references">
|
123
|
+
<element name="references">
|
124
|
+
<oneOrMore>
|
125
|
+
<ref name="bibitem"/>
|
126
|
+
</oneOrMore>
|
127
|
+
</element>
|
128
|
+
</define>
|
129
|
+
<define name="RequirementSubpart">
|
130
|
+
<optional>
|
131
|
+
<attribute name="type"/>
|
132
|
+
</optional>
|
133
|
+
<optional>
|
134
|
+
<attribute name="exclude">
|
135
|
+
<data type="boolean"/>
|
136
|
+
</attribute>
|
137
|
+
</optional>
|
138
|
+
<oneOrMore>
|
139
|
+
<ref name="BasicBlock"/>
|
140
|
+
</oneOrMore>
|
141
|
+
</define>
|
142
|
+
<define name="ObligationType">
|
143
|
+
<choice>
|
144
|
+
<value>requirement</value>
|
145
|
+
<value>recommendation</value>
|
146
|
+
<value>permission</value>
|
147
|
+
</choice>
|
148
|
+
</define>
|
149
|
+
<define name="classification">
|
150
|
+
<element name="classification">
|
151
|
+
<ref name="classification_tag"/>
|
152
|
+
<ref name="classification_value"/>
|
153
|
+
</element>
|
154
|
+
</define>
|
155
|
+
<define name="classification_tag">
|
156
|
+
<element name="tag">
|
157
|
+
<text/>
|
158
|
+
</element>
|
159
|
+
</define>
|
160
|
+
<define name="classification_value">
|
161
|
+
<element name="value">
|
162
|
+
<text/>
|
163
|
+
</element>
|
164
|
+
</define>
|
165
|
+
</grammar>
|
data/lib/relaton_ieee.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "digest/md5"
|
2
|
+
require "yaml"
|
3
|
+
require "relaton_bib"
|
4
|
+
require "relaton_ieee/version"
|
5
|
+
require "relaton_ieee/ieee_bibliography"
|
6
|
+
require "relaton_ieee/hit_collection"
|
7
|
+
require "relaton_ieee/hit"
|
8
|
+
require "relaton_ieee/scrapper"
|
9
|
+
require "relaton_ieee/ieee_bibliographic_item"
|
10
|
+
require "relaton_ieee/committee"
|
11
|
+
require "relaton_ieee/xml_parser"
|
12
|
+
require "relaton_ieee/hash_converter"
|
13
|
+
|
14
|
+
module RelatonIeee
|
15
|
+
class Error < StandardError; end
|
16
|
+
|
17
|
+
# Returns hash of XML reammar
|
18
|
+
# @return [String]
|
19
|
+
def self.grammar_hash
|
20
|
+
gem_path = File.expand_path "..", __dir__
|
21
|
+
grammars_path = File.join gem_path, "grammars", "*"
|
22
|
+
grammars = Dir[grammars_path].sort.map { |gp| File.read gp }.join
|
23
|
+
Digest::MD5.hexdigest grammars
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RelatonIeee
|
2
|
+
class Committee
|
3
|
+
# @return [String]
|
4
|
+
attr_reader :type, :name
|
5
|
+
|
6
|
+
# @return [String, NilClass]
|
7
|
+
attr_reader :chair
|
8
|
+
|
9
|
+
# @param type [String]
|
10
|
+
# @param name [String]
|
11
|
+
# @param chair [String, NilClass]
|
12
|
+
def initialize(type:, name:, chair: nil)
|
13
|
+
@type = type
|
14
|
+
@name = name
|
15
|
+
@chair = chair
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param builder [Nokogiri::XML::Builder]
|
19
|
+
def to_xml(builder)
|
20
|
+
builder.committee type: type do |b|
|
21
|
+
b.name name
|
22
|
+
b.chair chair if chair
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Hash]
|
27
|
+
def to_hash
|
28
|
+
hash = { "type" => type, "name" => name }
|
29
|
+
hash["chair"] = chair if chair
|
30
|
+
hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RelatonIeee
|
2
|
+
class HashConverter < RelatonBib::HashConverter
|
3
|
+
class << self
|
4
|
+
# @param args [Hash]
|
5
|
+
# @param neated [TrueClas, FalseClass] default true
|
6
|
+
# @return [Hash]
|
7
|
+
def hash_to_bib(args, nested = false)
|
8
|
+
hash = super
|
9
|
+
return nil unless hash.is_a?(Hash)
|
10
|
+
|
11
|
+
committee_hash_to_bib hash
|
12
|
+
hash
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param item_hash [Hash]
|
16
|
+
# @return [RelatonIeee::IeeeBibliographicItem]
|
17
|
+
def bib_item(item_hash)
|
18
|
+
IeeeBibliographicItem.new item_hash
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param hash [Hash]
|
22
|
+
def committee_hash_to_bib(hash)
|
23
|
+
return unless hash[:committee]
|
24
|
+
|
25
|
+
hash[:committee] = hash[:committee].map { |c| Committee.new c }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "relaton_ieee/hit"
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
module RelatonIeee
|
6
|
+
class HitCollection < RelatonBib::HitCollection
|
7
|
+
DOMAIN = "https://standards.ieee.org".freeze
|
8
|
+
DATADIR = File.expand_path ".relaton/ogc/", Dir.home
|
9
|
+
DATAFILE = File.expand_path "bibliography.json", DATADIR
|
10
|
+
ETAGFILE = File.expand_path "etag.txt", DATADIR
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/AbcSize
|
13
|
+
|
14
|
+
# @param ref [Strig]
|
15
|
+
# @param opts [Hash]
|
16
|
+
def initialize(ref)
|
17
|
+
super
|
18
|
+
code = ref.sub /^IEEE\s/, ""
|
19
|
+
search = CGI.escape({ data: { searchTerm: code } }.to_json)
|
20
|
+
url = "#{DOMAIN}/bin/standards/search?data=#{search}"
|
21
|
+
resp = Faraday.get url
|
22
|
+
resp_json = JSON.parse resp.body
|
23
|
+
json = JSON.parse resp_json["message"]
|
24
|
+
@array = json["response"]["searchResults"]["resultsMapList"].
|
25
|
+
reduce([]) do |s, hit|
|
26
|
+
/^(?<id>\d+)-(?<year>\d{4})/ =~ hit["record"]["recordTitle"]
|
27
|
+
next s unless id && code =~ %r{^#{id}}
|
28
|
+
|
29
|
+
s << Hit.new(hit["record"].merge(code: id, year: year.to_i), self)
|
30
|
+
end.sort_by { |h| h.hit[:year].to_s + h.hit["recordURL"] }.reverse
|
31
|
+
end
|
32
|
+
# rubocop:enable Metrics/AbcSize
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RelatonIeee
|
2
|
+
class IeeeBibliographicItem < RelatonBib::BibliographicItem
|
3
|
+
# @return [Array<RelatonIeee::Committee>]
|
4
|
+
attr_reader :committee
|
5
|
+
|
6
|
+
# @param committee [Array<RelatonIeee::Committee>]
|
7
|
+
def initialize(**args)
|
8
|
+
@committee = args.delete :committee
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param builder [Nokogiri::XML::Bilder]
|
13
|
+
# @parma bibdata [TrueClass, FalseClass, NilClass]
|
14
|
+
def to_xml(builder = nil, **opts)
|
15
|
+
super do |bldr|
|
16
|
+
if opts[:bibdata] && committee.any?
|
17
|
+
bldr.ext do |b|
|
18
|
+
committee.each { |c| c.to_xml b }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Hash]
|
25
|
+
def to_hash
|
26
|
+
hash = super
|
27
|
+
hash["committee"] = committee.map &:to_hash
|
28
|
+
hash
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module RelatonIeee
|
2
|
+
class IeeeBibliography
|
3
|
+
class << self
|
4
|
+
# @param text [String]
|
5
|
+
# @return [RelatonIeee::HitCollection]
|
6
|
+
def search(text)
|
7
|
+
HitCollection.new text
|
8
|
+
rescue Faraday::ConnectionFailed
|
9
|
+
raise RelatonBib::RequestError, "Could not access #{HitCollection::DOMAIN}"
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param code [String] the IEEE standard Code to look up (e..g "528-2019")
|
13
|
+
# @param year [String] the year the standard was published (optional)
|
14
|
+
# @param opts [Hash] options
|
15
|
+
#
|
16
|
+
# @return [Hash, NilClass] returns { ret: RelatonBib::BibliographicItem }
|
17
|
+
# if document is found else returns NilClass
|
18
|
+
def get(code, year = nil, _opts = {})
|
19
|
+
warn "[relaton-ieee] (\"#{code}\") fetching..."
|
20
|
+
result = search(code) || (return nil)
|
21
|
+
year ||= code.match(/(?<=-)\d{4}/)&.to_s
|
22
|
+
ret = bib_results_filter(result, year)
|
23
|
+
if ret[:ret]
|
24
|
+
item = ret[:ret].fetch
|
25
|
+
warn "[relaton-ieee] (\"#{code}\") found #{item.docidentifier.first.id}"
|
26
|
+
item
|
27
|
+
else
|
28
|
+
fetch_ref_err(code, year, ret[:years])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# Sort through the results from RelatonIeee, fetching them three at a time,
|
35
|
+
# and return the first result that matches the code,
|
36
|
+
# matches the year (if provided), and which # has a title (amendments do not).
|
37
|
+
# Only expects the first page of results to be populated.
|
38
|
+
# Does not match corrigenda etc (e.g. ISO 3166-1:2006/Cor 1:2007)
|
39
|
+
# If no match, returns any years which caused mismatch, for error reporting
|
40
|
+
#
|
41
|
+
# @param result [RelatonIeee::HitCollection]
|
42
|
+
# @param opts [Hash] options
|
43
|
+
#
|
44
|
+
# @return [Hash]
|
45
|
+
def bib_results_filter(result, year)
|
46
|
+
missed_years = []
|
47
|
+
result.each do |hit|
|
48
|
+
return { ret: hit } if !year
|
49
|
+
|
50
|
+
return { ret: hit } if year.to_i == hit.hit[:year]
|
51
|
+
|
52
|
+
missed_years << hit.hit[:year]
|
53
|
+
end
|
54
|
+
{ years: missed_years.uniq }
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param code [Strig]
|
58
|
+
# @param year [String]
|
59
|
+
# @param missed_years [Array<Strig>]
|
60
|
+
def fetch_ref_err(code, year, missed_years)
|
61
|
+
id = year ? "#{code} year #{year}" : code
|
62
|
+
warn "[relaton-ieee] WARNING: no match found online for #{id}. "\
|
63
|
+
"The code must be exactly like it is on the standards website."
|
64
|
+
unless missed_years.empty?
|
65
|
+
warn "[relaton-ieee] (There was no match for #{year}, though there were matches "\
|
66
|
+
"found for #{missed_years.join(', ')}.)"
|
67
|
+
end
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "relaton/processor"
|
2
|
+
|
3
|
+
module RelatonIeee
|
4
|
+
class Processor < Relaton::Processor
|
5
|
+
attr_reader :idtype
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@short = :relaton_ieee
|
9
|
+
@prefix = "IEEE"
|
10
|
+
@defaultprefix = %r{^IEEE\s}
|
11
|
+
@idtype = "IEEE"
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param code [String]
|
15
|
+
# @param date [String, NilClass] year
|
16
|
+
# @param opts [Hash]
|
17
|
+
# @return [RelatonIeee::IeeeBibliographicItem]
|
18
|
+
def get(code, date, opts)
|
19
|
+
::RelatonIeee::IeeeBibliography.get(code, date, opts)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param xml [String]
|
23
|
+
# @return [RelatonIeee::IeeeBibliographicItem]
|
24
|
+
def from_xml(xml)
|
25
|
+
::RelatonIeee::XMLParser.from_xml xml
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param hash [Hash]
|
29
|
+
# @return [RelatonIeee::IeeeBibliographicItem]
|
30
|
+
def hash_to_bib(hash)
|
31
|
+
item_hash = ::RelatonIeee::HashConverter.hash_to_bib(hash)
|
32
|
+
::RelatonIeee::IeeeBibliographicItem.new item_hash
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns hash of XML grammar
|
36
|
+
# @return [String]
|
37
|
+
def grammar_hash
|
38
|
+
@grammar_hash ||= ::RelatonIeee.grammar_hash
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|