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.
- checksums.yaml +4 -4
- data/bin/dim +9 -9
- data/lib/dim/commands/check.rb +13 -13
- data/lib/dim/commands/export.rb +145 -145
- data/lib/dim/commands/format.rb +196 -198
- data/lib/dim/commands/stats.rb +64 -64
- data/lib/dim/consistency.rb +157 -187
- data/lib/dim/dimmain.rb +28 -28
- data/lib/dim/encoding.rb +4 -4
- data/lib/dim/exit_helper.rb +23 -23
- data/lib/dim/exporter/csv.rb +24 -25
- data/lib/dim/exporter/exporterInterface.rb +37 -37
- data/lib/dim/exporter/json.rb +30 -32
- data/lib/dim/exporter/rst.rb +142 -142
- data/lib/dim/ext/psych.rb +63 -63
- data/lib/dim/ext/string.rb +85 -85
- data/lib/dim/globals.rb +12 -12
- data/lib/dim/helpers/attribute_helper.rb +126 -126
- data/lib/dim/helpers/file_helper.rb +25 -25
- data/lib/dim/loader.rb +561 -581
- data/lib/dim/options.rb +116 -116
- data/lib/dim/requirement.rb +217 -236
- data/lib/dim/ver.rb +7 -7
- data/lib/dim.rb +1 -1
- data/license.txt +205 -205
- data/version.txt +1 -1
- metadata +4 -4
data/lib/dim/commands/format.rb
CHANGED
@@ -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[
|
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
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
io.puts " #{k}:
|
128
|
-
when :
|
129
|
-
io.puts dump(" #{k}: ", req[k]
|
130
|
-
when :
|
131
|
-
|
132
|
-
|
133
|
-
arr
|
134
|
-
|
135
|
-
|
136
|
-
io.puts " #{k}: #{shift_str}
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
io.puts "enclosed
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
end
|
164
|
-
|
165
|
-
io
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
io
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
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
|
data/lib/dim/commands/stats.rb
CHANGED
@@ -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 # :
|
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
|