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.
@@ -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, :moduleName, :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
- 'test_setups' => { check: :check_multi_enum, format_style: :multi, format_shift: 0, default: nil,
33
- allowed: %w[none off_target on_target manual] },
34
- 'verification_methods' => { check: :check_multi_enum, format_style: :multi, format_shift: 0, default: nil,
35
- allowed: %w[none off_target on_target manual] },
36
- 'status' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: nil,
37
- allowed: %w[valid draft invalid] },
38
- 'review_status' => { check: :check_single_enum, format_style: :single, format_shift: 0, default: nil,
39
- allowed: %w[accepted unclear rejected not_reviewed not_relevant] },
40
- 'comment' => { check: nil, format_style: :text, format_shift: 0, default: '', allowed: nil },
41
- 'miscellaneous' => { check: nil, format_style: :text, format_shift: 0, default: '', allowed: nil },
42
- 'sources' => { check: nil, format_style: :split, format_shift: 0, default: '', allowed: nil },
43
- 'refs' => { check: nil, format_style: :split, format_shift: 0, default: '', allowed: nil }
44
- }
45
- # rubocop:enable Layout/LineLength, Layout/HashAlignment
46
-
47
- # this allows easy access to attribute names
48
- SYNTAX.each_key do |k|
49
- if %i[list multi split].include?(SYNTAX[k][:format_style])
50
- define_method(k) do
51
- @data[k].cleanUniqArray
52
- end
53
- else
54
- define_method(k) do
55
- @data[k]
56
- end
57
- end
58
- end
59
-
60
- def safety_relevant?
61
- !%w[QM not_set].include?(@data['asil'])
62
- end
63
-
64
- def security_relevant?
65
- !%w[QM not_set].include?(@data['cal'])
66
- end
67
-
68
- # this allows writing enum values without " in filter
69
- alias method_missing_org method_missing
70
- def method_missing(sym, *_args)
71
- str = sym.to_s
72
- return str if /\Aheading_(\d+)\z/ === str
73
- return str if SYNTAX.any? { |_name, attr| attr[:allowed].is_a?(Array) && attr[:allowed].include?(str) }
74
- return str if %w[input software architecture module system].include?(str)
75
-
76
- Dim::ExitHelper.exit(code: 1, msg: "\"#{str}\" is not a requirement attribute")
77
- end
78
-
79
- def filter(str)
80
- eval(str)
81
- end
82
-
83
- def initialize(id, document, filename, attr, origin, loader, category, line_number, all_attributes)
84
- @id = id
85
- @moduleName = document
86
- @document = document
87
- @filename = filename
88
- @data = attr
89
- @origin = origin
90
- @existingRefs = [] # needed later for "missing links" feature
91
- @backwardRefs = []
92
- @upstreamRefs = []
93
- @downstreamRefs = []
94
- @loader = loader
95
- @category = category
96
- @category_level = CATEGORY_ORDER[category] || 0
97
- @line_number = line_number
98
- @all_attributes = all_attributes
99
-
100
- define_custom_attribute_methods
101
- calc_depth
102
-
103
- check_unknown_keys
104
- check_invalid_values
105
- # TODO: Remove after completely removing test_setups
106
- merge_test_setups_and_verification_methods
107
- check_verification_methods
108
- end
109
-
110
- def define_custom_attribute_methods
111
- new_attributes = @all_attributes.keys - SYNTAX.keys
112
- new_attributes.each do |k|
113
- define_singleton_method(k) do
114
- @data[k]
115
- end
116
- end
117
- end
118
-
119
- def calc_depth
120
- @depth = 1
121
- hres = @data['type']&.scan(/^heading_(\d+)$/) || ''
122
- return unless hres.length > 0
123
-
124
- dep = hres[0][0].to_i
125
- return unless dep > 1
126
-
127
- if dep > 100
128
- Dim::ExitHelper.exit(
129
- code: 1,
130
- filename: filename,
131
- msg: "heading level above 100 is not allowed and makes absolutely no sense: #{@data['type']}"
132
- )
133
- end
134
-
135
- @depth = dep
136
- end
137
-
138
- def check_single_enum(elem, key, value)
139
- unless !elem[:allowed].include?(value) && !(elem[:allowed].include?('heading_<level>') && /\Aheading_\d+\Z/ === value)
140
- return
141
- end
142
-
143
- allowed_values = elem[:allowed].reject{ |a| a.nil? || a.empty? }.map { |e| "\"#{e}\"" }.join(', ')
144
- Dim::ExitHelper.exit(
145
- code: 1,
146
- filename: filename,
147
- msg: "attribute \"#{key}\" must not be \"#{value}\" (id: #{@id}). \"#{key}\" must be exactly " \
148
- "one of #{allowed_values}. #{"Default is \"#{elem[:default]}\"" if elem[:default]}."
149
- )
150
- end
151
-
152
- def check_multi_enum(element, key, value)
153
- value_array = value.cleanArray
154
- value_array = [''] if value == ''
155
- value_array.each do |v|
156
- next if element[:allowed].include?(v)
157
-
158
- allowed_values = element[:allowed].reject{ |a| a.nil? || a.empty? }.map { |e| "\"#{e}\"" }.join(', ')
159
- Dim::ExitHelper.exit(
160
- code: 1,
161
- filename: filename,
162
- msg: "attribute \"#{key}\" is invalid: \"#{v}\" (id: #{@id}). \"#{key}\" must be one or " \
163
- "more of #{allowed_values}."
164
- )
165
- end
166
- end
167
-
168
- def check_unknown_keys
169
- ks = @all_attributes.keys
170
- # sort reverse so that language keys are inserted into Requirement::SYNTAX in alphabetical order
171
- @data.keys.sort.reverse.each do |k|
172
- if /\A(text_|verification_criteria_|comment_)./ === k
173
- unless @all_attributes.include?(k)
174
- reference_key = k.gsub(/(text|verification_criteria|comment).*/, '\\1')
175
- reference_settings = @all_attributes[reference_key]
176
- # rebuild the hash to change the iteration order for later processing like formatting
177
- tmp = @all_attributes.dup
178
- @all_attributes.clear
179
- tmp.each do |key, value|
180
- @all_attributes[key] = value
181
- next unless key == reference_key
182
-
183
- @all_attributes[k] = {
184
- check: nil,
185
- new: '',
186
- default: '',
187
- allowed: nil,
188
- format_style: reference_settings[:format_style],
189
- format_shift: reference_settings[:format_shift]
190
- }
191
- end
192
- loader.requirements.each { |_id, r| r.data[k] = '' }
193
- Dim::Requirement.define_method(k) do
194
- @data[k]
195
- end
196
- end
197
- next
198
- end
199
-
200
- Dim::ExitHelper.exit(code: 1, filename: filename, msg: "attribute #{k} not allowed") unless ks.include?(k)
201
- end
202
- end
203
-
204
- def check_invalid_values
205
- @data.each do |k, v|
206
- if @all_attributes.key?(k) && (@all_attributes[k][:check])
207
- send(@all_attributes[k][:check], @all_attributes[k], k, v)
208
- end
209
- end
210
- end
211
-
212
- def merge_test_setups_and_verification_methods
213
- # Given verification_methods is empty
214
- # Given test_setups contains None
215
- # Then return None
216
- ts = @data['test_setups']&.cleanArray || []
217
- vm = @data['verification_methods']&.cleanArray || []
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'