dim-toolkit 2.1.0 → 2.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 +4 -4
- data/bin/dim +9 -9
- data/lib/dim/commands/check.rb +13 -13
- data/lib/dim/commands/export.rb +145 -145
- data/lib/dim/commands/format.rb +196 -198
- data/lib/dim/commands/stats.rb +64 -64
- data/lib/dim/consistency.rb +157 -187
- data/lib/dim/dimmain.rb +28 -28
- data/lib/dim/encoding.rb +4 -4
- data/lib/dim/exit_helper.rb +23 -23
- data/lib/dim/exporter/csv.rb +24 -25
- data/lib/dim/exporter/exporterInterface.rb +37 -37
- data/lib/dim/exporter/json.rb +30 -32
- data/lib/dim/exporter/rst.rb +142 -142
- data/lib/dim/ext/psych.rb +63 -63
- data/lib/dim/ext/string.rb +85 -85
- data/lib/dim/globals.rb +12 -12
- data/lib/dim/helpers/attribute_helper.rb +126 -126
- data/lib/dim/helpers/file_helper.rb +25 -25
- data/lib/dim/loader.rb +561 -581
- data/lib/dim/options.rb +116 -116
- data/lib/dim/requirement.rb +217 -236
- data/lib/dim/ver.rb +7 -7
- data/lib/dim.rb +1 -1
- data/license.txt +205 -205
- data/version.txt +1 -1
- metadata +6 -4
data/lib/dim/requirement.rb
CHANGED
@@ -1,236 +1,217 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
require_relative 'globals'
|
4
|
-
require_relative 'exit_helper'
|
5
|
-
require_relative 'ext/string'
|
6
|
-
|
7
|
-
module Dim
|
8
|
-
class Requirement
|
9
|
-
attr_accessor :data, :
|
10
|
-
:category, :line_number, :all_attributes, :upstreamRefs, :downstreamRefs, :category_level
|
11
|
-
|
12
|
-
# rubocop:disable Layout/LineLength, Layout/HashAlignment
|
13
|
-
SYNTAX = {
|
14
|
-
'type' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: 'requirement',
|
15
|
-
allowed: %w[requirement information heading_<level>] },
|
16
|
-
'text' => { check: nil, format_style: :text, format_shift: 28, default: '', allowed: nil },
|
17
|
-
'verification_criteria' => { check: nil, format_style: :text, format_shift: 32, default: '', allowed: nil },
|
18
|
-
'feature' => { check: nil, format_style: :text, format_shift: 0, default: '', allowed: nil },
|
19
|
-
'change_request' => { check: nil, format_style: :text, format_shift: 0, default: '', allowed: nil },
|
20
|
-
'tags' => { check: nil, format_style: :list, format_shift: 0, default: '', allowed: nil },
|
21
|
-
'asil' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: 'not_set',
|
22
|
-
allowed: %w[not_set
|
23
|
-
QM QM(A) QM(B) QM(C) QM(D)
|
24
|
-
ASIL_A ASIL_A(A) ASIL_A(B) ASIL_A(C) ASIL_A(D)
|
25
|
-
ASIL_B ASIL_B(B) ASIL_B(C) ASIL_B(D)
|
26
|
-
ASIL_C ASIL_C(C) ASIL_C(D)
|
27
|
-
ASIL_D ASIL_D(D)] },
|
28
|
-
'cal' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: 'not_set',
|
29
|
-
allowed: %w[QM CAL_1 CAL_2 CAL_3 CAL_4 not_set] },
|
30
|
-
'developer' => { check: nil, format_style: :list, format_shift: 0, default: nil, allowed: nil },
|
31
|
-
'tester' => { check: nil, format_style: :list, format_shift: 0, default: nil, allowed: nil },
|
32
|
-
'
|
33
|
-
allowed: %w[none off_target on_target manual] },
|
34
|
-
'
|
35
|
-
allowed: %w[
|
36
|
-
'
|
37
|
-
allowed: %w[
|
38
|
-
'
|
39
|
-
|
40
|
-
'
|
41
|
-
'
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
#
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
str
|
72
|
-
return str if
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
@
|
85
|
-
@
|
86
|
-
@
|
87
|
-
@
|
88
|
-
@
|
89
|
-
@
|
90
|
-
@
|
91
|
-
@
|
92
|
-
@
|
93
|
-
@
|
94
|
-
@
|
95
|
-
@
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
return if vm.empty? && ts.empty?
|
220
|
-
|
221
|
-
merged = ts.union(vm).join(', ')
|
222
|
-
@data['test_setups'] = merged
|
223
|
-
@data['verification_methods'] = merged
|
224
|
-
end
|
225
|
-
|
226
|
-
def check_verification_methods
|
227
|
-
vm = @data['verification_methods']&.cleanArray || []
|
228
|
-
return unless vm.include?('none') && vm.length > 1
|
229
|
-
|
230
|
-
vm.delete('none')
|
231
|
-
Dim::ExitHelper.exit(code: 1,
|
232
|
-
filename: filename,
|
233
|
-
msg: "verification_methods or test_setups for \"#{@id}\" can't include 'none' along with #{vm.join(', ')}.")
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
require_relative 'globals'
|
4
|
+
require_relative 'exit_helper'
|
5
|
+
require_relative 'ext/string'
|
6
|
+
|
7
|
+
module Dim
|
8
|
+
class Requirement
|
9
|
+
attr_accessor :data, :document, :depth, :id, :origin, :loader, :existingRefs, :backwardRefs, :filename,
|
10
|
+
:category, :line_number, :all_attributes, :upstreamRefs, :downstreamRefs, :category_level
|
11
|
+
|
12
|
+
# rubocop:disable Layout/LineLength, Layout/HashAlignment
|
13
|
+
SYNTAX = {
|
14
|
+
'type' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: 'requirement',
|
15
|
+
allowed: %w[requirement information heading_<level>] },
|
16
|
+
'text' => { check: nil, format_style: :text, format_shift: 28, default: '', allowed: nil },
|
17
|
+
'verification_criteria' => { check: nil, format_style: :text, format_shift: 32, default: '', allowed: nil },
|
18
|
+
'feature' => { check: nil, format_style: :text, format_shift: 0, default: '', allowed: nil },
|
19
|
+
'change_request' => { check: nil, format_style: :text, format_shift: 0, default: '', allowed: nil },
|
20
|
+
'tags' => { check: nil, format_style: :list, format_shift: 0, default: '', allowed: nil },
|
21
|
+
'asil' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: 'not_set',
|
22
|
+
allowed: %w[not_set
|
23
|
+
QM QM(A) QM(B) QM(C) QM(D)
|
24
|
+
ASIL_A ASIL_A(A) ASIL_A(B) ASIL_A(C) ASIL_A(D)
|
25
|
+
ASIL_B ASIL_B(B) ASIL_B(C) ASIL_B(D)
|
26
|
+
ASIL_C ASIL_C(C) ASIL_C(D)
|
27
|
+
ASIL_D ASIL_D(D)] },
|
28
|
+
'cal' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: 'not_set',
|
29
|
+
allowed: %w[QM CAL_1 CAL_2 CAL_3 CAL_4 not_set] },
|
30
|
+
'developer' => { check: nil, format_style: :list, format_shift: 0, default: nil, allowed: nil },
|
31
|
+
'tester' => { check: nil, format_style: :list, format_shift: 0, default: nil, allowed: nil },
|
32
|
+
'verification_methods' => { check: :check_multi_enum, format_style: :multi, format_shift: 0, default: nil,
|
33
|
+
allowed: %w[none off_target on_target manual] },
|
34
|
+
'status' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: nil,
|
35
|
+
allowed: %w[valid draft invalid] },
|
36
|
+
'review_status' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: nil,
|
37
|
+
allowed: %w[accepted unclear rejected not_reviewed not_relevant] },
|
38
|
+
'comment' => { check: nil, format_style: :text, format_shift: 0, default: '', allowed: nil },
|
39
|
+
'miscellaneous' => { check: nil, format_style: :text, format_shift: 0, default: '', allowed: nil },
|
40
|
+
'sources' => { check: nil, format_style: :split, format_shift: 0, default: '', allowed: nil },
|
41
|
+
'refs' => { check: nil, format_style: :split, format_shift: 0, default: '', allowed: nil }
|
42
|
+
}
|
43
|
+
# rubocop:enable Layout/LineLength, Layout/HashAlignment
|
44
|
+
|
45
|
+
# this allows easy access to attribute names
|
46
|
+
SYNTAX.each_key do |k|
|
47
|
+
if %i[list multi split].include?(SYNTAX[k][:format_style])
|
48
|
+
define_method(k) do
|
49
|
+
@data[k].cleanUniqArray
|
50
|
+
end
|
51
|
+
else
|
52
|
+
define_method(k) do
|
53
|
+
@data[k]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def safety_relevant?
|
59
|
+
!%w[QM not_set].include?(@data['asil'])
|
60
|
+
end
|
61
|
+
|
62
|
+
def security_relevant?
|
63
|
+
!%w[QM not_set].include?(@data['cal'])
|
64
|
+
end
|
65
|
+
|
66
|
+
# this allows writing enum values without " in filter
|
67
|
+
alias method_missing_org method_missing
|
68
|
+
def method_missing(sym, *_args)
|
69
|
+
str = sym.to_s
|
70
|
+
return str if /\Aheading_(\d+)\z/ === str
|
71
|
+
return str if SYNTAX.any? { |_name, attr| attr[:allowed].is_a?(Array) && attr[:allowed].include?(str) }
|
72
|
+
return str if %w[input software architecture module system].include?(str)
|
73
|
+
|
74
|
+
Dim::ExitHelper.exit(code: 1, msg: "\"#{str}\" is not a requirement attribute")
|
75
|
+
end
|
76
|
+
|
77
|
+
def filter(str)
|
78
|
+
eval(str)
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize(id, document, filename, attr, origin, loader, category, line_number, all_attributes)
|
82
|
+
@id = id
|
83
|
+
@document = document
|
84
|
+
@filename = filename
|
85
|
+
@data = attr
|
86
|
+
@origin = origin
|
87
|
+
@existingRefs = [] # needed later for "missing links" feature
|
88
|
+
@backwardRefs = []
|
89
|
+
@upstreamRefs = []
|
90
|
+
@downstreamRefs = []
|
91
|
+
@loader = loader
|
92
|
+
@category = category
|
93
|
+
@category_level = CATEGORY_ORDER[category] || 0
|
94
|
+
@line_number = line_number
|
95
|
+
@all_attributes = all_attributes
|
96
|
+
|
97
|
+
define_custom_attribute_methods
|
98
|
+
calc_depth
|
99
|
+
|
100
|
+
check_unknown_keys
|
101
|
+
check_invalid_values
|
102
|
+
check_verification_methods
|
103
|
+
end
|
104
|
+
|
105
|
+
def define_custom_attribute_methods
|
106
|
+
new_attributes = @all_attributes.keys - SYNTAX.keys
|
107
|
+
new_attributes.each do |k|
|
108
|
+
define_singleton_method(k) do
|
109
|
+
@data[k]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def calc_depth
|
115
|
+
@depth = 1
|
116
|
+
hres = @data['type']&.scan(/^heading_(\d+)$/) || ''
|
117
|
+
return unless hres.length > 0
|
118
|
+
|
119
|
+
dep = hres[0][0].to_i
|
120
|
+
return unless dep > 1
|
121
|
+
|
122
|
+
if dep > 100
|
123
|
+
Dim::ExitHelper.exit(
|
124
|
+
code: 1,
|
125
|
+
filename: filename,
|
126
|
+
msg: "heading level above 100 is not allowed and makes absolutely no sense: #{@data['type']}"
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
@depth = dep
|
131
|
+
end
|
132
|
+
|
133
|
+
def check_single_enum(elem, key, value)
|
134
|
+
unless !elem[:allowed].include?(value) && !(elem[:allowed].include?('heading_<level>') && /\Aheading_\d+\Z/ === value)
|
135
|
+
return
|
136
|
+
end
|
137
|
+
|
138
|
+
allowed_values = elem[:allowed].reject{ |a| a.nil? || a.empty? }.map { |e| "\"#{e}\"" }.join(', ')
|
139
|
+
Dim::ExitHelper.exit(
|
140
|
+
code: 1,
|
141
|
+
filename: filename,
|
142
|
+
msg: "attribute \"#{key}\" must not be \"#{value}\" (id: #{@id}). \"#{key}\" must be exactly " \
|
143
|
+
"one of #{allowed_values}. #{"Default is \"#{elem[:default]}\"" if elem[:default]}."
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
def check_multi_enum(element, key, value)
|
148
|
+
value_array = value.cleanArray
|
149
|
+
value_array = [''] if value == ''
|
150
|
+
value_array.each do |v|
|
151
|
+
next if element[:allowed].include?(v)
|
152
|
+
|
153
|
+
allowed_values = element[:allowed].reject{ |a| a.nil? || a.empty? }.map { |e| "\"#{e}\"" }.join(', ')
|
154
|
+
Dim::ExitHelper.exit(
|
155
|
+
code: 1,
|
156
|
+
filename: filename,
|
157
|
+
msg: "attribute \"#{key}\" is invalid: \"#{v}\" (id: #{@id}). \"#{key}\" must be one or " \
|
158
|
+
"more of #{allowed_values}."
|
159
|
+
)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def check_unknown_keys
|
164
|
+
ks = @all_attributes.keys
|
165
|
+
# sort reverse so that language keys are inserted into Requirement::SYNTAX in alphabetical order
|
166
|
+
@data.keys.sort.reverse.each do |k|
|
167
|
+
if /\A(text_|verification_criteria_|comment_)./ === k
|
168
|
+
unless @all_attributes.include?(k)
|
169
|
+
reference_key = k.gsub(/(text|verification_criteria|comment).*/, '\\1')
|
170
|
+
reference_settings = @all_attributes[reference_key]
|
171
|
+
# rebuild the hash to change the iteration order for later processing like formatting
|
172
|
+
tmp = @all_attributes.dup
|
173
|
+
@all_attributes.clear
|
174
|
+
tmp.each do |key, value|
|
175
|
+
@all_attributes[key] = value
|
176
|
+
next unless key == reference_key
|
177
|
+
|
178
|
+
@all_attributes[k] = {
|
179
|
+
check: nil,
|
180
|
+
new: '',
|
181
|
+
default: '',
|
182
|
+
allowed: nil,
|
183
|
+
format_style: reference_settings[:format_style],
|
184
|
+
format_shift: reference_settings[:format_shift]
|
185
|
+
}
|
186
|
+
end
|
187
|
+
loader.requirements.each { |_id, r| r.data[k] = '' }
|
188
|
+
Dim::Requirement.define_method(k) do
|
189
|
+
@data[k]
|
190
|
+
end
|
191
|
+
end
|
192
|
+
next
|
193
|
+
end
|
194
|
+
|
195
|
+
Dim::ExitHelper.exit(code: 1, filename: filename, msg: "attribute #{k} not allowed") unless ks.include?(k)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def check_invalid_values
|
200
|
+
@data.each do |k, v|
|
201
|
+
if @all_attributes.key?(k) && (@all_attributes[k][:check])
|
202
|
+
send(@all_attributes[k][:check], @all_attributes[k], k, v)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def check_verification_methods
|
208
|
+
vm = @data['verification_methods']&.cleanArray || []
|
209
|
+
return unless vm.include?('none') && vm.length > 1
|
210
|
+
|
211
|
+
vm.delete('none')
|
212
|
+
Dim::ExitHelper.exit(code: 1,
|
213
|
+
filename: filename,
|
214
|
+
msg: "verification_methods for \"#{@id}\" can't include 'none' along with #{vm.join(', ')}.")
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
data/lib/dim/ver.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
module Dim
|
2
|
-
class Ver
|
3
|
-
def self.sion
|
4
|
-
File.read(File.dirname(__FILE__) + '/../../version.txt').strip
|
5
|
-
end
|
6
|
-
end
|
7
|
-
end
|
1
|
+
module Dim
|
2
|
+
class Ver
|
3
|
+
def self.sion
|
4
|
+
File.read(File.dirname(__FILE__) + '/../../version.txt').strip
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
data/lib/dim.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require 'dim/dimmain'
|
1
|
+
require 'dim/dimmain'
|