dim-toolkit 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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 +4 -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'
|