class-metrix 0.1.2 → 1.0.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/.editorconfig +48 -0
- data/.vscode/README.md +72 -0
- data/.vscode/extensions.json +28 -0
- data/.vscode/launch.json +32 -0
- data/.vscode/settings.json +88 -0
- data/.vscode/tasks.json +99 -0
- data/CHANGELOG.md +71 -4
- data/README.md +41 -7
- data/docs/ARCHITECTURE.md +501 -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 +6 -5
- data/lib/class_metrix/formatters/components/footer_component.rb +1 -1
- 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 +138 -0
- data/lib/class_metrix/formatters/components/table_component/table_data_extractor.rb +54 -0
- data/lib/class_metrix/formatters/components/table_component/table_renderer.rb +55 -0
- data/lib/class_metrix/formatters/components/table_component.rb +30 -244
- data/lib/class_metrix/formatters/shared/markdown_table_builder.rb +10 -5
- data/lib/class_metrix/formatters/shared/table_builder.rb +84 -21
- 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
- metadata +17 -9
- 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
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ClassMetrix
|
|
4
|
+
module Utils
|
|
5
|
+
# Debug logging utility for ClassMetrix
|
|
6
|
+
# Provides safe, consistent debug output across all components
|
|
7
|
+
class DebugLogger
|
|
8
|
+
# Debug levels: :basic, :detailed, :verbose
|
|
9
|
+
LEVELS = { basic: 1, detailed: 2, verbose: 3 }.freeze
|
|
10
|
+
|
|
11
|
+
def initialize(component_name, debug_mode = false, level = :basic)
|
|
12
|
+
@component_name = component_name
|
|
13
|
+
@debug_mode = debug_mode
|
|
14
|
+
@level = LEVELS[level] || LEVELS[:basic]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def log(message, level = :basic)
|
|
18
|
+
return unless @debug_mode && LEVELS[level] <= @level
|
|
19
|
+
|
|
20
|
+
puts "[DEBUG #{@component_name}] #{message}"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def log_safe_operation(operation_name, level = :detailed, &block)
|
|
24
|
+
log("Starting #{operation_name}", level)
|
|
25
|
+
result = block.call
|
|
26
|
+
log("Completed #{operation_name} successfully", level)
|
|
27
|
+
result
|
|
28
|
+
rescue StandardError => e
|
|
29
|
+
log("Error in #{operation_name}: #{e.class.name}: #{e.message}")
|
|
30
|
+
raise
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Summary logging for groups of similar operations
|
|
34
|
+
def log_summary(operation, items, &block)
|
|
35
|
+
return unless @debug_mode
|
|
36
|
+
|
|
37
|
+
if @level >= LEVELS[:detailed]
|
|
38
|
+
log("#{operation} (#{items.length} items)")
|
|
39
|
+
items.each_with_index { |item, i| block.call(item, i) } if block_given?
|
|
40
|
+
else
|
|
41
|
+
log("#{operation} (#{items.length} items)")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def log_decision(decision, reason, level = :basic)
|
|
46
|
+
log("Decision: #{decision} - #{reason}", level)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def log_anomaly(description)
|
|
50
|
+
log("⚠️ Anomaly: #{description}")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Safe inspection methods to handle problematic objects
|
|
54
|
+
def safe_inspect(value)
|
|
55
|
+
value.inspect
|
|
56
|
+
rescue StandardError => e
|
|
57
|
+
"[inspect failed: #{e.class.name}]"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def safe_class(value)
|
|
61
|
+
value.class
|
|
62
|
+
rescue StandardError => e
|
|
63
|
+
"[class failed: #{e.class.name}]"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def safe_keys(value)
|
|
67
|
+
value.keys
|
|
68
|
+
rescue StandardError => e
|
|
69
|
+
"[keys failed: #{e.class.name}]"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def safe_length(value)
|
|
73
|
+
value.length
|
|
74
|
+
rescue StandardError
|
|
75
|
+
"[length failed]"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def safe_truncate(str, max_length)
|
|
79
|
+
return str unless str.respond_to?(:length) && str.respond_to?(:[])
|
|
80
|
+
|
|
81
|
+
str.length > max_length ? "#{str[0...max_length]}..." : str
|
|
82
|
+
rescue StandardError => e
|
|
83
|
+
"[truncate failed: #{e.class.name}]"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def safe_to_s(value)
|
|
87
|
+
value.to_s
|
|
88
|
+
rescue StandardError => e
|
|
89
|
+
begin
|
|
90
|
+
value.class.name
|
|
91
|
+
rescue StandardError => e2
|
|
92
|
+
"[to_s failed: #{e.class.name}, class failed: #{e2.class.name}]"
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def log_value_details(value, index = nil, level = :verbose)
|
|
97
|
+
return unless @debug_mode && @level >= LEVELS[level]
|
|
98
|
+
|
|
99
|
+
prefix = index ? "Value #{index}" : "Value"
|
|
100
|
+
log("#{prefix}: #{safe_inspect(value)} (#{safe_class(value)})", level)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def log_hash_detection(value, index = nil, level = :detailed)
|
|
104
|
+
return unless @debug_mode && @level >= LEVELS[level]
|
|
105
|
+
|
|
106
|
+
prefix = index ? "Value #{index}" : "Value"
|
|
107
|
+
is_hash = value.is_a?(Hash)
|
|
108
|
+
is_real_hash = value.is_a?(Hash) && value.instance_of?(Hash)
|
|
109
|
+
|
|
110
|
+
return unless is_hash
|
|
111
|
+
|
|
112
|
+
log("#{prefix} hash detection:")
|
|
113
|
+
log(" is_a?(Hash): #{is_hash}, class == Hash: #{is_real_hash}")
|
|
114
|
+
log(" respond_to?(:keys): #{value.respond_to?(:keys)}")
|
|
115
|
+
|
|
116
|
+
if is_hash && is_real_hash
|
|
117
|
+
log(" keys: #{safe_keys(value)}")
|
|
118
|
+
elsif is_hash
|
|
119
|
+
log_anomaly("Hash-like object (#{safe_class(value)}) but not real Hash - will be skipped")
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Smart hash detection summary
|
|
124
|
+
def log_hash_detection_summary(values)
|
|
125
|
+
return unless @debug_mode
|
|
126
|
+
|
|
127
|
+
hash_count = 0
|
|
128
|
+
real_hash_count = 0
|
|
129
|
+
anomaly_count = 0
|
|
130
|
+
|
|
131
|
+
values.each do |value|
|
|
132
|
+
next unless value.is_a?(Hash)
|
|
133
|
+
|
|
134
|
+
hash_count += 1
|
|
135
|
+
if value.instance_of?(Hash)
|
|
136
|
+
real_hash_count += 1
|
|
137
|
+
else
|
|
138
|
+
anomaly_count += 1
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
return unless hash_count.positive?
|
|
143
|
+
|
|
144
|
+
log("Hash detection summary: #{real_hash_count} real hashes, #{anomaly_count} hash-like objects")
|
|
145
|
+
log_anomaly("Found #{anomaly_count} hash-like proxy objects") if anomaly_count.positive?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def enabled?
|
|
149
|
+
@debug_mode
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
attr_reader :level
|
|
153
|
+
|
|
154
|
+
def set_level(level)
|
|
155
|
+
@level = LEVELS[level] || LEVELS[:basic]
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
data/lib/class_metrix/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: class-metrix
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Huy Nguyen
|
|
@@ -47,23 +47,26 @@ executables: []
|
|
|
47
47
|
extensions: []
|
|
48
48
|
extra_rdoc_files: []
|
|
49
49
|
files:
|
|
50
|
+
- ".editorconfig"
|
|
50
51
|
- ".rspec"
|
|
51
52
|
- ".rubocop.yml"
|
|
52
53
|
- ".tool-versions"
|
|
54
|
+
- ".vscode/README.md"
|
|
55
|
+
- ".vscode/extensions.json"
|
|
56
|
+
- ".vscode/launch.json"
|
|
57
|
+
- ".vscode/settings.json"
|
|
58
|
+
- ".vscode/tasks.json"
|
|
53
59
|
- CHANGELOG.md
|
|
54
60
|
- LICENSE.txt
|
|
55
61
|
- README.md
|
|
56
62
|
- RELEASE_GUIDE.md
|
|
57
63
|
- Rakefile
|
|
64
|
+
- docs/ARCHITECTURE.md
|
|
58
65
|
- examples/README.md
|
|
59
|
-
- examples/
|
|
60
|
-
- examples/
|
|
61
|
-
- examples/
|
|
62
|
-
- examples/
|
|
63
|
-
- examples/basic/03_multi_type_extraction.rb
|
|
64
|
-
- examples/components/configurable_reports.rb
|
|
65
|
-
- examples/csv_output_demo.rb
|
|
66
|
-
- examples/real_world/microservices_audit.rb
|
|
66
|
+
- examples/basic_usage.rb
|
|
67
|
+
- examples/debug_levels_demo.rb
|
|
68
|
+
- examples/debug_mode_demo.rb
|
|
69
|
+
- examples/inheritance_and_modules.rb
|
|
67
70
|
- lib/class_metrix.rb
|
|
68
71
|
- lib/class_metrix/extractor.rb
|
|
69
72
|
- lib/class_metrix/extractors/constants_extractor.rb
|
|
@@ -76,6 +79,10 @@ files:
|
|
|
76
79
|
- lib/class_metrix/formatters/components/header_component.rb
|
|
77
80
|
- lib/class_metrix/formatters/components/missing_behaviors_component.rb
|
|
78
81
|
- lib/class_metrix/formatters/components/table_component.rb
|
|
82
|
+
- lib/class_metrix/formatters/components/table_component/column_width_calculator.rb
|
|
83
|
+
- lib/class_metrix/formatters/components/table_component/row_processor.rb
|
|
84
|
+
- lib/class_metrix/formatters/components/table_component/table_data_extractor.rb
|
|
85
|
+
- lib/class_metrix/formatters/components/table_component/table_renderer.rb
|
|
79
86
|
- lib/class_metrix/formatters/csv_formatter.rb
|
|
80
87
|
- lib/class_metrix/formatters/markdown_formatter.rb
|
|
81
88
|
- lib/class_metrix/formatters/shared/csv_table_builder.rb
|
|
@@ -84,6 +91,7 @@ files:
|
|
|
84
91
|
- lib/class_metrix/formatters/shared/value_processor.rb
|
|
85
92
|
- lib/class_metrix/processors/value_processor.rb
|
|
86
93
|
- lib/class_metrix/utils/class_resolver.rb
|
|
94
|
+
- lib/class_metrix/utils/debug_logger.rb
|
|
87
95
|
- lib/class_metrix/version.rb
|
|
88
96
|
- sig/class/metrix.rbs
|
|
89
97
|
homepage: https://github.com/patrick204nqh/class-metrix
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require_relative "../../lib/class_metrix"
|
|
5
|
-
|
|
6
|
-
puts "=== Advanced Example: Error Handling ==="
|
|
7
|
-
puts
|
|
8
|
-
|
|
9
|
-
# Classes that demonstrate various error scenarios
|
|
10
|
-
class WorkingService
|
|
11
|
-
# Working constants
|
|
12
|
-
SERVICE_NAME = "working"
|
|
13
|
-
VERSION = "1.0.0"
|
|
14
|
-
ENABLED = true
|
|
15
|
-
|
|
16
|
-
# Working methods
|
|
17
|
-
def self.status
|
|
18
|
-
"healthy"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def self.version
|
|
22
|
-
"1.0.0"
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.health_check
|
|
26
|
-
{ status: "ok", uptime: 12_345 }
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def self.enabled?
|
|
30
|
-
true
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
class PartiallyBrokenService
|
|
35
|
-
# Working constants
|
|
36
|
-
SERVICE_NAME = "partially_broken"
|
|
37
|
-
VERSION = "0.9.0"
|
|
38
|
-
# Missing ENABLED constant
|
|
39
|
-
|
|
40
|
-
# Working methods
|
|
41
|
-
def self.status
|
|
42
|
-
"degraded"
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def self.version
|
|
46
|
-
"0.9.0"
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
# Broken method that raises an error
|
|
50
|
-
def self.health_check
|
|
51
|
-
raise StandardError, "Health check failed!"
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def self.enabled?
|
|
55
|
-
false
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Method that returns nil
|
|
59
|
-
def self.uptime
|
|
60
|
-
nil
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Method with complex error
|
|
64
|
-
def self.database_connection
|
|
65
|
-
raise ActiveRecord::ConnectionNotEstablished, "Database unavailable"
|
|
66
|
-
rescue NameError
|
|
67
|
-
# If ActiveRecord is not available, raise a different error
|
|
68
|
-
raise "Connection library not available"
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
class CompletelyBrokenService
|
|
73
|
-
# Has some constants
|
|
74
|
-
SERVICE_NAME = "broken"
|
|
75
|
-
# Missing VERSION and ENABLED
|
|
76
|
-
|
|
77
|
-
# Has working method
|
|
78
|
-
def self.status
|
|
79
|
-
"down"
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
# Missing version method
|
|
83
|
-
|
|
84
|
-
# Broken health_check
|
|
85
|
-
def self.health_check
|
|
86
|
-
raise NoMethodError, "Health monitoring not implemented"
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# Method that raises during execution
|
|
90
|
-
def self.enabled?
|
|
91
|
-
some_undefined_variable.call
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
# Method that returns false
|
|
95
|
-
def self.deprecated?
|
|
96
|
-
true
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
puts "=== Service Classes Defined ==="
|
|
101
|
-
puts "WorkingService: All methods work"
|
|
102
|
-
puts "PartiallyBrokenService: Some methods fail"
|
|
103
|
-
puts "CompletelyBrokenService: Most methods fail"
|
|
104
|
-
puts
|
|
105
|
-
|
|
106
|
-
# 1. Extract without error handling (will raise errors)
|
|
107
|
-
puts "💥 1. WITHOUT ERROR HANDLING (This will show errors)"
|
|
108
|
-
puts "-" * 60
|
|
109
|
-
|
|
110
|
-
begin
|
|
111
|
-
result = ClassMetrix.extract(:class_methods)
|
|
112
|
-
.from([WorkingService, PartiallyBrokenService])
|
|
113
|
-
.filter(/health_check/)
|
|
114
|
-
.to_markdown
|
|
115
|
-
puts result
|
|
116
|
-
rescue StandardError => e
|
|
117
|
-
puts "❌ Error occurred: #{e.class.name}: #{e.message}"
|
|
118
|
-
end
|
|
119
|
-
puts
|
|
120
|
-
|
|
121
|
-
# 2. Extract with error handling
|
|
122
|
-
puts "🛡️ 2. WITH ERROR HANDLING (Graceful failure)"
|
|
123
|
-
puts "-" * 60
|
|
124
|
-
result = ClassMetrix.extract(:class_methods)
|
|
125
|
-
.from([WorkingService, PartiallyBrokenService, CompletelyBrokenService])
|
|
126
|
-
.handle_errors
|
|
127
|
-
.to_markdown
|
|
128
|
-
|
|
129
|
-
puts result
|
|
130
|
-
puts
|
|
131
|
-
|
|
132
|
-
# 3. Constants with missing values
|
|
133
|
-
puts "📋 3. CONSTANTS WITH MISSING VALUES"
|
|
134
|
-
puts "-" * 60
|
|
135
|
-
result = ClassMetrix.extract(:constants)
|
|
136
|
-
.from([WorkingService, PartiallyBrokenService, CompletelyBrokenService])
|
|
137
|
-
.handle_errors
|
|
138
|
-
.to_markdown
|
|
139
|
-
|
|
140
|
-
puts result
|
|
141
|
-
puts
|
|
142
|
-
|
|
143
|
-
# 4. Multi-type extraction with errors
|
|
144
|
-
puts "📊 4. MULTI-TYPE WITH ERROR HANDLING"
|
|
145
|
-
puts "-" * 60
|
|
146
|
-
result = ClassMetrix.extract(:constants, :class_methods)
|
|
147
|
-
.from([WorkingService, PartiallyBrokenService, CompletelyBrokenService])
|
|
148
|
-
.filter(/SERVICE_NAME|status|enabled/)
|
|
149
|
-
.handle_errors
|
|
150
|
-
.to_markdown
|
|
151
|
-
|
|
152
|
-
puts result
|
|
153
|
-
puts
|
|
154
|
-
|
|
155
|
-
# 5. Focus on problematic methods
|
|
156
|
-
puts "🔍 5. PROBLEMATIC METHODS ANALYSIS"
|
|
157
|
-
puts "-" * 60
|
|
158
|
-
result = ClassMetrix.extract(:class_methods)
|
|
159
|
-
.from([WorkingService, PartiallyBrokenService, CompletelyBrokenService])
|
|
160
|
-
.filter(/health_check|database|uptime/)
|
|
161
|
-
.handle_errors
|
|
162
|
-
.to_markdown
|
|
163
|
-
|
|
164
|
-
puts result
|
|
165
|
-
puts
|
|
166
|
-
|
|
167
|
-
# 6. Boolean and nil value handling
|
|
168
|
-
puts "✅ 6. BOOLEAN AND NIL VALUE HANDLING"
|
|
169
|
-
puts "-" * 60
|
|
170
|
-
result = ClassMetrix.extract(:class_methods)
|
|
171
|
-
.from([WorkingService, PartiallyBrokenService, CompletelyBrokenService])
|
|
172
|
-
.filter(/enabled\?|deprecated\?|uptime/)
|
|
173
|
-
.handle_errors
|
|
174
|
-
.to_markdown
|
|
175
|
-
|
|
176
|
-
puts result
|
|
177
|
-
puts
|
|
178
|
-
|
|
179
|
-
# 7. Save comprehensive error analysis report
|
|
180
|
-
puts "💾 7. SAVING COMPREHENSIVE ERROR ANALYSIS REPORT"
|
|
181
|
-
puts "-" * 60
|
|
182
|
-
report = ClassMetrix.extract(:constants, :class_methods)
|
|
183
|
-
.from([WorkingService, PartiallyBrokenService, CompletelyBrokenService])
|
|
184
|
-
.handle_errors
|
|
185
|
-
.to_markdown("error_analysis_report.md", title: "Service Health Analysis Report")
|
|
186
|
-
|
|
187
|
-
puts "✅ Comprehensive error analysis saved to: error_analysis_report.md"
|
|
188
|
-
puts "📊 Report contains #{report.lines.count} lines with rich metadata"
|
|
189
|
-
puts
|
|
190
|
-
|
|
191
|
-
puts "🛡️ Enhanced Error Handling Features Demonstrated:"
|
|
192
|
-
puts "• 🚫 Missing constants: '🚫 Not defined'"
|
|
193
|
-
puts "• 🚫 Missing methods: '🚫 No method'"
|
|
194
|
-
puts "• ⚠️ Runtime errors: '⚠️ Error: [descriptive message]'"
|
|
195
|
-
puts "• ❌ Boolean false and nil values: '❌'"
|
|
196
|
-
puts "• ✅ Boolean true values: '✅'"
|
|
197
|
-
puts "• 📊 Rich markdown reports with titles and metadata"
|
|
198
|
-
puts "• 📋 Missing behaviors summary per class"
|
|
199
|
-
puts "• 🛡️ handle_errors flag enables graceful degradation"
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require_relative "../../lib/class_metrix"
|
|
5
|
-
|
|
6
|
-
puts "=== Advanced Example: Hash Expansion ==="
|
|
7
|
-
puts
|
|
8
|
-
|
|
9
|
-
# Configuration classes with complex hash structures
|
|
10
|
-
class DatabaseConfig
|
|
11
|
-
# Hash constants
|
|
12
|
-
DEFAULT_CONFIG = {
|
|
13
|
-
host: "localhost",
|
|
14
|
-
port: 5432,
|
|
15
|
-
ssl: true,
|
|
16
|
-
pool_size: 5
|
|
17
|
-
}.freeze
|
|
18
|
-
|
|
19
|
-
CONNECTION_POOLS = {
|
|
20
|
-
read: { size: 10, timeout: 30 },
|
|
21
|
-
write: { size: 5, timeout: 15 },
|
|
22
|
-
admin: { size: 2, timeout: 60 }
|
|
23
|
-
}.freeze
|
|
24
|
-
|
|
25
|
-
# Hash methods
|
|
26
|
-
def self.production_config
|
|
27
|
-
{
|
|
28
|
-
host: "db.production.com",
|
|
29
|
-
port: 5432,
|
|
30
|
-
database: "myapp_production",
|
|
31
|
-
ssl: true,
|
|
32
|
-
pool_size: 20,
|
|
33
|
-
timeout: 30,
|
|
34
|
-
backup_enabled: true
|
|
35
|
-
}
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def self.development_config
|
|
39
|
-
{
|
|
40
|
-
host: "localhost",
|
|
41
|
-
port: 5432,
|
|
42
|
-
database: "myapp_development",
|
|
43
|
-
ssl: false,
|
|
44
|
-
pool_size: 5,
|
|
45
|
-
timeout: 10
|
|
46
|
-
}
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def self.simple_value
|
|
50
|
-
"not a hash"
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
class RedisConfig
|
|
55
|
-
# Hash constants
|
|
56
|
-
DEFAULT_CONFIG = {
|
|
57
|
-
host: "localhost",
|
|
58
|
-
port: 6379,
|
|
59
|
-
ssl: false,
|
|
60
|
-
timeout: 5
|
|
61
|
-
}.freeze
|
|
62
|
-
|
|
63
|
-
CLUSTER_CONFIG = {
|
|
64
|
-
nodes: 3,
|
|
65
|
-
replication: true,
|
|
66
|
-
failover: "auto"
|
|
67
|
-
}.freeze
|
|
68
|
-
|
|
69
|
-
# Hash methods
|
|
70
|
-
def self.production_config
|
|
71
|
-
{
|
|
72
|
-
host: "redis.internal",
|
|
73
|
-
port: 6379,
|
|
74
|
-
database: 0,
|
|
75
|
-
ssl: false,
|
|
76
|
-
max_connections: 100,
|
|
77
|
-
cluster_enabled: true
|
|
78
|
-
}
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def self.development_config
|
|
82
|
-
{
|
|
83
|
-
host: "localhost",
|
|
84
|
-
port: 6379,
|
|
85
|
-
database: 1,
|
|
86
|
-
ssl: false,
|
|
87
|
-
max_connections: 10
|
|
88
|
-
}
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def self.simple_value
|
|
92
|
-
42
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
puts "=== Configuration Classes Defined ==="
|
|
97
|
-
puts "DatabaseConfig and RedisConfig with hash constants and methods"
|
|
98
|
-
puts
|
|
99
|
-
|
|
100
|
-
# 1. Normal output (without expansion)
|
|
101
|
-
puts "📋 1. NORMAL OUTPUT (Hashes as inspect strings)"
|
|
102
|
-
puts "-" * 60
|
|
103
|
-
result = ClassMetrix.extract(:class_methods)
|
|
104
|
-
.from([DatabaseConfig, RedisConfig])
|
|
105
|
-
.filter(/config$/)
|
|
106
|
-
.to_markdown
|
|
107
|
-
|
|
108
|
-
puts result
|
|
109
|
-
puts
|
|
110
|
-
|
|
111
|
-
# 2. Expanded output
|
|
112
|
-
puts "🔍 2. EXPANDED OUTPUT (Hash keys as sub-rows)"
|
|
113
|
-
puts "-" * 60
|
|
114
|
-
result = ClassMetrix.extract(:class_methods)
|
|
115
|
-
.from([DatabaseConfig, RedisConfig])
|
|
116
|
-
.filter(/config$/)
|
|
117
|
-
.expand_hashes
|
|
118
|
-
.to_markdown
|
|
119
|
-
|
|
120
|
-
puts result
|
|
121
|
-
puts
|
|
122
|
-
|
|
123
|
-
# 3. Constants with expansion
|
|
124
|
-
puts "📊 3. CONSTANTS WITH HASH EXPANSION"
|
|
125
|
-
puts "-" * 60
|
|
126
|
-
result = ClassMetrix.extract(:constants)
|
|
127
|
-
.from([DatabaseConfig, RedisConfig])
|
|
128
|
-
.filter(/CONFIG/)
|
|
129
|
-
.expand_hashes
|
|
130
|
-
.handle_errors
|
|
131
|
-
.to_markdown
|
|
132
|
-
|
|
133
|
-
puts result
|
|
134
|
-
puts
|
|
135
|
-
|
|
136
|
-
# 4. Mixed data types with expansion
|
|
137
|
-
puts "🔧 4. MIXED DATA TYPES WITH EXPANSION"
|
|
138
|
-
puts "-" * 60
|
|
139
|
-
result = ClassMetrix.extract(:class_methods)
|
|
140
|
-
.from([DatabaseConfig, RedisConfig])
|
|
141
|
-
.expand_hashes
|
|
142
|
-
.to_markdown
|
|
143
|
-
|
|
144
|
-
puts result
|
|
145
|
-
puts
|
|
146
|
-
|
|
147
|
-
# 5. Multi-type extraction with expansion
|
|
148
|
-
puts "🚀 5. MULTI-TYPE WITH HASH EXPANSION"
|
|
149
|
-
puts "-" * 60
|
|
150
|
-
result = ClassMetrix.extract(:constants, :class_methods)
|
|
151
|
-
.from([DatabaseConfig, RedisConfig])
|
|
152
|
-
.filter(/DEFAULT_CONFIG|production_config/)
|
|
153
|
-
.expand_hashes
|
|
154
|
-
.handle_errors
|
|
155
|
-
.to_markdown
|
|
156
|
-
|
|
157
|
-
puts result
|
|
158
|
-
puts
|
|
159
|
-
|
|
160
|
-
# 6. Save expanded report
|
|
161
|
-
puts "💾 6. SAVING EXPANDED REPORT"
|
|
162
|
-
puts "-" * 60
|
|
163
|
-
report = ClassMetrix.extract(:constants, :class_methods)
|
|
164
|
-
.from([DatabaseConfig, RedisConfig])
|
|
165
|
-
.expand_hashes
|
|
166
|
-
.handle_errors
|
|
167
|
-
.to_markdown("config_analysis_expanded.md")
|
|
168
|
-
|
|
169
|
-
puts "✅ Expanded report saved to: config_analysis_expanded.md"
|
|
170
|
-
puts "📊 Report contains #{report.lines.count} lines"
|
|
171
|
-
puts
|
|
172
|
-
|
|
173
|
-
puts "✨ Hash Expansion Features Demonstrated:"
|
|
174
|
-
puts "• 📋 Hash indicators show number of keys"
|
|
175
|
-
puts "• └─ Sub-rows show individual key-value pairs"
|
|
176
|
-
puts "• ❌ Missing keys shown clearly"
|
|
177
|
-
puts "• — Non-hash values shown with dash"
|
|
178
|
-
puts "• Mixed data types handled properly"
|
|
179
|
-
puts "• Works with both constants and methods"
|
|
180
|
-
puts "• Compatible with multi-type extraction"
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require_relative "../../lib/class_metrix"
|
|
5
|
-
|
|
6
|
-
puts "=== Basic Example 1: Simple Constants ==="
|
|
7
|
-
puts
|
|
8
|
-
|
|
9
|
-
# Define some simple classes with constants
|
|
10
|
-
class User
|
|
11
|
-
ROLE_NAME = "user"
|
|
12
|
-
MAX_LOGIN_ATTEMPTS = 3
|
|
13
|
-
ACCOUNT_TYPE = "standard"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
class Admin
|
|
17
|
-
ROLE_NAME = "admin"
|
|
18
|
-
MAX_LOGIN_ATTEMPTS = 5
|
|
19
|
-
ACCOUNT_TYPE = "premium"
|
|
20
|
-
ADMIN_LEVEL = 10
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
class Guest
|
|
24
|
-
ROLE_NAME = "guest"
|
|
25
|
-
MAX_LOGIN_ATTEMPTS = 1
|
|
26
|
-
ACCOUNT_TYPE = "basic"
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
puts "Classes defined: User, Admin, Guest"
|
|
30
|
-
puts "Constants: ROLE_NAME, MAX_LOGIN_ATTEMPTS, ACCOUNT_TYPE, ADMIN_LEVEL"
|
|
31
|
-
puts
|
|
32
|
-
|
|
33
|
-
# Extract all constants
|
|
34
|
-
puts "📋 All Constants:"
|
|
35
|
-
puts ClassMetrix.extract(:constants)
|
|
36
|
-
.from([User, Admin, Guest])
|
|
37
|
-
.to_markdown
|
|
38
|
-
puts
|
|
39
|
-
|
|
40
|
-
# Extract filtered constants
|
|
41
|
-
puts "🔍 Filtered Constants (ROLE and MAX):"
|
|
42
|
-
puts ClassMetrix.extract(:constants)
|
|
43
|
-
.from([User, Admin, Guest])
|
|
44
|
-
.filter(/ROLE|MAX/)
|
|
45
|
-
.to_markdown
|
|
46
|
-
puts
|
|
47
|
-
|
|
48
|
-
# Extract with regex filter
|
|
49
|
-
puts "🎯 Regex Filter (starting with ACCOUNT):"
|
|
50
|
-
puts ClassMetrix.extract(:constants)
|
|
51
|
-
.from([User, Admin, Guest])
|
|
52
|
-
.filter(/^ACCOUNT/)
|
|
53
|
-
.to_markdown
|
|
54
|
-
puts
|
|
55
|
-
|
|
56
|
-
puts "✨ This example shows basic constant extraction and filtering!"
|