relaton-iho 1.2.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,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