relaton-ieee 1.1.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/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
|