rails_lens 0.5.4 → 0.10.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/CHANGELOG.md +7 -0
- data/README.md +1 -1
- data/lib/rails_lens/analyzers/composite_keys.rb +3 -37
- data/lib/rails_lens/commands.rb +3 -3
- data/lib/rails_lens/erd/column_type_formatter.rb +6 -1
- data/lib/rails_lens/erd/visualizer.rb +41 -39
- data/lib/rails_lens/errors.rb +3 -3
- data/lib/rails_lens/mailer/annotator.rb +1 -0
- data/lib/rails_lens/route/annotator.rb +1 -0
- data/lib/rails_lens/schema/adapters/base.rb +4 -3
- data/lib/rails_lens/schema/adapters/postgresql.rb +3 -3
- data/lib/rails_lens/schema/annotation_manager.rb +16 -2
- data/lib/rails_lens/tasks/annotate.rake +6 -1
- data/lib/rails_lens/version.rb +1 -1
- data/lib/rails_lens.rb +4 -0
- metadata +9 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0f010a15d0d3afdf64754e866cac571fcb1c91e4bd3981c8aa9bdece8d30f85a
|
|
4
|
+
data.tar.gz: 11e8b6ad7da6461bdc846952151537d3495d67cd812cd9f7e4b3ca40dbc37fbb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 22963fce37978c1a4157d9c1ffe236a3ca41c0a97d8b492a832729b467c91923810cc70126c4717c17cbbac9596dfbcd620a34cdb482092b34a8692a37351c23
|
|
7
|
+
data.tar.gz: 4c5bd10154b4d44b4dfda08ec21ebcd3632b6a740e7a9d28ddd7d5a35289fec248fcf76b61bc19db8a53f548691a5597df326bda48f25ad0cc200c94468f94bf
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.0](https://github.com/seuros/rails_lens/compare/rails_lens/v0.5.4...rails_lens/v0.10.0) (2026-08-10)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* composite primary keys ([#45](https://github.com/seuros/rails_lens/issues/45)) ([8d934b5](https://github.com/seuros/rails_lens/commit/8d934b51b310252ce42f3db9aa85894161d562f3))
|
|
9
|
+
|
|
3
10
|
## [0.5.4](https://github.com/seuros/rails_lens/compare/rails_lens/v0.5.3...rails_lens/v0.5.4) (2026-06-26)
|
|
4
11
|
|
|
5
12
|
|
data/README.md
CHANGED
|
@@ -4,22 +4,10 @@ module RailsLens
|
|
|
4
4
|
module Analyzers
|
|
5
5
|
class CompositeKeys < Base
|
|
6
6
|
def analyze
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
keys = model_class.primary_keys
|
|
10
|
-
return format_composite_keys(keys) if keys.length > 1
|
|
11
|
-
end
|
|
7
|
+
pk = model_class.primary_key
|
|
8
|
+
return nil unless pk.is_a?(Array)
|
|
12
9
|
|
|
13
|
-
|
|
14
|
-
if adapter_name == 'PostgreSQL'
|
|
15
|
-
keys = detect_composite_primary_key_from_db
|
|
16
|
-
return format_composite_keys(keys) if keys && keys.length > 1
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
nil
|
|
20
|
-
rescue NoMethodError => e
|
|
21
|
-
RailsLens.logger.debug { "Failed to analyze composite keys for #{model_class.name}: #{e.message}" }
|
|
22
|
-
nil
|
|
10
|
+
format_composite_keys(pk)
|
|
23
11
|
rescue ActiveRecord::ConnectionNotEstablished => e
|
|
24
12
|
RailsLens.logger.debug { "No database connection for #{model_class.name}: #{e.message}" }
|
|
25
13
|
nil
|
|
@@ -32,28 +20,6 @@ module RailsLens
|
|
|
32
20
|
lines << "keys = #{TomlFormat.quoted_array(keys)}"
|
|
33
21
|
lines.join("\n")
|
|
34
22
|
end
|
|
35
|
-
|
|
36
|
-
def detect_composite_primary_key_from_db
|
|
37
|
-
# Query PostgreSQL system catalogs to find composite primary keys
|
|
38
|
-
sql = <<~SQL.squish
|
|
39
|
-
SELECT a.attname
|
|
40
|
-
FROM pg_index i
|
|
41
|
-
JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
|
|
42
|
-
WHERE i.indrelid = '#{table_name}'::regclass
|
|
43
|
-
AND i.indisprimary
|
|
44
|
-
ORDER BY array_position(i.indkey, a.attnum)
|
|
45
|
-
SQL
|
|
46
|
-
|
|
47
|
-
result = connection.execute(sql)
|
|
48
|
-
keys = result.pluck('attname')
|
|
49
|
-
keys.empty? ? nil : keys
|
|
50
|
-
rescue ActiveRecord::StatementInvalid => e
|
|
51
|
-
RailsLens.logger.debug { "Failed to detect composite keys from database for #{table_name}: #{e.message}" }
|
|
52
|
-
nil
|
|
53
|
-
rescue PG::Error => e
|
|
54
|
-
RailsLens.logger.debug { "PostgreSQL error detecting composite keys: #{e.message}" }
|
|
55
|
-
nil
|
|
56
|
-
end
|
|
57
23
|
end
|
|
58
24
|
end
|
|
59
25
|
end
|
data/lib/rails_lens/commands.rb
CHANGED
|
@@ -59,9 +59,9 @@ module RailsLens
|
|
|
59
59
|
|
|
60
60
|
def generate_erd(options = {})
|
|
61
61
|
visualizer = ERD::Visualizer.new(options: options)
|
|
62
|
-
|
|
63
|
-
output.say "Entity Relationship Diagram generated at #{filename}", :green
|
|
64
|
-
|
|
62
|
+
filenames = Array(visualizer.generate)
|
|
63
|
+
filenames.each { |filename| output.say "Entity Relationship Diagram generated at #{filename}", :green }
|
|
64
|
+
filenames.length == 1 ? filenames.first : filenames
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def lint(options = {})
|
|
@@ -24,7 +24,12 @@ module RailsLens
|
|
|
24
24
|
when :binary then 'blob'
|
|
25
25
|
when :json, :jsonb then 'json'
|
|
26
26
|
else
|
|
27
|
-
|
|
27
|
+
# column.type is nil for types the adapter can't resolve (e.g. a
|
|
28
|
+
# PostGIS geometry column without activerecord-postgis loaded);
|
|
29
|
+
# the diagram gem rejects empty attribute types.
|
|
30
|
+
fallback = @column.type.to_s
|
|
31
|
+
fallback = @column.sql_type.to_s if fallback.empty?
|
|
32
|
+
fallback.empty? ? 'unknown' : fallback
|
|
28
33
|
end
|
|
29
34
|
end
|
|
30
35
|
end
|
|
@@ -20,7 +20,13 @@ module RailsLens
|
|
|
20
20
|
|
|
21
21
|
def generate
|
|
22
22
|
models = load_models
|
|
23
|
-
|
|
23
|
+
if config[:group_by_database]
|
|
24
|
+
group_models_by_database(models).map do |db_name, group|
|
|
25
|
+
generate_mermaid(group, basename: "erd_#{db_name}")
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
generate_mermaid(models)
|
|
29
|
+
end
|
|
24
30
|
end
|
|
25
31
|
|
|
26
32
|
private
|
|
@@ -29,11 +35,15 @@ module RailsLens
|
|
|
29
35
|
ModelDetector.detect_models(options)
|
|
30
36
|
end
|
|
31
37
|
|
|
32
|
-
def
|
|
38
|
+
def group_models_by_database(models)
|
|
39
|
+
models.group_by { |model| model.connection_pool.db_config.name }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def generate_mermaid(models, basename: 'erd')
|
|
33
43
|
if models.blank?
|
|
34
44
|
# Still need to save the output even if no models found
|
|
35
45
|
mermaid_output = "erDiagram\n %% No models found"
|
|
36
|
-
return save_output(mermaid_output, 'mmd')
|
|
46
|
+
return save_output(mermaid_output, 'mmd', basename: basename)
|
|
37
47
|
end
|
|
38
48
|
|
|
39
49
|
# Create new ERDiagram using mermaid-ruby gem
|
|
@@ -41,25 +51,15 @@ module RailsLens
|
|
|
41
51
|
|
|
42
52
|
# Process models and add them to the diagram
|
|
43
53
|
models.each do |model|
|
|
44
|
-
|
|
45
|
-
next if model.abstract_class?
|
|
46
|
-
|
|
47
|
-
# Skip models without valid tables/views or columns
|
|
48
|
-
is_view = ModelDetector.view_exists?(model)
|
|
49
|
-
has_data_source = is_view || (model.table_exists? && model.columns.present?)
|
|
50
|
-
next unless has_data_source
|
|
54
|
+
next unless renderable?(model)
|
|
51
55
|
|
|
52
56
|
begin
|
|
53
57
|
# Create attributes for the entity
|
|
54
|
-
attributes =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
keys = determine_keys(model, column)
|
|
58
|
-
|
|
59
|
-
attributes << {
|
|
60
|
-
type: type_str,
|
|
58
|
+
attributes = model.columns.map do |column|
|
|
59
|
+
{
|
|
60
|
+
type: format_column_type(column),
|
|
61
61
|
name: column.name,
|
|
62
|
-
keys:
|
|
62
|
+
keys: determine_keys(model, column)
|
|
63
63
|
}
|
|
64
64
|
end
|
|
65
65
|
|
|
@@ -74,26 +74,31 @@ module RailsLens
|
|
|
74
74
|
RailsLens.logger.debug { "Warning: Could not add entity #{model.name}: #{e.message}" }
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
is_view = ModelDetector.view_exists?(model)
|
|
81
|
-
has_data_source = is_view || (model.table_exists? && model.columns.present?)
|
|
82
|
-
next unless has_data_source
|
|
83
|
-
|
|
84
|
-
add_model_relationships(diagram, model, models)
|
|
77
|
+
# Relationships require both entities to exist in the diagram
|
|
78
|
+
add_model_relationships(diagram, model, models) if diagram.entities.key?(model.name)
|
|
85
79
|
end
|
|
86
80
|
|
|
87
81
|
# Generate mermaid syntax using the gem
|
|
88
82
|
mermaid_output = diagram.to_mermaid
|
|
89
83
|
|
|
90
84
|
# Save output
|
|
91
|
-
filename = save_output(mermaid_output, 'mmd')
|
|
85
|
+
filename = save_output(mermaid_output, 'mmd', basename: basename)
|
|
92
86
|
|
|
93
87
|
RailsLens.logger.debug 'ERD generated successfully!'
|
|
94
88
|
filename # Return the filename instead of content
|
|
95
89
|
end
|
|
96
90
|
|
|
91
|
+
# A model renders when it is concrete and its table/view is reachable;
|
|
92
|
+
# an unavailable connection just drops the model from the diagram.
|
|
93
|
+
def renderable?(model)
|
|
94
|
+
return false if model.abstract_class?
|
|
95
|
+
|
|
96
|
+
ModelDetector.view_exists?(model) || (model.table_exists? && model.columns.present?)
|
|
97
|
+
rescue ActiveRecord::ActiveRecordError => e
|
|
98
|
+
RailsLens.logger.debug { "Skipping #{model.name}: #{e.message}" }
|
|
99
|
+
false
|
|
100
|
+
end
|
|
101
|
+
|
|
97
102
|
def format_column_type(column)
|
|
98
103
|
formatter_class = case column.sql_type
|
|
99
104
|
when /jsonb|uuid|inet|array|tsvector/i
|
|
@@ -109,13 +114,10 @@ module RailsLens
|
|
|
109
114
|
|
|
110
115
|
def determine_keys(model, column)
|
|
111
116
|
keys = []
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
model.reflect_on_all_associations(:belongs_to).each do |assoc|
|
|
117
|
-
keys << :FK if assoc.foreign_key.to_s == column.name
|
|
118
|
-
end
|
|
117
|
+
# primary_key and foreign_key are arrays for composite keys
|
|
118
|
+
keys << :PK if Array(model.primary_key).include?(column.name)
|
|
119
|
+
keys << :FK if model.reflect_on_all_associations(:belongs_to).any? do |assoc|
|
|
120
|
+
Array(assoc.foreign_key).map(&:to_s).include?(column.name)
|
|
119
121
|
end
|
|
120
122
|
|
|
121
123
|
# Check unique indexes - use UK which will be automatically quoted as comment
|
|
@@ -143,9 +145,9 @@ module RailsLens
|
|
|
143
145
|
|
|
144
146
|
next unless target_model && models.include?(target_model)
|
|
145
147
|
|
|
146
|
-
# Skip
|
|
147
|
-
|
|
148
|
-
next unless
|
|
148
|
+
# Skip targets whose entity was not added to the diagram
|
|
149
|
+
# (abstract, unreachable connection, or add_entity failed)
|
|
150
|
+
next unless diagram.entities.key?(target_model.name)
|
|
149
151
|
|
|
150
152
|
add_association_relationship(diagram, model, association, target_model)
|
|
151
153
|
end
|
|
@@ -181,11 +183,11 @@ module RailsLens
|
|
|
181
183
|
end
|
|
182
184
|
end
|
|
183
185
|
|
|
184
|
-
def save_output(content, extension)
|
|
186
|
+
def save_output(content, extension, basename: 'erd')
|
|
185
187
|
output_dir = config[:output_dir] || 'doc/erd'
|
|
186
188
|
FileUtils.mkdir_p(output_dir)
|
|
187
189
|
|
|
188
|
-
filename = File.join(output_dir, "
|
|
190
|
+
filename = File.join(output_dir, "#{basename}.#{extension}")
|
|
189
191
|
File.write(filename, content)
|
|
190
192
|
|
|
191
193
|
RailsLens.logger.debug { "ERD saved to: #{filename}" }
|
data/lib/rails_lens/errors.rb
CHANGED
|
@@ -42,7 +42,7 @@ module RailsLens
|
|
|
42
42
|
class ErrorReporter
|
|
43
43
|
class << self
|
|
44
44
|
def report(error, context = {})
|
|
45
|
-
return unless RailsLens.verbose || RailsLens.debug
|
|
45
|
+
return unless RailsLens.config.verbose || RailsLens.config.debug
|
|
46
46
|
|
|
47
47
|
message = build_error_message(error, context)
|
|
48
48
|
|
|
@@ -50,7 +50,7 @@ module RailsLens
|
|
|
50
50
|
RailsLens.logger.error message
|
|
51
51
|
|
|
52
52
|
# Use kernel output for debug mode to ensure visibility
|
|
53
|
-
return unless RailsLens.debug
|
|
53
|
+
return unless RailsLens.config.debug
|
|
54
54
|
|
|
55
55
|
RailsLens.logger.debug message
|
|
56
56
|
end
|
|
@@ -59,7 +59,7 @@ module RailsLens
|
|
|
59
59
|
yield
|
|
60
60
|
rescue StandardError => e
|
|
61
61
|
report(e, context)
|
|
62
|
-
raise if RailsLens.raise_on_error
|
|
62
|
+
raise if RailsLens.config.raise_on_error
|
|
63
63
|
|
|
64
64
|
nil
|
|
65
65
|
end
|
|
@@ -164,11 +164,12 @@ module RailsLens
|
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
def primary_key?(column)
|
|
167
|
-
column.name
|
|
167
|
+
primary_key_names.include?(column.name)
|
|
168
168
|
end
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
170
|
+
# The singular connection.primary_key returns nil for composite keys.
|
|
171
|
+
def primary_key_names
|
|
172
|
+
@primary_key_names ||= connection.primary_keys(unqualified_table_name)
|
|
172
173
|
end
|
|
173
174
|
|
|
174
175
|
def column_name_width
|
|
@@ -112,9 +112,9 @@ module RailsLens
|
|
|
112
112
|
end
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
-
def
|
|
116
|
-
@
|
|
117
|
-
connection.
|
|
115
|
+
def primary_key_names
|
|
116
|
+
@primary_key_names ||= with_schema_in_search_path do
|
|
117
|
+
connection.primary_keys(unqualified_table_name)
|
|
118
118
|
end
|
|
119
119
|
end
|
|
120
120
|
|
|
@@ -104,19 +104,33 @@ module RailsLens
|
|
|
104
104
|
results = { annotated: [], skipped: [], failed: [] }
|
|
105
105
|
|
|
106
106
|
begin
|
|
107
|
-
models = source.models(options)
|
|
107
|
+
models = filter_models_by_names(source.models(options), options[:models])
|
|
108
108
|
puts " Found #{models.size} #{source.source_name} models" if options[:verbose]
|
|
109
109
|
|
|
110
110
|
models.each do |model|
|
|
111
111
|
record_result(results, source.annotate_model(model, options))
|
|
112
112
|
end
|
|
113
113
|
rescue StandardError => e
|
|
114
|
-
|
|
114
|
+
results[:failed] << { model: "#{source.source_name} (source)", error: e.message }
|
|
115
115
|
end
|
|
116
116
|
|
|
117
117
|
results
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
+
# Enforce the models filter for every source, including sources whose
|
|
121
|
+
# own #models implementation ignores options[:models].
|
|
122
|
+
def self.filter_models_by_names(models, names)
|
|
123
|
+
names = Array(names)
|
|
124
|
+
return models if names.empty?
|
|
125
|
+
|
|
126
|
+
models.select do |model|
|
|
127
|
+
names.any? do |name|
|
|
128
|
+
model.name == name ||
|
|
129
|
+
(model.respond_to?(:table_name) && model.table_name == name)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
120
134
|
# Merge source results into main results. +primary_key+ is the
|
|
121
135
|
# source-specific success bucket (:annotated or :removed).
|
|
122
136
|
def self.merge_results(main, source, primary_key)
|
|
@@ -13,7 +13,7 @@ namespace :rails_lens do
|
|
|
13
13
|
|
|
14
14
|
if results[:by_source]&.any?
|
|
15
15
|
results[:by_source].each do |source_name, count|
|
|
16
|
-
puts "Annotated #{count} #{source_name} models"
|
|
16
|
+
puts "Annotated #{count} #{source_name} models"
|
|
17
17
|
end
|
|
18
18
|
else
|
|
19
19
|
puts "Annotated #{results[:annotated].length} models"
|
|
@@ -25,6 +25,11 @@ namespace :rails_lens do
|
|
|
25
25
|
puts " - #{failure[:model]}: #{failure[:error]}"
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
|
+
if options[:models] && results.values_at(:annotated, :skipped, :failed).all?(&:empty?)
|
|
29
|
+
warn "No models matched '#{options[:models].join(', ')}'. The task argument is a " \
|
|
30
|
+
'comma-separated list of model class names, e.g. rails_lens:annotate[User,Admin::Account]. ' \
|
|
31
|
+
'Run rails_lens:annotate without arguments to annotate everything.'
|
|
32
|
+
end
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
desc 'Remove all annotations from models'
|
data/lib/rails_lens/version.rb
CHANGED
data/lib/rails_lens.rb
CHANGED
|
@@ -31,6 +31,9 @@ module RailsLens
|
|
|
31
31
|
extend Configuration
|
|
32
32
|
|
|
33
33
|
class << self
|
|
34
|
+
# Path of the loaded config file, nil when running on defaults.
|
|
35
|
+
attr_reader :config_file
|
|
36
|
+
|
|
34
37
|
def logger
|
|
35
38
|
@logger ||= config.logger || default_logger
|
|
36
39
|
end
|
|
@@ -52,6 +55,7 @@ module RailsLens
|
|
|
52
55
|
def load_config_file(path = '.rails-lens.yml')
|
|
53
56
|
return unless File.exist?(path)
|
|
54
57
|
|
|
58
|
+
@config_file = path
|
|
55
59
|
yaml = YAML.load_file(path)
|
|
56
60
|
|
|
57
61
|
yaml.each do |section, settings|
|
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.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Abdelkader Boudih
|
|
@@ -15,28 +15,28 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 8.0.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
25
|
+
version: 8.0.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: railties
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version:
|
|
32
|
+
version: 8.0.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version:
|
|
39
|
+
version: 8.0.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: ostruct
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -85,14 +85,14 @@ dependencies:
|
|
|
85
85
|
requirements:
|
|
86
86
|
- - ">="
|
|
87
87
|
- !ruby/object:Gem::Version
|
|
88
|
-
version:
|
|
88
|
+
version: 8.0.0
|
|
89
89
|
type: :development
|
|
90
90
|
prerelease: false
|
|
91
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
93
|
- - ">="
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
|
-
version:
|
|
95
|
+
version: 8.0.0
|
|
96
96
|
- !ruby/object:Gem::Dependency
|
|
97
97
|
name: dotenv
|
|
98
98
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -149,7 +149,7 @@ dependencies:
|
|
|
149
149
|
- - "~>"
|
|
150
150
|
- !ruby/object:Gem::Version
|
|
151
151
|
version: '2.0'
|
|
152
|
-
description: Rails Lens provides unified visualization and annotation for Rails
|
|
152
|
+
description: Rails Lens provides unified visualization and annotation for Rails 8.0+
|
|
153
153
|
applications, integrating ERD generation and model annotations.
|
|
154
154
|
email:
|
|
155
155
|
- terminale@gmail.com
|
|
@@ -273,7 +273,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
273
273
|
- !ruby/object:Gem::Version
|
|
274
274
|
version: '0'
|
|
275
275
|
requirements: []
|
|
276
|
-
rubygems_version: 4.0.
|
|
276
|
+
rubygems_version: 4.0.10
|
|
277
277
|
specification_version: 4
|
|
278
278
|
summary: Comprehensive Rails application visualization and annotation
|
|
279
279
|
test_files: []
|