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,198 +1,196 @@
1
- require 'fileutils'
2
-
3
- require_relative '../globals'
4
-
5
- module Dim
6
- class Format
7
- SUBCOMMANDS['format'] = self
8
- TARGET_WIDTH = 120
9
- TARGET_WIDTH_ONE_LINER = 150
10
- WIDTH_MIN = 50 # used when ID in one-liner or language-attr is very long
11
-
12
- def initialize(loader)
13
- @loader = loader
14
- end
15
-
16
- def short_type(type)
17
- return "h#{type[8..]}" if /\Aheading_(\d+)\z/ === type
18
-
19
- 'info' # type == "information"
20
- end
21
-
22
- def create_string_array(val, line_width, line_width_first)
23
- input = val.strip
24
- return ['|'] + input.split("\n") if input.include?("\n")
25
-
26
- if "#,[]{}&*!|>\)\"%@`'?:-".include?(input[0]) || input =~ /(:(\s|\Z)|\s#)/ || (input.length > line_width_first && input =~ /\s\s/)
27
- return ['|', input] if input.length <= line_width_first
28
-
29
- res = ['>']
30
- else
31
- res = []
32
- end
33
- until input.empty?
34
- width = (res.empty? ? line_width_first : line_width)
35
- if input.length <= width
36
- res << input
37
- break
38
- end
39
- pos = input[0, width + 2].rindex(/ \w/)
40
- if pos
41
- res << input[0, pos]
42
- input = input[pos + 1..]
43
- else
44
- pos = input.index(/ \w/)
45
- if pos
46
- res << input[0, pos]
47
- input = input[pos + 1..]
48
- else
49
- res << input
50
- break
51
- end
52
- end
53
- end
54
- res
55
- end
56
-
57
- def dump(attr, val, shift, target_width = TARGET_WIDTH)
58
- shift_first = [shift - attr.length, 0].max
59
-
60
- line_width = [target_width - shift, WIDTH_MIN].max
61
- line_width_first = [target_width - [shift, attr.length].max, WIDTH_MIN].max
62
-
63
- array = create_string_array(val, line_width, line_width_first)
64
- array[0] = attr + ' ' * shift_first + array[0]
65
- (1..array.length - 1).each do |i|
66
- array[i] = ' ' * shift + array[i]
67
- end
68
- array
69
- end
70
-
71
- def format_file(data)
72
- io = StringIO.new
73
-
74
- io.puts "document: #{data['document']}\n\n"
75
-
76
- if data.key?('metadata') && !data['metadata'].empty?
77
- io.puts dump('metadata: ', data['metadata'], 10)
78
- io.puts "\n"
79
- end
80
-
81
- data.each do |id, req|
82
- next if %w[module enclosed document].include? id
83
-
84
- # do not write default values
85
- next unless req.is_a?(Hash)
86
-
87
- req.delete_if { |_key, value| value.nil? }
88
-
89
- req.delete('test_setups')
90
-
91
- %w[tags verification_methods refs].each do |e|
92
- req[e] = req[e].cleanUniqString if req.key?(e) && req[e].is_a?(String)
93
- end
94
-
95
- # use oneliner style for headings and information if reasonable
96
- if req.keys.length == 2 &&
97
- %w[type text].all? { |e| req.key?(e) } &&
98
- (req['type'] =~ /\Aheading_\d+\Z/ ||
99
- req['type'] =~ /\Ainformation\Z/)
100
- stripped = req['text'].strip
101
- unless stripped.include?("\n")
102
- one_liner = "#{short_type(req['type'])} #{req['text']}"
103
- str = dump("#{id}: ", one_liner, Requirement::SYNTAX['text'][:format_shift], TARGET_WIDTH_ONE_LINER)
104
- if str.length == 1
105
- io.puts str
106
- io.puts "\n"
107
- next
108
- end
109
- end
110
- end
111
-
112
- io.puts "#{id}:"
113
- @loader.all_attributes.each_key do |k|
114
- next unless req.key?(k)
115
-
116
- if req[k] && req[k].empty? || req[k].nil?
117
- io.puts " #{k}:"
118
- next
119
- end
120
- shift = [@loader.all_attributes[k][:format_shift], k.length + 4].max
121
- case @loader.all_attributes[k][:format_style]
122
- when :single
123
- shift_str = ' ' * [shift - (k.length + 4), 0].max
124
- io.puts " #{k}: #{shift_str}#{req[k].strip}"
125
- when :multi
126
- shift_str = ' ' * [shift - (k.length + 4), 0].max
127
- io.puts " #{k}: #{shift_str}#{req[k].cleanUniqString}"
128
- when :list
129
- io.puts dump(" #{k}: ", req[k].cleanUniqString, shift)
130
- when :text
131
- io.puts dump(" #{k}: ", req[k], shift)
132
- when :split
133
- arr = req[k].cleanUniqArray
134
-
135
- if arr.length == 1
136
- io.puts " #{k}: #{shift_str}#{arr[0]}"
137
- else
138
- io.puts " #{k}: #{shift_str}>"
139
- shift_str = ' ' * shift
140
- arr.each_with_index do |a, i|
141
- io.puts "#{shift_str}#{a}#{i < arr.length - 1 ? ',' : ''}"
142
- end
143
- end
144
- else
145
- Dim::ExitHelper.exit(code: 1, msg: 'Invalid format style')
146
- end
147
- end
148
-
149
- io.puts "\n"
150
- end
151
-
152
- if data.key?('enclosed')
153
- a = Array(data['enclosed'])
154
- if a.length == 1
155
- io.puts "enclosed: #{a[0]}\n\n"
156
- else
157
- io.puts "enclosed:\n"
158
- Array(data['enclosed']).each do |e|
159
- io.puts " - #{e}"
160
- end
161
- io.puts "\n"
162
- end
163
- end
164
-
165
- io.truncate(io.length - 1) # do not print two line breaks at the end
166
-
167
- io
168
- end
169
-
170
- def execute(silent: true)
171
- puts OPTIONS[:output_format] == 'check-only' ? 'Checking format...' : 'Formatting...' unless silent
172
-
173
- incorrect_files = []
174
- @loader.original_data.each do |filename, data|
175
- formatted_data = format_file(data).string
176
- if OPTIONS[:output_format] == 'check-only'
177
- original_data = File.read(filename).universal_newline
178
- incorrect_files << filename if original_data != formatted_data
179
- elsif OPTIONS[:output_format] == 'stdout'
180
- puts formatted_data
181
- next
182
- else
183
- output_filename = OPTIONS[:output_format] == 'extra' ? "#{filename}.formatted" : filename
184
- File.write(output_filename, formatted_data)
185
- end
186
- end
187
-
188
- unless incorrect_files.empty?
189
- io = StringIO.new
190
- io.puts 'The following files are not formatted correctly:'
191
- io.puts(incorrect_files.map { |f| "- #{f}" })
192
- Dim::ExitHelper.exit(code: 1, msg: io.string)
193
- end
194
-
195
- puts 'Done.' unless silent
196
- end
197
- end
198
- end
1
+ require 'fileutils'
2
+
3
+ require_relative '../globals'
4
+
5
+ module Dim
6
+ class Format
7
+ SUBCOMMANDS['format'] = self
8
+ TARGET_WIDTH = 120
9
+ TARGET_WIDTH_ONE_LINER = 150
10
+ WIDTH_MIN = 50 # used when ID in one-liner or language-attr is very long
11
+
12
+ def initialize(loader)
13
+ @loader = loader
14
+ end
15
+
16
+ def short_type(type)
17
+ return "h#{type[8..]}" if /\Aheading_(\d+)\z/ === type
18
+
19
+ 'info' # type == "information"
20
+ end
21
+
22
+ def create_string_array(val, line_width, line_width_first)
23
+ input = val.strip
24
+ return ['|'] + input.split("\n") if input.include?("\n")
25
+
26
+ if "#,[]{}&*!|>\)\"%@`'?:-".include?(input[0]) || input =~ /(:(\s|\Z)|\s#)/ || (input.length > line_width_first && input =~ /\s\s/)
27
+ return ['|', input] if input.length <= line_width_first
28
+
29
+ res = ['>']
30
+ else
31
+ res = []
32
+ end
33
+ until input.empty?
34
+ width = (res.empty? ? line_width_first : line_width)
35
+ if input.length <= width
36
+ res << input
37
+ break
38
+ end
39
+ pos = input[0, width + 2].rindex(/ \w/)
40
+ if pos
41
+ res << input[0, pos]
42
+ input = input[pos + 1..]
43
+ else
44
+ pos = input.index(/ \w/)
45
+ if pos
46
+ res << input[0, pos]
47
+ input = input[pos + 1..]
48
+ else
49
+ res << input
50
+ break
51
+ end
52
+ end
53
+ end
54
+ res
55
+ end
56
+
57
+ def dump(attr, val, shift, target_width = TARGET_WIDTH)
58
+ shift_first = [shift - attr.length, 0].max
59
+
60
+ line_width = [target_width - shift, WIDTH_MIN].max
61
+ line_width_first = [target_width - [shift, attr.length].max, WIDTH_MIN].max
62
+
63
+ array = create_string_array(val, line_width, line_width_first)
64
+ array[0] = attr + ' ' * shift_first + array[0]
65
+ (1..array.length - 1).each do |i|
66
+ array[i] = ' ' * shift + array[i]
67
+ end
68
+ array
69
+ end
70
+
71
+ def format_file(data)
72
+ io = StringIO.new
73
+
74
+ io.puts "document: #{data['document']}\n\n"
75
+
76
+ if data.key?('metadata') && !data['metadata'].empty?
77
+ io.puts dump('metadata: ', data['metadata'], 10)
78
+ io.puts "\n"
79
+ end
80
+
81
+ data.each do |id, req|
82
+ next if %w[enclosed document].include? id
83
+
84
+ # do not write default values
85
+ next unless req.is_a?(Hash)
86
+
87
+ req.delete_if { |_key, value| value.nil? }
88
+
89
+ %w[tags verification_methods refs].each do |e|
90
+ req[e] = req[e].cleanUniqString if req.key?(e) && req[e].is_a?(String)
91
+ end
92
+
93
+ # use oneliner style for headings and information if reasonable
94
+ if req.keys.length == 2 &&
95
+ %w[type text].all? { |e| req.key?(e) } &&
96
+ (req['type'] =~ /\Aheading_\d+\Z/ ||
97
+ req['type'] =~ /\Ainformation\Z/)
98
+ stripped = req['text'].strip
99
+ unless stripped.include?("\n")
100
+ one_liner = "#{short_type(req['type'])} #{req['text']}"
101
+ str = dump("#{id}: ", one_liner, Requirement::SYNTAX['text'][:format_shift], TARGET_WIDTH_ONE_LINER)
102
+ if str.length == 1
103
+ io.puts str
104
+ io.puts "\n"
105
+ next
106
+ end
107
+ end
108
+ end
109
+
110
+ io.puts "#{id}:"
111
+ @loader.all_attributes.each_key do |k|
112
+ next unless req.key?(k)
113
+
114
+ if req[k] && req[k].empty? || req[k].nil?
115
+ io.puts " #{k}:"
116
+ next
117
+ end
118
+ shift = [@loader.all_attributes[k][:format_shift], k.length + 4].max
119
+ case @loader.all_attributes[k][:format_style]
120
+ when :single
121
+ shift_str = ' ' * [shift - (k.length + 4), 0].max
122
+ io.puts " #{k}: #{shift_str}#{req[k].strip}"
123
+ when :multi
124
+ shift_str = ' ' * [shift - (k.length + 4), 0].max
125
+ io.puts " #{k}: #{shift_str}#{req[k].cleanUniqString}"
126
+ when :list
127
+ io.puts dump(" #{k}: ", req[k].cleanUniqString, shift)
128
+ when :text
129
+ io.puts dump(" #{k}: ", req[k], shift)
130
+ when :split
131
+ arr = req[k].cleanUniqArray
132
+
133
+ if arr.length == 1
134
+ io.puts " #{k}: #{shift_str}#{arr[0]}"
135
+ else
136
+ io.puts " #{k}: #{shift_str}>"
137
+ shift_str = ' ' * shift
138
+ arr.each_with_index do |a, i|
139
+ io.puts "#{shift_str}#{a}#{i < arr.length - 1 ? ',' : ''}"
140
+ end
141
+ end
142
+ else
143
+ Dim::ExitHelper.exit(code: 1, msg: 'Invalid format style')
144
+ end
145
+ end
146
+
147
+ io.puts "\n"
148
+ end
149
+
150
+ if data.key?('enclosed')
151
+ a = Array(data['enclosed'])
152
+ if a.length == 1
153
+ io.puts "enclosed: #{a[0]}\n\n"
154
+ else
155
+ io.puts "enclosed:\n"
156
+ Array(data['enclosed']).each do |e|
157
+ io.puts " - #{e}"
158
+ end
159
+ io.puts "\n"
160
+ end
161
+ end
162
+
163
+ io.truncate(io.length - 1) # do not print two line breaks at the end
164
+
165
+ io
166
+ end
167
+
168
+ def execute(silent: true)
169
+ puts OPTIONS[:output_format] == 'check-only' ? 'Checking format...' : 'Formatting...' unless silent
170
+
171
+ incorrect_files = []
172
+ @loader.original_data.each do |filename, data|
173
+ formatted_data = format_file(data).string
174
+ if OPTIONS[:output_format] == 'check-only'
175
+ original_data = File.read(filename).universal_newline
176
+ incorrect_files << filename if original_data != formatted_data
177
+ elsif OPTIONS[:output_format] == 'stdout'
178
+ puts formatted_data
179
+ next
180
+ else
181
+ output_filename = OPTIONS[:output_format] == 'extra' ? "#{filename}.formatted" : filename
182
+ File.write(output_filename, formatted_data)
183
+ end
184
+ end
185
+
186
+ unless incorrect_files.empty?
187
+ io = StringIO.new
188
+ io.puts 'The following files are not formatted correctly:'
189
+ io.puts(incorrect_files.map { |f| "- #{f}" })
190
+ Dim::ExitHelper.exit(code: 1, msg: io.string)
191
+ end
192
+
193
+ puts 'Done.' unless silent
194
+ end
195
+ end
196
+ end
@@ -1,64 +1,64 @@
1
- module Dim
2
- class Stats
3
- SUBCOMMANDS['stats'] = self
4
-
5
- def initialize(loader)
6
- @loader = loader
7
- end
8
-
9
- def execute(silent: true)
10
- print_stats
11
- end
12
-
13
- def print_owner(type, module_name = nil)
14
- if type == :all
15
- top = 'ALL'
16
- is_owner = proc { |_x| true }
17
- else # :module
18
- is_owner = proc { |x| x.document == module_name }
19
- top = "DOCUMENT: #{module_name}"
20
- end
21
-
22
- puts "\n#{top}\n#{'-' * top.length}"
23
- all_reqs = @loader.requirements.values
24
- reqs_owner = all_reqs.select { |r| is_owner.call(r) }
25
-
26
- num_files = if type == :module
27
- @loader.module_data[module_name][:files].length
28
- else
29
- @loader.module_data.values.map { |e| e[:files].keys }.flatten.length
30
- end
31
- puts "Number of files: #{num_files}"
32
-
33
- if type != :module
34
- mods = reqs_owner.map(&:document).uniq
35
- puts "Number of modules: #{mods.count}"
36
- end
37
-
38
- puts "Number of entries: #{reqs_owner.length}"
39
- real_reqs_owner = reqs_owner.select { |r| r.data['type'] == 'requirement' }
40
- puts "Requirements: #{real_reqs_owner.length}"
41
- valid_reqs = real_reqs_owner.select { |r| r.data['status'] == 'valid' }
42
- puts "Valid requirements: #{valid_reqs.length}"
43
- accepted = valid_reqs.select { |r| r.data['review_status'] == 'accepted' }
44
- puts " Accepted: #{accepted.length}"
45
- covered = accepted.select { |r| r.data['tags'].include?('covered') }
46
- puts " Covered: #{covered.length}"
47
- not_covered_num = accepted.length - covered.length
48
- puts " Not covered: #{not_covered_num}"
49
- rejected = valid_reqs.select { |r| r.data['review_status'] == 'rejected' }
50
- puts " Rejected: #{rejected.length}"
51
- unclear = valid_reqs.select { |r| r.data['review_status'] == 'unclear' }
52
- puts " Unclear: #{unclear.length}"
53
- not_reviewed = valid_reqs.select { |r| r.data['review_status'] == 'not_reviewed' }
54
- puts " Not reviewed: #{not_reviewed.length}"
55
- end
56
-
57
- def print_stats
58
- @loader.requirements.values.map(&:document).uniq.each do |mod|
59
- print_owner(:module, mod)
60
- end
61
- print_owner(:all)
62
- end
63
- end
64
- end
1
+ module Dim
2
+ class Stats
3
+ SUBCOMMANDS['stats'] = self
4
+
5
+ def initialize(loader)
6
+ @loader = loader
7
+ end
8
+
9
+ def execute(silent: true)
10
+ print_stats
11
+ end
12
+
13
+ def print_owner(type, module_name = nil)
14
+ if type == :all
15
+ top = 'ALL'
16
+ is_owner = proc { |_x| true }
17
+ else # :document
18
+ is_owner = proc { |x| x.document == module_name }
19
+ top = "DOCUMENT: #{module_name}"
20
+ end
21
+
22
+ puts "\n#{top}\n#{'-' * top.length}"
23
+ all_reqs = @loader.requirements.values
24
+ reqs_owner = all_reqs.select { |r| is_owner.call(r) }
25
+
26
+ num_files = if type == :module
27
+ @loader.module_data[module_name][:files].length
28
+ else
29
+ @loader.module_data.values.map { |e| e[:files].keys }.flatten.length
30
+ end
31
+ puts "Number of files: #{num_files}"
32
+
33
+ if type != :module
34
+ mods = reqs_owner.map(&:document).uniq
35
+ puts "Number of modules: #{mods.count}"
36
+ end
37
+
38
+ puts "Number of entries: #{reqs_owner.length}"
39
+ real_reqs_owner = reqs_owner.select { |r| r.data['type'] == 'requirement' }
40
+ puts "Requirements: #{real_reqs_owner.length}"
41
+ valid_reqs = real_reqs_owner.select { |r| r.data['status'] == 'valid' }
42
+ puts "Valid requirements: #{valid_reqs.length}"
43
+ accepted = valid_reqs.select { |r| r.data['review_status'] == 'accepted' }
44
+ puts " Accepted: #{accepted.length}"
45
+ covered = accepted.select { |r| r.data['tags'].include?('covered') }
46
+ puts " Covered: #{covered.length}"
47
+ not_covered_num = accepted.length - covered.length
48
+ puts " Not covered: #{not_covered_num}"
49
+ rejected = valid_reqs.select { |r| r.data['review_status'] == 'rejected' }
50
+ puts " Rejected: #{rejected.length}"
51
+ unclear = valid_reqs.select { |r| r.data['review_status'] == 'unclear' }
52
+ puts " Unclear: #{unclear.length}"
53
+ not_reviewed = valid_reqs.select { |r| r.data['review_status'] == 'not_reviewed' }
54
+ puts " Not reviewed: #{not_reviewed.length}"
55
+ end
56
+
57
+ def print_stats
58
+ @loader.requirements.values.map(&:document).uniq.each do |mod|
59
+ print_owner(:module, mod)
60
+ end
61
+ print_owner(:all)
62
+ end
63
+ end
64
+ end