dim-toolkit 2.1.1 → 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.
@@ -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'