relaton-iho 1.2.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.
@@ -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,22 @@
1
+ require "digest/md5"
2
+ require "relaton_bib"
3
+ require "relaton_iho/version"
4
+ require "relaton_iho/iho_bibliography"
5
+ require "relaton_iho/hash_converter"
6
+ require "relaton_iho/xml_parser"
7
+ require "relaton_iho/editorial_group"
8
+ require "relaton_iho/comment_periond"
9
+ require "relaton_iho/iho_bibliographic_item"
10
+
11
+ module RelatonIho
12
+ class Error < StandardError; end
13
+
14
+ # Returns hash of XML reammar
15
+ # @return [String]
16
+ def self.grammar_hash
17
+ gem_path = File.expand_path "..", __dir__
18
+ grammars_path = File.join gem_path, "grammars", "*"
19
+ grammars = Dir[grammars_path].sort.map { |gp| File.read gp }.join
20
+ Digest::MD5.hexdigest grammars
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ module RelatonIho
2
+ class CommentPeriond
3
+ # @return [Date]
4
+ attr_reader :from
5
+
6
+ # @return [Date, NilClass]
7
+ attr_reader :to
8
+
9
+ # @param from [String] date
10
+ # @parma to [String, NilClass] date
11
+ def initialize(from:, to: nil)
12
+ @from = Date.parse from
13
+ @to = Date.parse to if to
14
+ end
15
+
16
+ # @param builder [Nokogiri::XML::builder]
17
+ def to_xml(builder)
18
+ builder.commentperiod do
19
+ builder.from from.to_s
20
+ builder.to to.to_s if to
21
+ end
22
+ end
23
+
24
+ # @return [Hash]
25
+ def to_hash
26
+ hash = { "from" => from.to_s }
27
+ hash["to"] = to.to_s if to
28
+ hash
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,59 @@
1
+ module RelatonIho
2
+ class EditorialGroupCollection
3
+ extend Forwardable
4
+ include RelatonBib
5
+
6
+ def_delegators :@collection, :first, :any?
7
+
8
+ # @return [Array<RelatonIho::editorialgroup]
9
+ attr_reader :collection
10
+
11
+ # @param collection [Array<RelatonIho::EditorialGroup>]
12
+ def initialize(collection)
13
+ @collection = collection
14
+ end
15
+
16
+ # @param builder [Nokogiro::XML::Builder]
17
+ def to_xml(builder)
18
+ collection.each { |eg| eg.to_xml builder }
19
+ end
20
+
21
+ # @return [Hash]
22
+ def to_hash
23
+ single_element_array collection
24
+ end
25
+
26
+ # @return [Boolean]
27
+ def presence?
28
+ any?
29
+ end
30
+ end
31
+
32
+ class EditorialGroup
33
+ # @return [String]
34
+ attr_reader :committee, :workgroup
35
+
36
+ # @parma committee [String]
37
+ # @param workgroup [String]
38
+ def initialize(committee:, workgroup:)
39
+ unless %[hssc ircc].include? committee
40
+ warn "[relaton-iho] WARNING: invalid committee: #{committee}"
41
+ end
42
+ @committee = committee
43
+ @workgroup = workgroup
44
+ end
45
+
46
+ # @param builder [Nokogiro::XML::Builder]
47
+ def to_xml(builder)
48
+ builder.editorialgroup do
49
+ builder.committee committee
50
+ builder.workgroup workgroup
51
+ end
52
+ end
53
+
54
+ # @return [Hash]
55
+ def to_hash
56
+ { "committee" => committee, "workgroup" => workgroup }
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,33 @@
1
+ module RelatonIho
2
+ class HashConverter < RelatonBib::HashConverter
3
+ class << self
4
+ # @override RelatonIsoBib::HashConverter.hash_to_bib
5
+ # @param args [Hash]
6
+ # @param nested [TrueClass, FalseClass]
7
+ # @return [Hash]
8
+ def hash_to_bib(args, nested = false)
9
+ ret = super
10
+ return if ret.nil?
11
+
12
+ commentperiod_hash_to_bib ret
13
+ ret
14
+ end
15
+
16
+ private
17
+
18
+ # @param ret [Hash]
19
+ def commentperiod_hash_to_bib(ret)
20
+ ret[:commentperiod] &&= CommentPeriond.new(ret[:commentperiod])
21
+ end
22
+
23
+ # @param ret [Hash]
24
+ def editorialgroup_hash_to_bib(ret)
25
+ eg = ret[:editorialgroup]
26
+ return unless eg.is_a?(Hash) || eg&.any?
27
+
28
+ collection = array(eg).map { |g| EditorialGroup.new g }
29
+ ret[:editorialgroup] = EditorialGroupCollection.new collection
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,73 @@
1
+ require "faraday"
2
+ require "yaml"
3
+ require "fileutils"
4
+
5
+ module RelatonIho
6
+ class HitCollection < RelatonBib::HitCollection
7
+ ENDPOINT = "https://raw.githubusercontent.com/relaton/relaton-data-iho/master/data/".freeze
8
+
9
+ # @param ref [Strig]
10
+ # @param year [String]
11
+ # @param opts [Hash]
12
+ def initialize(ref, year = nil)
13
+ super
14
+ @array = from_yaml(ref).sort_by do |hit|
15
+ hit.hit["revdate"] ? Date.parse(hit.hit["revdate"]) : Date.new
16
+ end.reverse
17
+ end
18
+
19
+ private
20
+
21
+ #
22
+ # Fetch data form yaml
23
+ #
24
+ # @param docid [String]
25
+ def from_yaml(docid, **_opts)
26
+ data["root"]["items"].select do |doc|
27
+ doc["docid"] && doc["docid"]["id"].include?(docid)
28
+ end.map { |h| Hit.new(h, self) }
29
+ end
30
+
31
+ #
32
+ # Fetches YAML data
33
+ #
34
+ # @return [Hash]
35
+ def data
36
+ FileUtils.mkdir_p DATADIR
37
+ ctime = File.ctime DATAFILE if File.exist? DATAFILE
38
+ fetch_data if !ctime || ctime.to_date < Date.today
39
+ @data ||= YAML.safe_load File.read(DATAFILE, encoding: "UTF-8")
40
+ end
41
+
42
+ #
43
+ # fetch data form server and save it to file.
44
+ #
45
+ def fetch_data
46
+ resp = Faraday.new(ENDPOINT, headers: { "If-None-Match" => etag }).get
47
+ # return if there aren't any changes since last fetching
48
+ return unless resp.status == 200
49
+
50
+ self.etag = resp[:etag]
51
+ @data = YAML.safe_load resp.body
52
+ File.write DATAFILE, @data.to_yaml, encoding: "UTF-8"
53
+ end
54
+
55
+ #
56
+ # Read ETag form file
57
+ #
58
+ # @return [String, NilClass]
59
+ def etag
60
+ @etag ||= if File.exist? ETAGFILE
61
+ File.read ETAGFILE, encoding: "UTF-8"
62
+ end
63
+ end
64
+
65
+ #
66
+ # Save ETag to file
67
+ #
68
+ # @param tag [String]
69
+ def etag=(e_tag)
70
+ File.write ETAGFILE, e_tag, encoding: "UTF-8"
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,40 @@
1
+ module RelatonIho
2
+ class IhoBibliographicItem < RelatonBib::BibliographicItem
3
+ TYPES = %w[policy-and-procedures best-practices supporting-document
4
+ report legal directives proposal standard].freeze
5
+
6
+ # @return [RelatonIho::CommentPeriod, NilClass]
7
+ attr_reader :commentperiod
8
+
9
+ # @param editorialgroup [RelatonIho::EditorialGroupCollection]
10
+ # @param commentperiod [RelatonIho::CommentPeriod, NilClass]
11
+ def initialize(**args)
12
+ @commentperiod = args.delete :commentperiod
13
+ super
14
+ end
15
+
16
+ # @param builder [Nokogiri::XML::Builder]
17
+ # @param bibdata [TrueClasss, FalseClass, NilClass]
18
+ def to_xml(builer = nil, **opts)
19
+ opts[:ext] = !commentperiod.nil?
20
+ super do |b|
21
+ if opts[:bibdata] && (doctype || editorialgroup&.presence? ||
22
+ ics.any? || commentperiod)
23
+ b.ext do
24
+ b.doctype doctype if doctype
25
+ editorialgroup&.to_xml b
26
+ ics.each { |i| i.to_xml b }
27
+ commentperiod&.to_xml b
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ # @return [Hash]
34
+ def to_hash
35
+ hash = super
36
+ hash["commentperiod"] = commentperiod.to_hash if commentperiod
37
+ hash
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ module RelatonIho
2
+ class IhoBibliography
3
+ ENDPOINT = "https://raw.githubusercontent.com/relaton/relaton-data-iho/"\
4
+ "master/data/".freeze
5
+
6
+ class << self
7
+ # @param text [String]
8
+ # @return [RelatonIho::IhoBibliographicItem]
9
+ def search(text, _year = nil, _opts = {})
10
+ warn "[relaton-iho] (\"#{text}\") fetching..."
11
+ ref = text.sub(/^IHO\s/, "").downcase
12
+ uri = URI("#{ENDPOINT}#{ref}.yaml")
13
+ resp = Net::HTTP.get_response uri
14
+ returm unless resp.code == "200"
15
+
16
+ hash = HashConverter.hash_to_bib YAML.safe_load(resp.body, [Date])
17
+ item = IhoBibliographicItem.new hash
18
+ warn "[relaton-iho] (\"#{text}\") found #{item.docidentifier.first.id}"
19
+ item
20
+ rescue SocketError, Errno::EINVAL, Errno::ECONNRESET, EOFError,
21
+ Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
22
+ Net::ProtocolError, Net::ReadTimeout, OpenSSL::SSL::SSLError,
23
+ Errno::ETIMEDOUT => e
24
+ raise RelatonBib::RequestError, "Could not access #{uri}: #{e.message}"
25
+ end
26
+
27
+ # @param ref [String] the IHO standard Code to look up (e..g "IHO B-11")
28
+ # @param year [String] the year the standard was published (optional)
29
+ #
30
+ # @param opts [Hash] options
31
+ # @option opts [TrueClass, FalseClass] :all_parts restricted to all parts
32
+ # if all-parts reference is required
33
+ # @option opts [TrueClass, FalseClass] :bibdata
34
+ #
35
+ # @return [RelatonIho::IhoBibliographicItem]
36
+ def get(ref, year = nil, opts = {})
37
+ search(ref, year, opts)
38
+ end
39
+ end
40
+ end
41
+ end