rails_lens 0.5.0 → 0.5.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 983d1382bf42b79549a4a504e696814846eccf606cd17f9fc3e521cce211f729
4
- data.tar.gz: 69714d9bfaf91dc139158649596b8111b6910d7515adb9be9928476ff95e6c3a
3
+ metadata.gz: 5180524144ca10c72173e0410e924877e7de878379a7924a0931adba19be185b
4
+ data.tar.gz: 4b76f310866feb24bb206b9004a4091c78553c147e9e0114131a693eb1d78097
5
5
  SHA512:
6
- metadata.gz: e580de20d715134c6066995921030e9aaf27ecdce188f455b93eb4bfd3b84d1bf9fcce109d75fe0d0fd340fd856c428d8da0e338e5d3b97299efc60098f72ebd
7
- data.tar.gz: b069e0140d3ff3924b4f0ba18695f7646a88167a797e10bdd35d5fb25783ac2f8c7c305e59b22458b1424be22b75c494d2ab37b6f4d4d79448ee189624c869aa
6
+ metadata.gz: 655c2c927177454346c7b0dae09c4faaed881e2df93941c27a29511ba2c48dd5e42742f426036c0187f60bfa631ec60941e0e00de8b26b91012ef6e6a4727a9f
7
+ data.tar.gz: b7d9465fdb5daa3ed000dbca03c673a39fc8c7141ccebeb3d7c050d478358b99ba25a95c1f425365472d75c1ed06cf1cc4e332f78e0015a1bd289bf8eb5beff9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.2](https://github.com/seuros/rails_lens/compare/rails_lens/v0.5.1...rails_lens/v0.5.2) (2026-02-16)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * reduce INVERSE_OF false positives for vanilla associations ([#39](https://github.com/seuros/rails_lens/issues/39)) ([b209c2a](https://github.com/seuros/rails_lens/commit/b209c2a6b2a894193561e9aa30985c3043b40ac3))
9
+
10
+ ## [0.5.1](https://github.com/seuros/rails_lens/compare/rails_lens/v0.5.0...rails_lens/v0.5.1) (2025-12-07)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * add by_source ([f6693f3](https://github.com/seuros/rails_lens/commit/f6693f384761de505eac0e525c7b70f4c053d14c))
16
+
3
17
  ## [0.5.0](https://github.com/seuros/rails_lens/compare/rails_lens/v0.3.0...rails_lens/v0.5.0) (2025-12-06)
4
18
 
5
19
 
@@ -42,7 +42,7 @@ module RailsLens
42
42
  def associations_needing_inverse
43
43
  all_associations.select do |association|
44
44
  association.options[:inverse_of].nil? &&
45
- !association.options[:through] &&
45
+ needs_explicit_inverse_of?(association) &&
46
46
  !association.polymorphic? &&
47
47
  bidirectional_association?(association)
48
48
  end
@@ -71,6 +71,16 @@ 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
+
74
84
  def should_have_counter_cache?(association)
75
85
  return false unless association.macro == :belongs_to
76
86
 
@@ -116,23 +116,23 @@ module RailsLens
116
116
  case filter
117
117
  when Symbol
118
118
  # Check if method is defined in the model class itself
119
- return true if model_class.instance_methods(false).include?(filter)
120
- return true if model_class.private_instance_methods(false).include?(filter)
119
+ return true if model_class.method_defined?(filter, false)
120
+ return true if model_class.private_method_defined?(filter, false)
121
121
 
122
122
  # Check if defined in included concerns (non-Rails modules)
123
123
  model_class.included_modules.each do |mod|
124
124
  next if mod.name.nil?
125
125
  next if mod.name.start_with?('ActiveRecord', 'ActiveModel', 'ActiveSupport')
126
126
 
127
- return true if mod.instance_methods(false).include?(filter)
128
- return true if mod.private_instance_methods(false).include?(filter)
127
+ return true if mod.method_defined?(filter, false)
128
+ return true if mod.private_method_defined?(filter, false)
129
129
  end
130
130
 
131
131
  # For STI: check parent classes up to (but not including) ActiveRecord::Base
132
132
  klass = model_class.superclass
133
133
  while klass && klass < ActiveRecord::Base
134
- return true if klass.instance_methods(false).include?(filter)
135
- return true if klass.private_instance_methods(false).include?(filter)
134
+ return true if klass.method_defined?(filter, false)
135
+ return true if klass.private_method_defined?(filter, false)
136
136
 
137
137
  klass = klass.superclass
138
138
  end
@@ -35,7 +35,7 @@ module RailsLens
35
35
 
36
36
  def detect_composite_primary_key_from_db
37
37
  # Query PostgreSQL system catalogs to find composite primary keys
38
- sql = <<-SQL.squish
38
+ sql = <<~SQL.squish
39
39
  SELECT a.attname
40
40
  FROM pg_index i
41
41
  JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
@@ -22,7 +22,7 @@ module RailsLens
22
22
 
23
23
  def detect_generated_columns
24
24
  # PostgreSQL system query to find generated columns
25
- sql = <<-SQL.squish
25
+ sql = <<~SQL.squish
26
26
  SELECT
27
27
  a.attname AS column_name,
28
28
  pg_get_expr(d.adbin, d.adrelid) AS generation_expression
@@ -312,8 +312,7 @@ module RailsLens
312
312
  def associations_needing_inverse
313
313
  associations.select do |association|
314
314
  association.options[:inverse_of].nil? &&
315
- !association.options[:through] &&
316
- !association.options[:as] &&
315
+ needs_explicit_inverse_of?(association) &&
317
316
  association.macro != :has_and_belongs_to_many
318
317
  end
319
318
  end
@@ -418,6 +417,16 @@ module RailsLens
418
417
  RailsLens.logger.debug { "Error checking view existence for #{view_name}: #{e.message}" }
419
418
  false
420
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
421
430
  end
422
431
  end
423
432
  end
@@ -84,7 +84,7 @@ module RailsLens
84
84
  def extensions
85
85
  return [] unless adapter_name == 'PostgreSQL'
86
86
 
87
- connection.select_all(<<-SQL.squish).to_a
87
+ connection.select_all(<<~SQL.squish).to_a
88
88
  SELECT extname as name, extversion as version
89
89
  FROM pg_extension
90
90
  WHERE extname NOT IN ('plpgsql')
@@ -97,7 +97,7 @@ module RailsLens
97
97
  def schemas
98
98
  return [] unless adapter_name == 'PostgreSQL'
99
99
 
100
- connection.select_values(<<-SQL.squish)
100
+ connection.select_values(<<~SQL.squish)
101
101
  SELECT schema_name
102
102
  FROM information_schema.schemata
103
103
  WHERE schema_name NOT IN ('pg_catalog', 'information_schema', 'pg_toast')
@@ -211,12 +211,12 @@ module RailsLens
211
211
  def has_partitions?
212
212
  return false unless connection.respond_to?(:execute)
213
213
 
214
- result = connection.execute(<<-SQL.squish)
215
- SELECT COUNT(*) as count
216
- FROM information_schema.partitions
217
- WHERE table_schema = DATABASE()
218
- AND table_name = '#{table_name}'
219
- AND partition_name IS NOT NULL
214
+ result = connection.execute(<<~SQL.squish)
215
+ SELECT COUNT(*) as count
216
+ FROM information_schema.partitions
217
+ WHERE table_schema = DATABASE()
218
+ AND table_name = '#{table_name}'
219
+ AND partition_name IS NOT NULL
220
220
  SQL
221
221
 
222
222
  count = if result.first.is_a?(Hash)
@@ -241,13 +241,13 @@ module RailsLens
241
241
  def add_partitions(lines)
242
242
  return unless connection.respond_to?(:execute)
243
243
 
244
- partitions = connection.execute(<<-SQL.squish)
245
- SELECT partition_name, partition_expression, partition_description
246
- FROM information_schema.partitions
247
- WHERE table_schema = DATABASE()
248
- AND table_name = '#{table_name}'
249
- AND partition_name IS NOT NULL
250
- ORDER BY partition_ordinal_position
244
+ partitions = connection.execute(<<~SQL.squish)
245
+ SELECT partition_name, partition_expression, partition_description
246
+ FROM information_schema.partitions
247
+ WHERE table_schema = DATABASE()
248
+ AND table_name = '#{table_name}'
249
+ AND partition_name IS NOT NULL
250
+ ORDER BY partition_ordinal_position
251
251
  SQL
252
252
 
253
253
  return if partitions.none?
@@ -269,13 +269,13 @@ module RailsLens
269
269
  def add_partitions_toml(lines)
270
270
  return unless connection.respond_to?(:execute)
271
271
 
272
- partitions = connection.execute(<<-SQL.squish)
273
- SELECT partition_name, partition_expression, partition_description
274
- FROM information_schema.partitions
275
- WHERE table_schema = DATABASE()
276
- AND table_name = '#{table_name}'
277
- AND partition_name IS NOT NULL
278
- ORDER BY partition_ordinal_position
272
+ partitions = connection.execute(<<~SQL.squish)
273
+ SELECT partition_name, partition_expression, partition_description
274
+ FROM information_schema.partitions
275
+ WHERE table_schema = DATABASE()
276
+ AND table_name = '#{table_name}'
277
+ AND partition_name IS NOT NULL
278
+ ORDER BY partition_ordinal_position
279
279
  SQL
280
280
 
281
281
  return if partitions.none?
@@ -148,12 +148,13 @@ module RailsLens
148
148
  end
149
149
 
150
150
  def self.annotate_all(options = {})
151
- results = { annotated: [], skipped: [], failed: [] }
151
+ results = { annotated: [], skipped: [], failed: [], by_source: {} }
152
152
 
153
153
  # Iterate through all model sources
154
154
  ModelSourceLoader.load_sources.each do |source|
155
155
  puts "Annotating #{source.source_name} models..." if options[:verbose]
156
156
  source_results = annotate_source(source, options)
157
+ results[:by_source][source.source_name] = source_results[:annotated].length
157
158
  merge_results(results, source_results)
158
159
  end
159
160
 
@@ -312,12 +313,13 @@ module RailsLens
312
313
  end
313
314
 
314
315
  def self.remove_all(options = {})
315
- results = { removed: [], skipped: [], failed: [] }
316
+ results = { removed: [], skipped: [], failed: [], by_source: {} }
316
317
 
317
318
  # Iterate through all model sources
318
319
  ModelSourceLoader.load_sources.each do |source|
319
320
  puts "Removing annotations from #{source.source_name} models..." if options[:verbose]
320
321
  source_results = remove_source(source, options)
322
+ results[:by_source][source.source_name] = source_results[:removed].length
321
323
  merge_remove_results(results, source_results)
322
324
  end
323
325
 
@@ -11,7 +11,13 @@ namespace :rails_lens do
11
11
 
12
12
  results = RailsLens::Schema::AnnotationManager.annotate_all(options)
13
13
 
14
- puts "Annotated #{results[:annotated].length} models"
14
+ if results[:by_source]&.any?
15
+ results[:by_source].each do |source_name, count|
16
+ puts "Annotated #{count} #{source_name} models" if count.positive?
17
+ end
18
+ else
19
+ puts "Annotated #{results[:annotated].length} models"
20
+ end
15
21
  puts "Skipped #{results[:skipped].length} models" if results[:skipped].any?
16
22
  if results[:failed].any?
17
23
  puts "Failed to annotate #{results[:failed].length} models:"
@@ -27,7 +33,13 @@ namespace :rails_lens do
27
33
 
28
34
  results = RailsLens::Schema::AnnotationManager.remove_all
29
35
 
30
- puts "Removed annotations from #{results[:removed].length} models" if results[:removed].any?
36
+ if results[:by_source]&.any?
37
+ results[:by_source].each do |source_name, count|
38
+ puts "Removed annotations from #{count} #{source_name} models" if count.positive?
39
+ end
40
+ elsif results[:removed].any?
41
+ puts "Removed annotations from #{results[:removed].length} models"
42
+ end
31
43
  puts "Skipped #{results[:skipped].length} models (no annotations)" if results[:skipped].any?
32
44
  if results[:failed].any?
33
45
  puts "Failed to remove annotations from #{results[:failed].length} models:"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsLens
4
- VERSION = '0.5.0'
4
+ VERSION = '0.5.2'
5
5
  end
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.5.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdelkader Boudih
@@ -270,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
270
270
  - !ruby/object:Gem::Version
271
271
  version: '0'
272
272
  requirements: []
273
- rubygems_version: 3.6.9
273
+ rubygems_version: 4.0.3
274
274
  specification_version: 4
275
275
  summary: Comprehensive Rails application visualization and annotation
276
276
  test_files: []