eager_eye 1.1.0 → 1.1.1

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.
@@ -5,11 +5,8 @@ module EagerEye
5
5
  class LoopAssociation < Base
6
6
  ITERATION_METHODS = %i[each map collect select find find_all reject filter filter_map flat_map].freeze
7
7
  PRELOAD_METHODS = %i[includes preload eager_load].freeze
8
- # Methods that return a single record (not a collection)
9
8
  SINGLE_RECORD_METHODS = %i[find find_by find_by! first first! last last! take take! second third fourth fifth
10
9
  forty_two sole find_sole_by].freeze
11
-
12
- # Common association names (belongs_to = singular, has_many = plural)
13
10
  ASSOCIATION_NAMES = Set.new(%w[
14
11
  author user owner creator admin member customer client post article comment category tag
15
12
  parent company organization project task item order product account profile setting image
@@ -18,8 +15,6 @@ module EagerEye
18
15
  tasks items orders products accounts profiles settings images avatars photos attachments
19
16
  documents
20
17
  ]).freeze
21
-
22
- # Methods that should NOT be treated as associations
23
18
  EXCLUDED_METHODS = %i[
24
19
  id to_s to_h to_a to_json to_xml inspect class object_id nil? blank? present? empty?
25
20
  any? none? size count length save save! update update! destroy destroy! delete delete!
@@ -73,46 +68,32 @@ module EagerEye
73
68
  end
74
69
 
75
70
  def infer_model_name_from_collection(node)
76
- # Infer model name from collection (posts -> Post, users -> User)
77
71
  return nil unless node&.type == :send
78
72
 
79
- # Handle: Model.includes, @var.method calls
80
73
  receiver = node.children[0]
81
- case receiver&.type
82
- when :const
83
- receiver.children[1].to_s
84
- end
74
+ receiver.children[1].to_s if receiver&.type == :const
85
75
  end
86
76
 
87
77
  def iteration_block?(node)
88
- return false unless node.type == :block
89
-
90
- send_node = node.children[0]
91
- return false unless send_node&.type == :send
92
-
93
- method_name = send_node.children[1]
94
- ITERATION_METHODS.include?(method_name)
78
+ node.type == :block && node.children[0]&.type == :send &&
79
+ ITERATION_METHODS.include?(node.children[0].children[1])
95
80
  end
96
81
 
97
82
  def extract_block_variable(block_node)
98
- args = block_node&.children&.fetch(1, nil)
99
- first_child = args&.children&.first
100
- first_child&.type == :arg ? first_child.children[0] : nil
83
+ args = block_node&.children&.[](1)
84
+ first_arg = args&.children&.first
85
+ first_arg&.type == :arg ? first_arg.children[0] : nil
101
86
  end
102
87
 
103
88
  def extract_included_associations(collection_node)
104
89
  included = Set.new
105
90
  return included unless collection_node&.type == :send
106
91
 
107
- # Traverse through chained method calls to find includes/preload/eager_load
108
92
  current = collection_node
109
93
  while current&.type == :send
110
- method_name = current.children[1]
111
- extract_includes_from_method(current, included) if PRELOAD_METHODS.include?(method_name)
112
-
94
+ extract_includes_from_method(current, included) if PRELOAD_METHODS.include?(current.children[1])
113
95
  current = current.children[0]
114
96
  end
115
-
116
97
  included
117
98
  end
118
99
 
@@ -177,10 +158,6 @@ module EagerEye
177
158
  included_set.merge(extract_symbols_from_args(args))
178
159
  end
179
160
 
180
- def extract_from_hash(hash_node, included_set)
181
- extract_symbols_from_hash(hash_node, included_set)
182
- end
183
-
184
161
  def find_association_calls(node, block_var, file_path, issues, included_associations = Set.new)
185
162
  reported = Set.new
186
163
  traverse_ast(node) do |child|
@@ -3,22 +3,14 @@
3
3
  module EagerEye
4
4
  module Detectors
5
5
  class MissingCounterCache < Base
6
- # Methods that trigger COUNT queries
7
6
  COUNT_METHODS = %i[count size length].freeze
8
-
9
- # Common has_many association names (plural)
10
7
  PLURAL_ASSOCIATIONS = %w[
11
- posts comments tags categories articles users members
12
- items orders products tasks projects images attachments
13
- documents files messages notifications reviews ratings
14
- followers followings likes favorites bookmarks votes
15
- children replies responses answers questions
8
+ posts comments tags categories articles users members items orders products tasks projects
9
+ images attachments documents files messages notifications reviews ratings followers followings
10
+ likes favorites bookmarks votes children replies responses answers questions
16
11
  ].freeze
17
-
18
- # Iteration methods that indicate a loop context
19
- ITERATION_METHODS = %i[each map collect select reject find_all
20
- filter filter_map flat_map each_with_index
21
- each_with_object reduce inject sum].freeze
12
+ ITERATION_METHODS = %i[each map collect select reject find_all filter filter_map flat_map
13
+ each_with_index each_with_object reduce inject sum].freeze
22
14
 
23
15
  def self.detector_name
24
16
  :missing_counter_cache
@@ -51,68 +43,45 @@ module EagerEye
51
43
 
52
44
  def count_on_association?(node)
53
45
  return false unless node.type == :send
54
-
55
- method_name = node.children[1]
56
- return false unless COUNT_METHODS.include?(method_name)
46
+ return false unless COUNT_METHODS.include?(node.children[1])
57
47
 
58
48
  receiver = node.children[0]
59
- return false unless receiver
60
-
61
- likely_association_receiver?(receiver)
49
+ receiver && likely_association_receiver?(receiver)
62
50
  end
63
51
 
64
52
  def likely_association_receiver?(node)
65
- return false unless node.type == :send
66
-
67
- method_name = node.children[1]
68
- PLURAL_ASSOCIATIONS.include?(method_name.to_s)
53
+ node.type == :send && PLURAL_ASSOCIATIONS.include?(node.children[1].to_s)
69
54
  end
70
55
 
71
56
  def extract_association_name(node)
72
57
  receiver = node.children[0]
73
- return nil unless receiver&.type == :send
74
-
75
- receiver.children[1].to_s
58
+ receiver.children[1].to_s if receiver&.type == :send
76
59
  end
77
60
 
78
- # Check if the node is inside an iteration block
79
61
  def inside_iteration?(node)
80
62
  parent = node
81
- while (parent = find_parent(parent))
63
+ while (parent = @parent_map[parent])
82
64
  return true if iteration_block?(parent)
83
65
  end
84
66
  false
85
67
  end
86
68
 
87
- def find_parent(node)
88
- @parent_map ||= {}
89
- @parent_map[node]
90
- end
91
-
92
- # Override traverse_ast to build parent map
93
69
  def traverse_ast(node, &block)
94
70
  return unless node.is_a?(Parser::AST::Node)
95
71
 
96
72
  @parent_map ||= {}
97
-
98
73
  yield node
99
-
100
74
  node.children.each do |child|
101
- if child.is_a?(Parser::AST::Node)
102
- @parent_map[child] = node
103
- traverse_ast(child, &block)
104
- end
75
+ next unless child.is_a?(Parser::AST::Node)
76
+
77
+ @parent_map[child] = node
78
+ traverse_ast(child, &block)
105
79
  end
106
80
  end
107
81
 
108
82
  def iteration_block?(node)
109
- return false unless node.type == :block
110
-
111
- send_node = node.children[0]
112
- return false unless send_node&.type == :send
113
-
114
- method_name = send_node.children[1]
115
- ITERATION_METHODS.include?(method_name)
83
+ node.type == :block && node.children[0]&.type == :send &&
84
+ ITERATION_METHODS.include?(node.children[0].children[1])
116
85
  end
117
86
  end
118
87
  end
@@ -49,100 +49,67 @@ module EagerEye
49
49
  add_issue(node) if regular_pluck?(node)
50
50
  end
51
51
 
52
- def local_variable_assignment?(node)
53
- node.type == :lvasgn
54
- end
52
+ def local_variable_assignment?(node) = node.type == :lvasgn
55
53
 
56
- def where_call?(node)
57
- node.type == :send && node.children[1] == :where
58
- end
54
+ def where_call?(node) = node.type == :send && node.children[1] == :where
59
55
 
60
56
  def pluck_call?(node)
61
- return false unless node.is_a?(Parser::AST::Node) && node.type == :send
62
-
63
- method = node.children[1]
64
- %i[pluck ids].include?(method)
57
+ node.is_a?(Parser::AST::Node) && node.type == :send && %i[pluck ids].include?(node.children[1])
65
58
  end
66
59
 
67
60
  def all_pluck_call?(node)
68
61
  return false unless pluck_call?(node)
69
62
 
70
63
  receiver = node.children[0]
71
- receiver.is_a?(Parser::AST::Node) && receiver.type == :send &&
72
- receiver.children[1] == :all
64
+ receiver.is_a?(Parser::AST::Node) && receiver.type == :send && receiver.children[1] == :all
73
65
  end
74
66
 
75
67
  def map_id_call?(node)
76
- return false unless node.is_a?(Parser::AST::Node)
77
-
78
- block_map?(node) || send_map?(node)
68
+ node.is_a?(Parser::AST::Node) && (block_map?(node) || send_map?(node))
79
69
  end
80
70
 
81
71
  def block_map?(node)
82
- return false unless node.type == :block
83
-
84
- send_node = node.children[0]
85
- send_node&.type == :send && %i[map collect].include?(send_node.children[1])
72
+ node.type == :block && node.children[0]&.type == :send &&
73
+ %i[map collect].include?(node.children[0].children[1])
86
74
  end
87
75
 
88
76
  def send_map?(node)
89
- return false unless node.type == :send
90
-
91
- method = node.children[1]
92
- %i[map collect].include?(method) &&
77
+ node.type == :send && %i[map collect].include?(node.children[1]) &&
93
78
  node.children[2..].any? { |arg| symbol_to_proc_id?(arg) }
94
79
  end
95
80
 
96
81
  def symbol_to_proc_id?(node)
97
82
  return false unless node.is_a?(Parser::AST::Node) && node.type == :block_pass
98
83
 
99
- sym = node.children[0]
100
- sym&.type == :sym && %i[id to_i].include?(sym.children[0])
84
+ node.children[0]&.type == :sym && %i[id to_i].include?(node.children[0].children[0])
101
85
  end
102
86
 
103
87
  def regular_pluck?(node)
104
- where_args = node.children[2..]
105
- where_args.any? { |arg| pluck_var_in_hash?(arg) }
88
+ node.children[2..].any? { |arg| pluck_var_in_hash?(arg) }
106
89
  end
107
90
 
108
91
  def critical_pluck?(node)
109
- where_args = node.children[2..]
110
- where_args.any? { |arg| critical_pluck_in_hash?(arg) }
92
+ node.children[2..].any? { |arg| critical_pluck_in_hash?(arg) }
111
93
  end
112
94
 
113
95
  def pluck_var_in_hash?(node)
114
96
  return false unless node.is_a?(Parser::AST::Node) && node.type == :hash
115
97
 
116
- node.children.any? do |pair|
117
- next false unless pair.type == :pair
118
-
119
- pluck_value?(pair.children[1])
120
- end
98
+ node.children.any? { |pair| pair.type == :pair && pluck_value?(pair.children[1]) }
121
99
  end
122
100
 
123
101
  def critical_pluck_in_hash?(node)
124
102
  return false unless node.is_a?(Parser::AST::Node) && node.type == :hash
125
103
 
126
- node.children.any? do |pair|
127
- next false unless pair.type == :pair
128
-
129
- critical_value?(pair.children[1])
130
- end
104
+ node.children.any? { |pair| pair.type == :pair && critical_value?(pair.children[1]) }
131
105
  end
132
106
 
133
107
  def pluck_value?(value)
134
- return false unless value.type == :lvar
135
-
136
- var_name = value.children[0]
137
- @pluck_variables.key?(var_name) || @map_id_variables.key?(var_name)
108
+ value.type == :lvar && (@pluck_variables.key?(value.children[0]) || @map_id_variables.key?(value.children[0]))
138
109
  end
139
110
 
140
111
  def critical_value?(value)
141
- if value.type == :lvar
142
- @critical_pluck_variables.key?(value.children[0])
143
- else
144
- all_pluck_call?(value)
145
- end
112
+ value.type == :lvar ? @critical_pluck_variables.key?(value.children[0]) : all_pluck_call?(value)
146
113
  end
147
114
 
148
115
  def add_issue(node)
@@ -3,26 +3,10 @@
3
3
  module EagerEye
4
4
  module Detectors
5
5
  class SerializerNesting < Base
6
- # Serializer base classes to detect
7
- SERIALIZER_PATTERNS = [
8
- "ActiveModel::Serializer",
9
- "ActiveModelSerializers::Model",
10
- "Blueprinter::Base",
11
- "Alba::Resource"
12
- ].freeze
13
-
14
- # Method names that define attributes in serializers
6
+ SERIALIZER_PATTERNS = %w[ActiveModel::Serializer ActiveModelSerializers::Model Blueprinter::Base Alba::Resource].freeze
15
7
  ATTRIBUTE_METHODS = %i[attribute field attributes].freeze
16
-
17
- # Object reference names in serializers
18
8
  OBJECT_REFS = %i[object record resource].freeze
19
-
20
- # Common association names (same as LoopAssociation)
21
- ASSOCIATION_NAMES = %w[
22
- author user owner creator admin member customer client
23
- post article comment category tag parent company organization
24
- project task item order product account profile setting
25
- image avatar photo attachment document
9
+ HAS_MANY_ASSOCIATIONS = %w[
26
10
  authors users owners creators admins members customers clients
27
11
  posts articles comments categories tags children companies organizations
28
12
  projects tasks items orders products accounts profiles settings
@@ -52,21 +36,16 @@ module EagerEye
52
36
  def serializer_class?(node)
53
37
  return false unless node.type == :class
54
38
 
55
- # Check class name ends with Serializer, Blueprint, or Resource
56
39
  class_name = extract_class_name(node)
57
40
  return false unless class_name
58
41
 
59
42
  class_name.end_with?("Serializer", "Blueprint", "Resource") ||
60
- inherits_from_serializer?(node) ||
61
- includes_serializer_module?(node)
43
+ inherits_from_serializer?(node) || includes_serializer_module?(node)
62
44
  end
63
45
 
64
46
  def extract_class_name(class_node)
65
47
  name_node = class_node.children[0]
66
- return nil unless name_node
67
- return nil unless name_node.type == :const
68
-
69
- name_node.children[1].to_s
48
+ name_node.children[1].to_s if name_node&.type == :const
70
49
  end
71
50
 
72
51
  def inherits_from_serializer?(class_node)
@@ -74,7 +53,7 @@ module EagerEye
74
53
  return false unless parent_node
75
54
 
76
55
  parent_name = const_to_string(parent_node)
77
- SERIALIZER_PATTERNS.any? { |pattern| parent_name&.include?(pattern.split("::").last) }
56
+ SERIALIZER_PATTERNS.any? { |p| parent_name&.include?(p.split("::").last) }
78
57
  end
79
58
 
80
59
  def includes_serializer_module?(class_node)
@@ -82,20 +61,14 @@ module EagerEye
82
61
  return false unless body
83
62
 
84
63
  traverse_ast(body) do |node|
85
- next unless node.type == :send
86
-
87
- method = node.children[1]
88
- return true if method == :include && alba_resource?(node)
64
+ return true if node.type == :send && node.children[1] == :include && alba_resource?(node)
89
65
  end
90
-
91
66
  false
92
67
  end
93
68
 
94
69
  def alba_resource?(include_node)
95
70
  arg = include_node.children[2]
96
- return false unless arg
97
-
98
- const_to_string(arg)&.include?("Alba")
71
+ arg && const_to_string(arg)&.include?("Alba")
99
72
  end
100
73
 
101
74
  def const_to_string(node)
@@ -103,12 +76,10 @@ module EagerEye
103
76
 
104
77
  parts = []
105
78
  current = node
106
-
107
79
  while current&.type == :const
108
80
  parts.unshift(current.children[1].to_s)
109
81
  current = current.children[0]
110
82
  end
111
-
112
83
  parts.join("::")
113
84
  end
114
85
 
@@ -117,34 +88,24 @@ module EagerEye
117
88
  return unless body
118
89
 
119
90
  traverse_ast(body) do |node|
120
- next unless attribute_block?(node)
121
-
122
- block_body = node.children[2]
123
- next unless block_body
91
+ next unless attribute_block?(node) && node.children[2]
124
92
 
125
- find_association_in_block(block_body, node, file_path, issues)
93
+ find_association_in_block(node.children[2], file_path, issues)
126
94
  end
127
95
  end
128
96
 
129
97
  def attribute_block?(node)
130
- return false unless node.type == :block
131
-
132
- send_node = node.children[0]
133
- return false unless send_node&.type == :send
134
-
135
- method_name = send_node.children[1]
136
- ATTRIBUTE_METHODS.include?(method_name)
98
+ node.type == :block && node.children[0]&.type == :send &&
99
+ ATTRIBUTE_METHODS.include?(node.children[0].children[1])
137
100
  end
138
101
 
139
- def find_association_in_block(block_body, _block_node, file_path, issues)
102
+ def find_association_in_block(block_body, file_path, issues)
140
103
  traverse_ast(block_body) do |node|
141
104
  next unless node.type == :send
142
105
 
143
106
  receiver = node.children[0]
144
107
  method_name = node.children[1]
145
-
146
- next unless object_reference?(receiver)
147
- next unless likely_association?(method_name)
108
+ next unless object_reference?(receiver) && likely_association?(method_name)
148
109
 
149
110
  issues << create_issue(
150
111
  file_path: file_path,
@@ -159,33 +120,22 @@ module EagerEye
159
120
  return false unless node
160
121
 
161
122
  case node.type
162
- when :send
163
- # object.something or record.something
164
- receiver = node.children[0]
165
- method = node.children[1]
166
-
167
- receiver.nil? && OBJECT_REFS.include?(method)
168
- when :lvar
169
- # Block variable like |post|
170
- true
171
- else
172
- false
123
+ when :send then node.children[0].nil? && OBJECT_REFS.include?(node.children[1])
124
+ when :lvar then true
125
+ else false
173
126
  end
174
127
  end
175
128
 
176
129
  def receiver_name(node)
177
130
  case node.type
178
- when :send
179
- node.children[1].to_s
180
- when :lvar
181
- node.children[0].to_s
182
- else
183
- "object"
131
+ when :send then node.children[1].to_s
132
+ when :lvar then node.children[0].to_s
133
+ else "object"
184
134
  end
185
135
  end
186
136
 
187
137
  def likely_association?(method_name)
188
- ASSOCIATION_NAMES.include?(method_name.to_s)
138
+ HAS_MANY_ASSOCIATIONS.include?(method_name.to_s)
189
139
  end
190
140
  end
191
141
  end
@@ -3,27 +3,20 @@
3
3
  module EagerEye
4
4
  module Fixers
5
5
  class PluckToSelect < Base
6
- # This fixer only works for single-line pluck + where patterns
7
- # Two-line patterns are too complex to fix automatically
8
-
9
6
  def fixable?
10
- issue.detector == :pluck_to_array &&
11
- single_line_pattern?
7
+ issue.detector == :pluck_to_array && single_line_pattern?
12
8
  end
13
9
 
14
10
  protected
15
11
 
16
12
  def fixed_content
17
- # Model.where(col: OtherModel.pluck(:id)) -> Model.where(col: OtherModel.select(:id))
18
13
  line_content.gsub(/\.pluck\((:\w+)\)/, '.select(\1)')
19
14
  end
20
15
 
21
16
  private
22
17
 
23
18
  def single_line_pattern?
24
- return false unless line_content
25
-
26
- line_content.include?(".pluck(") && line_content.include?(".where(")
19
+ line_content&.include?(".pluck(") && line_content.include?(".where(")
27
20
  end
28
21
  end
29
22
  end
@@ -40,20 +40,13 @@ module EagerEye
40
40
  end
41
41
 
42
42
  def ==(other)
43
- return false unless other.is_a?(Issue)
44
-
45
- detector == other.detector &&
46
- file_path == other.file_path &&
47
- line_number == other.line_number &&
48
- message == other.message &&
49
- severity == other.severity &&
50
- suggestion == other.suggestion
43
+ other.is_a?(Issue) && to_h == other.to_h
51
44
  end
52
45
 
53
46
  alias eql? ==
54
47
 
55
48
  def hash
56
- [detector, file_path, line_number, message, severity, suggestion].hash
49
+ to_h.hash
57
50
  end
58
51
 
59
52
  private
@@ -10,32 +10,20 @@ module EagerEye
10
10
  namespace :eager_eye do
11
11
  desc "Analyze Rails application for N+1 query issues"
12
12
  task analyze: :environment do
13
- require "eager_eye"
14
-
15
- load_config_file
16
-
17
- analyzer = EagerEye::Analyzer.new
18
- issues = analyzer.run
19
-
20
- reporter = EagerEye::Reporters::Console.new(issues)
21
- puts reporter.report
22
-
23
- exit 1 if issues.any? && EagerEye.configuration.fail_on_issues
13
+ puts run_analysis(EagerEye::Reporters::Console)
24
14
  end
25
15
 
26
16
  desc "Analyze and output results as JSON"
27
17
  task json: :environment do
28
- require "eager_eye"
18
+ puts run_analysis(EagerEye::Reporters::Json, pretty: true)
19
+ end
29
20
 
21
+ def run_analysis(reporter_class, **opts)
22
+ require "eager_eye"
30
23
  load_config_file
31
-
32
- analyzer = EagerEye::Analyzer.new
33
- issues = analyzer.run
34
-
35
- reporter = EagerEye::Reporters::Json.new(issues, pretty: true)
36
- puts reporter.report
37
-
24
+ issues = EagerEye::Analyzer.new.run
38
25
  exit 1 if issues.any? && EagerEye.configuration.fail_on_issues
26
+ reporter_class.new(issues, **opts).report
39
27
  end
40
28
 
41
29
  def load_config_file
@@ -55,7 +43,6 @@ module EagerEye
55
43
  end
56
44
  end
57
45
 
58
- # Generate initializer for configuration
59
46
  generators do
60
47
  require_relative "generators/install_generator"
61
48
  end
@@ -48,15 +48,7 @@ module EagerEye
48
48
  end
49
49
 
50
50
  def file_section(file_path, file_issues)
51
- lines = []
52
- lines << colorize(file_path, :cyan)
53
-
54
- file_issues.each do |issue|
55
- lines << format_issue(issue)
56
- end
57
-
58
- lines << ""
59
- lines.join("\n")
51
+ [colorize(file_path, :cyan), *file_issues.map { |i| format_issue(i) }, ""].join("\n")
60
52
  end
61
53
 
62
54
  def format_issue(issue)
@@ -81,15 +73,12 @@ module EagerEye
81
73
  end
82
74
 
83
75
  def summary
84
- total = issues.size
85
- errors = error_count
86
- warnings = warning_count
87
- infos = info_count
88
-
89
- "Total: #{total} issue#{"s" unless total == 1} " \
90
- "(#{errors} error#{"s" unless errors == 1}, " \
91
- "#{warnings} warning#{"s" unless warnings == 1}, " \
92
- "#{infos} info)"
76
+ t = issues.size
77
+ e = error_count
78
+ w = warning_count
79
+ i = info_count
80
+ "Total: #{t} issue#{"s" unless t == 1} " \
81
+ "(#{e} error#{"s" unless e == 1}, #{w} warning#{"s" unless w == 1}, #{i} info)"
93
82
  end
94
83
 
95
84
  def colorize(text, color)
@@ -19,8 +19,7 @@ module EagerEye
19
19
  def matches?(path)
20
20
  @path = path
21
21
  configure_eager_eye
22
- analyzer = build_analyzer
23
- @issues = analyzer.run
22
+ @issues = EagerEye::Analyzer.new(paths: [@path]).run
24
23
  @issues.count <= @max_issues
25
24
  end
26
25
 
@@ -61,10 +60,6 @@ module EagerEye
61
60
  config.fail_on_issues = false
62
61
  end
63
62
  end
64
-
65
- def build_analyzer
66
- EagerEye::Analyzer.new(paths: [@path])
67
- end
68
63
  end
69
64
  end
70
65
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EagerEye
4
- VERSION = "1.1.0"
4
+ VERSION = "1.1.1"
5
5
  end
data/lib/eager_eye.rb CHANGED
@@ -41,5 +41,4 @@ module EagerEye
41
41
  end
42
42
  end
43
43
 
44
- # Load Railtie only if Rails is defined
45
44
  require_relative "eager_eye/railtie" if defined?(Rails::Railtie)
data/sig/eager_eye.rbs CHANGED
@@ -1,4 +1,3 @@
1
1
  module EagerEye
2
2
  VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
3
  end