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,187 +1,157 @@
1
- require_relative 'globals'
2
- require_relative 'exit_helper'
3
-
4
- module Dim
5
- class Consistency
6
- def initialize(loader)
7
- @loader = loader
8
- end
9
-
10
- def cyclic_check(ref, previous_ref, checked_ids = {}, list = [])
11
- return if checked_ids[ref.id]
12
-
13
- # Circular dependency can occur only on same category level
14
- return if previous_ref && (ref.category_level != previous_ref.category_level)
15
-
16
- if list.include?(ref.id)
17
- Dim::ExitHelper.exit(
18
- code: 1,
19
- filename: ref.filename,
20
- msg: "\"#{ref.id}\" is cyclically referenced: #{list.join(' -> ')} -> #{ref.id}"
21
- )
22
- end
23
-
24
- list << ref.id
25
-
26
- ref.existingRefs.each do |ref_id|
27
- cyclic_check(@loader.requirements[ref_id], ref, checked_ids, list)
28
- end
29
-
30
- list.pop
31
-
32
- # Any value other than nil and false will work, as this is being used to check
33
- # boolean condition on line#11
34
- checked_ids[ref.id] = 1 if list.empty?
35
- end
36
- private :cyclic_check
37
-
38
- def insert_default_values(req)
39
- req.all_attributes.each do |key, config|
40
- next if req.data.key?(key)
41
-
42
- req.data[key] = config[:default]
43
- end
44
- end
45
-
46
- def insert_property_file_definitions(ref)
47
- @loader.property_table.fetch(ref.document, {}).each do |attr, value|
48
- ref.data[attr] = value if ref.data[attr].nil?
49
-
50
- if attr == 'test_setups' && (ref.data['verification_methods'].nil? || ref.data['verification_methods'] == '')
51
- ref.data['verification_methods'] = value
52
- end
53
- end
54
- end
55
-
56
- def merge_test_setups_and_verification_methods(ref)
57
- return if ref.data.key?('verification_methods') && !ref.data['verification_methods'].nil?
58
-
59
- ref.data['verification_methods'] = ref.data['test_setups'].clone
60
- end
61
-
62
- def calculate_test_setups(ref)
63
- return unless ref.data['test_setups'].nil?
64
-
65
- tags = ref.data['tags'].cleanArray
66
-
67
- ref.data['test_setups'] = if ref.data['type'] != 'requirement' || tags.include?('process')
68
- 'none'
69
- elsif ref.category == 'input' || ref.category == 'unspecified'
70
- 'none'
71
- elsif ref.category == 'module'
72
- 'off_target'
73
- elsif tags.include?('tool')
74
- 'off_target'
75
- else
76
- 'on_target'
77
- end
78
- end
79
-
80
- def calculate_verification_methods(ref)
81
- return unless ref.data['verification_methods'].nil?
82
-
83
- tags = ref.data['tags'].cleanArray
84
-
85
- ref.data['verification_methods'] = if ref.data['type'] != 'requirement' || tags.include?('process')
86
- 'none'
87
- elsif ref.category == 'input' || ref.category == 'unspecified'
88
- 'none'
89
- elsif ref.category == 'module'
90
- 'off_target'
91
- elsif tags.include?('tool')
92
- 'off_target'
93
- else
94
- 'on_target'
95
- end
96
- end
97
-
98
- def calculate_review_status(ref)
99
- return unless ref.data['review_status'].nil?
100
-
101
- ref.data['review_status'] = if ref.category == 'input' || ref.category == 'unspecified'
102
- 'not_reviewed'
103
- else
104
- 'accepted'
105
- end
106
- end
107
-
108
- def clean_comma_separated(ref)
109
- %w[tags developer tester refs test_setups verification_methods].each do |var|
110
- ref.data[var] = ref.data[var].cleanString
111
- end
112
- end
113
-
114
- def calculate_developer_tester(ref)
115
- %w[developer tester].each do |t|
116
- next unless ref.data[t].nil?
117
-
118
- ref.data[t] = if ref.data['type'] != 'requirement'
119
- ''
120
- elsif ref.data['tags'].cleanArray.include?('process') && t == 'tester'
121
- ''
122
- elsif ref.category == 'input' || ref.category == 'unspecified'
123
- ''
124
- else
125
- ref.origin
126
- end
127
- end
128
- end
129
-
130
- def calculate_status(ref)
131
- return unless ref.data['status'].nil?
132
-
133
- ref.data['status'] = %w[requirement information].include?(ref.data['type']) ? 'draft' : 'valid'
134
- end
135
-
136
- def check(allow_missing:)
137
- requirements_by_module = {}
138
- @loader.module_data.keys.each { |um| requirements_by_module[um] = [] }
139
- @loader.requirements.each { |_id, r| requirements_by_module[r.document] << r }
140
-
141
- @loader.requirements.each do |_id, r|
142
- insert_property_file_definitions(r)
143
- insert_default_values(r)
144
- merge_test_setups_and_verification_methods(r)
145
- calculate_test_setups(r)
146
- calculate_verification_methods(r)
147
- calculate_review_status(r)
148
- calculate_developer_tester(r)
149
- calculate_status(r)
150
- end
151
-
152
- @loader.requirements.each do |_id, r|
153
- clean_comma_separated(r)
154
- end
155
-
156
- @loader.requirements.each do |id, r|
157
- r.data['refs'].cleanArray.each do |ref|
158
- if !@loader.requirements.has_key?(ref)
159
- unless allow_missing
160
- Dim::ExitHelper.exit(
161
- code: 1,
162
- filename: r.filename,
163
- msg: "\"#{id}\" refers to non-existing \"#{ref}\""
164
- )
165
- end
166
- else
167
- # Generate upstream and downstream refs based on category level
168
- if @loader.requirements[id].category_level <= @loader.requirements[ref].category_level
169
- @loader.requirements[id].downstreamRefs |= [ref]
170
- @loader.requirements[ref].upstreamRefs |= [id]
171
- else
172
- @loader.requirements[id].upstreamRefs |= [ref]
173
- @loader.requirements[ref].downstreamRefs |= [id]
174
- end
175
- @loader.requirements[ref].backwardRefs << id
176
- r.existingRefs << ref
177
- end
178
- end
179
- end
180
-
181
- @checked_ids = {}
182
- @loader.requirements.each do |_id, r|
183
- cyclic_check(r, nil, @checked_ids)
184
- end
185
- end
186
- end
187
- end
1
+ require_relative 'globals'
2
+ require_relative 'exit_helper'
3
+
4
+ module Dim
5
+ class Consistency
6
+ def initialize(loader)
7
+ @loader = loader
8
+ end
9
+
10
+ def cyclic_check(ref, previous_ref, checked_ids = {}, list = [])
11
+ return if checked_ids[ref.id]
12
+
13
+ # Circular dependency can occur only on same category level
14
+ return if previous_ref && (ref.category_level != previous_ref.category_level)
15
+
16
+ if list.include?(ref.id)
17
+ Dim::ExitHelper.exit(
18
+ code: 1,
19
+ filename: ref.filename,
20
+ msg: "\"#{ref.id}\" is cyclically referenced: #{list.join(' -> ')} -> #{ref.id}"
21
+ )
22
+ end
23
+
24
+ list << ref.id
25
+
26
+ ref.existingRefs.each do |ref_id|
27
+ cyclic_check(@loader.requirements[ref_id], ref, checked_ids, list)
28
+ end
29
+
30
+ list.pop
31
+
32
+ # Any value other than nil and false will work, as this is being used to check
33
+ # boolean condition on line#11
34
+ checked_ids[ref.id] = 1 if list.empty?
35
+ end
36
+ private :cyclic_check
37
+
38
+ def insert_default_values(req)
39
+ req.all_attributes.each do |key, config|
40
+ next if req.data.key?(key)
41
+
42
+ req.data[key] = config[:default]
43
+ end
44
+ end
45
+
46
+ def insert_property_file_definitions(ref)
47
+ @loader.property_table.fetch(ref.document, {}).each do |attr, value|
48
+ ref.data[attr] = value if ref.data[attr].nil?
49
+ end
50
+ end
51
+
52
+ def calculate_verification_methods(ref)
53
+ return unless ref.data['verification_methods'].nil?
54
+
55
+ tags = ref.data['tags'].cleanArray
56
+
57
+ ref.data['verification_methods'] = if ref.data['type'] != 'requirement' || tags.include?('process')
58
+ 'none'
59
+ elsif ref.category == 'input' || ref.category == 'unspecified'
60
+ 'none'
61
+ elsif ref.category == 'module'
62
+ 'off_target'
63
+ elsif tags.include?('tool')
64
+ 'off_target'
65
+ else
66
+ 'on_target'
67
+ end
68
+ end
69
+
70
+ def calculate_review_status(ref)
71
+ return unless ref.data['review_status'].nil?
72
+
73
+ ref.data['review_status'] = if ref.category == 'input' || ref.category == 'unspecified'
74
+ 'not_reviewed'
75
+ else
76
+ 'accepted'
77
+ end
78
+ end
79
+
80
+ def clean_comma_separated(ref)
81
+ %w[tags developer tester refs verification_methods].each do |var|
82
+ ref.data[var] = ref.data[var].cleanString
83
+ end
84
+ end
85
+
86
+ def calculate_developer_tester(ref)
87
+ %w[developer tester].each do |t|
88
+ next unless ref.data[t].nil?
89
+
90
+ ref.data[t] = if ref.data['type'] != 'requirement'
91
+ ''
92
+ elsif ref.data['tags'].cleanArray.include?('process') && t == 'tester'
93
+ ''
94
+ elsif ref.category == 'input' || ref.category == 'unspecified'
95
+ ''
96
+ else
97
+ ref.origin
98
+ end
99
+ end
100
+ end
101
+
102
+ def calculate_status(ref)
103
+ return unless ref.data['status'].nil?
104
+
105
+ ref.data['status'] = %w[requirement information].include?(ref.data['type']) ? 'draft' : 'valid'
106
+ end
107
+
108
+ def check(allow_missing:)
109
+ requirements_by_module = {}
110
+ @loader.module_data.keys.each { |um| requirements_by_module[um] = [] }
111
+ @loader.requirements.each { |_id, r| requirements_by_module[r.document] << r }
112
+
113
+ @loader.requirements.each do |_id, r|
114
+ insert_property_file_definitions(r)
115
+ insert_default_values(r)
116
+ calculate_verification_methods(r)
117
+ calculate_review_status(r)
118
+ calculate_developer_tester(r)
119
+ calculate_status(r)
120
+ end
121
+
122
+ @loader.requirements.each do |_id, r|
123
+ clean_comma_separated(r)
124
+ end
125
+
126
+ @loader.requirements.each do |id, r|
127
+ r.data['refs'].cleanArray.each do |ref|
128
+ if !@loader.requirements.has_key?(ref)
129
+ unless allow_missing
130
+ Dim::ExitHelper.exit(
131
+ code: 1,
132
+ filename: r.filename,
133
+ msg: "\"#{id}\" refers to non-existing \"#{ref}\""
134
+ )
135
+ end
136
+ else
137
+ # Generate upstream and downstream refs based on category level
138
+ if @loader.requirements[id].category_level <= @loader.requirements[ref].category_level
139
+ @loader.requirements[id].downstreamRefs |= [ref]
140
+ @loader.requirements[ref].upstreamRefs |= [id]
141
+ else
142
+ @loader.requirements[id].upstreamRefs |= [ref]
143
+ @loader.requirements[ref].downstreamRefs |= [id]
144
+ end
145
+ @loader.requirements[ref].backwardRefs << id
146
+ r.existingRefs << ref
147
+ end
148
+ end
149
+ end
150
+
151
+ @checked_ids = {}
152
+ @loader.requirements.each do |_id, r|
153
+ cyclic_check(r, nil, @checked_ids)
154
+ end
155
+ end
156
+ end
157
+ end
data/lib/dim/dimmain.rb CHANGED
@@ -1,28 +1,28 @@
1
- $stdout.sync = true
2
-
3
- require 'yaml'
4
-
5
- require_relative 'globals'
6
- require_relative 'exit_helper'
7
- require_relative 'ext/string'
8
- require_relative 'loader'
9
- require_relative 'ver'
10
- require_relative 'requirement'
11
- require_relative 'commands/stats'
12
- require_relative 'commands/check'
13
- require_relative 'commands/export'
14
- require_relative 'commands/format'
15
- require_relative 'options'
16
-
17
- module Dim
18
- def self.main(args = ARGV)
19
- Dim::Options.parse(args)
20
- loader = Dim::Loader.new
21
- loader.load(file: OPTIONS[:input],
22
- attributes_file: OPTIONS[:attributes],
23
- allow_missing: OPTIONS[:allow_missing],
24
- no_check_enclosed: OPTIONS[:no_check_enclosed] || false,
25
- silent: OPTIONS[:silent] || false)
26
- SUBCOMMANDS[OPTIONS[:subcommand]].new(loader).execute(silent: OPTIONS[:silent] || false)
27
- end
28
- end
1
+ $stdout.sync = true
2
+
3
+ require 'yaml'
4
+
5
+ require_relative 'globals'
6
+ require_relative 'exit_helper'
7
+ require_relative 'ext/string'
8
+ require_relative 'loader'
9
+ require_relative 'ver'
10
+ require_relative 'requirement'
11
+ require_relative 'commands/stats'
12
+ require_relative 'commands/check'
13
+ require_relative 'commands/export'
14
+ require_relative 'commands/format'
15
+ require_relative 'options'
16
+
17
+ module Dim
18
+ def self.main(args = ARGV)
19
+ Dim::Options.parse(args)
20
+ loader = Dim::Loader.new
21
+ loader.load(file: OPTIONS[:input],
22
+ attributes_file: OPTIONS[:attributes],
23
+ allow_missing: OPTIONS[:allow_missing],
24
+ no_check_enclosed: OPTIONS[:no_check_enclosed] || false,
25
+ silent: OPTIONS[:silent] || false)
26
+ SUBCOMMANDS[OPTIONS[:subcommand]].new(loader).execute(silent: OPTIONS[:silent] || false)
27
+ end
28
+ end
data/lib/dim/encoding.rb CHANGED
@@ -1,4 +1,4 @@
1
- # This overwrites the configuration of local machines,
2
- # Dim shall read, process and write only UTF_8.
3
- Encoding.default_external = Encoding::UTF_8
4
- Encoding.default_internal = Encoding::UTF_8
1
+ # This overwrites the configuration of local machines,
2
+ # Dim shall read, process and write only UTF_8.
3
+ Encoding.default_external = Encoding::UTF_8
4
+ Encoding.default_internal = Encoding::UTF_8
@@ -1,23 +1,23 @@
1
- module Dim
2
- class ExitHelper
3
- @exit_code = 0
4
-
5
- class << self
6
- def exit_code
7
- @exit_code
8
- end
9
-
10
- def reset_exit_code
11
- @exit_code = 0
12
- end
13
-
14
- def exit(msg:, code: 0, filename: nil)
15
- @exit_code = code
16
- inf = filename ? "in #{filename}: " : ''
17
- pre = code.positive? ? 'Error: ' : ''
18
- warn("#{pre}#{inf}#{msg}")
19
- Kernel.exit(code)
20
- end
21
- end
22
- end
23
- end
1
+ module Dim
2
+ class ExitHelper
3
+ @exit_code = 0
4
+
5
+ class << self
6
+ def exit_code
7
+ @exit_code
8
+ end
9
+
10
+ def reset_exit_code
11
+ @exit_code = 0
12
+ end
13
+
14
+ def exit(msg:, code: 0, filename: nil)
15
+ @exit_code = code
16
+ inf = filename ? "in #{filename}: " : ''
17
+ pre = code.positive? ? 'Error: ' : ''
18
+ warn("#{pre}#{inf}#{msg}")
19
+ Kernel.exit(code)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,25 +1,24 @@
1
- require_relative '../globals'
2
- require_relative '../requirement'
3
-
4
- module Dim
5
- class Csv < ExporterInterface
6
- EXPORTER['csv'] = self
7
-
8
- def header(content)
9
- @keys = @loader.all_attributes.keys
10
- @keys.delete('test_setups')
11
- content.puts 'Sep=,'
12
- content.puts "id,document_name,originator,#{@keys.join(',')}"
13
- end
14
-
15
- def requirement(content, req)
16
- vals = [req.id, req.document, req.origin]
17
- @keys.each { |k| vals << req.data[k] }
18
- # These values will never be nil.
19
- # ID cannot be nil in Dim file, so as origin (default is "") and
20
- # document cannot be missing in Dim files.
21
- # Which leaves with data and YAML file cannot define nil value.
22
- content.puts(vals.map { |a| "\"#{a.gsub('"', '""')}\"" }.join(','))
23
- end
24
- end
25
- end
1
+ require_relative '../globals'
2
+ require_relative '../requirement'
3
+
4
+ module Dim
5
+ class Csv < ExporterInterface
6
+ EXPORTER['csv'] = self
7
+
8
+ def header(content)
9
+ @keys = @loader.all_attributes.keys
10
+ content.puts 'Sep=,'
11
+ content.puts "id,document_name,originator,#{@keys.join(',')}"
12
+ end
13
+
14
+ def requirement(content, req)
15
+ vals = [req.id, req.document, req.origin]
16
+ @keys.each { |k| vals << req.data[k] }
17
+ # These values will never be nil.
18
+ # ID cannot be nil in Dim file, so as origin (default is "") and
19
+ # document cannot be missing in Dim files.
20
+ # Which leaves with data and YAML file cannot define nil value.
21
+ content.puts(vals.map { |a| "\"#{a.gsub('"', '""')}\"" }.join(','))
22
+ end
23
+ end
24
+ end
@@ -1,37 +1,37 @@
1
- module Dim
2
- # This is how the interface is used by the Dim::Export:
3
- #
4
- # initialize()
5
- #
6
- # for every module:
7
- # header()
8
- # document()
9
- # metadata()
10
- # for every requirement in module:
11
- # requirement()
12
- # footer()
13
- #
14
- # if hasIndex:
15
- # for every originator/category combination:
16
- # index()
17
- class ExporterInterface
18
- attr_reader :hasIndex
19
-
20
- def initialize(loader)
21
- @hasIndex = false
22
- @loader = loader
23
- end
24
-
25
- def header(f); end
26
-
27
- def document(f, name); end
28
-
29
- def metadata(f, metadata); end
30
-
31
- def requirement(f, r); end
32
-
33
- def footer(f); end
34
-
35
- def index(f, category, origin, modules); end
36
- end
37
- end
1
+ module Dim
2
+ # This is how the interface is used by the Dim::Export:
3
+ #
4
+ # initialize()
5
+ #
6
+ # for every document:
7
+ # header()
8
+ # document()
9
+ # metadata()
10
+ # for every requirement in document:
11
+ # requirement()
12
+ # footer()
13
+ #
14
+ # if hasIndex:
15
+ # for every originator/category combination:
16
+ # index()
17
+ class ExporterInterface
18
+ attr_reader :hasIndex
19
+
20
+ def initialize(loader)
21
+ @hasIndex = false
22
+ @loader = loader
23
+ end
24
+
25
+ def header(f); end
26
+
27
+ def document(f, name); end
28
+
29
+ def metadata(f, metadata); end
30
+
31
+ def requirement(f, r); end
32
+
33
+ def footer(f); end
34
+
35
+ def index(f, category, origin, modules); end
36
+ end
37
+ end
@@ -1,32 +1,30 @@
1
- require 'json'
2
-
3
- require_relative '../globals'
4
- require_relative '../requirement'
5
-
6
- module Dim
7
- class Json < ExporterInterface
8
- EXPORTER['json'] = self
9
-
10
- def header(_f)
11
- @content = []
12
- end
13
-
14
- def requirement(_f, r)
15
- vals = { 'id' => r.id, 'document_name' => r.document, 'originator' => r.origin }
16
-
17
- @loader.all_attributes.keys.each do |k|
18
- next if k == 'test_setups'
19
-
20
- v = r.data[k]
21
- v = v.cleanUniqArray.join(',') if k == 'refs'
22
- vals[k] = v.strip
23
- end
24
-
25
- @content << vals
26
- end
27
-
28
- def footer(f)
29
- f.puts(JSON.pretty_generate(@content))
30
- end
31
- end
32
- end
1
+ require 'json'
2
+
3
+ require_relative '../globals'
4
+ require_relative '../requirement'
5
+
6
+ module Dim
7
+ class Json < ExporterInterface
8
+ EXPORTER['json'] = self
9
+
10
+ def header(_f)
11
+ @content = []
12
+ end
13
+
14
+ def requirement(_f, r)
15
+ vals = { 'id' => r.id, 'document_name' => r.document, 'originator' => r.origin }
16
+
17
+ @loader.all_attributes.keys.each do |k|
18
+ v = r.data[k]
19
+ v = v.cleanUniqArray.join(',') if k == 'refs'
20
+ vals[k] = v.strip
21
+ end
22
+
23
+ @content << vals
24
+ end
25
+
26
+ def footer(f)
27
+ f.puts(JSON.pretty_generate(@content))
28
+ end
29
+ end
30
+ end