class-metrix 0.1.2 → 1.0.1
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/.editorconfig +48 -0
- data/.vscode/README.md +128 -0
- data/.vscode/extensions.json +31 -0
- data/.vscode/keybindings.json +26 -0
- data/.vscode/launch.json +32 -0
- data/.vscode/rbs.code-snippets +61 -0
- data/.vscode/settings.json +112 -0
- data/.vscode/tasks.json +240 -0
- data/CHANGELOG.md +73 -4
- data/README.md +86 -22
- data/Steepfile +26 -0
- data/docs/ARCHITECTURE.md +501 -0
- data/docs/CHANGELOG_EVOLUTION_EXAMPLE.md +95 -0
- data/examples/README.md +161 -114
- data/examples/basic_usage.rb +88 -0
- data/examples/debug_levels_demo.rb +65 -0
- data/examples/debug_mode_demo.rb +75 -0
- data/examples/inheritance_and_modules.rb +155 -0
- data/lib/class_metrix/extractor.rb +106 -11
- data/lib/class_metrix/extractors/constants_extractor.rb +155 -21
- data/lib/class_metrix/extractors/methods_extractor.rb +186 -21
- data/lib/class_metrix/extractors/multi_type_extractor.rb +8 -7
- data/lib/class_metrix/formatters/base/base_formatter.rb +3 -3
- data/lib/class_metrix/formatters/components/footer_component.rb +4 -4
- data/lib/class_metrix/formatters/components/generic_header_component.rb +2 -2
- data/lib/class_metrix/formatters/components/header_component.rb +4 -4
- data/lib/class_metrix/formatters/components/missing_behaviors_component.rb +7 -7
- data/lib/class_metrix/formatters/components/table_component/column_width_calculator.rb +56 -0
- data/lib/class_metrix/formatters/components/table_component/row_processor.rb +141 -0
- data/lib/class_metrix/formatters/components/table_component/table_data_extractor.rb +57 -0
- data/lib/class_metrix/formatters/components/table_component/table_renderer.rb +55 -0
- data/lib/class_metrix/formatters/components/table_component.rb +32 -245
- data/lib/class_metrix/formatters/csv_formatter.rb +3 -3
- data/lib/class_metrix/formatters/markdown_formatter.rb +3 -4
- data/lib/class_metrix/formatters/shared/markdown_table_builder.rb +12 -7
- data/lib/class_metrix/formatters/shared/table_builder.rb +92 -27
- data/lib/class_metrix/formatters/shared/value_processor.rb +72 -16
- data/lib/class_metrix/utils/debug_logger.rb +159 -0
- data/lib/class_metrix/version.rb +1 -1
- data/sig/class_metrix.rbs +8 -0
- data/sig/extractor.rbs +54 -0
- data/sig/extractors.rbs +84 -0
- data/sig/formatters_base.rbs +59 -0
- data/sig/formatters_components.rbs +133 -0
- data/sig/formatters_main.rbs +20 -0
- data/sig/formatters_shared.rbs +102 -0
- data/sig/manifest.yaml +32 -0
- data/sig/utils.rbs +57 -0
- data/sig/value_processor.rbs +11 -0
- data/sig/version.rbs +4 -0
- metadata +60 -10
- data/examples/advanced/error_handling.rb +0 -199
- data/examples/advanced/hash_expansion.rb +0 -180
- data/examples/basic/01_simple_constants.rb +0 -56
- data/examples/basic/02_simple_methods.rb +0 -99
- data/examples/basic/03_multi_type_extraction.rb +0 -116
- data/examples/components/configurable_reports.rb +0 -201
- data/examples/csv_output_demo.rb +0 -237
- data/examples/real_world/microservices_audit.rb +0 -312
- data/sig/class/metrix.rbs +0 -6
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ClassMetrix
|
4
|
+
module Formatters
|
5
|
+
module Components
|
6
|
+
class TableComponent
|
7
|
+
class TableDataExtractor
|
8
|
+
def initialize(headers)
|
9
|
+
@headers = headers
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_type_column?
|
13
|
+
@headers.first == "Type"
|
14
|
+
end
|
15
|
+
|
16
|
+
def value_start_index
|
17
|
+
has_type_column? ? 2 : 1
|
18
|
+
end
|
19
|
+
|
20
|
+
def behavior_column_index
|
21
|
+
has_type_column? ? 1 : 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def extract_row_data(row)
|
25
|
+
if has_type_column?
|
26
|
+
{
|
27
|
+
type_value: row[0],
|
28
|
+
behavior_name: row[1],
|
29
|
+
values: row[2..]
|
30
|
+
}
|
31
|
+
else
|
32
|
+
{
|
33
|
+
behavior_name: row[0],
|
34
|
+
values: row[1..]
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def row_has_expandable_hash?(row)
|
40
|
+
values = row[value_start_index..] || []
|
41
|
+
return false if values.nil?
|
42
|
+
|
43
|
+
values.any? { |cell| cell.is_a?(Hash) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def collect_hash_keys(values)
|
47
|
+
all_hash_keys = Set.new
|
48
|
+
values.each do |value|
|
49
|
+
all_hash_keys.merge(value.keys.map(&:to_s)) if value.is_a?(Hash)
|
50
|
+
end
|
51
|
+
all_hash_keys
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ClassMetrix
|
4
|
+
module Formatters
|
5
|
+
module Components
|
6
|
+
class TableComponent
|
7
|
+
class TableRenderer
|
8
|
+
def initialize(table_style: :standard, max_column_width: 50)
|
9
|
+
@table_style = table_style
|
10
|
+
@max_column_width = max_column_width
|
11
|
+
end
|
12
|
+
|
13
|
+
def render_table(headers, rows, column_widths)
|
14
|
+
output = [] # : Array[String]
|
15
|
+
output << build_row(headers, column_widths)
|
16
|
+
output << build_separator(column_widths)
|
17
|
+
|
18
|
+
rows.each do |row|
|
19
|
+
output << build_row(row, column_widths)
|
20
|
+
end
|
21
|
+
|
22
|
+
output
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def build_row(cells, col_widths)
|
28
|
+
formatted_cells = format_cells(cells, col_widths)
|
29
|
+
"|#{formatted_cells.join("|")}|"
|
30
|
+
end
|
31
|
+
|
32
|
+
def format_cells(cells, col_widths)
|
33
|
+
cells.each_with_index.map do |cell, i|
|
34
|
+
width = col_widths[i] || 10
|
35
|
+
cell_str = format_cell_content(cell)
|
36
|
+
" #{cell_str.ljust(width)} "
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def format_cell_content(cell)
|
41
|
+
cell_str = cell.to_s
|
42
|
+
return cell_str unless @table_style == :compact && cell_str.length > @max_column_width
|
43
|
+
|
44
|
+
"#{cell_str[0...(@max_column_width - 3)]}..."
|
45
|
+
end
|
46
|
+
|
47
|
+
def build_separator(col_widths)
|
48
|
+
separators = col_widths.map { |width| "-" * (width + 2) }
|
49
|
+
"|#{separators.join("|")}|"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
3
|
+
require_relative "table_component/table_data_extractor"
|
4
|
+
require_relative "table_component/row_processor"
|
5
|
+
require_relative "table_component/column_width_calculator"
|
6
|
+
require_relative "table_component/table_renderer"
|
4
7
|
|
5
8
|
module ClassMetrix
|
6
9
|
module Formatters
|
@@ -10,257 +13,41 @@ module ClassMetrix
|
|
10
13
|
@data = data
|
11
14
|
@options = options
|
12
15
|
@expand_hashes = options.fetch(:expand_hashes, false)
|
13
|
-
@table_style = options.fetch(:table_style, :standard)
|
16
|
+
@table_style = options.fetch(:table_style, :standard)
|
14
17
|
@min_column_width = options.fetch(:min_column_width, 3)
|
15
18
|
@max_column_width = options.fetch(:max_column_width, 50)
|
19
|
+
@hide_main_row = options.fetch(:hide_main_row, false)
|
20
|
+
@hide_key_rows = options.fetch(:hide_key_rows, true) # Default: show only main rows
|
21
|
+
|
22
|
+
# Initialize helper objects
|
23
|
+
@data_extractor = TableDataExtractor.new(@data[:headers])
|
24
|
+
@row_processor = RowProcessor.new(@data_extractor, {
|
25
|
+
hide_main_row: @hide_main_row,
|
26
|
+
hide_key_rows: @hide_key_rows
|
27
|
+
})
|
28
|
+
@width_calculator = ColumnWidthCalculator.new(
|
29
|
+
table_style: @table_style,
|
30
|
+
min_column_width: @min_column_width,
|
31
|
+
max_column_width: @max_column_width
|
32
|
+
)
|
33
|
+
@renderer = TableRenderer.new(
|
34
|
+
table_style: @table_style,
|
35
|
+
max_column_width: @max_column_width
|
36
|
+
)
|
16
37
|
end
|
17
38
|
|
18
39
|
def generate
|
19
|
-
return "" if @data[:headers].empty? || @data[:rows].empty?
|
40
|
+
return [""] if @data[:headers].empty? || @data[:rows].empty?
|
20
41
|
|
21
|
-
if @expand_hashes
|
22
|
-
format_with_hash_expansion
|
23
|
-
else
|
24
|
-
format_simple_table
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def format_simple_table
|
31
|
-
headers = @data[:headers]
|
32
|
-
rows = @data[:rows]
|
33
|
-
|
34
|
-
processed_rows = process_simple_rows(rows)
|
35
|
-
build_table(headers, processed_rows)
|
36
|
-
end
|
37
|
-
|
38
|
-
def format_with_hash_expansion
|
39
42
|
headers = @data[:headers]
|
40
|
-
rows = @
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
processed_row = [row[0]] # Keep the behavior name as-is
|
49
|
-
row[1..].each do |value|
|
50
|
-
processed_row << ValueProcessor.process(value)
|
51
|
-
end
|
52
|
-
processed_row
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def process_expanded_rows(rows, headers)
|
57
|
-
expanded_rows = []
|
58
|
-
|
59
|
-
rows.each do |row|
|
60
|
-
if row_has_expandable_hash?(row, headers)
|
61
|
-
expanded_rows.concat(expand_row(row, headers))
|
62
|
-
else
|
63
|
-
expanded_rows << process_non_hash_row(row, headers)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
expanded_rows
|
68
|
-
end
|
69
|
-
|
70
|
-
def row_has_expandable_hash?(row, headers)
|
71
|
-
has_type_column = headers.first == "Type"
|
72
|
-
value_start_index = has_type_column ? 2 : 1
|
73
|
-
row[value_start_index..].any? { |cell| cell.is_a?(Hash) }
|
74
|
-
end
|
75
|
-
|
76
|
-
def process_non_hash_row(row, headers)
|
77
|
-
has_type_column = headers.first == "Type"
|
78
|
-
if has_type_column
|
79
|
-
[row[0], row[1]] + row[2..].map { |value| ValueProcessor.process(value) }
|
80
|
-
else
|
81
|
-
[row[0]] + row[1..].map { |value| ValueProcessor.process(value) }
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def build_table(headers, rows)
|
86
|
-
col_widths = calculate_column_widths(headers, rows)
|
87
|
-
|
88
|
-
output = []
|
89
|
-
output << build_row(headers, col_widths)
|
90
|
-
output << build_separator(col_widths)
|
91
|
-
|
92
|
-
rows.each do |row|
|
93
|
-
output << build_row(row, col_widths)
|
94
|
-
end
|
95
|
-
|
96
|
-
output.join("\n")
|
97
|
-
end
|
98
|
-
|
99
|
-
def expand_row(row, headers)
|
100
|
-
has_type_column = headers.first == "Type"
|
101
|
-
row_data = extract_row_data(row, has_type_column)
|
102
|
-
|
103
|
-
all_hash_keys = collect_hash_keys(row_data[:values])
|
104
|
-
return [row] if all_hash_keys.empty?
|
105
|
-
|
106
|
-
build_expanded_rows(row_data, all_hash_keys, has_type_column, row)
|
107
|
-
end
|
108
|
-
|
109
|
-
def extract_row_data(row, has_type_column)
|
110
|
-
if has_type_column
|
111
|
-
build_type_column_data(row)
|
112
|
-
else
|
113
|
-
build_standard_column_data(row)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def build_type_column_data(row)
|
118
|
-
{
|
119
|
-
type_value: row[0],
|
120
|
-
behavior_name: row[1],
|
121
|
-
values: row[2..]
|
122
|
-
}
|
123
|
-
end
|
124
|
-
|
125
|
-
def build_standard_column_data(row)
|
126
|
-
{
|
127
|
-
behavior_name: row[0],
|
128
|
-
values: row[1..]
|
129
|
-
}
|
130
|
-
end
|
131
|
-
|
132
|
-
def collect_hash_keys(values)
|
133
|
-
all_hash_keys = Set.new
|
134
|
-
values.each do |value|
|
135
|
-
all_hash_keys.merge(value.keys.map(&:to_s)) if value.is_a?(Hash)
|
136
|
-
end
|
137
|
-
all_hash_keys
|
138
|
-
end
|
139
|
-
|
140
|
-
def build_expanded_rows(row_data, all_hash_keys, has_type_column, original_row)
|
141
|
-
expanded_rows = []
|
142
|
-
|
143
|
-
# Add main row
|
144
|
-
expanded_rows << build_main_expanded_row(row_data, has_type_column)
|
145
|
-
|
146
|
-
# Add key rows
|
147
|
-
all_hash_keys.to_a.sort.each do |key|
|
148
|
-
expanded_rows << build_key_row(key, row_data, has_type_column, original_row)
|
149
|
-
end
|
150
|
-
|
151
|
-
expanded_rows
|
152
|
-
end
|
153
|
-
|
154
|
-
def build_main_expanded_row(row_data, has_type_column)
|
155
|
-
processed_values = row_data[:values].map { |value| ValueProcessor.process(value) }
|
156
|
-
|
157
|
-
if has_type_column
|
158
|
-
[row_data[:type_value], row_data[:behavior_name]] + processed_values
|
159
|
-
else
|
160
|
-
[row_data[:behavior_name]] + processed_values
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def build_key_row(key, row_data, has_type_column, original_row)
|
165
|
-
path_name = ".#{key}"
|
166
|
-
key_values = process_key_values(key, row_data[:values], has_type_column, original_row)
|
167
|
-
|
168
|
-
if has_type_column
|
169
|
-
["-", path_name] + key_values
|
170
|
-
else
|
171
|
-
[path_name] + key_values
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def process_key_values(key, values, has_type_column, original_row)
|
176
|
-
values.map.with_index do |value, index|
|
177
|
-
if value.is_a?(Hash)
|
178
|
-
extract_hash_value(value, key)
|
179
|
-
else
|
180
|
-
handle_non_hash_value(original_row, index, has_type_column)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def extract_hash_value(hash, key)
|
186
|
-
has_key = hash.key?(key.to_sym) || hash.key?(key.to_s)
|
187
|
-
if has_key
|
188
|
-
hash_value = hash[key.to_sym] || hash[key.to_s]
|
189
|
-
ValueProcessor.process(hash_value)
|
190
|
-
else
|
191
|
-
"—" # Missing hash key
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
def handle_non_hash_value(original_row, index, has_type_column)
|
196
|
-
original_value = original_row[has_type_column ? (index + 2) : (index + 1)]
|
197
|
-
if original_value.to_s.include?("🚫")
|
198
|
-
"🚫 Not defined"
|
199
|
-
else
|
200
|
-
"—" # Non-hash values don't have this key
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
def calculate_column_widths(headers, rows)
|
205
|
-
col_count = headers.length
|
206
|
-
widths = initialize_column_widths(col_count, headers)
|
207
|
-
|
208
|
-
update_widths_from_rows(widths, rows, col_count)
|
209
|
-
apply_minimum_widths(widths)
|
210
|
-
end
|
211
|
-
|
212
|
-
def initialize_column_widths(col_count, headers)
|
213
|
-
widths = Array.new(col_count, 0)
|
214
|
-
headers.each_with_index do |header, i|
|
215
|
-
widths[i] = [widths[i], header.to_s.length].max
|
216
|
-
end
|
217
|
-
widths
|
218
|
-
end
|
219
|
-
|
220
|
-
def update_widths_from_rows(widths, rows, col_count)
|
221
|
-
rows.each do |row|
|
222
|
-
row.each_with_index do |cell, i|
|
223
|
-
next if i >= col_count
|
224
|
-
|
225
|
-
cell_width = calculate_cell_width(cell)
|
226
|
-
widths[i] = [widths[i], cell_width].max
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
def calculate_cell_width(cell)
|
232
|
-
cell_width = cell.to_s.length
|
233
|
-
# Apply max width limit for readability
|
234
|
-
@table_style == :compact ? [@max_column_width, cell_width].min : cell_width
|
235
|
-
end
|
236
|
-
|
237
|
-
def apply_minimum_widths(widths)
|
238
|
-
widths.map { |w| [w, @min_column_width].max }
|
239
|
-
end
|
240
|
-
|
241
|
-
def build_row(cells, col_widths)
|
242
|
-
formatted_cells = format_cells(cells, col_widths)
|
243
|
-
"|#{formatted_cells.join("|")}|"
|
244
|
-
end
|
245
|
-
|
246
|
-
def format_cells(cells, col_widths)
|
247
|
-
cells.each_with_index.map do |cell, i|
|
248
|
-
width = col_widths[i] || 10
|
249
|
-
cell_str = format_cell_content(cell)
|
250
|
-
" #{cell_str.ljust(width)} "
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
def format_cell_content(cell)
|
255
|
-
cell_str = cell.to_s
|
256
|
-
return cell_str unless @table_style == :compact && cell_str.length > @max_column_width
|
257
|
-
|
258
|
-
"#{cell_str[0...(@max_column_width - 3)]}..."
|
259
|
-
end
|
260
|
-
|
261
|
-
def build_separator(col_widths)
|
262
|
-
separators = col_widths.map { |width| "-" * (width + 2) }
|
263
|
-
"|#{separators.join("|")}|"
|
43
|
+
rows = if @expand_hashes
|
44
|
+
@row_processor.process_expanded_rows(@data[:rows])
|
45
|
+
else
|
46
|
+
@row_processor.process_simple_rows(@data[:rows])
|
47
|
+
end
|
48
|
+
|
49
|
+
column_widths = @width_calculator.calculate_widths(headers, rows)
|
50
|
+
@renderer.render_table(headers, rows, column_widths)
|
264
51
|
end
|
265
52
|
end
|
266
53
|
end
|
@@ -15,7 +15,7 @@ module ClassMetrix
|
|
15
15
|
def format
|
16
16
|
return "" if @data[:headers].empty? || @data[:rows].empty?
|
17
17
|
|
18
|
-
output_lines = []
|
18
|
+
output_lines = [] # : Array[String]
|
19
19
|
|
20
20
|
# Add CSV header comments
|
21
21
|
if @options.fetch(:show_metadata, true)
|
@@ -65,7 +65,7 @@ module ClassMetrix
|
|
65
65
|
|
66
66
|
return [] if headers.empty?
|
67
67
|
|
68
|
-
output = []
|
68
|
+
output = [] # : Array[String]
|
69
69
|
separator = @options.fetch(:separator, ",")
|
70
70
|
quote_char = @options.fetch(:quote_char, '"')
|
71
71
|
|
@@ -75,7 +75,7 @@ module ClassMetrix
|
|
75
75
|
csv_rows.each do |row|
|
76
76
|
# Ensure all row values are strings and properly quoted
|
77
77
|
formatted_row = row.map { |cell| format_csv_cell(cell) }
|
78
|
-
csv_line = CSV.
|
78
|
+
csv_line = CSV.generate(col_sep: separator, quote_char: quote_char) { |csv| csv << formatted_row }.chomp
|
79
79
|
output << csv_line
|
80
80
|
end
|
81
81
|
|
@@ -16,7 +16,7 @@ module ClassMetrix
|
|
16
16
|
def format
|
17
17
|
return "" if @data[:headers].empty? || @data[:rows].empty?
|
18
18
|
|
19
|
-
output = []
|
19
|
+
output = [] # : Array[String]
|
20
20
|
|
21
21
|
# Add header sections (title, classes, extraction info)
|
22
22
|
if @options.fetch(:show_metadata, true)
|
@@ -77,7 +77,7 @@ module ClassMetrix
|
|
77
77
|
|
78
78
|
widths = calculate_column_widths(headers, rows)
|
79
79
|
|
80
|
-
output = []
|
80
|
+
output = [] # : Array[String]
|
81
81
|
output << build_header_row(headers, widths)
|
82
82
|
output << build_separator_row(widths)
|
83
83
|
output.concat(build_data_rows(rows, headers, widths))
|
@@ -170,8 +170,7 @@ module ClassMetrix
|
|
170
170
|
if max_width >= 15
|
171
171
|
# Look for the first complete key-value pair (handle :symbol=>value format)
|
172
172
|
match = text.match(/\{(:[^,}]+=>[^,}]+)/)
|
173
|
-
if match
|
174
|
-
first_pair = match[1]
|
173
|
+
if match && (first_pair = match[1])
|
175
174
|
needed_length = first_pair.length + 6 # For "{", ", ...}"
|
176
175
|
return "{#{first_pair}, ...}" if needed_length <= max_width
|
177
176
|
end
|
@@ -9,7 +9,7 @@ module ClassMetrix
|
|
9
9
|
private
|
10
10
|
|
11
11
|
def process_value(value)
|
12
|
-
@value_processor.process_for_markdown(value)
|
12
|
+
@value_processor.process_for_markdown(value, debug_mode: @options.fetch(:debug_mode, false))
|
13
13
|
end
|
14
14
|
|
15
15
|
def get_null_value
|
@@ -19,7 +19,7 @@ module ClassMetrix
|
|
19
19
|
# Create proper flat table structure for hash expansion
|
20
20
|
def expand_row(row, _headers)
|
21
21
|
behavior_name = row[behavior_column_index]
|
22
|
-
values = row[value_start_index..]
|
22
|
+
values = row[value_start_index..] || []
|
23
23
|
|
24
24
|
all_hash_keys = collect_unique_hash_keys(values)
|
25
25
|
return [process_row(row)] if all_hash_keys.empty?
|
@@ -36,9 +36,14 @@ module ClassMetrix
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def build_expanded_row_structure(row, behavior_name, values, all_hash_keys)
|
39
|
-
expanded_rows = []
|
40
|
-
|
41
|
-
|
39
|
+
expanded_rows = [] # : Array[Array[String]]
|
40
|
+
|
41
|
+
# Add main row if configured to show
|
42
|
+
expanded_rows << build_main_row(row, behavior_name, values) if should_show_main_row?
|
43
|
+
|
44
|
+
# Add key rows if configured to show
|
45
|
+
expanded_rows.concat(build_hash_key_rows(row, behavior_name, values, all_hash_keys)) if should_show_key_rows?
|
46
|
+
|
42
47
|
expanded_rows
|
43
48
|
end
|
44
49
|
|
@@ -84,8 +89,8 @@ module ClassMetrix
|
|
84
89
|
end
|
85
90
|
|
86
91
|
def extract_hash_key_value(hash, key)
|
87
|
-
if @value_processor.has_hash_key?(hash, key)
|
88
|
-
hash_value = @value_processor.safe_hash_lookup(hash, key)
|
92
|
+
if @value_processor.has_hash_key?(hash, key, debug_mode: @options.fetch(:debug_mode, false))
|
93
|
+
hash_value = @value_processor.safe_hash_lookup(hash, key, debug_mode: @options.fetch(:debug_mode, false))
|
89
94
|
process_value(hash_value)
|
90
95
|
else
|
91
96
|
get_null_value
|