dim-toolkit 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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