eager_eye 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dce399f8b8160530246911ddbd4c9c5a9fb6cad487d409924c6e520993ff37cc
4
- data.tar.gz: 3be96cbcf42c206f0348c63a91991c1a872addd775d5054be9e3dc44cc8b4f52
3
+ metadata.gz: 4adfe62f9c9082d1c0f1e9b149af5f2cc09db5a455af6c0262687a5770b2c50b
4
+ data.tar.gz: 5284a262cf22fc9e7191dafa0a45383b3f073565313e02d202fb902bc250e7bb
5
5
  SHA512:
6
- metadata.gz: 23923fe65f0f51de105b9a6df93a8a115d9ceb40042dedc9d112ccfbdc48a324935cd48f18306944708ca355cb463caad4b97b994f619dff24d8c6cf475180c0
7
- data.tar.gz: efc5cfe923e04b55b3e5f2a9a6b201298176e4370a5cac92825bd01649ec528ea978fb378151ea7b74c2a82ce6194a02df6ce8c52018725f86bd83736410b71d
6
+ metadata.gz: e40d5802cd52757817d3c6f071abb7203d05ca5b127a72ee5534066b59b4addb2fdec1a592f703864710eec81fa571ef774ada0cd2381995b3819b711366d939
7
+ data.tar.gz: 50d3bcfa2029032200cae2b4e05ba5ef319f1a981acfc1b8b2969e0dcd977d849d01c2edab51f42808d0bdda538a63be280ad2063f5927907b64e579185c223e
data/CHANGELOG.md CHANGED
@@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] - 2025-12-15
11
+
12
+ ### Added
13
+
14
+ - **New Detector: `CustomMethodQuery`** - Detects query methods called inside iteration blocks
15
+ - Catches `.where`, `.find_by`, `.find_by!`, `.exists?` patterns that Bullet cannot detect
16
+ - Detects `.find`, `.first`, `.last`, `.take` inside loops
17
+ - Detects aggregation methods: `.pluck`, `.ids`, `.count`, `.sum`, `.average`, `.minimum`, `.maximum`
18
+ - Provides suggestions for preloading data before loops
19
+
20
+ ### Changed
21
+
22
+ - Updated default `enabled_detectors` to include `:custom_method_query`
23
+ - Updated README with new detector documentation and comparison table
24
+
10
25
  ## [0.1.0] - 2025-12-15
11
26
 
12
27
  ### Added
data/README.md CHANGED
@@ -14,7 +14,7 @@ EagerEye analyzes your Ruby code without running it, using AST (Abstract Syntax
14
14
  Unlike runtime tools like Bullet, EagerEye:
15
15
 
16
16
  - **Runs without executing code** - Works in CI pipelines without a test suite
17
- - **Catches more patterns** - Detects serializer N+1s and missing counter caches
17
+ - **Catches more patterns** - Detects serializer N+1s, missing counter caches, and query methods in loops
18
18
  - **Proactive detection** - Finds issues at code review time, not after deployment
19
19
 
20
20
  | Feature | EagerEye | Bullet |
@@ -23,6 +23,7 @@ Unlike runtime tools like Bullet, EagerEye:
23
23
  | Requires test suite | No | Yes |
24
24
  | Serializer N+1 detection | Yes | Limited |
25
25
  | Counter cache suggestions | Yes | No |
26
+ | Query methods in loops | Yes | No |
26
27
  | CI integration | Native | Requires tests |
27
28
  | False positive rate | Higher | Lower |
28
29
 
@@ -146,6 +147,35 @@ belongs_to :post, counter_cache: true
146
147
  post.comments_count
147
148
  ```
148
149
 
150
+ ### 4. Custom Method Query (N+1 in query methods)
151
+
152
+ Detects query methods (`.where`, `.find_by`, `.exists?`, etc.) called on associations inside loops. **These patterns are invisible to Bullet.**
153
+
154
+ ```ruby
155
+ # Bad - Bullet CANNOT catch this
156
+ class User < ApplicationRecord
157
+ def supports?(team_name)
158
+ teams.where(name: team_name).exists?
159
+ end
160
+ end
161
+
162
+ @users.each do |user|
163
+ user.supports?("Lakers") # Query for each user!
164
+ end
165
+
166
+ # Bad - find_by inside loop
167
+ @orders.each do |order|
168
+ order.line_items.find_by(featured: true)
169
+ end
170
+
171
+ # Good - Preload and filter in Ruby
172
+ @users.includes(:teams).each do |user|
173
+ user.teams.any? { |t| t.name == "Lakers" }
174
+ end
175
+ ```
176
+
177
+ **Detected methods:** `where`, `find_by`, `find_by!`, `exists?`, `find`, `first`, `last`, `take`, `pluck`, `ids`, `count`, `sum`, `average`, `minimum`, `maximum`
178
+
149
179
  ## Configuration
150
180
 
151
181
  ### Config File (.eager_eye.yml)
@@ -161,6 +191,7 @@ enabled_detectors:
161
191
  - loop_association
162
192
  - serializer_nesting
163
193
  - missing_counter_cache
194
+ - custom_method_query
164
195
 
165
196
  # Base path to analyze (default: app)
166
197
  app_path: app
@@ -7,7 +7,8 @@ module EagerEye
7
7
  DETECTOR_CLASSES = {
8
8
  loop_association: Detectors::LoopAssociation,
9
9
  serializer_nesting: Detectors::SerializerNesting,
10
- missing_counter_cache: Detectors::MissingCounterCache
10
+ missing_counter_cache: Detectors::MissingCounterCache,
11
+ custom_method_query: Detectors::CustomMethodQuery
11
12
  }.freeze
12
13
 
13
14
  attr_reader :paths, :issues
@@ -4,7 +4,7 @@ module EagerEye
4
4
  class Configuration
5
5
  attr_accessor :excluded_paths, :enabled_detectors, :app_path, :fail_on_issues
6
6
 
7
- DEFAULT_DETECTORS = %i[loop_association serializer_nesting missing_counter_cache].freeze
7
+ DEFAULT_DETECTORS = %i[loop_association serializer_nesting missing_counter_cache custom_method_query].freeze
8
8
 
9
9
  def initialize
10
10
  @excluded_paths = []
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EagerEye
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/eager_eye.rb CHANGED
@@ -7,6 +7,7 @@ require_relative "eager_eye/detectors/base"
7
7
  require_relative "eager_eye/detectors/loop_association"
8
8
  require_relative "eager_eye/detectors/serializer_nesting"
9
9
  require_relative "eager_eye/detectors/missing_counter_cache"
10
+ require_relative "eager_eye/detectors/custom_method_query"
10
11
  require_relative "eager_eye/analyzer"
11
12
  require_relative "eager_eye/reporters/base"
12
13
  require_relative "eager_eye/reporters/console"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eager_eye
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - hamzagedikkaya
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-12-14 00:00:00.000000000 Z
11
+ date: 2025-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ast