mn-requirements 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/rake.yml +15 -0
- data/.github/workflows/release.yml +24 -0
- data/.hound.yml +5 -0
- data/.rubocop.yml +13 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +12 -0
- data/LICENSE +25 -0
- data/README.adoc +26 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/rspec +17 -0
- data/bin/setup +8 -0
- data/lib/metanorma/default/cleanup.rb +146 -0
- data/lib/metanorma/default/default.rb +99 -0
- data/lib/metanorma/default/isodoc.rb +106 -0
- data/lib/metanorma/default/utils.rb +27 -0
- data/lib/metanorma/default/xrefs.rb +35 -0
- data/lib/metanorma/modspec/cleanup.rb +89 -0
- data/lib/metanorma/modspec/isodoc.rb +238 -0
- data/lib/metanorma/modspec/modspec.rb +9 -0
- data/lib/metanorma/modspec/reqt_label.rb +80 -0
- data/lib/metanorma/modspec/xrefs.rb +66 -0
- data/lib/metanorma/requirements/selector.rb +94 -0
- data/lib/metanorma/requirements/version.rb +5 -0
- data/lib/mn-requirements.rb +2 -0
- data/mn-requirements.gemspec +42 -0
- metadata +267 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
module Metanorma
|
2
|
+
class Requirements
|
3
|
+
class Modspec < Default
|
4
|
+
def requirement_type_cleanup(reqt)
|
5
|
+
reqt["type"] = case reqt["type"]
|
6
|
+
when "requirement", "recommendation", "permission"
|
7
|
+
"general"
|
8
|
+
when "requirements_class" then "class"
|
9
|
+
when "conformance_test" then "verification"
|
10
|
+
when "conformance_class" then "conformanceclass"
|
11
|
+
when "abstract_test" then "abstracttest"
|
12
|
+
else reqt["type"]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def requirement_metadata_component_tags
|
17
|
+
%w(test-purpose test-method test-method-type conditions part description
|
18
|
+
reference step requirement permission recommendation)
|
19
|
+
end
|
20
|
+
|
21
|
+
def requirement_metadata1(reqt, dlist, ins)
|
22
|
+
ins1 = super
|
23
|
+
dlist.xpath("./dt").each do |e|
|
24
|
+
tag = e&.text&.gsub(/ /, "-")&.downcase
|
25
|
+
next unless requirement_metadata_component_tags.include? tag
|
26
|
+
|
27
|
+
ins1.next = requirement_metadata1_component(e, tag)
|
28
|
+
ins1 = ins1.next
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def requirement_metadata1_component(term, tag)
|
33
|
+
val = term.at("./following::dd")
|
34
|
+
val.name = tag
|
35
|
+
val.xpath("./dl").each do |d|
|
36
|
+
requirement_metadata1(val, d, d)
|
37
|
+
d.remove
|
38
|
+
end
|
39
|
+
if REQS.include?(term.text) && !val.text.empty?
|
40
|
+
val["label"] = val.text.strip
|
41
|
+
val.children.remove
|
42
|
+
end
|
43
|
+
val
|
44
|
+
end
|
45
|
+
|
46
|
+
# separate from default model requirement_metadata_cleanup,
|
47
|
+
# which extracts model:: ogc into reqt["model"]
|
48
|
+
def requirement_metadata_cleanup(reqt)
|
49
|
+
super
|
50
|
+
requirement_metadata_to_component(reqt)
|
51
|
+
requirement_metadata_to_requirement(reqt)
|
52
|
+
requirement_subparts_to_blocks(reqt)
|
53
|
+
requirement_target_identifiers(reqt)
|
54
|
+
end
|
55
|
+
|
56
|
+
def requirement_target_identifiers(reqt)
|
57
|
+
reqt.xpath("./classification[tag = 'target']/value[link]").each do |v|
|
58
|
+
v.children = v.at("./link/@target").text
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def requirement_metadata_to_component(reqt)
|
63
|
+
reqt.xpath(".//test-method | .//test-purpose | .//conditions | "\
|
64
|
+
".//part | .//test-method-type | .//step | .//reference")
|
65
|
+
.each do |c|
|
66
|
+
c["class"] = c.name
|
67
|
+
c.name = "component"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def requirement_metadata_to_requirement(reqt)
|
72
|
+
reqt.xpath("./requirement | ./permission | ./recommendation")
|
73
|
+
.each do |c|
|
74
|
+
c["id"] = Metanorma::Utils::anchor_or_uuid
|
75
|
+
c["model"] = reqt["model"] # all requirements must have a model
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def requirement_subparts_to_blocks(reqt)
|
80
|
+
reqt.xpath(".//component | .//description").each do |c|
|
81
|
+
next if %w(p ol ul dl table component description)
|
82
|
+
.include?(c&.elements&.first&.name)
|
83
|
+
|
84
|
+
c.children = "<p>#{c.children.to_xml}</p>"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require_relative "xrefs"
|
2
|
+
require_relative "reqt_label"
|
3
|
+
|
4
|
+
module Metanorma
|
5
|
+
class Requirements
|
6
|
+
class Modspec < Default
|
7
|
+
def requirement_render1(node)
|
8
|
+
requirement_table_cleanup(super)
|
9
|
+
end
|
10
|
+
|
11
|
+
def recommendation_base(node, klass)
|
12
|
+
out = node.document.create_element("table")
|
13
|
+
out.default_namespace = node.namespace.href
|
14
|
+
%w(id keep-with-next keep-lines-together unnumbered).each do |x|
|
15
|
+
out[x] = node[x] if node[x]
|
16
|
+
end
|
17
|
+
out["class"] = klass
|
18
|
+
out["type"] = recommend_class(node)
|
19
|
+
recommendation_component_labels(node)
|
20
|
+
out
|
21
|
+
end
|
22
|
+
|
23
|
+
def recommendation_component_labels(node)
|
24
|
+
node.xpath(ns("./component[@class = 'part']")).each_with_index do |c, i|
|
25
|
+
c["label"] = (i + "A".ord).chr.to_s
|
26
|
+
end
|
27
|
+
node.xpath(ns("./component[not(@class = 'part')]")).each do |c|
|
28
|
+
c["label"] = recommend_component_label(c)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def recommendation_header(recommend, out)
|
33
|
+
h = out.add_child("<thead><tr><th scope='colgroup' colspan='2'>"\
|
34
|
+
"</th></tr></thead>").first
|
35
|
+
recommendation_name(recommend, h.at(ns(".//th")))
|
36
|
+
out
|
37
|
+
end
|
38
|
+
|
39
|
+
def recommendation_name(node, out)
|
40
|
+
b = out.add_child("<p class='#{recommend_name_class(node)}'></p>").first
|
41
|
+
name = node.at(ns("./name")) and name.children.each do |n|
|
42
|
+
b << n
|
43
|
+
end
|
44
|
+
title = node.at(ns("./title"))
|
45
|
+
return unless title &&
|
46
|
+
node.ancestors("requirement, recommendation, permission").empty?
|
47
|
+
|
48
|
+
b << l10n(": ") if name
|
49
|
+
title.children.each { |n| b << n }
|
50
|
+
end
|
51
|
+
|
52
|
+
def recommendation_attributes(node, out)
|
53
|
+
ins = out.add_child("<tbody></tbody>").first
|
54
|
+
recommend_title(node, ins)
|
55
|
+
recommendation_attributes1(node).each do |i|
|
56
|
+
ins.add_child("<tr><td>#{i[0]}</td><td>#{i[1]}</td></tr>")
|
57
|
+
end
|
58
|
+
ins
|
59
|
+
end
|
60
|
+
|
61
|
+
def recommend_title(node, out)
|
62
|
+
label = node.at(ns("./identifier")) or return
|
63
|
+
b = out.add_child("<tr><td colspan='2'><p></p></td></tr>")
|
64
|
+
p = b.at(ns(".//p"))
|
65
|
+
p["class"] = "RecommendationLabel"
|
66
|
+
p << label.children.to_xml
|
67
|
+
end
|
68
|
+
|
69
|
+
def recommendation_attributes1(node)
|
70
|
+
ret = recommendation_attributes1_head(node, [])
|
71
|
+
node.xpath(ns("./classification")).each do |c|
|
72
|
+
line = recommendation_attr_keyvalue(c, "tag",
|
73
|
+
"value") and ret << line
|
74
|
+
end
|
75
|
+
ret
|
76
|
+
end
|
77
|
+
|
78
|
+
def recommendation_attributes1_head(node, head)
|
79
|
+
oblig = node["obligation"] and head << ["Obligation", oblig]
|
80
|
+
subj = node.at(ns("./subject"))&.children and
|
81
|
+
head << [rec_subj(node), subj]
|
82
|
+
node.xpath(ns("./classification[tag = 'target']/value")).each do |v|
|
83
|
+
xref = recommendation_id(node.document, v.text) and head << [
|
84
|
+
rec_target(node), xref
|
85
|
+
]
|
86
|
+
end
|
87
|
+
%w(general class).include?(node["type"]) and
|
88
|
+
xref = recommendation_link(node.document,
|
89
|
+
node.at(ns("./identifier"))&.text) and
|
90
|
+
head << ["Conformance test", xref]
|
91
|
+
recommendation_attributes1_dependencies(node, head)
|
92
|
+
end
|
93
|
+
|
94
|
+
def recommendation_attributes1_dependencies(node, head)
|
95
|
+
node.xpath(ns("./inherit")).each do |i|
|
96
|
+
head << ["Dependency",
|
97
|
+
recommendation_id(node.document, i.children.to_xml)]
|
98
|
+
end
|
99
|
+
node.xpath(ns("./classification[tag = 'indirect-dependency']/value"))
|
100
|
+
.each do |v|
|
101
|
+
xref = recommendation_id(node.document, v.children.to_xml) and
|
102
|
+
head << ["Indirect Dependency", xref]
|
103
|
+
end
|
104
|
+
head
|
105
|
+
end
|
106
|
+
|
107
|
+
def recommendation_steps(node)
|
108
|
+
node.elements.each { |e| recommendation_steps(e) }
|
109
|
+
return node unless node.at(ns("./component[@class = 'step']"))
|
110
|
+
|
111
|
+
d = node.at(ns("./component[@class = 'step']"))
|
112
|
+
d = d.replace("<ol class='steps'><li>#{d.children.to_xml}</li></ol>")
|
113
|
+
.first
|
114
|
+
node.xpath(ns("./component[@class = 'step']")).each do |f|
|
115
|
+
f = f.replace("<li>#{f.children.to_xml}</li>").first
|
116
|
+
d << f
|
117
|
+
end
|
118
|
+
node
|
119
|
+
end
|
120
|
+
|
121
|
+
def recommendation_attributes1_component(node, out)
|
122
|
+
node = recommendation_steps(node)
|
123
|
+
out << "<tr><td>#{node['label']}</td><td>#{node.children}</td></tr>"
|
124
|
+
out
|
125
|
+
end
|
126
|
+
|
127
|
+
def recommendation_attr_keyvalue(node, key, value)
|
128
|
+
tag = node.at(ns("./#{key}"))
|
129
|
+
value = node.at(ns("./#{value}"))
|
130
|
+
(tag && value && !%w(target
|
131
|
+
indirect-dependency).include?(tag.text)) or
|
132
|
+
return nil
|
133
|
+
[tag.text.capitalize, value.children]
|
134
|
+
end
|
135
|
+
|
136
|
+
def reqt_component_type(node)
|
137
|
+
klass = node.name
|
138
|
+
klass == "component" and klass = node["class"]
|
139
|
+
"requirement-#{klass}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def preserve_in_nested_table?(node)
|
143
|
+
%w(recommendation requirement permission
|
144
|
+
table ol dl ul).include?(node.name)
|
145
|
+
end
|
146
|
+
|
147
|
+
def requirement_component_parse(node, out)
|
148
|
+
return out if node["exclude"] == "true"
|
149
|
+
|
150
|
+
node.elements.size == 1 && node.first_element_child.name == "dl" and
|
151
|
+
return reqt_dl(node.first_element_child, out)
|
152
|
+
node.name == "component" and
|
153
|
+
return recommendation_attributes1_component(node, out)
|
154
|
+
out.add_child("<tr><td colspan='2'></td></tr>").first
|
155
|
+
.at(ns(".//td")) <<
|
156
|
+
(preserve_in_nested_table?(node) ? node : node.children)
|
157
|
+
out
|
158
|
+
end
|
159
|
+
|
160
|
+
def reqt_dl(node, out)
|
161
|
+
node.xpath(ns("./dt")).each do |dt|
|
162
|
+
dd = dt.next_element
|
163
|
+
dd&.name == "dd" or next
|
164
|
+
out.add_child("<tr><td>#{dt.children.to_xml}</td>"\
|
165
|
+
"<td>#{dd.children.to_xml}</td></tr>")
|
166
|
+
end
|
167
|
+
out
|
168
|
+
end
|
169
|
+
|
170
|
+
def requirement_table_cleanup(table)
|
171
|
+
return table unless table["type"] == "recommendclass"
|
172
|
+
|
173
|
+
table.xpath(ns("./tbody/tr/td/table")).each do |t|
|
174
|
+
t.xpath(ns("./thead | ./tbody |./tfoot")).each do |x|
|
175
|
+
x.replace(x.children)
|
176
|
+
end
|
177
|
+
(x = t.at(ns("./tr/th[@colspan = '2']"))) &&
|
178
|
+
(y = t.at(ns("./tr/td[@colspan = '2']"))) and
|
179
|
+
requirement_table_cleanup1(x, y)
|
180
|
+
t.parent.parent.replace(t.children)
|
181
|
+
end
|
182
|
+
table
|
183
|
+
end
|
184
|
+
|
185
|
+
# table nested in table: merge label and caption into a single row
|
186
|
+
def requirement_table_cleanup1(outer, inner)
|
187
|
+
outer.delete("colspan")
|
188
|
+
outer.delete("scope")
|
189
|
+
inner.delete("colspan")
|
190
|
+
inner.delete("scope")
|
191
|
+
outer.name = "td"
|
192
|
+
p = outer.at(ns("./p[@class = 'RecommendationTitle']")) and
|
193
|
+
p.delete("class")
|
194
|
+
outer.parent << inner.dup
|
195
|
+
inner.parent.remove
|
196
|
+
end
|
197
|
+
|
198
|
+
def rec_subj(node)
|
199
|
+
case node["type"]
|
200
|
+
when "class" then "Target type"
|
201
|
+
else "Subject"
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def rec_target(node)
|
206
|
+
case node["type"]
|
207
|
+
when "class" then "Target type"
|
208
|
+
when "conformanceclass" then "Requirements class"
|
209
|
+
when "verification", "abstracttest" then "Requirement"
|
210
|
+
else "Target"
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def recommend_class(node)
|
215
|
+
case node["type"]
|
216
|
+
when "verification", "abstracttest" then "recommendtest"
|
217
|
+
when "class", "conformanceclass" then "recommendclass"
|
218
|
+
else "recommend"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def recommend_name_class(node)
|
223
|
+
if %w(verification abstracttest).include?(node["type"])
|
224
|
+
"RecommendationTestTitle"
|
225
|
+
else "RecommendationTitle"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def recommend_component_label(node)
|
230
|
+
case node["class"]
|
231
|
+
when "test-purpose" then "Test purpose"
|
232
|
+
when "test-method" then "Test method"
|
233
|
+
else Metanorma::Utils.strict_capitalize_first(node["class"])
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Metanorma
|
2
|
+
class Requirements
|
3
|
+
class Modspec < Default
|
4
|
+
def recommendation_label(elem, type, xrefs)
|
5
|
+
label = elem.at(ns("./identifier"))&.text
|
6
|
+
if inject_crossreference_reqt?(elem, label)
|
7
|
+
number = xrefs.anchor(reqtlabels(elem.document, label), :xref, false)
|
8
|
+
number.nil? ? type : number
|
9
|
+
else
|
10
|
+
type = recommendation_class_label(elem)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def reqtlabels(doc, label)
|
16
|
+
@reqtlabels ||= doc
|
17
|
+
.xpath(ns("//requirement | //recommendation | //permission"))
|
18
|
+
.each_with_object({}) do |r, m|
|
19
|
+
l = r.at(ns("./label"))&.text and m[l] = r["id"]
|
20
|
+
end
|
21
|
+
@reqtlabels[label]
|
22
|
+
end
|
23
|
+
|
24
|
+
# embedded reqts xref to top level reqts via label lookup
|
25
|
+
def inject_crossreference_reqt?(node, label)
|
26
|
+
!node.ancestors("requirement, recommendation, permission").empty? &&
|
27
|
+
reqtlabels(node.document, label)
|
28
|
+
end
|
29
|
+
|
30
|
+
def recommendation_class_label(node)
|
31
|
+
case node["type"]
|
32
|
+
when "verification" then @labels["#{node.name}test"]
|
33
|
+
when "class" then @labels["#{node.name}class"]
|
34
|
+
when "abstracttest" then @labels["abstracttest"]
|
35
|
+
when "conformanceclass" then @labels["conformanceclass"]
|
36
|
+
else
|
37
|
+
case node.name
|
38
|
+
when "recommendation" then @labels["recommendation"]
|
39
|
+
when "requirement" then @labels["requirement"]
|
40
|
+
when "permission" then @labels["permission"]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def reqt_ids(docxml)
|
46
|
+
docxml.xpath(ns("//requirement | //recommendation | //permission"))
|
47
|
+
.each_with_object({}) do |r, m|
|
48
|
+
id = r.at(ns("./identifier")) or next
|
49
|
+
m[id.text] = r["id"]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def reqt_links(docxml)
|
54
|
+
docxml.xpath(ns("//requirement | //recommendation | //permission"))
|
55
|
+
.each_with_object({}) do |r, m|
|
56
|
+
next unless %w(conformanceclass
|
57
|
+
verification).include?(r["type"])
|
58
|
+
|
59
|
+
subj = r.at(ns("./classification[tag = 'target']/value"))
|
60
|
+
id = r.at(ns("./identifier"))
|
61
|
+
next unless subj && id
|
62
|
+
|
63
|
+
m[subj.text] = { lbl: id.text, id: r["id"] }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def recommendation_link(docxml, ident)
|
68
|
+
@reqt_links ||= reqt_links(docxml)
|
69
|
+
test = @reqt_links[ident&.strip] or return nil
|
70
|
+
"<xref target='#{test[:id]}'>#{test[:lbl]}</xref>"
|
71
|
+
end
|
72
|
+
|
73
|
+
def recommendation_id(docxml, ident)
|
74
|
+
@reqt_ids ||= reqt_ids(docxml)
|
75
|
+
test = @reqt_ids[ident&.strip] or return ident&.strip
|
76
|
+
"<xref target='#{test}'>#{ident.strip}</xref>"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Metanorma
|
2
|
+
class Requirements
|
3
|
+
class Modspec < Default
|
4
|
+
def req_class_paths
|
5
|
+
[
|
6
|
+
{ klass: "permissionclass", label: "permissionclass",
|
7
|
+
xpath: "permission[@type = 'class']" },
|
8
|
+
{ klass: "requirementclass", label: "requirementclass",
|
9
|
+
xpath: "requirement[@type = 'class']" },
|
10
|
+
{ klass: "recommendationclass", label: "recommendationclass",
|
11
|
+
xpath: "recommendation[@type = 'class']" },
|
12
|
+
{ klass: "permissiontest", label: "permissiontest",
|
13
|
+
xpath: "permission[@type = 'verification']" },
|
14
|
+
{ klass: "recommendationtest", label: "recommendationtest",
|
15
|
+
xpath: "recommendation[@type = 'verification']" },
|
16
|
+
{ klass: "requirementtest", label: "requirementtest",
|
17
|
+
xpath: "requirement[@type = 'verification']" },
|
18
|
+
{ klass: "abstracttest", label: "abstracttest",
|
19
|
+
xpath: "permission[@type = 'abstracttest']" },
|
20
|
+
{ klass: "abstracttest", label: "abstracttest",
|
21
|
+
xpath: "requirement[@type = 'abstracttest']" },
|
22
|
+
{ klass: "abstracttest", label: "abstracttest",
|
23
|
+
xpath: "recommendation[@type = 'abstracttest']" },
|
24
|
+
{ klass: "conformanceclass", label: "conformanceclass",
|
25
|
+
xpath: "permission[@type = 'conformanceclass']" },
|
26
|
+
{ klass: "conformanceclass", label: "conformanceclass",
|
27
|
+
xpath: "requirement[@type = 'conformanceclass']" },
|
28
|
+
{ klass: "conformanceclass", label: "conformanceclass",
|
29
|
+
xpath: "recommendation[@type = 'conformanceclass']" },
|
30
|
+
{ klass: "permission", label: "permission",
|
31
|
+
xpath: "permission[not(@type = 'verification' or @type = 'class' "\
|
32
|
+
"or @type = 'abstracttest' or @type = 'conformanceclass')]" },
|
33
|
+
{ klass: "recommendation", label: "recommendation",
|
34
|
+
xpath: "recommendation[not(@type = 'verification' or "\
|
35
|
+
"@type = 'class' or @type = 'abstracttest' or "\
|
36
|
+
"@type = 'conformanceclass')]" },
|
37
|
+
{ klass: "requirement", label: "requirement",
|
38
|
+
xpath: "requirement[not(@type = 'verification' or @type = 'class' "\
|
39
|
+
"or @type = 'abstracttest' or @type = 'conformanceclass')]" },
|
40
|
+
]
|
41
|
+
end
|
42
|
+
|
43
|
+
def req_nested_class_paths
|
44
|
+
req_class_paths
|
45
|
+
end
|
46
|
+
|
47
|
+
def permission_parts(block, block_id, label, klass)
|
48
|
+
block.xpath(ns("./component[@class = 'part']"))
|
49
|
+
.each_with_index.with_object([]) do |(c, i), m|
|
50
|
+
next if c["id"].nil? || c["id"].empty?
|
51
|
+
|
52
|
+
m << { id: c["id"], number: l10n("#{block_id} #{(i + 'A'.ord).chr}"),
|
53
|
+
elem: c, label: label, klass: klass }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def postprocess_anchor_struct(block, anchor)
|
58
|
+
super
|
59
|
+
if l = block.at(ns("./identifier"))&.text
|
60
|
+
anchor[:xref] += l10n(": ") + "<tt>#{l}</tt>"
|
61
|
+
end
|
62
|
+
anchor
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require_relative "../default/default"
|
2
|
+
require_relative "../modspec/modspec"
|
3
|
+
require "isodoc-i18n"
|
4
|
+
|
5
|
+
module Metanorma
|
6
|
+
class Requirements
|
7
|
+
attr_accessor :i18n, :labels
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@default = options[:default]
|
11
|
+
@i18n = ::IsoDoc::I18n.new(options[:lang] || "en",
|
12
|
+
options[:script] || "Latn")
|
13
|
+
@labels = options[:labels]
|
14
|
+
@models = {}
|
15
|
+
model_names.each { |k| @models[k] = create(k) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def model_names
|
19
|
+
%i[default ogc]
|
20
|
+
end
|
21
|
+
|
22
|
+
# all roles that can be assigned to an example to make it a reqt,
|
23
|
+
# across all models (because the model may not be an attribute but
|
24
|
+
# embedded in the definition list). Mapped to obligation
|
25
|
+
# TODO may need to make it conditional on model
|
26
|
+
def requirement_roles
|
27
|
+
{
|
28
|
+
recommendation: "recommendation",
|
29
|
+
requirement: "requirement",
|
30
|
+
permission: "permission",
|
31
|
+
requirements_class: "requirement",
|
32
|
+
conformance_test: "requirement",
|
33
|
+
conformance_class: "requirement",
|
34
|
+
abstract_test: "requirement",
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def create(type)
|
39
|
+
case type
|
40
|
+
when :modspec, :ogc
|
41
|
+
Metanorma::Requirements::Modspec.new(parent: self)
|
42
|
+
else Metanorma::Requirements::Default.new(parent: self)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def model(type)
|
47
|
+
@models[type&.to_sym] || @models[@default]
|
48
|
+
end
|
49
|
+
|
50
|
+
REQRECPER = "//requirement | //recommendation | //permission".freeze
|
51
|
+
|
52
|
+
# all cleanup steps by all possible models are included here, and each model
|
53
|
+
# can skip a given step. This class iterates through the entire document,
|
54
|
+
# and picks the model for each requirement; then that model's method is
|
55
|
+
# applied to that particular requirement instance
|
56
|
+
def requirement_cleanup(xmldoc)
|
57
|
+
requirement_metadata_cleanup(xmldoc)
|
58
|
+
requirement_type_cleanup(xmldoc)
|
59
|
+
requirement_inherit_cleanup(xmldoc)
|
60
|
+
requirement_descriptions_cleanup(xmldoc)
|
61
|
+
requirement_identifier_cleanup(xmldoc)
|
62
|
+
end
|
63
|
+
|
64
|
+
def requirement_type_cleanup(xmldoc)
|
65
|
+
xmldoc.xpath(REQRECPER).each do |r|
|
66
|
+
model(r["model"]).requirement_type_cleanup(r)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def requirement_metadata_cleanup(xmldoc)
|
71
|
+
xmldoc.xpath(REQRECPER).each do |r|
|
72
|
+
model(r["model"]).requirement_metadata_cleanup(r)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def requirement_inherit_cleanup(xmldoc)
|
77
|
+
xmldoc.xpath(REQRECPER).each do |r|
|
78
|
+
model(r["model"]).requirement_inherit_cleanup(r)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def requirement_descriptions_cleanup(xmldoc)
|
83
|
+
xmldoc.xpath(REQRECPER).each do |r|
|
84
|
+
model(r["model"]).requirement_descriptions_cleanup(r)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def requirement_identifier_cleanup(xmldoc)
|
89
|
+
xmldoc.xpath(REQRECPER).each do |r|
|
90
|
+
model(r["model"]).requirement_identifier_cleanup(r)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "metanorma/requirements/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "mn-requirements"
|
7
|
+
spec.version = Metanorma::Requirements::VERSION
|
8
|
+
spec.authors = ["Ribose Inc."]
|
9
|
+
spec.email = ["open.source@ribose.com"]
|
10
|
+
|
11
|
+
spec.summary = "Requirements processing and rendering according to different models"
|
12
|
+
spec.description = <<~DESCRIPTION
|
13
|
+
Requirements processing and rendering according to different models
|
14
|
+
DESCRIPTION
|
15
|
+
|
16
|
+
spec.homepage = "https://github.com/metanorma/mn-requirements"
|
17
|
+
spec.license = "BSD-2-Clause"
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(test|spec|features)/})
|
21
|
+
end
|
22
|
+
spec.bindir = "exe"
|
23
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
+
spec.require_paths = ["lib"]
|
25
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
26
|
+
|
27
|
+
spec.add_dependency "isodoc-i18n", "~> 1.0.0"
|
28
|
+
spec.add_dependency "metanorma-utils", "~> 1.3.0"
|
29
|
+
|
30
|
+
spec.add_development_dependency "debug"
|
31
|
+
spec.add_development_dependency "equivalent-xml", "~> 0.6"
|
32
|
+
spec.add_development_dependency "guard", "~> 2.14"
|
33
|
+
spec.add_development_dependency "guard-rspec", "~> 4.7"
|
34
|
+
spec.add_development_dependency "isodoc", "~> 2"
|
35
|
+
spec.add_development_dependency "metanorma-standoc", "~> 2"
|
36
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
37
|
+
spec.add_development_dependency "rspec", "~> 3.6"
|
38
|
+
spec.add_development_dependency "rubocop", "~> 1.5.2"
|
39
|
+
spec.add_development_dependency "sassc", "2.4.0"
|
40
|
+
spec.add_development_dependency "simplecov", "~> 0.15"
|
41
|
+
spec.add_development_dependency "timecop", "~> 0.9"
|
42
|
+
end
|