eager_eye 1.3.1 → 1.3.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 +4 -4
- data/CHANGELOG.md +32 -0
- data/lib/eager_eye/analyzer.rb +22 -8
- data/lib/eager_eye/detectors/base.rb +7 -4
- data/lib/eager_eye/schema_parser.rb +8 -5
- data/lib/eager_eye/serializer_usage_parser.rb +1 -1
- data/lib/eager_eye/version.rb +1 -1
- data/lib/eager_eye.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cf62f7a72d83da98d52ebb908f4d90e64b5833bf7a06e93f70fdf048c5e4acef
|
|
4
|
+
data.tar.gz: c6e7bf356eb50ca8c3b38fd25370bba07be422936e1077630be0a514aa5ba9db
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3b2501ee3da617e3c141f44563c6bd0313862b174a19637f2e563bdfa5419424a95cc31748c0ef0b57d01513075d468385806561ba3b8e83581d2fcbd6596f34
|
|
7
|
+
data.tar.gz: 2ab7ec6aef2c2d89b83b8b29f7de5849404af0351f5d3cbd585b2447b369da25ba08129e9c7b88f5004669c0ee17190df181c7980f4c20e0bb5c25c4dbd124ba
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.3.2] - 2026-07-09
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **Unparseable files are reported once, by name — not as raw parser dumps.**
|
|
16
|
+
A file the parser gem cannot lex (e.g. a model holding a binary string
|
|
17
|
+
literal whose escapes are invalid UTF-8) used to trigger the default
|
|
18
|
+
diagnostic consumer, which dumped a three-line error block to stderr on
|
|
19
|
+
*every* analysis pass — three times per scan — labelled `(string):63` with
|
|
20
|
+
no hint of which file was affected, while the file itself was silently
|
|
21
|
+
dropped from analysis. All parsing now goes through the new
|
|
22
|
+
`EagerEye::SourceParser` (quiet diagnostics, buffers named after the real
|
|
23
|
+
file), and the analyzer emits a single clear line per file instead:
|
|
24
|
+
`EagerEye: Skipped unparseable file app/models/coupon.rb: literal contains
|
|
25
|
+
escape sequences incompatible with UTF-8`. Skipped files and their reasons
|
|
26
|
+
are also exposed programmatically via `Analyzer#skipped_files` (reset on
|
|
27
|
+
every `#run`). Unknown magic encoding comments (`# encoding: utf8` — a
|
|
28
|
+
`Parser::UnknownEncodingInMagicComment`, which is an ArgumentError rather
|
|
29
|
+
than a SyntaxError and previously crashed the whole run) are handled the
|
|
30
|
+
same way, and an unparseable `db/schema.rb` now warns explicitly that
|
|
31
|
+
schema-aware column checks are disabled instead of degrading precision in
|
|
32
|
+
silence.
|
|
33
|
+
- **No more `parser/current` version-deviation warning.** EagerEye now
|
|
34
|
+
requires the grammar matching the running Ruby's *minor* version
|
|
35
|
+
(`parser/ruby33` on any 3.3.x) instead of `parser/current`, which insists
|
|
36
|
+
on an exact patch match and warned on every load ("parser/current is
|
|
37
|
+
loading parser/ruby33, which recognizes 3.3.4-compliant syntax, but you
|
|
38
|
+
are running 3.3.1"). Grammar only changes between minor versions, so
|
|
39
|
+
behaviour is identical; Rubies without a bundled grammar file fall back to
|
|
40
|
+
`parser/current` as before.
|
|
41
|
+
|
|
10
42
|
## [1.3.1] - 2026-06-12
|
|
11
43
|
|
|
12
44
|
### Changed — precision (fewer false positives)
|
data/lib/eager_eye/analyzer.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require_relative "source_parser"
|
|
4
4
|
|
|
5
5
|
module EagerEye
|
|
6
6
|
class Analyzer
|
|
@@ -32,7 +32,7 @@ module EagerEye
|
|
|
32
32
|
|
|
33
33
|
attr_reader :paths, :issues, :association_preloads, :association_names, :method_queries, :delegation_maps,
|
|
34
34
|
:scope_maps, :uniqueness_models, :associations_by_model, :all_columns, :columns_by_model,
|
|
35
|
-
:serializer_usage
|
|
35
|
+
:serializer_usage, :skipped_files
|
|
36
36
|
|
|
37
37
|
def initialize(paths: nil)
|
|
38
38
|
@paths = Array(paths || EagerEye.configuration.app_path)
|
|
@@ -47,10 +47,12 @@ module EagerEye
|
|
|
47
47
|
@all_columns = Set.new
|
|
48
48
|
@columns_by_model = {}
|
|
49
49
|
@serializer_usage = SerializerUsageParser.new
|
|
50
|
+
@skipped_files = {}
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
def run
|
|
53
54
|
@issues = []
|
|
55
|
+
@skipped_files = {}
|
|
54
56
|
collect_schema
|
|
55
57
|
collect_model_metadata
|
|
56
58
|
collect_serializer_usage
|
|
@@ -73,7 +75,7 @@ module EagerEye
|
|
|
73
75
|
# this to stay silent on associations preloaded at all render sites.
|
|
74
76
|
def collect_serializer_usage
|
|
75
77
|
ruby_files.each do |file_path|
|
|
76
|
-
ast = parse_source(File.read(file_path))
|
|
78
|
+
ast = parse_source(File.read(file_path), file_path)
|
|
77
79
|
@serializer_usage.parse_file(ast) if ast
|
|
78
80
|
rescue Errno::ENOENT, Errno::EACCES
|
|
79
81
|
next
|
|
@@ -82,7 +84,7 @@ module EagerEye
|
|
|
82
84
|
|
|
83
85
|
def collect_model_metadata
|
|
84
86
|
model_files.each do |file_path|
|
|
85
|
-
ast = parse_source(File.read(file_path))
|
|
87
|
+
ast = parse_source(File.read(file_path), file_path)
|
|
86
88
|
next unless ast
|
|
87
89
|
|
|
88
90
|
model_name = extract_model_name(file_path)
|
|
@@ -143,7 +145,7 @@ module EagerEye
|
|
|
143
145
|
|
|
144
146
|
def analyze_file(file_path)
|
|
145
147
|
source = File.read(file_path)
|
|
146
|
-
ast = parse_source(source)
|
|
148
|
+
ast = parse_source(source, file_path)
|
|
147
149
|
return unless ast
|
|
148
150
|
|
|
149
151
|
comment_parser = CommentParser.new(source)
|
|
@@ -160,12 +162,24 @@ module EagerEye
|
|
|
160
162
|
warn "EagerEye: Could not read file #{file_path}: #{e.message}"
|
|
161
163
|
end
|
|
162
164
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
# A file the parser cannot handle (syntax error, binary literal whose
|
|
166
|
+
# escapes are invalid UTF-8, ...) is skipped from analysis entirely. Each
|
|
167
|
+
# such file is recorded in #skipped_files and warned about exactly once,
|
|
168
|
+
# even though every file is parsed by multiple passes.
|
|
169
|
+
def parse_source(source, file_path)
|
|
170
|
+
SourceParser.parse(source, file_path)
|
|
171
|
+
rescue Parser::SyntaxError, Parser::UnknownEncodingInMagicComment, EncodingError => e
|
|
172
|
+
register_unparseable(file_path, e.message)
|
|
166
173
|
nil
|
|
167
174
|
end
|
|
168
175
|
|
|
176
|
+
def register_unparseable(file_path, message)
|
|
177
|
+
return if @skipped_files.key?(file_path)
|
|
178
|
+
|
|
179
|
+
@skipped_files[file_path] = message
|
|
180
|
+
warn "EagerEye: Skipped unparseable file #{file_path}: #{message}"
|
|
181
|
+
end
|
|
182
|
+
|
|
169
183
|
def detector_args(detector, ast, file_path)
|
|
170
184
|
extra = DETECTOR_EXTRA_ARGS.find { |klass, _| detector.is_a?(klass) }&.last || []
|
|
171
185
|
[ast, file_path, *extra.map { |name| instance_variable_get(:"@#{name}") }]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require_relative "../source_parser"
|
|
4
4
|
|
|
5
5
|
module EagerEye
|
|
6
6
|
module Detectors
|
|
@@ -43,9 +43,12 @@ module EagerEye
|
|
|
43
43
|
node.children.each { |child| traverse_ast(child, &block) }
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
# Convenience for detector subclasses; returns nil (without any stderr
|
|
47
|
+
# output) when the source cannot be parsed. Pass file_path so any
|
|
48
|
+
# diagnostics you inspect on the raised error name the real file.
|
|
49
|
+
def parse_source(source, file_path = "(string)")
|
|
50
|
+
SourceParser.parse(source, file_path)
|
|
51
|
+
rescue Parser::SyntaxError, Parser::UnknownEncodingInMagicComment, EncodingError
|
|
49
52
|
nil
|
|
50
53
|
end
|
|
51
54
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require_relative "source_parser"
|
|
4
4
|
|
|
5
5
|
module EagerEye
|
|
6
6
|
# Parses db/schema.rb to learn the real column names of each table. Columns are
|
|
@@ -31,7 +31,7 @@ module EagerEye
|
|
|
31
31
|
schema = locate_schema(start_path)
|
|
32
32
|
return false unless schema
|
|
33
33
|
|
|
34
|
-
ast = parse(File.read(schema))
|
|
34
|
+
ast = parse(File.read(schema), schema)
|
|
35
35
|
return false unless ast
|
|
36
36
|
|
|
37
37
|
walk(ast)
|
|
@@ -62,9 +62,12 @@ module EagerEye
|
|
|
62
62
|
nil
|
|
63
63
|
end
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
# An unparseable schema silently disables the column disambiguation that
|
|
66
|
+
# filters most false positives, so the failure must not be swallowed.
|
|
67
|
+
def parse(source, file_path)
|
|
68
|
+
SourceParser.parse(source, file_path)
|
|
69
|
+
rescue Parser::SyntaxError, Parser::UnknownEncodingInMagicComment, EncodingError => e
|
|
70
|
+
warn "EagerEye: Could not parse schema #{file_path}: #{e.message} (schema-aware column checks disabled)"
|
|
68
71
|
nil
|
|
69
72
|
end
|
|
70
73
|
|
data/lib/eager_eye/version.rb
CHANGED
data/lib/eager_eye.rb
CHANGED
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: 1.3.
|
|
4
|
+
version: 1.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- hamzagedikkaya
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-07-09 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ast
|