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.
- checksums.yaml +7 -0
- data/.github/workflows/macos.yml +32 -0
- data/.github/workflows/ubuntu.yml +32 -0
- data/.github/workflows/windows.yml +35 -0
- data/.gitignore +14 -0
- data/.rspec +1 -0
- data/.rubocop.yml +10 -0
- data/Gemfile +6 -0
- data/README.adoc +131 -0
- data/Rakefile +6 -0
- data/bin/rspec +29 -0
- data/grammars/basicdoc.rng +986 -0
- data/grammars/biblio.rng +1237 -0
- data/grammars/iho.rng +144 -0
- data/grammars/isodoc.rng +1504 -0
- data/grammars/reqt.rng +165 -0
- data/lib/relaton_iho.rb +22 -0
- data/lib/relaton_iho/comment_periond.rb +31 -0
- data/lib/relaton_iho/editorial_group.rb +59 -0
- data/lib/relaton_iho/hash_converter.rb +33 -0
- data/lib/relaton_iho/hit_collection.rb +73 -0
- data/lib/relaton_iho/iho_bibliographic_item.rb +40 -0
- data/lib/relaton_iho/iho_bibliography.rb +41 -0
- data/lib/relaton_iho/processor.rb +41 -0
- data/lib/relaton_iho/version.rb +3 -0
- data/lib/relaton_iho/xml_parser.rb +45 -0
- data/relaton_iho.gemspec +36 -0
- metadata +225 -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_iho.rb
ADDED
@@ -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
|