mn-requirements 0.2.2 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 30c82855931f4c0fb8b033a7fcb15583826ef041cee6ff1c4630570abd42a074
4
- data.tar.gz: c3765be67270e9fdad7d61b30654ce5a7ed5a7327d3b77598170354cd930c91a
3
+ metadata.gz: 4f81b57e8350c7018f06bb68420de8d7b409b7f9ff4b81eb0d98d06f484e246e
4
+ data.tar.gz: 771ba5edb39491ad133dfc2d8cacaba2e11a0eba8b95389a2d834ddd84d0227a
5
5
  SHA512:
6
- metadata.gz: '098e5bd08fdb6628f7b493e5cbdde2ff793168008837f5b0184034ed79e202a31295d29ba8e5707aa56c2abfdee7bf31c8a7677ed7deb3f7fc2732e9f731cb6e'
7
- data.tar.gz: ddcd729ae096912a304b1763092c135d5967f1a21d35f5f907dc16b408c75e8c64c3ba1864fd5941d08b36e77e6051e339353b6f19e92244e700f775c4dd5c21
6
+ metadata.gz: 38d500ecb762b731b2ef373c55c67b0cfef8e4a93bfcf4619d629c6fe69fae635c4362502bf3235a94f3b5cfbab7248fcd5e7110c42640916bd4e3b3b33e21dc
7
+ data.tar.gz: 8d5c5b770acd55b9b0006345f3c743e863239257c353626e4f56f0cb50dc218f9512338080e30bec75160e89b61bf85b747296ead049480812625799cc3fc74e
@@ -95,7 +95,9 @@ module Metanorma
95
95
  end.join("\n")
96
96
  end
97
97
 
98
- def validate(reqt, log); end
98
+ def validate(_reqt, _log)
99
+ []
100
+ end
99
101
  end
100
102
  end
101
103
  end
@@ -197,9 +197,9 @@ module Metanorma
197
197
  end
198
198
 
199
199
  def requirement_description_parse(node, out)
200
- lbl = "statement"
201
- recommend_class(node.parent) == "recommendclass" and
202
- lbl = "description"
200
+ lbl = "description"
201
+ recommend_class(node.parent) == "recommend" and
202
+ lbl = "statement"
203
203
  out << "<tr><th>#{@labels['modspec'][lbl]}</th>" \
204
204
  "<td>#{node.children.to_xml}</td></tr>"
205
205
  out
@@ -1,3 +1,10 @@
1
+ class Nokogiri::XML::Document
2
+ def reqt_iter(&block)
3
+ xpath("//xmlns:requirement | //xmlns:recommendation | //xmlns:permission")
4
+ .each_with_object({}, &block)
5
+ end
6
+ end
7
+
1
8
  module Metanorma
2
9
  class Requirements
3
10
  class Modspec < Default
@@ -36,10 +43,9 @@ module Metanorma
36
43
  end
37
44
 
38
45
  def reqtlabels(doc)
39
- doc.xpath(ns("//requirement | //recommendation | //permission"))
40
- .each_with_object({}) do |r, m|
41
- l = r.at(ns("./identifier"))&.text and m[l] = r["id"]
42
- end
46
+ doc.reqt_iter do |r, m|
47
+ l = r.at(ns("./identifier"))&.text and m[l] = r["id"]
48
+ end
43
49
  end
44
50
 
45
51
  # embedded reqts xref to reqts via label lookup
@@ -64,30 +70,23 @@ module Metanorma
64
70
  end
65
71
 
66
72
  def reqt_ids(docxml)
67
- docxml.xpath(ns("//requirement | //recommendation | //permission"))
68
- .each_with_object({}) do |r, m|
69
- id = r.at(ns("./identifier")) or next
70
- m[id.text] =
71
- { id: r["id"], lbl: @xrefs.anchor(r["id"], :xref, false) }
72
- end
73
+ docxml.reqt_iter do |r, m|
74
+ id = r.at(ns("./identifier")) or next
75
+ m[id.text] =
76
+ { id: r["id"], lbl: @xrefs.anchor(r["id"], :xref, false) }
77
+ end
73
78
  end
74
79
 
75
80
  def reqt_links_test(docxml)
76
- docxml.xpath(ns("//requirement | //recommendation | //permission"))
77
- .each_with_object({}) do |r, m|
78
- reqt_links_test1(r, m)
79
- end
81
+ docxml.reqt_iter { |r, m| reqt_links_test1(r, m) }
80
82
  end
81
83
 
82
84
  def reqt_links_test1(reqt, acc)
83
- return unless %w(conformanceclass
84
- verification).include?(reqt["type"])
85
-
85
+ %w(conformanceclass verification).include?(reqt["type"]) or return
86
86
  subj = reqt_extract_target(reqt)
87
87
  id = reqt.at(ns("./identifier")) or return
88
88
  lbl = @xrefs.anchor(@reqt_ids[id.text.strip][:id], :xref, false)
89
- return unless subj && lbl
90
-
89
+ (subj && lbl) or return
91
90
  acc[subj.text] = { lbl: lbl, id: reqt["id"] }
92
91
  end
93
92
 
@@ -110,23 +109,20 @@ module Metanorma
110
109
 
111
110
  # we have not implemented multiple levels of nesting of classes
112
111
  def reqt_links_class(docxml)
113
- docxml.xpath(ns("//requirement | //recommendation | //permission"))
114
- .each_with_object({}) do |r, m|
115
- next unless %w(class conformanceclass).include?(r["type"])
116
-
117
- id = r.at(ns("./identifier")) or next
118
- r.xpath(ns("./requirement | ./recommendation | ./permission"))
119
- .each do |r1|
120
- m = reqt_links_class1(id, r, r1, m)
121
- end
112
+ docxml.reqt_iter do |r, m|
113
+ %w(class conformanceclass).include?(r["type"]) or next
114
+ id = r.at(ns("./identifier")) or next
115
+ r.xpath(ns("./requirement | ./recommendation | ./permission"))
116
+ .each do |r1|
117
+ m = reqt_links_class1(id, r, r1, m)
122
118
  end
119
+ end
123
120
  end
124
121
 
125
122
  def reqt_links_class1(id, parent_reqt, reqt, acc)
126
123
  id1 = reqt.at(ns("./identifier")) or return acc
127
124
  lbl = @xrefs.anchor(@reqt_ids[id.text.strip][:id], :xref, false)
128
- return acc unless lbl
129
-
125
+ lbl or return acc
130
126
  acc[id1.text] = { lbl: lbl, id: parent_reqt["id"] }
131
127
  acc
132
128
  end
@@ -139,10 +135,7 @@ module Metanorma
139
135
  end
140
136
 
141
137
  def reqt_id_base_init(docxml)
142
- docxml.xpath(ns("//requirement | //recommendation | //permission"))
143
- .each_with_object({}) do |r, m|
144
- m[r["id"]] = reqt_extract_id_base(r)&.text
145
- end
138
+ docxml.reqt_iter { |r, m| m[r["id"]] = reqt_extract_id_base(r)&.text }
146
139
  end
147
140
 
148
141
  def reqt_id_base_inherit(ret, class2reqt)
@@ -1,10 +1,15 @@
1
+ require "tsort"
2
+
1
3
  module Metanorma
2
4
  class Requirements
3
5
  class Modspec < Default
4
6
  def validate(reqt, log)
7
+ @fatalerrors = []
5
8
  @log ||= log
6
9
  @ids ||= reqt_links(reqt.document)
10
+ reqt_cycles_validate
7
11
  reqt_link_validate(reqt)
12
+ @fatalerrors
8
13
  end
9
14
 
10
15
  def nested_reqt?(reqt)
@@ -109,17 +114,26 @@ module Metanorma
109
114
  .each_with_object({ id: {}, class: {}, label: {} }) do |r, m|
110
115
  next if nested_reqt?(r)
111
116
 
112
- reqt_links1(r, m)
117
+ reqt_links1(r, m, type2validate(r), reqt_links_struct(r))
113
118
  end
114
119
  end
115
120
 
116
- def reqt_links1(reqt, hash)
117
- type = type2validate(reqt)
118
- a = reqt_links_struct(reqt)
119
- hash[:id][reqt["id"]] = a
121
+ def reqt_links1(reqt, hash, type, struct)
122
+ hash[:id][reqt["id"]] = struct
120
123
  hash[:class][type] ||= []
121
- hash[:class][type] << a
122
- hash[:label][a[:label]] = reqt["id"]
124
+ hash[:class][type] << struct
125
+ reqt_links1_label(reqt, hash, struct)
126
+ end
127
+
128
+ def reqt_links1_label(reqt, hash, struct)
129
+ return hash unless struct[:label]
130
+
131
+ if hash[:label][struct[:label]]
132
+ msg = "Modspec identifier #{struct[:label]} is used more than once"
133
+ @log.add("Requirements", reqt, msg)
134
+ @fatalerrors << msg
135
+ end
136
+ hash[:label][struct[:label]] = reqt["id"]
123
137
  hash
124
138
  end
125
139
 
@@ -140,6 +154,54 @@ module Metanorma
140
154
  indirect_dependency: classif_tag(reqt, "indirect-dependency"),
141
155
  implements: classif_tag(reqt, "implements") }
142
156
  end
157
+
158
+ def reqt_cycles_validate
159
+ @cycles_validated and return
160
+ @cycles_validated = true
161
+ %i(child dependency indirect_dependency implements).each do |x|
162
+ reqt_cycles_validate1(x)
163
+ end
164
+ end
165
+
166
+ def reqt_cycles_validate1(link)
167
+ arr = TSHash.new(@ids[:id].values)
168
+ arr.link = link
169
+ TSort.each_strongly_connected_component(
170
+ lambda { |&b| arr.tsort_each_node(&b) },
171
+ lambda { |n, &b| arr.tsort_each_child(n, &b) },
172
+ ) do |c|
173
+ c.size == 1 and next
174
+ log_cycle(link, c)
175
+ end
176
+ end
177
+
178
+ def log_cycle(link, path)
179
+ @log.add("Requirements", nil, <<~MSG
180
+ Cycle in Modspec linkages through #{link}: #{(path << path.first).join(' => ')}
181
+ MSG
182
+ )
183
+ end
184
+
185
+ class TSHash
186
+ include TSort
187
+ attr_accessor :link
188
+
189
+ def initialize(arr)
190
+ @hash = arr.each_with_object({}) do |v, m|
191
+ m[v[:label]] = v
192
+ end
193
+ end
194
+
195
+ def tsort_each_node(&block)
196
+ @hash.keys.each(&block)
197
+ end
198
+
199
+ def tsort_each_child(node, &block)
200
+ (@hash[node] || {})[@link]&.each(&block)
201
+ end
202
+ end
203
+
204
+ def reqt_cycles_validate_dependency; end
143
205
  end
144
206
  end
145
207
  end
@@ -1,5 +1,5 @@
1
1
  module Metanorma
2
2
  class Requirements
3
- VERSION = "0.2.2".freeze
3
+ VERSION = "0.3.0".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mn-requirements
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-09 00:00:00.000000000 Z
11
+ date: 2022-11-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: isodoc-i18n