relaton-ieee 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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>
@@ -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,9 @@
1
+ module RelatonIeee
2
+ class Hit < RelatonBib::Hit
3
+ # Parse page.
4
+ # @return [RelatonIeee::IeeeBliographicItem]
5
+ def fetch
6
+ @fetch ||= Scrapper.parse_page hit
7
+ end
8
+ end
9
+ 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