rails_lens 0.5.3 → 0.5.4
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/lib/rails_lens/analyzers/association_analyzer.rb +0 -10
- data/lib/rails_lens/analyzers/base.rb +16 -0
- data/lib/rails_lens/analyzers/best_practices_analyzer.rb +0 -14
- data/lib/rails_lens/analyzers/callbacks.rb +11 -23
- data/lib/rails_lens/analyzers/composite_keys.rb +1 -1
- data/lib/rails_lens/analyzers/delegated_types.rb +1 -1
- data/lib/rails_lens/analyzers/enums.rb +1 -1
- data/lib/rails_lens/analyzers/error_handling.rb +11 -25
- data/lib/rails_lens/analyzers/inheritance.rb +4 -4
- data/lib/rails_lens/analyzers/notes.rb +0 -10
- data/lib/rails_lens/analyzers/performance_analyzer.rb +6 -30
- data/lib/rails_lens/annotation_pipeline.rb +14 -8
- data/lib/rails_lens/cli.rb +11 -22
- data/lib/rails_lens/cli_error_handler.rb +19 -20
- data/lib/rails_lens/commands.rb +30 -38
- data/lib/rails_lens/erd/visualizer.rb +15 -58
- data/lib/rails_lens/extensions/base.rb +1 -1
- data/lib/rails_lens/file_insertion_helper.rb +33 -6
- data/lib/rails_lens/mailer/annotator.rb +0 -16
- data/lib/rails_lens/mailer/extractor.rb +6 -8
- data/lib/rails_lens/model_detector.rb +27 -31
- data/lib/rails_lens/parsers/class_info.rb +1 -27
- data/lib/rails_lens/parsers/module_info.rb +1 -26
- data/lib/rails_lens/parsers/node_info.rb +34 -0
- data/lib/rails_lens/providers/view_provider.rb +1 -1
- data/lib/rails_lens/schema/adapters/base.rb +34 -1
- data/lib/rails_lens/schema/adapters/database_info.rb +1 -1
- data/lib/rails_lens/schema/adapters/mysql.rb +26 -80
- data/lib/rails_lens/schema/adapters/postgresql.rb +0 -19
- data/lib/rails_lens/schema/adapters/sqlite3.rb +0 -31
- data/lib/rails_lens/schema/annotation_manager.rb +72 -125
- data/lib/rails_lens/schema/annotation_removal.rb +24 -0
- data/lib/rails_lens/schema/database_annotator.rb +2 -15
- data/lib/rails_lens/toml_format.rb +14 -0
- data/lib/rails_lens/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4e504fa26391d500a945947795688a4a52a23922e0ea6a760762415c698d91fc
|
|
4
|
+
data.tar.gz: 800c91d7df514dc2c745235cf9f5423a7a68d6499cee7221d5cb89adaa95157b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0c17d650e862adcf76e32d7a4a5398cd8c4827b8dd0e0424f01e307a76285e18001c5431561807a049695fbe3c4eaf68960add7d139427b1fcabb36ef2692e06
|
|
7
|
+
data.tar.gz: 31bf7b191ec9f5dfedabf351798d38b217a71b85c9ceba7e458ed7b45d61662b367989a40b3e311f9fc1e21f270eacbf55e6998e5b28ff0114fa0b5b37b9ab80
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.4](https://github.com/seuros/rails_lens/compare/rails_lens/v0.5.3...rails_lens/v0.5.4) (2026-06-26)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* prevent duplicate extension annotation blocks on re-annotate ([0e85197](https://github.com/seuros/rails_lens/commit/0e8519742c751eb26d225a3a9a8434a4da4053b1))
|
|
9
|
+
|
|
3
10
|
## [0.5.3](https://github.com/seuros/rails_lens/compare/rails_lens/v0.5.2...rails_lens/v0.5.3) (2026-02-17)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -71,16 +71,6 @@ module RailsLens
|
|
|
71
71
|
false
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def needs_explicit_inverse_of?(association)
|
|
75
|
-
# Rails can auto-infer inverse_of for vanilla associations
|
|
76
|
-
# Only require explicit inverse_of when using custom options
|
|
77
|
-
association.options[:class_name].present? ||
|
|
78
|
-
association.options[:foreign_key].present? ||
|
|
79
|
-
association.options[:as].present? ||
|
|
80
|
-
association.options[:source].present? ||
|
|
81
|
-
association.options[:through].present?
|
|
82
|
-
end
|
|
83
|
-
|
|
84
74
|
def should_have_counter_cache?(association)
|
|
85
75
|
return false unless association.macro == :belongs_to
|
|
86
76
|
|
|
@@ -30,6 +30,22 @@ module RailsLens
|
|
|
30
30
|
def adapter_name
|
|
31
31
|
@adapter_name ||= connection.adapter_name
|
|
32
32
|
end
|
|
33
|
+
|
|
34
|
+
def indexed?(column)
|
|
35
|
+
connection.indexes(table_name).any? do |index|
|
|
36
|
+
index.columns.include?(column.name)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def needs_explicit_inverse_of?(association)
|
|
41
|
+
# Rails can auto-infer inverse_of for vanilla associations
|
|
42
|
+
# Only require explicit inverse_of when using custom options
|
|
43
|
+
association.options[:class_name].present? ||
|
|
44
|
+
association.options[:foreign_key].present? ||
|
|
45
|
+
association.options[:as].present? ||
|
|
46
|
+
association.options[:source].present? ||
|
|
47
|
+
association.options[:through].present?
|
|
48
|
+
end
|
|
33
49
|
end
|
|
34
50
|
end
|
|
35
51
|
end
|
|
@@ -71,23 +71,9 @@ module RailsLens
|
|
|
71
71
|
model_class.column_names.include?(name)
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def indexed?(column)
|
|
75
|
-
connection.indexes(table_name).any? do |index|
|
|
76
|
-
index.columns.include?(column.name)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
74
|
def columns
|
|
81
75
|
@columns ||= model_class.columns
|
|
82
76
|
end
|
|
83
|
-
|
|
84
|
-
def connection
|
|
85
|
-
model_class.connection
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def table_name
|
|
89
|
-
model_class.table_name
|
|
90
|
-
end
|
|
91
77
|
end
|
|
92
78
|
end
|
|
93
79
|
end
|
|
@@ -178,18 +178,13 @@ module RailsLens
|
|
|
178
178
|
def extract_options(callback)
|
|
179
179
|
options = {}
|
|
180
180
|
|
|
181
|
-
# Extract :if
|
|
182
|
-
if
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
options[:if] = formatted if formatted.any?
|
|
186
|
-
end
|
|
181
|
+
# Extract :if / :unless conditions (stored as matching instance variables)
|
|
182
|
+
%i[if unless].each do |key|
|
|
183
|
+
ivar = :"@#{key}"
|
|
184
|
+
next unless callback.instance_variable_defined?(ivar) && callback.instance_variable_get(ivar).present?
|
|
187
185
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
conditions = callback.instance_variable_get(:@unless)
|
|
191
|
-
formatted = format_conditions(conditions)
|
|
192
|
-
options[:unless] = formatted if formatted.any?
|
|
186
|
+
formatted = format_conditions(callback.instance_variable_get(ivar))
|
|
187
|
+
options[key] = formatted if formatted.any?
|
|
193
188
|
end
|
|
194
189
|
|
|
195
190
|
# Extract :on option (for validation and commit callbacks)
|
|
@@ -274,19 +269,12 @@ module RailsLens
|
|
|
274
269
|
parts = []
|
|
275
270
|
parts << "method = \"#{escape_toml(callback[:method])}\""
|
|
276
271
|
|
|
277
|
-
if
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
if callback[:options][:unless]&.any?
|
|
283
|
-
unless_values = callback[:options][:unless].map { |v| "\"#{escape_toml(v)}\"" }.join(', ')
|
|
284
|
-
parts << "unless = [#{unless_values}]"
|
|
285
|
-
end
|
|
272
|
+
%i[if unless on].each do |key|
|
|
273
|
+
values = callback[:options][key]
|
|
274
|
+
next unless values&.any?
|
|
286
275
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
parts << "on = [#{on_values}]"
|
|
276
|
+
escaped = values.map { |v| "\"#{escape_toml(v)}\"" }.join(', ')
|
|
277
|
+
parts << "#{key} = [#{escaped}]"
|
|
290
278
|
end
|
|
291
279
|
|
|
292
280
|
parts << 'prepend = true' if callback[:options][:prepend]
|
|
@@ -11,7 +11,7 @@ module RailsLens
|
|
|
11
11
|
|
|
12
12
|
model_class.defined_enums.each do |name, values|
|
|
13
13
|
# Format as TOML inline table: name = { key = "value", ... }
|
|
14
|
-
formatted_values = if values.values.all?
|
|
14
|
+
formatted_values = if values.values.all?(Integer)
|
|
15
15
|
# Integer-based enum
|
|
16
16
|
values.map { |k, v| "#{k} = #{v}" }.join(', ')
|
|
17
17
|
else
|
|
@@ -16,49 +16,35 @@ module RailsLens
|
|
|
16
16
|
|
|
17
17
|
private
|
|
18
18
|
|
|
19
|
+
# Report an analyzer error with the shared analyzer/model context plus any
|
|
20
|
+
# call-specific +context+ keys.
|
|
21
|
+
def report_analyzer_error(error, **context)
|
|
22
|
+
ErrorReporter.report(error, { analyzer: self.class.name, model: model_class.name }.merge(context))
|
|
23
|
+
end
|
|
24
|
+
|
|
19
25
|
def handle_database_error(error)
|
|
20
|
-
|
|
21
|
-
analyzer: self.class.name,
|
|
22
|
-
model: model_class.name,
|
|
23
|
-
table: model_class.table_name
|
|
24
|
-
})
|
|
26
|
+
report_analyzer_error(error, table: model_class.table_name)
|
|
25
27
|
[]
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
def handle_method_error(error)
|
|
29
31
|
# These are likely bugs in our code, so we should log them prominently
|
|
30
|
-
|
|
31
|
-
analyzer: self.class.name,
|
|
32
|
-
model: model_class.name,
|
|
33
|
-
method: error.name
|
|
34
|
-
})
|
|
32
|
+
report_analyzer_error(error, method: error.name)
|
|
35
33
|
[]
|
|
36
34
|
end
|
|
37
35
|
|
|
38
36
|
def handle_unexpected_error(error)
|
|
39
|
-
|
|
40
|
-
analyzer: self.class.name,
|
|
41
|
-
model: model_class.name,
|
|
42
|
-
type: 'unexpected'
|
|
43
|
-
})
|
|
37
|
+
report_analyzer_error(error, type: 'unexpected')
|
|
44
38
|
[]
|
|
45
39
|
end
|
|
46
40
|
|
|
47
41
|
def safe_call(default = nil)
|
|
48
42
|
yield
|
|
49
43
|
rescue ActiveRecord::StatementInvalid => e
|
|
50
|
-
|
|
51
|
-
analyzer: self.class.name,
|
|
52
|
-
model: model_class.name,
|
|
53
|
-
operation: 'database_query'
|
|
54
|
-
})
|
|
44
|
+
report_analyzer_error(e, operation: 'database_query')
|
|
55
45
|
default
|
|
56
46
|
rescue NoMethodError, NameError => e
|
|
57
|
-
|
|
58
|
-
analyzer: self.class.name,
|
|
59
|
-
model: model_class.name,
|
|
60
|
-
operation: 'method_call'
|
|
61
|
-
})
|
|
47
|
+
report_analyzer_error(e, operation: 'method_call')
|
|
62
48
|
default
|
|
63
49
|
end
|
|
64
50
|
end
|
|
@@ -46,7 +46,7 @@ module RailsLens
|
|
|
46
46
|
if model_class.base_class == model_class
|
|
47
47
|
# This is the base class
|
|
48
48
|
subclasses = find_sti_subclasses
|
|
49
|
-
lines << "subclasses =
|
|
49
|
+
lines << "subclasses = #{TomlFormat.quoted_array(subclasses)}" if subclasses.any?
|
|
50
50
|
lines << 'base = true'
|
|
51
51
|
else
|
|
52
52
|
# This is a subclass
|
|
@@ -55,7 +55,7 @@ module RailsLens
|
|
|
55
55
|
|
|
56
56
|
# Find siblings
|
|
57
57
|
siblings = find_sti_siblings
|
|
58
|
-
lines << "siblings =
|
|
58
|
+
lines << "siblings = #{TomlFormat.quoted_array(siblings)}" if siblings.any?
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
lines.join("\n")
|
|
@@ -73,7 +73,7 @@ module RailsLens
|
|
|
73
73
|
|
|
74
74
|
# Try to find known types
|
|
75
75
|
types = find_delegated_types(reflection)
|
|
76
|
-
lines << "types =
|
|
76
|
+
lines << "types = #{TomlFormat.quoted_array(types)}" if types.any?
|
|
77
77
|
|
|
78
78
|
lines.join("\n")
|
|
79
79
|
end
|
|
@@ -163,7 +163,7 @@ module RailsLens
|
|
|
163
163
|
[]
|
|
164
164
|
end
|
|
165
165
|
if types.any?
|
|
166
|
-
"{ name = \"#{reflection.name}\", type_col = \"#{reflection.foreign_type}\", id_col = \"#{reflection.foreign_key}\", types =
|
|
166
|
+
"{ name = \"#{reflection.name}\", type_col = \"#{reflection.foreign_type}\", id_col = \"#{reflection.foreign_key}\", types = #{TomlFormat.quoted_array(types)} }"
|
|
167
167
|
else
|
|
168
168
|
"{ name = \"#{reflection.name}\", type_col = \"#{reflection.foreign_type}\", id_col = \"#{reflection.foreign_key}\" }"
|
|
169
169
|
end
|
|
@@ -417,16 +417,6 @@ module RailsLens
|
|
|
417
417
|
RailsLens.logger.debug { "Error checking view existence for #{view_name}: #{e.message}" }
|
|
418
418
|
false
|
|
419
419
|
end
|
|
420
|
-
|
|
421
|
-
def needs_explicit_inverse_of?(association)
|
|
422
|
-
# Rails can auto-infer inverse_of for vanilla associations
|
|
423
|
-
# Only require explicit inverse_of when using custom options
|
|
424
|
-
association.options[:class_name].present? ||
|
|
425
|
-
association.options[:foreign_key].present? ||
|
|
426
|
-
association.options[:as].present? ||
|
|
427
|
-
association.options[:source].present? ||
|
|
428
|
-
association.options[:through].present?
|
|
429
|
-
end
|
|
430
420
|
end
|
|
431
421
|
end
|
|
432
422
|
end
|
|
@@ -27,23 +27,13 @@ module RailsLens
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def analyze_query_performance
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
commonly_queried_columns.each do |column|
|
|
34
|
-
next if indexed?(column)
|
|
35
|
-
|
|
36
|
-
notes << NoteCodes.note(column.name, NoteCodes::INDEX)
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Check for missing indexes on scoped columns
|
|
40
|
-
scoped_columns.each do |column|
|
|
41
|
-
next if indexed?(column)
|
|
42
|
-
|
|
43
|
-
notes << NoteCodes.note(column.name, NoteCodes::INDEX)
|
|
44
|
-
end
|
|
30
|
+
# Flag commonly-queried and scoped columns that lack an index
|
|
31
|
+
index_notes_for(commonly_queried_columns) + index_notes_for(scoped_columns)
|
|
32
|
+
end
|
|
45
33
|
|
|
46
|
-
|
|
34
|
+
def index_notes_for(columns)
|
|
35
|
+
columns.reject { |column| indexed?(column) }
|
|
36
|
+
.map { |column| NoteCodes.note(column.name, NoteCodes::INDEX) }
|
|
47
37
|
end
|
|
48
38
|
|
|
49
39
|
def uuid_columns
|
|
@@ -68,20 +58,6 @@ module RailsLens
|
|
|
68
58
|
column.name.end_with?('_id')
|
|
69
59
|
end
|
|
70
60
|
end
|
|
71
|
-
|
|
72
|
-
def indexed?(column)
|
|
73
|
-
connection.indexes(table_name).any? do |index|
|
|
74
|
-
index.columns.include?(column.name)
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def connection
|
|
79
|
-
model_class.connection
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def table_name
|
|
83
|
-
model_class.table_name
|
|
84
|
-
end
|
|
85
61
|
end
|
|
86
62
|
end
|
|
87
63
|
end
|
|
@@ -20,6 +20,19 @@ module RailsLens
|
|
|
20
20
|
|
|
21
21
|
delegate :clear, to: :@providers
|
|
22
22
|
|
|
23
|
+
# Route a single provider's result into the accumulator hash based on the
|
|
24
|
+
# provider's declared type. Shared by the pipeline and AnnotationManager.
|
|
25
|
+
def self.accumulate_result(results, provider, result)
|
|
26
|
+
case provider.type
|
|
27
|
+
when :schema
|
|
28
|
+
results[:schema] = result
|
|
29
|
+
when :section
|
|
30
|
+
results[:sections] << result if result
|
|
31
|
+
when :notes
|
|
32
|
+
results[:notes].concat(Array(result))
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
23
36
|
def process(model_class)
|
|
24
37
|
results = {
|
|
25
38
|
schema: nil,
|
|
@@ -35,14 +48,7 @@ module RailsLens
|
|
|
35
48
|
begin
|
|
36
49
|
result = provider.process(model_class, connection)
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
when :schema
|
|
40
|
-
results[:schema] = result
|
|
41
|
-
when :section
|
|
42
|
-
results[:sections] << result if result
|
|
43
|
-
when :notes
|
|
44
|
-
results[:notes].concat(Array(result))
|
|
45
|
-
end
|
|
51
|
+
self.class.accumulate_result(results, provider, result)
|
|
46
52
|
rescue ActiveRecord::StatementInvalid => e
|
|
47
53
|
warn "Provider #{provider.class} database error for #{model_class}: #{e.message}"
|
|
48
54
|
rescue ActiveRecord::ConnectionNotDefined => e
|
data/lib/rails_lens/cli.rb
CHANGED
|
@@ -34,13 +34,13 @@ module RailsLens
|
|
|
34
34
|
commands = Commands.new(self)
|
|
35
35
|
|
|
36
36
|
# Annotate models (default behavior or when --all is specified)
|
|
37
|
-
results[:models] = commands.annotate_models(options) if
|
|
37
|
+
results[:models] = commands.annotate_models(options) if target_models?
|
|
38
38
|
|
|
39
39
|
# Annotate routes
|
|
40
|
-
results[:routes] = commands.annotate_routes(options) if
|
|
40
|
+
results[:routes] = commands.annotate_routes(options) if target_routes?
|
|
41
41
|
|
|
42
42
|
# Annotate mailers
|
|
43
|
-
results[:mailers] = commands.annotate_mailers(options) if
|
|
43
|
+
results[:mailers] = commands.annotate_mailers(options) if target_mailers?
|
|
44
44
|
|
|
45
45
|
results
|
|
46
46
|
end
|
|
@@ -58,13 +58,13 @@ module RailsLens
|
|
|
58
58
|
commands = Commands.new(self)
|
|
59
59
|
|
|
60
60
|
# Remove model annotations (default behavior or when --all is specified)
|
|
61
|
-
results[:models] = commands.remove_models(options) if
|
|
61
|
+
results[:models] = commands.remove_models(options) if target_models?
|
|
62
62
|
|
|
63
63
|
# Remove route annotations
|
|
64
|
-
results[:routes] = commands.remove_routes(options) if
|
|
64
|
+
results[:routes] = commands.remove_routes(options) if target_routes?
|
|
65
65
|
|
|
66
66
|
# Remove mailer annotations
|
|
67
|
-
results[:mailers] = commands.remove_mailers(options) if
|
|
67
|
+
results[:mailers] = commands.remove_mailers(options) if target_mailers?
|
|
68
68
|
|
|
69
69
|
results
|
|
70
70
|
end
|
|
@@ -158,28 +158,17 @@ module RailsLens
|
|
|
158
158
|
RailsLens.config.debug = options[:debug]
|
|
159
159
|
end
|
|
160
160
|
|
|
161
|
-
# Helper methods to determine what to annotate/remove
|
|
162
|
-
|
|
161
|
+
# Helper methods to determine what to annotate/remove. The same targeting
|
|
162
|
+
# rules apply to both the annotate and remove commands.
|
|
163
|
+
def target_models?
|
|
163
164
|
(!options[:routes] && !options[:mailers]) || options[:all]
|
|
164
165
|
end
|
|
165
166
|
|
|
166
|
-
def
|
|
167
|
+
def target_routes?
|
|
167
168
|
options[:routes] || options[:all]
|
|
168
169
|
end
|
|
169
170
|
|
|
170
|
-
def
|
|
171
|
-
options[:mailers] || options[:all]
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def should_remove_models?
|
|
175
|
-
(!options[:routes] && !options[:mailers]) || options[:all]
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def should_remove_routes?
|
|
179
|
-
options[:routes] || options[:all]
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
def should_remove_mailers?
|
|
171
|
+
def target_mailers?
|
|
183
172
|
options[:mailers] || options[:all]
|
|
184
173
|
end
|
|
185
174
|
end
|
|
@@ -31,32 +31,31 @@ module RailsLens
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def handle_model_error(error)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
say 'Try running: bundle exec rails_lens annotate', :yellow
|
|
38
|
-
end
|
|
39
|
-
exit 1
|
|
34
|
+
report_error('Model Error', error,
|
|
35
|
+
'Make sure your Rails application is properly loaded',
|
|
36
|
+
'Try running: bundle exec rails_lens annotate')
|
|
40
37
|
end
|
|
41
38
|
|
|
42
39
|
def handle_database_error(error)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
say ' - Permission denied', :yellow
|
|
50
|
-
end
|
|
51
|
-
exit 1
|
|
40
|
+
report_error('Database Error', error,
|
|
41
|
+
'Possible causes:',
|
|
42
|
+
' - Database server is not running',
|
|
43
|
+
' - Invalid database credentials',
|
|
44
|
+
' - Table does not exist',
|
|
45
|
+
' - Permission denied')
|
|
52
46
|
end
|
|
53
47
|
|
|
54
48
|
def handle_annotation_error(error)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
report_error('Annotation Error', error,
|
|
50
|
+
'Failed to annotate one or more files',
|
|
51
|
+
'Check file permissions and syntax')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Print a red "<label>: <message>", optional verbose-only yellow hints,
|
|
55
|
+
# then exit non-zero.
|
|
56
|
+
def report_error(label, error, *verbose_hints)
|
|
57
|
+
say "#{label}: #{error.message}", :red
|
|
58
|
+
verbose_hints.each { |hint| say hint, :yellow } if options[:verbose]
|
|
60
59
|
exit 1
|
|
61
60
|
end
|
|
62
61
|
|
data/lib/rails_lens/commands.rb
CHANGED
|
@@ -15,14 +15,7 @@ module RailsLens
|
|
|
15
15
|
results = Schema::AnnotationManager.annotate_all(options)
|
|
16
16
|
|
|
17
17
|
output.say "Annotated #{results[:annotated].length} models", :green
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if results[:failed].any?
|
|
21
|
-
output.say "Failed to annotate #{results[:failed].length} models:", :red
|
|
22
|
-
results[:failed].each do |failure|
|
|
23
|
-
output.say " - #{failure[:model]}: #{failure[:error]}", :red
|
|
24
|
-
end
|
|
25
|
-
end
|
|
18
|
+
report_skipped_and_failed(results, 'models')
|
|
26
19
|
|
|
27
20
|
# Also annotate database-level objects (functions, etc.)
|
|
28
21
|
if options[:include_database_objects]
|
|
@@ -37,36 +30,17 @@ module RailsLens
|
|
|
37
30
|
results = Schema::DatabaseAnnotator.annotate_all(options)
|
|
38
31
|
|
|
39
32
|
output.say "Annotated #{results[:annotated].length} abstract base classes with database objects", :green
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if results[:failed].any?
|
|
43
|
-
output.say "Failed to annotate #{results[:failed].length} abstract classes:", :red
|
|
44
|
-
results[:failed].each do |failure|
|
|
45
|
-
output.say " - #{failure[:model]}: #{failure[:error]}", :red
|
|
46
|
-
end
|
|
47
|
-
end
|
|
33
|
+
report_skipped_and_failed(results, 'abstract classes')
|
|
48
34
|
|
|
49
35
|
results
|
|
50
36
|
end
|
|
51
37
|
|
|
52
38
|
def annotate_routes(options = {})
|
|
53
|
-
|
|
54
|
-
changed_files = annotator.annotate_all
|
|
55
|
-
|
|
56
|
-
output.say "Annotated #{changed_files.length} controller files with routes", :green
|
|
57
|
-
changed_files.each { |file| output.say " - #{file}", :blue } if options[:verbose] && changed_files.any?
|
|
58
|
-
|
|
59
|
-
{ changed_files: changed_files }
|
|
39
|
+
annotate_files(Route::Annotator.new(dry_run: options[:dry_run]), 'controller files with routes', options)
|
|
60
40
|
end
|
|
61
41
|
|
|
62
42
|
def annotate_mailers(options = {})
|
|
63
|
-
|
|
64
|
-
changed_files = annotator.annotate_all
|
|
65
|
-
|
|
66
|
-
output.say "Annotated #{changed_files.length} mailer files", :green
|
|
67
|
-
changed_files.each { |file| output.say " - #{file}", :blue } if options[:verbose] && changed_files.any?
|
|
68
|
-
|
|
69
|
-
{ changed_files: changed_files }
|
|
43
|
+
annotate_files(Mailer::Annotator.new(dry_run: options[:dry_run]), 'mailer files', options)
|
|
70
44
|
end
|
|
71
45
|
|
|
72
46
|
def remove_models(options = {})
|
|
@@ -76,17 +50,11 @@ module RailsLens
|
|
|
76
50
|
end
|
|
77
51
|
|
|
78
52
|
def remove_routes(options = {})
|
|
79
|
-
|
|
80
|
-
changed_files = annotator.remove_all
|
|
81
|
-
output.say "Removed route annotations from #{changed_files.length} controller files", :green
|
|
82
|
-
{ changed_files: changed_files }
|
|
53
|
+
remove_files(Route::Annotator.new(dry_run: options[:dry_run]), 'route', 'controller files')
|
|
83
54
|
end
|
|
84
55
|
|
|
85
56
|
def remove_mailers(options = {})
|
|
86
|
-
|
|
87
|
-
changed_files = annotator.remove_all
|
|
88
|
-
output.say "Removed mailer annotations from #{changed_files.length} mailer files", :green
|
|
89
|
-
{ changed_files: changed_files }
|
|
57
|
+
remove_files(Mailer::Annotator.new(dry_run: options[:dry_run]), 'mailer', 'mailer files')
|
|
90
58
|
end
|
|
91
59
|
|
|
92
60
|
def generate_erd(options = {})
|
|
@@ -227,6 +195,30 @@ module RailsLens
|
|
|
227
195
|
|
|
228
196
|
private
|
|
229
197
|
|
|
198
|
+
# Report skipped/failed counts for a model-annotation results hash.
|
|
199
|
+
def report_skipped_and_failed(results, noun)
|
|
200
|
+
output.say "Skipped #{results[:skipped].length} #{noun}", :yellow if results[:skipped].any?
|
|
201
|
+
return unless results[:failed].any?
|
|
202
|
+
|
|
203
|
+
output.say "Failed to annotate #{results[:failed].length} #{noun}:", :red
|
|
204
|
+
results[:failed].each do |failure|
|
|
205
|
+
output.say " - #{failure[:model]}: #{failure[:error]}", :red
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def annotate_files(annotator, label, options)
|
|
210
|
+
changed_files = annotator.annotate_all
|
|
211
|
+
output.say "Annotated #{changed_files.length} #{label}", :green
|
|
212
|
+
changed_files.each { |file| output.say " - #{file}", :blue } if options[:verbose] && changed_files.any?
|
|
213
|
+
{ changed_files: changed_files }
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def remove_files(annotator, kind, target)
|
|
217
|
+
changed_files = annotator.remove_all
|
|
218
|
+
output.say "Removed #{kind} annotations from #{changed_files.length} #{target}", :green
|
|
219
|
+
{ changed_files: changed_files }
|
|
220
|
+
end
|
|
221
|
+
|
|
230
222
|
def rake_task_template
|
|
231
223
|
<<~RAKE
|
|
232
224
|
# frozen_string_literal: true
|