rails_lens 0.2.5 → 0.2.6
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/CHANGELOG.md +7 -0
- data/README.md +3 -4
- data/lib/rails_lens/analyzers/association_analyzer.rb +2 -2
- data/lib/rails_lens/analyzers/composite_keys.rb +4 -4
- data/lib/rails_lens/analyzers/database_constraints.rb +2 -2
- data/lib/rails_lens/analyzers/delegated_types.rb +4 -4
- data/lib/rails_lens/analyzers/generated_columns.rb +2 -2
- data/lib/rails_lens/analyzers/inheritance.rb +10 -10
- data/lib/rails_lens/analyzers/notes.rb +10 -10
- data/lib/rails_lens/cli.rb +1 -1
- data/lib/rails_lens/cli_error_handler.rb +1 -1
- data/lib/rails_lens/configuration.rb +93 -0
- data/lib/rails_lens/erd/visualizer.rb +11 -11
- data/lib/rails_lens/errors.rb +2 -2
- data/lib/rails_lens/extension_loader.rb +2 -10
- data/lib/rails_lens/extensions/base.rb +2 -10
- data/lib/rails_lens/model_detector.rb +14 -14
- data/lib/rails_lens/schema/adapters/mysql.rb +13 -13
- data/lib/rails_lens/schema/adapters/postgresql.rb +7 -7
- data/lib/rails_lens/schema/adapters/sqlite3.rb +5 -5
- data/lib/rails_lens/version.rb +1 -1
- data/lib/rails_lens.rb +29 -79
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9c79f3cf64c15c090934062200871d4166ecc1a68ae4942a078ea4bf39c7c09
|
4
|
+
data.tar.gz: b91275cfeb9c312c6498da217eb0b907e8e6e220793007a75ea27b5d9b6f19e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ccba97c7621956220bce1cfb2c2c6f1152fec52bf95b70247a53e20ccacea4ad414575d41a27a41b43b6818ad9e1d617a57e594820c8d789f1d917e78018f15
|
7
|
+
data.tar.gz: 803764fabe90e5029a46682063980601dba2c8775db3b7e0eb095751270dfce77028ccbe0940876c058b9cc6f0c0d1d909885af7c16a86457a1757af143a0739
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.2.6](https://github.com/seuros/rails_lens/compare/rails_lens/v0.2.5...rails_lens/v0.2.6) (2025-08-06)
|
4
|
+
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
* improve logger configuration and use ActiveRecord ignore_tables ([#16](https://github.com/seuros/rails_lens/issues/16)) ([cf914b9](https://github.com/seuros/rails_lens/commit/cf914b9a421f2f69328e80733229408c9f362963))
|
9
|
+
|
3
10
|
## [0.2.5](https://github.com/seuros/rails_lens/compare/rails_lens/v0.2.4...rails_lens/v0.2.5) (2025-07-31)
|
4
11
|
|
5
12
|
|
data/README.md
CHANGED
@@ -154,13 +154,12 @@ bundle exec rails_lens erd --verbose
|
|
154
154
|
|
155
155
|
```yaml
|
156
156
|
# .rails-lens.yml (optional)
|
157
|
-
|
158
|
-
|
159
|
-
include_notes: true # Performance recommendations
|
157
|
+
schema:
|
158
|
+
include_notes: true # Performance recommendations
|
160
159
|
extensions:
|
161
160
|
enabled: true # ClosureTree, PostGIS, etc.
|
162
161
|
erd:
|
163
|
-
|
162
|
+
output_dir: doc/diagrams # You need to add mermaid gem to your Gemfile
|
164
163
|
```
|
165
164
|
|
166
165
|
**Database Support**:
|
@@ -69,10 +69,10 @@ module RailsLens
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
rescue NameError => e
|
72
|
-
|
72
|
+
RailsLens.logger.debug { "Failed to check bidirectional association: #{e.message}" }
|
73
73
|
false
|
74
74
|
rescue NoMethodError => e
|
75
|
-
|
75
|
+
RailsLens.logger.debug { "Method error checking bidirectional association: #{e.message}" }
|
76
76
|
false
|
77
77
|
end
|
78
78
|
|
@@ -21,10 +21,10 @@ module RailsLens
|
|
21
21
|
|
22
22
|
nil
|
23
23
|
rescue NoMethodError => e
|
24
|
-
|
24
|
+
RailsLens.logger.debug { "Failed to analyze composite keys for #{model_class.name}: #{e.message}" }
|
25
25
|
nil
|
26
26
|
rescue ActiveRecord::ConnectionNotEstablished => e
|
27
|
-
|
27
|
+
RailsLens.logger.debug { "No database connection for #{model_class.name}: #{e.message}" }
|
28
28
|
nil
|
29
29
|
end
|
30
30
|
|
@@ -51,10 +51,10 @@ module RailsLens
|
|
51
51
|
keys = result.pluck('attname')
|
52
52
|
keys.empty? ? nil : keys
|
53
53
|
rescue ActiveRecord::StatementInvalid => e
|
54
|
-
|
54
|
+
RailsLens.logger.debug { "Failed to detect composite keys from database for #{table_name}: #{e.message}" }
|
55
55
|
nil
|
56
56
|
rescue PG::Error => e
|
57
|
-
|
57
|
+
RailsLens.logger.debug { "PostgreSQL error detecting composite keys: #{e.message}" }
|
58
58
|
nil
|
59
59
|
end
|
60
60
|
end
|
@@ -24,10 +24,10 @@ module RailsLens
|
|
24
24
|
|
25
25
|
constraints.empty? ? nil : constraints.join("\n")
|
26
26
|
rescue ActiveRecord::StatementInvalid => e
|
27
|
-
|
27
|
+
RailsLens.logger.debug { "Failed to fetch check constraints for #{table_name}: #{e.message}" }
|
28
28
|
nil
|
29
29
|
rescue NoMethodError => e
|
30
|
-
|
30
|
+
RailsLens.logger.debug { "Check constraints not supported by adapter: #{e.message}" }
|
31
31
|
nil
|
32
32
|
end
|
33
33
|
end
|
@@ -81,10 +81,10 @@ module RailsLens
|
|
81
81
|
|
82
82
|
delegated_info
|
83
83
|
rescue NoMethodError => e
|
84
|
-
|
84
|
+
RailsLens.logger.debug { "Failed to find delegated type info for #{model_class.name}: #{e.message}" }
|
85
85
|
nil
|
86
86
|
rescue ActiveRecord::StatementInvalid => e
|
87
|
-
|
87
|
+
RailsLens.logger.debug { "Database error finding delegated type info: #{e.message}" }
|
88
88
|
nil
|
89
89
|
end
|
90
90
|
|
@@ -118,10 +118,10 @@ module RailsLens
|
|
118
118
|
[]
|
119
119
|
end
|
120
120
|
rescue ActiveRecord::StatementInvalid => e
|
121
|
-
|
121
|
+
RailsLens.logger.debug { "Database error inferring delegated types: #{e.message}" }
|
122
122
|
[]
|
123
123
|
rescue Errno::ENOENT => e
|
124
|
-
|
124
|
+
RailsLens.logger.debug { "File not found when inferring delegated types: #{e.message}" }
|
125
125
|
[]
|
126
126
|
end
|
127
127
|
end
|
@@ -45,10 +45,10 @@ module RailsLens
|
|
45
45
|
}
|
46
46
|
end
|
47
47
|
rescue ActiveRecord::StatementInvalid => e
|
48
|
-
|
48
|
+
RailsLens.logger.debug { "Failed to detect generated columns for #{table_name}: #{e.message}" }
|
49
49
|
[]
|
50
50
|
rescue PG::Error => e
|
51
|
-
|
51
|
+
RailsLens.logger.debug { "PostgreSQL error detecting generated columns: #{e.message}" }
|
52
52
|
[]
|
53
53
|
end
|
54
54
|
end
|
@@ -33,10 +33,10 @@ module RailsLens
|
|
33
33
|
model_class.respond_to?(:delegated_type_reflection) &&
|
34
34
|
model_class.delegated_type_reflection.present?
|
35
35
|
rescue NoMethodError => e
|
36
|
-
|
36
|
+
RailsLens.logger.debug { "Failed to check delegated type for #{model_class.name}: #{e.message}" }
|
37
37
|
false
|
38
38
|
rescue NameError => e
|
39
|
-
|
39
|
+
RailsLens.logger.debug { "Name error checking delegated type: #{e.message}" }
|
40
40
|
false
|
41
41
|
end
|
42
42
|
|
@@ -91,10 +91,10 @@ module RailsLens
|
|
91
91
|
|
92
92
|
subclasses.sort
|
93
93
|
rescue NoMethodError => e
|
94
|
-
|
94
|
+
RailsLens.logger.debug { "Failed to find STI subclasses for #{model_class.name}: #{e.message}" }
|
95
95
|
[]
|
96
96
|
rescue NameError => e
|
97
|
-
|
97
|
+
RailsLens.logger.debug { "Name error finding STI subclasses: #{e.message}" }
|
98
98
|
[]
|
99
99
|
end
|
100
100
|
|
@@ -110,10 +110,10 @@ module RailsLens
|
|
110
110
|
|
111
111
|
siblings.sort
|
112
112
|
rescue NoMethodError => e
|
113
|
-
|
113
|
+
RailsLens.logger.debug { "Failed to find STI siblings for #{model_class.name}: #{e.message}" }
|
114
114
|
[]
|
115
115
|
rescue NameError => e
|
116
|
-
|
116
|
+
RailsLens.logger.debug { "Name error finding STI siblings: #{e.message}" }
|
117
117
|
[]
|
118
118
|
end
|
119
119
|
|
@@ -136,10 +136,10 @@ module RailsLens
|
|
136
136
|
|
137
137
|
types.uniq.sort
|
138
138
|
rescue ActiveRecord::StatementInvalid => e
|
139
|
-
|
139
|
+
RailsLens.logger.debug { "Database error finding delegated types for #{model_class.name}: #{e.message}" }
|
140
140
|
[]
|
141
141
|
rescue ActiveRecord::ConnectionNotEstablished => e
|
142
|
-
|
142
|
+
RailsLens.logger.debug { "No database connection for #{model_class.name}: #{e.message}" }
|
143
143
|
[]
|
144
144
|
end
|
145
145
|
|
@@ -201,10 +201,10 @@ module RailsLens
|
|
201
201
|
.compact
|
202
202
|
.sort
|
203
203
|
rescue ActiveRecord::StatementInvalid => e
|
204
|
-
|
204
|
+
RailsLens.logger.debug { "Database error finding polymorphic types for #{model_class.name}: #{e.message}" }
|
205
205
|
[]
|
206
206
|
rescue ActiveRecord::ConnectionNotEstablished => e
|
207
|
-
|
207
|
+
RailsLens.logger.debug { "No database connection for #{model_class.name}: #{e.message}" }
|
208
208
|
[]
|
209
209
|
end
|
210
210
|
end
|
@@ -11,15 +11,15 @@ module RailsLens
|
|
11
11
|
@connection = model_class.connection
|
12
12
|
@table_name = model_class.table_name
|
13
13
|
rescue ActiveRecord::ConnectionNotEstablished => e
|
14
|
-
|
14
|
+
RailsLens.logger.debug { "No database connection for #{model_class.name}: #{e.message}" }
|
15
15
|
@connection = nil
|
16
16
|
@table_name = nil
|
17
17
|
rescue NoMethodError => e
|
18
|
-
|
18
|
+
RailsLens.logger.debug { "Failed to initialize Notes analyzer for #{model_class.name}: #{e.message}" }
|
19
19
|
@connection = nil
|
20
20
|
@table_name = nil
|
21
21
|
rescue RuntimeError => e
|
22
|
-
|
22
|
+
RailsLens.logger.debug { "Runtime error initializing Notes analyzer for #{model_class.name}: #{e.message}" }
|
23
23
|
@connection = nil
|
24
24
|
@table_name = nil
|
25
25
|
end
|
@@ -48,10 +48,10 @@ module RailsLens
|
|
48
48
|
|
49
49
|
notes.compact.uniq
|
50
50
|
rescue ActiveRecord::StatementInvalid => e
|
51
|
-
|
51
|
+
RailsLens.logger.debug { "Database error analyzing notes for #{@table_name}: #{e.message}" }
|
52
52
|
nil
|
53
53
|
rescue NoMethodError => e
|
54
|
-
|
54
|
+
RailsLens.logger.debug { "Method error analyzing notes for #{@table_name}: #{e.message}" }
|
55
55
|
nil
|
56
56
|
end
|
57
57
|
|
@@ -72,7 +72,7 @@ module RailsLens
|
|
72
72
|
|
73
73
|
notes
|
74
74
|
rescue StandardError => e
|
75
|
-
|
75
|
+
RailsLens.logger.debug { "Error checking view readonly status for #{model_class.name}: #{e.message}" }
|
76
76
|
[]
|
77
77
|
end
|
78
78
|
|
@@ -101,7 +101,7 @@ module RailsLens
|
|
101
101
|
|
102
102
|
notes
|
103
103
|
rescue StandardError => e
|
104
|
-
|
104
|
+
RailsLens.logger.debug { "Error analyzing view gotchas for #{model_class.name}: #{e.message}" }
|
105
105
|
[]
|
106
106
|
end
|
107
107
|
|
@@ -341,10 +341,10 @@ module RailsLens
|
|
341
341
|
inverse = association.klass.reflect_on_association(association.inverse_of&.name || model_class.name.underscore.pluralize)
|
342
342
|
inverse && inverse.macro == :has_many && !association.options[:counter_cache]
|
343
343
|
rescue NameError => e
|
344
|
-
|
344
|
+
RailsLens.logger.debug { "Failed to check counter cache for association: #{e.message}" }
|
345
345
|
false
|
346
346
|
rescue NoMethodError => e
|
347
|
-
|
347
|
+
RailsLens.logger.debug { "Method error checking counter cache: #{e.message}" }
|
348
348
|
false
|
349
349
|
end
|
350
350
|
end
|
@@ -425,7 +425,7 @@ module RailsLens
|
|
425
425
|
false
|
426
426
|
end
|
427
427
|
rescue StandardError => e
|
428
|
-
|
428
|
+
RailsLens.logger.debug { "Error checking view existence for #{view_name}: #{e.message}" }
|
429
429
|
false
|
430
430
|
end
|
431
431
|
end
|
data/lib/rails_lens/cli.rb
CHANGED
@@ -79,7 +79,7 @@ module RailsLens
|
|
79
79
|
|
80
80
|
# Transform CLI options to visualizer options
|
81
81
|
visualizer_options = options.dup
|
82
|
-
visualizer_options[:output_dir] = options[:output]
|
82
|
+
visualizer_options[:output_dir] = options[:output] if options[:output]
|
83
83
|
|
84
84
|
commands = Commands.new(self)
|
85
85
|
commands.generate_erd(visualizer_options)
|
@@ -79,7 +79,7 @@ module RailsLens
|
|
79
79
|
say error.backtrace.first(10).join("\n"), :yellow
|
80
80
|
end
|
81
81
|
|
82
|
-
say "\nPlease report this issue at: https://github.com/
|
82
|
+
say "\nPlease report this issue at: https://github.com/seuros/rails_lens/issues", :cyan
|
83
83
|
exit 1
|
84
84
|
end
|
85
85
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsLens
|
4
|
+
module Configuration
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
# Add configuration for error handling
|
9
|
+
config_accessor :verbose, default: false
|
10
|
+
config_accessor :debug, default: false
|
11
|
+
config_accessor :raise_on_error, default: false
|
12
|
+
|
13
|
+
# Logger configuration
|
14
|
+
config_accessor :logger
|
15
|
+
|
16
|
+
# Configuration using ActiveSupport::Configurable
|
17
|
+
config_accessor :annotations do
|
18
|
+
{
|
19
|
+
position: :before,
|
20
|
+
format: :rdoc
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
config_accessor :erd do
|
25
|
+
{
|
26
|
+
output_dir: 'doc/erd',
|
27
|
+
orientation: 'TB',
|
28
|
+
theme: true,
|
29
|
+
default_colors: %w[
|
30
|
+
lightblue
|
31
|
+
lightcoral
|
32
|
+
lightgreen
|
33
|
+
lightyellow
|
34
|
+
plum
|
35
|
+
lightcyan
|
36
|
+
lightgray
|
37
|
+
]
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
config_accessor :schema do
|
42
|
+
{
|
43
|
+
adapter: :auto,
|
44
|
+
include_notes: true,
|
45
|
+
exclude_tables: nil, # Will use ActiveRecord::SchemaDumper.ignore_tables if nil
|
46
|
+
format_options: {
|
47
|
+
show_defaults: true,
|
48
|
+
show_comments: true,
|
49
|
+
show_foreign_keys: true,
|
50
|
+
show_indexes: true,
|
51
|
+
show_check_constraints: true
|
52
|
+
}
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
config_accessor :extensions do
|
57
|
+
{
|
58
|
+
enabled: true,
|
59
|
+
autoload: true,
|
60
|
+
interface_version: '1.0',
|
61
|
+
ignore: [],
|
62
|
+
custom_paths: [],
|
63
|
+
error_reporting: :warn, # :silent, :warn, :verbose
|
64
|
+
fail_safe_mode: true, # Continue processing if extensions fail
|
65
|
+
track_health: false # Track extension success/failure rates
|
66
|
+
}
|
67
|
+
end
|
68
|
+
|
69
|
+
config_accessor :routes do
|
70
|
+
{
|
71
|
+
enabled: true,
|
72
|
+
include_defaults: true,
|
73
|
+
include_constraints: true,
|
74
|
+
pattern: '**/*_controller.rb',
|
75
|
+
exclusion_pattern: 'vendor/**/*_controller.rb'
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
config_accessor :mailers do
|
80
|
+
{
|
81
|
+
enabled: true,
|
82
|
+
include_templates: true,
|
83
|
+
include_delivery_methods: true,
|
84
|
+
include_variables: true,
|
85
|
+
include_locales: true,
|
86
|
+
include_defaults: true,
|
87
|
+
pattern: '**/*_mailer.rb',
|
88
|
+
exclusion_pattern: 'vendor/**/*_mailer.rb'
|
89
|
+
}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -93,14 +93,14 @@ module RailsLens
|
|
93
93
|
if columns_added
|
94
94
|
output << ' }'
|
95
95
|
output << ''
|
96
|
-
|
96
|
+
RailsLens.logger.debug { "Added entity: #{model_display_name}" } if options[:verbose]
|
97
97
|
else
|
98
98
|
# Remove the opening brace if no columns were added
|
99
99
|
output.slice!(brace_position..-1)
|
100
|
-
|
100
|
+
RailsLens.logger.debug { "Skipped entity #{model_display_name}: no columns found" } if options[:verbose]
|
101
101
|
end
|
102
102
|
rescue StandardError => e
|
103
|
-
|
103
|
+
RailsLens.logger.debug { "Warning: Could not add entity #{model.name}: #{e.message}" }
|
104
104
|
# Remove any partial entity content added since the opening brace
|
105
105
|
if output.size > brace_position
|
106
106
|
output.slice!(brace_position..-1)
|
@@ -131,7 +131,7 @@ module RailsLens
|
|
131
131
|
# Save output
|
132
132
|
filename = save_output(mermaid_output, 'mmd')
|
133
133
|
|
134
|
-
|
134
|
+
RailsLens.logger.debug 'ERD generated successfully!'
|
135
135
|
filename # Return the filename instead of content
|
136
136
|
end
|
137
137
|
|
@@ -211,7 +211,7 @@ module RailsLens
|
|
211
211
|
def add_belongs_to_relationship(output, model, association, target_model)
|
212
212
|
output << " #{format_model_name(model)} }o--|| #{format_model_name(target_model)} : \"#{association.name}\""
|
213
213
|
rescue StandardError => e
|
214
|
-
|
214
|
+
RailsLens.logger.debug do
|
215
215
|
"Warning: Could not add belongs_to relationship #{model.name} -> #{association.name}: #{e.message}"
|
216
216
|
end
|
217
217
|
end
|
@@ -219,7 +219,7 @@ module RailsLens
|
|
219
219
|
def add_has_one_relationship(output, model, association, target_model)
|
220
220
|
output << " #{format_model_name(model)} ||--o| #{format_model_name(target_model)} : \"#{association.name}\""
|
221
221
|
rescue StandardError => e
|
222
|
-
|
222
|
+
RailsLens.logger.debug do
|
223
223
|
"Warning: Could not add has_one relationship #{model.name} -> #{association.name}: #{e.message}"
|
224
224
|
end
|
225
225
|
end
|
@@ -227,7 +227,7 @@ module RailsLens
|
|
227
227
|
def add_has_many_relationship(output, model, association, target_model)
|
228
228
|
output << " #{format_model_name(model)} ||--o{ #{format_model_name(target_model)} : \"#{association.name}\""
|
229
229
|
rescue StandardError => e
|
230
|
-
|
230
|
+
RailsLens.logger.debug do
|
231
231
|
"Warning: Could not add has_many relationship #{model.name} -> #{association.name}: #{e.message}"
|
232
232
|
end
|
233
233
|
end
|
@@ -235,7 +235,7 @@ module RailsLens
|
|
235
235
|
def add_habtm_relationship(output, model, association, target_model)
|
236
236
|
output << " #{format_model_name(model)} }o--o{ #{format_model_name(target_model)} : \"#{association.name}\""
|
237
237
|
rescue StandardError => e
|
238
|
-
|
238
|
+
RailsLens.logger.debug do
|
239
239
|
"Warning: Could not add habtm relationship #{model.name} -> #{association.name}: #{e.message}"
|
240
240
|
end
|
241
241
|
end
|
@@ -294,7 +294,7 @@ module RailsLens
|
|
294
294
|
output << " class #{model_display_name} tableEntity"
|
295
295
|
end
|
296
296
|
rescue StandardError => e
|
297
|
-
|
297
|
+
RailsLens.logger.debug { "Warning: Could not apply styling to #{model.name}: #{e.message}" }
|
298
298
|
end
|
299
299
|
|
300
300
|
output << ''
|
@@ -308,7 +308,7 @@ module RailsLens
|
|
308
308
|
db_name = model.connection.pool.db_config.name
|
309
309
|
grouped[db_name] << model
|
310
310
|
rescue StandardError => e
|
311
|
-
|
311
|
+
RailsLens.logger.debug { "Warning: Could not determine database for #{model.name}: #{e.message}" }
|
312
312
|
grouped['unknown'] << model
|
313
313
|
end
|
314
314
|
|
@@ -368,7 +368,7 @@ module RailsLens
|
|
368
368
|
filename = File.join(output_dir, "erd.#{extension}")
|
369
369
|
File.write(filename, content)
|
370
370
|
|
371
|
-
|
371
|
+
RailsLens.logger.debug { "ERD saved to: #{filename}" }
|
372
372
|
filename # Return the filename
|
373
373
|
end
|
374
374
|
end
|
data/lib/rails_lens/errors.rb
CHANGED
@@ -47,12 +47,12 @@ module RailsLens
|
|
47
47
|
message = build_error_message(error, context)
|
48
48
|
|
49
49
|
# Use Rails logger for verbose mode
|
50
|
-
|
50
|
+
RailsLens.logger.error message
|
51
51
|
|
52
52
|
# Use kernel output for debug mode to ensure visibility
|
53
53
|
return unless RailsLens.debug
|
54
54
|
|
55
|
-
|
55
|
+
RailsLens.logger.debug message
|
56
56
|
end
|
57
57
|
|
58
58
|
def handle(context = {})
|
@@ -229,17 +229,9 @@ module RailsLens
|
|
229
229
|
when :silent
|
230
230
|
# Do nothing
|
231
231
|
when :warn
|
232
|
-
if
|
233
|
-
Rails.logger.warn "[RailsLens Extensions] #{message}#{" (#{context})" if context}"
|
234
|
-
else
|
235
|
-
Rails.logger.debug { "Warning: [RailsLens Extensions] #{message}#{" (#{context})" if context}" }
|
236
|
-
end
|
232
|
+
RailsLens.logger.warn "[RailsLens Extensions] #{message}#{" (#{context})" if context}"
|
237
233
|
when :verbose
|
238
|
-
if
|
239
|
-
Rails.logger.error "[RailsLens Extensions] #{message}#{" (#{context})" if context}"
|
240
|
-
else
|
241
|
-
Rails.logger.debug { "Error: [RailsLens Extensions] #{message}#{" (#{context})" if context}" }
|
242
|
-
end
|
234
|
+
RailsLens.logger.error "[RailsLens Extensions] #{message}#{" (#{context})" if context}"
|
243
235
|
end
|
244
236
|
end
|
245
237
|
|
@@ -176,17 +176,9 @@ module RailsLens
|
|
176
176
|
when :silent
|
177
177
|
# Do nothing
|
178
178
|
when :warn
|
179
|
-
|
180
|
-
Rails.logger.warn "[RailsLens Extensions] Method failed: #{message} (#{context})"
|
181
|
-
else
|
182
|
-
Rails.logger.debug { "Warning: [RailsLens Extensions] Method failed: #{message} (#{context})" }
|
183
|
-
end
|
179
|
+
RailsLens.logger.warn "[RailsLens Extensions] Method failed: #{message} (#{context})"
|
184
180
|
when :verbose
|
185
|
-
|
186
|
-
Rails.logger.error "[RailsLens Extensions] Method failed: #{message} (#{context})"
|
187
|
-
else
|
188
|
-
Rails.logger.debug { "Error: [RailsLens Extensions] Method failed: #{message} (#{context})" }
|
189
|
-
end
|
181
|
+
RailsLens.logger.error "[RailsLens Extensions] Method failed: #{message} (#{context})"
|
190
182
|
end
|
191
183
|
end
|
192
184
|
end
|
@@ -126,7 +126,7 @@ module RailsLens
|
|
126
126
|
trace_filtering = options[:trace_filtering] || ENV.fetch('RAILS_LENS_TRACE_FILTERING', nil)
|
127
127
|
|
128
128
|
original_count = models.size
|
129
|
-
|
129
|
+
RailsLens.logger.debug { "[ModelDetector] Starting with #{original_count} models" } if trace_filtering
|
130
130
|
|
131
131
|
# Remove anonymous classes and non-class objects
|
132
132
|
before_count = models.size
|
@@ -157,7 +157,7 @@ module RailsLens
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
if excluded && trace_filtering
|
160
|
-
|
160
|
+
RailsLens.logger.debug do
|
161
161
|
"[ModelDetector] Excluding #{model.name}: matched exclude pattern"
|
162
162
|
end
|
163
163
|
end
|
@@ -182,12 +182,12 @@ module RailsLens
|
|
182
182
|
end
|
183
183
|
end
|
184
184
|
if included && trace_filtering
|
185
|
-
|
185
|
+
RailsLens.logger.debug do
|
186
186
|
"[ModelDetector] Including #{model.name}: matched include pattern"
|
187
187
|
end
|
188
188
|
end
|
189
189
|
if !included && trace_filtering
|
190
|
-
|
190
|
+
RailsLens.logger.debug { "[ModelDetector] Excluding #{model.name}: did not match include patterns" }
|
191
191
|
end
|
192
192
|
included
|
193
193
|
end
|
@@ -203,13 +203,13 @@ module RailsLens
|
|
203
203
|
log_filter_step('Abstract/invalid table removal', before_count, models.size, trace_filtering)
|
204
204
|
|
205
205
|
# Exclude tables from configuration
|
206
|
-
excluded_tables = RailsLens.
|
206
|
+
excluded_tables = RailsLens.excluded_tables
|
207
207
|
before_count = models.size
|
208
208
|
models = models.reject do |model|
|
209
209
|
begin
|
210
210
|
excluded = excluded_tables.include?(model.table_name)
|
211
211
|
if excluded && trace_filtering
|
212
|
-
|
212
|
+
RailsLens.logger.debug do
|
213
213
|
"[ModelDetector] Excluding #{model.name}: table '#{model.table_name}' in exclude_tables config"
|
214
214
|
end
|
215
215
|
end
|
@@ -218,7 +218,7 @@ module RailsLens
|
|
218
218
|
# This can happen in multi-db setups if the connection is not yet established
|
219
219
|
# We will assume the model should be kept in this case
|
220
220
|
if trace_filtering
|
221
|
-
|
221
|
+
RailsLens.logger.debug do
|
222
222
|
"[ModelDetector] Keeping #{model.name}: connection not defined, assuming keep"
|
223
223
|
end
|
224
224
|
end
|
@@ -226,7 +226,7 @@ module RailsLens
|
|
226
226
|
end
|
227
227
|
rescue ActiveRecord::StatementInvalid => e
|
228
228
|
if trace_filtering
|
229
|
-
|
229
|
+
RailsLens.logger.debug do
|
230
230
|
"[ModelDetector] Keeping #{model.name}: database error checking exclude_tables - #{e.message}"
|
231
231
|
end
|
232
232
|
end
|
@@ -235,11 +235,11 @@ module RailsLens
|
|
235
235
|
log_filter_step('Configuration exclude_tables', before_count, models.size, trace_filtering)
|
236
236
|
|
237
237
|
if trace_filtering
|
238
|
-
|
238
|
+
RailsLens.logger.debug do
|
239
239
|
"[ModelDetector] Final result: #{models.size} models after all filtering"
|
240
240
|
end
|
241
241
|
end
|
242
|
-
|
242
|
+
RailsLens.logger.debug { "[ModelDetector] Final models: #{models.map(&:name).join(', ')}" } if trace_filtering
|
243
243
|
|
244
244
|
models
|
245
245
|
end
|
@@ -249,11 +249,11 @@ module RailsLens
|
|
249
249
|
|
250
250
|
filtered_count = before_count - after_count
|
251
251
|
if filtered_count.positive?
|
252
|
-
|
252
|
+
RailsLens.logger.debug do
|
253
253
|
"[ModelDetector] #{step_name}: filtered out #{filtered_count} models (#{before_count} -> #{after_count})"
|
254
254
|
end
|
255
255
|
else
|
256
|
-
|
256
|
+
RailsLens.logger.debug { "[ModelDetector] #{step_name}: no models filtered (#{after_count} remain)" }
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
@@ -301,7 +301,7 @@ module RailsLens
|
|
301
301
|
|
302
302
|
if trace_filtering
|
303
303
|
action = should_exclude ? 'Excluding' : 'Keeping'
|
304
|
-
|
304
|
+
RailsLens.logger.debug { "[ModelDetector] #{action} #{model.name}: #{reason}" }
|
305
305
|
end
|
306
306
|
|
307
307
|
{ model: model, exclude: should_exclude }
|
@@ -408,7 +408,7 @@ module RailsLens
|
|
408
408
|
|
409
409
|
if trace_filtering
|
410
410
|
action = should_exclude ? 'Excluding' : 'Keeping'
|
411
|
-
|
411
|
+
RailsLens.logger.debug { "[ModelDetector] #{action} #{model.name}: #{reason}" }
|
412
412
|
end
|
413
413
|
|
414
414
|
{ model: model, exclude: should_exclude }
|
@@ -144,10 +144,10 @@ module RailsLens
|
|
144
144
|
result[1] # Engine is typically the second column
|
145
145
|
end
|
146
146
|
rescue ActiveRecord::StatementInvalid => e
|
147
|
-
|
147
|
+
RailsLens.logger.debug { "Failed to fetch storage engine for #{table_name}: #{e.message}" }
|
148
148
|
nil
|
149
149
|
rescue => e
|
150
|
-
|
150
|
+
RailsLens.logger.debug { "MySQL error fetching storage engine: #{e.message}" }
|
151
151
|
nil
|
152
152
|
end
|
153
153
|
|
@@ -164,10 +164,10 @@ module RailsLens
|
|
164
164
|
|
165
165
|
collation&.split('_')&.first
|
166
166
|
rescue ActiveRecord::StatementInvalid => e
|
167
|
-
|
167
|
+
RailsLens.logger.debug { "Failed to fetch charset for #{table_name}: #{e.message}" }
|
168
168
|
nil
|
169
169
|
rescue => e
|
170
|
-
|
170
|
+
RailsLens.logger.debug { "MySQL error fetching charset: #{e.message}" }
|
171
171
|
nil
|
172
172
|
end
|
173
173
|
|
@@ -182,10 +182,10 @@ module RailsLens
|
|
182
182
|
result[14] # Collation is typically the 15th column
|
183
183
|
end
|
184
184
|
rescue ActiveRecord::StatementInvalid => e
|
185
|
-
|
185
|
+
RailsLens.logger.debug { "Failed to fetch collation for #{table_name}: #{e.message}" }
|
186
186
|
nil
|
187
187
|
rescue => e
|
188
|
-
|
188
|
+
RailsLens.logger.debug { "MySQL error fetching collation: #{e.message}" }
|
189
189
|
nil
|
190
190
|
end
|
191
191
|
|
@@ -229,11 +229,11 @@ module RailsLens
|
|
229
229
|
count.to_i.positive?
|
230
230
|
rescue ActiveRecord::StatementInvalid => e
|
231
231
|
# Table doesn't exist or no permission to query information_schema
|
232
|
-
|
232
|
+
RailsLens.logger.debug { "Failed to check partitions for #{table_name}: #{e.message}" }
|
233
233
|
false
|
234
234
|
rescue => e
|
235
235
|
# MySQL specific errors (connection issues, etc)
|
236
|
-
|
236
|
+
RailsLens.logger.debug { "MySQL error checking partitions: #{e.message}" }
|
237
237
|
false
|
238
238
|
end
|
239
239
|
|
@@ -259,10 +259,10 @@ module RailsLens
|
|
259
259
|
end
|
260
260
|
rescue ActiveRecord::StatementInvalid => e
|
261
261
|
# Permission denied or table doesn't exist
|
262
|
-
|
262
|
+
RailsLens.logger.debug { "Failed to fetch partitions for #{table_name}: #{e.message}" }
|
263
263
|
rescue => e
|
264
264
|
# MySQL specific errors
|
265
|
-
|
265
|
+
RailsLens.logger.debug { "MySQL error fetching partitions: #{e.message}" }
|
266
266
|
end
|
267
267
|
|
268
268
|
def add_partitions_toml(lines)
|
@@ -297,10 +297,10 @@ module RailsLens
|
|
297
297
|
lines << ']'
|
298
298
|
rescue ActiveRecord::StatementInvalid => e
|
299
299
|
# Permission denied or table doesn't exist
|
300
|
-
|
300
|
+
RailsLens.logger.debug { "Failed to fetch partitions for #{table_name}: #{e.message}" }
|
301
301
|
rescue => e
|
302
302
|
# MySQL specific errors
|
303
|
-
|
303
|
+
RailsLens.logger.debug { "MySQL error fetching partitions: #{e.message}" }
|
304
304
|
end
|
305
305
|
|
306
306
|
def add_view_dependencies_toml(lines, view_info)
|
@@ -345,7 +345,7 @@ module RailsLens
|
|
345
345
|
dependencies: row[1].to_s.split(',').reject(&:empty?)
|
346
346
|
}
|
347
347
|
rescue ActiveRecord::StatementInvalid, Mysql2::Error => e
|
348
|
-
|
348
|
+
RailsLens.logger.debug { "Failed to fetch view metadata for #{table_name}: #{e.message}" }
|
349
349
|
nil
|
350
350
|
end
|
351
351
|
|
@@ -150,11 +150,11 @@ module RailsLens
|
|
150
150
|
end
|
151
151
|
rescue ActiveRecord::StatementInvalid => e
|
152
152
|
# Table doesn't exist or other database error
|
153
|
-
|
153
|
+
RailsLens.logger.debug { "Failed to fetch check constraints for #{table_name}: #{e.message}" }
|
154
154
|
[]
|
155
155
|
rescue PG::Error => e
|
156
156
|
# PostgreSQL specific errors
|
157
|
-
|
157
|
+
RailsLens.logger.debug { "PostgreSQL error fetching check constraints: #{e.message}" }
|
158
158
|
[]
|
159
159
|
end
|
160
160
|
|
@@ -164,11 +164,11 @@ module RailsLens
|
|
164
164
|
connection.column_comment(table_name, column_name)
|
165
165
|
rescue ActiveRecord::StatementInvalid => e
|
166
166
|
# Table or column doesn't exist
|
167
|
-
|
167
|
+
RailsLens.logger.debug { "Failed to fetch column comment for #{table_name}.#{column_name}: #{e.message}" }
|
168
168
|
nil
|
169
169
|
rescue PG::Error => e
|
170
170
|
# PostgreSQL specific errors
|
171
|
-
|
171
|
+
RailsLens.logger.debug { "PostgreSQL error fetching column comment: #{e.message}" }
|
172
172
|
nil
|
173
173
|
end
|
174
174
|
|
@@ -178,11 +178,11 @@ module RailsLens
|
|
178
178
|
connection.table_comment(table_name)
|
179
179
|
rescue ActiveRecord::StatementInvalid => e
|
180
180
|
# Table doesn't exist
|
181
|
-
|
181
|
+
RailsLens.logger.debug { "Failed to fetch table comment for #{table_name}: #{e.message}" }
|
182
182
|
nil
|
183
183
|
rescue PG::Error => e
|
184
184
|
# PostgreSQL specific errors
|
185
|
-
|
185
|
+
RailsLens.logger.debug { "PostgreSQL error fetching table comment: #{e.message}" }
|
186
186
|
nil
|
187
187
|
end
|
188
188
|
|
@@ -292,7 +292,7 @@ module RailsLens
|
|
292
292
|
dependencies: row[2] || []
|
293
293
|
}
|
294
294
|
rescue ActiveRecord::StatementInvalid, PG::Error => e
|
295
|
-
|
295
|
+
RailsLens.logger.debug { "Failed to fetch view metadata for #{table_name}: #{e.message}" }
|
296
296
|
nil
|
297
297
|
end
|
298
298
|
|
@@ -93,10 +93,10 @@ module RailsLens
|
|
93
93
|
lines << 'FOREIGN_KEYS_ENABLED: false' if fk_status && fk_status['foreign_keys'].zero?
|
94
94
|
rescue ActiveRecord::StatementInvalid => e
|
95
95
|
# SQLite doesn't recognize the pragma or access denied
|
96
|
-
|
96
|
+
RailsLens.logger.debug { "Failed to fetch SQLite foreign_keys pragma: #{e.message}" }
|
97
97
|
rescue SQLite3::Exception => e
|
98
98
|
# SQLite specific errors (database locked, etc)
|
99
|
-
|
99
|
+
RailsLens.logger.debug { "SQLite error fetching pragmas: #{e.message}" }
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
@@ -113,10 +113,10 @@ module RailsLens
|
|
113
113
|
end
|
114
114
|
rescue ActiveRecord::StatementInvalid => e
|
115
115
|
# SQLite doesn't recognize the pragma or access denied
|
116
|
-
|
116
|
+
RailsLens.logger.debug { "Failed to fetch SQLite foreign_keys pragma: #{e.message}" }
|
117
117
|
rescue SQLite3::Exception => e
|
118
118
|
# SQLite specific errors (database locked, etc)
|
119
|
-
|
119
|
+
RailsLens.logger.debug { "SQLite error fetching pragmas: #{e.message}" }
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
@@ -164,7 +164,7 @@ module RailsLens
|
|
164
164
|
dependencies: tables.sort
|
165
165
|
}
|
166
166
|
rescue ActiveRecord::StatementInvalid, SQLite3::Exception => e
|
167
|
-
|
167
|
+
RailsLens.logger.debug { "Failed to fetch view metadata for #{table_name}: #{e.message}" }
|
168
168
|
nil
|
169
169
|
end
|
170
170
|
|
data/lib/rails_lens/version.rb
CHANGED
data/lib/rails_lens.rb
CHANGED
@@ -26,92 +26,31 @@ loader.setup
|
|
26
26
|
|
27
27
|
require_relative 'rails_lens/errors'
|
28
28
|
require_relative 'rails_lens/cli'
|
29
|
+
require_relative 'rails_lens/configuration'
|
29
30
|
|
30
31
|
module RailsLens
|
31
32
|
include ActiveSupport::Configurable
|
33
|
+
include Configuration
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
# Configuration using ActiveSupport::Configurable
|
39
|
-
config_accessor :annotations do
|
40
|
-
{
|
41
|
-
position: :before,
|
42
|
-
format: :rdoc
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
config_accessor :erd do
|
47
|
-
{
|
48
|
-
output_dir: 'doc/erd',
|
49
|
-
orientation: 'TB',
|
50
|
-
theme: true,
|
51
|
-
default_colors: %w[
|
52
|
-
lightblue
|
53
|
-
lightcoral
|
54
|
-
lightgreen
|
55
|
-
lightyellow
|
56
|
-
plum
|
57
|
-
lightcyan
|
58
|
-
lightgray
|
59
|
-
]
|
60
|
-
}
|
61
|
-
end
|
62
|
-
|
63
|
-
config_accessor :schema do
|
64
|
-
{
|
65
|
-
adapter: :auto,
|
66
|
-
include_notes: true,
|
67
|
-
exclude_tables: %w[schema_migrations ar_internal_metadata],
|
68
|
-
format_options: {
|
69
|
-
show_defaults: true,
|
70
|
-
show_comments: true,
|
71
|
-
show_foreign_keys: true,
|
72
|
-
show_indexes: true,
|
73
|
-
show_check_constraints: true
|
74
|
-
}
|
75
|
-
}
|
76
|
-
end
|
77
|
-
|
78
|
-
config_accessor :extensions do
|
79
|
-
{
|
80
|
-
enabled: true,
|
81
|
-
autoload: true,
|
82
|
-
interface_version: '1.0',
|
83
|
-
ignore: [],
|
84
|
-
custom_paths: [],
|
85
|
-
error_reporting: :warn, # :silent, :warn, :verbose
|
86
|
-
fail_safe_mode: true, # Continue processing if extensions fail
|
87
|
-
track_health: false # Track extension success/failure rates
|
88
|
-
}
|
89
|
-
end
|
35
|
+
class << self
|
36
|
+
def logger
|
37
|
+
@logger ||= config.logger || default_logger
|
38
|
+
end
|
90
39
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
include_constraints: true,
|
96
|
-
pattern: '**/*_controller.rb',
|
97
|
-
exclusion_pattern: 'vendor/**/*_controller.rb'
|
98
|
-
}
|
99
|
-
end
|
40
|
+
def logger=(new_logger)
|
41
|
+
@logger = new_logger
|
42
|
+
config.logger = new_logger
|
43
|
+
end
|
100
44
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
pattern: '**/*_mailer.rb',
|
110
|
-
exclusion_pattern: 'vendor/**/*_mailer.rb'
|
111
|
-
}
|
112
|
-
end
|
45
|
+
def default_logger
|
46
|
+
if defined?(Rails.logger) && Rails.logger
|
47
|
+
Rails.logger
|
48
|
+
else
|
49
|
+
require 'logger'
|
50
|
+
Logger.new($stdout)
|
51
|
+
end
|
52
|
+
end
|
113
53
|
|
114
|
-
class << self
|
115
54
|
def load_config_file(path = '.rails-lens.yml')
|
116
55
|
return unless File.exist?(path)
|
117
56
|
|
@@ -130,6 +69,17 @@ module RailsLens
|
|
130
69
|
end
|
131
70
|
end
|
132
71
|
|
72
|
+
# Get tables to exclude
|
73
|
+
def excluded_tables
|
74
|
+
custom_excludes = config.schema[:exclude_tables]
|
75
|
+
if custom_excludes.nil?
|
76
|
+
# Use ActiveRecord's default ignore tables
|
77
|
+
ActiveRecord::SchemaDumper.ignore_tables.to_a
|
78
|
+
else
|
79
|
+
Array(custom_excludes)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
133
83
|
# Schema annotation methods
|
134
84
|
def annotate_models(options = {})
|
135
85
|
Schema::AnnotationManager.annotate_all(options)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_lens
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abdelkader Boudih
|
@@ -182,6 +182,7 @@ files:
|
|
182
182
|
- lib/rails_lens/cli.rb
|
183
183
|
- lib/rails_lens/cli_error_handler.rb
|
184
184
|
- lib/rails_lens/commands.rb
|
185
|
+
- lib/rails_lens/configuration.rb
|
185
186
|
- lib/rails_lens/connection.rb
|
186
187
|
- lib/rails_lens/erd/column_type_formatter.rb
|
187
188
|
- lib/rails_lens/erd/domain_color_mapper.rb
|