rubocop-require_tools 0.2.0 → 0.3.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/Gemfile.lock +5 -5
- data/lib/rubocop/cop/require/missing_require_statement.rb +55 -16
- data/lib/rubocop/helper/state.rb +10 -0
- data/lib/rubocop/require_tools/version.rb +1 -1
- data/rubocop-require_tools.gemspec +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 904921f72984631692f9d38ce8f6e6ba4ebc99383c871bb09bb518c419336f60
|
|
4
|
+
data.tar.gz: d6838acd03ecd1c02de7baa0c62ff2ed66944d3d82b8f4127c594e2215682534
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ac6e57ced1eda99834806160ff201a5dc2c5beaf0f139143ed5ac8db628efe7f66e2d6adafeb70b79be827f8217690edda25d96f49f8afee6c4223e84abbd0c7
|
|
7
|
+
data.tar.gz: 24b98cecaa56dd3992a09be447a686291f65960caa1a88a6d0736c03c29dd7224e04442e2a688bea5776326d967d8b02f9270a56abdac33b33fd57f2c730f1ff
|
data/Gemfile.lock
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
rubocop-require_tools (0.
|
|
5
|
-
rubocop (>= 0
|
|
4
|
+
rubocop-require_tools (0.3.0)
|
|
5
|
+
rubocop (>= 1.0)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
8
8
|
remote: https://rubygems.org/
|
|
@@ -11,7 +11,7 @@ GEM
|
|
|
11
11
|
coderay (1.1.3)
|
|
12
12
|
diff-lcs (1.6.2)
|
|
13
13
|
io-console (0.8.2)
|
|
14
|
-
json (2.19.
|
|
14
|
+
json (2.19.9)
|
|
15
15
|
language_server-protocol (3.17.0.5)
|
|
16
16
|
lint_roller (1.1.0)
|
|
17
17
|
method_source (1.1.0)
|
|
@@ -78,7 +78,7 @@ CHECKSUMS
|
|
|
78
78
|
coderay (1.1.3) sha256=dc530018a4684512f8f38143cd2a096c9f02a1fc2459edcfe534787a7fc77d4b
|
|
79
79
|
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
|
|
80
80
|
io-console (0.8.2) sha256=d6e3ae7a7cc7574f4b8893b4fca2162e57a825b223a177b7afa236c5ef9814cc
|
|
81
|
-
json (2.19.
|
|
81
|
+
json (2.19.9) sha256=9b9025b7cdddafa38d316eca0b2358488e42d417045c1b90d216a9fefe46b79a
|
|
82
82
|
language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
|
|
83
83
|
lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
|
|
84
84
|
method_source (1.1.0) sha256=181301c9c45b731b4769bc81e8860e72f9161ad7d66dd99103c9ab84f560f5c5
|
|
@@ -98,7 +98,7 @@ CHECKSUMS
|
|
|
98
98
|
rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
|
|
99
99
|
rubocop (1.86.2) sha256=bb2e97f635eda42c448f2588f4a6ff78f221b8bdfdf65b1e9b07fbd57521b45d
|
|
100
100
|
rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
|
|
101
|
-
rubocop-require_tools (0.
|
|
101
|
+
rubocop-require_tools (0.3.0)
|
|
102
102
|
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
103
103
|
unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
|
|
104
104
|
unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
|
|
@@ -16,7 +16,7 @@ module RuboCop
|
|
|
16
16
|
# require 'faraday'
|
|
17
17
|
#
|
|
18
18
|
# Faraday.new
|
|
19
|
-
class MissingRequireStatement <
|
|
19
|
+
class MissingRequireStatement < Base
|
|
20
20
|
MSG = '`%<constant>s` not found, you\'re probably missing a require statement or there is a cycle in your dependencies.'.freeze
|
|
21
21
|
|
|
22
22
|
attr_writer :timeline
|
|
@@ -26,7 +26,7 @@ module RuboCop
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
# Builds
|
|
29
|
-
def
|
|
29
|
+
def on_new_investigation
|
|
30
30
|
processing_methods = self.methods.select { |m| m.to_s.start_with? 'process_' }
|
|
31
31
|
|
|
32
32
|
stack = [processed_source.ast]
|
|
@@ -63,19 +63,6 @@ module RuboCop
|
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
def add_offense(node, location: nil, message:)
|
|
67
|
-
# Work around breaking API changes between rubocop 0.49.1 and later (...)
|
|
68
|
-
signature_old = %i[node loc message severity]
|
|
69
|
-
param_info = RuboCop::Cop::Cop.instance_method(:add_offense).parameters
|
|
70
|
-
if param_info.map(&:last) == signature_old
|
|
71
|
-
super(node, location || :expression, message)
|
|
72
|
-
elsif location
|
|
73
|
-
super(node, location: location, message: message)
|
|
74
|
-
else
|
|
75
|
-
super(node, message: message)
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
66
|
def_node_matcher :extract_inner_const, <<-PATTERN
|
|
80
67
|
(const $!nil? _)
|
|
81
68
|
PATTERN
|
|
@@ -102,11 +89,47 @@ module RuboCop
|
|
|
102
89
|
return unless consts
|
|
103
90
|
const_name = consts.join('::')
|
|
104
91
|
|
|
105
|
-
self.timeline << { event: :const_access, name: const_name, node: node }
|
|
92
|
+
self.timeline << { event: :const_access, name: const_name, node: node } unless guarded?(node, const_name)
|
|
106
93
|
|
|
107
94
|
{ skip: node.children }
|
|
108
95
|
end
|
|
109
96
|
|
|
97
|
+
def_node_matcher :const_defined_check, <<-PATTERN
|
|
98
|
+
(send $_ :const_defined? ({str sym} $_) ...)
|
|
99
|
+
PATTERN
|
|
100
|
+
|
|
101
|
+
# True where a check that this very constant is defined has just passed: in the true branch of
|
|
102
|
+
# an `if`, or on the right of an `&&`. Code that tests for an optional dependency is not missing a
|
|
103
|
+
# require. A check on Foo does not cover Foo::Bar, which may still not be loaded.
|
|
104
|
+
def guarded?(node, const_name)
|
|
105
|
+
child = node
|
|
106
|
+
node.each_ancestor do |ancestor|
|
|
107
|
+
return true if ancestor.type == :defined? # defined?(Foo) is itself the check, and never raises
|
|
108
|
+
|
|
109
|
+
condition = ancestor.children[0] if (ancestor.if_type? || ancestor.and_type?) && child.equal?(ancestor.children[1])
|
|
110
|
+
return true if condition && checked_constants(condition).include?(const_name)
|
|
111
|
+
|
|
112
|
+
child = ancestor
|
|
113
|
+
end
|
|
114
|
+
false
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def checked_constants(condition)
|
|
118
|
+
return condition.children.flat_map { |c| checked_constants(c) } if condition.and_type?
|
|
119
|
+
|
|
120
|
+
if (checked = const_defined_check(condition))
|
|
121
|
+
receiver, name = checked
|
|
122
|
+
return [] unless receiver&.const_type?
|
|
123
|
+
|
|
124
|
+
path = find_consts(receiver).join('::')
|
|
125
|
+
return [path == 'Object' ? name.to_s : "#{path}::#{name}"]
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# `defined?` cannot be written as a node pattern: the pattern language reads it as a predicate
|
|
129
|
+
checked = condition.children.first if condition.type == :defined?
|
|
130
|
+
checked&.const_type? ? [find_consts(checked).join('::')] : []
|
|
131
|
+
end
|
|
132
|
+
|
|
110
133
|
def_node_matcher :extract_const_assignment, <<-PATTERN
|
|
111
134
|
(casgn nil? $_ ...)
|
|
112
135
|
PATTERN
|
|
@@ -164,6 +187,20 @@ module RuboCop
|
|
|
164
187
|
{ skip: skip_list, push: push_list }
|
|
165
188
|
end
|
|
166
189
|
|
|
190
|
+
def_node_matcher :extract_include, <<-PATTERN
|
|
191
|
+
(send nil? :include $(const ...))
|
|
192
|
+
PATTERN
|
|
193
|
+
|
|
194
|
+
# `include Foo` makes Foo's constants reachable unqualified in the enclosing class or module.
|
|
195
|
+
def process_include(node, _source)
|
|
196
|
+
return unless node.kind_of? RuboCop::AST::Node
|
|
197
|
+
included = extract_include(node)
|
|
198
|
+
return unless included
|
|
199
|
+
|
|
200
|
+
self.timeline << { event: :include, name: find_consts(included).join('::') }
|
|
201
|
+
nil
|
|
202
|
+
end
|
|
203
|
+
|
|
167
204
|
def_node_matcher :extract_require, <<-PATTERN
|
|
168
205
|
(send nil? ${:require :require_relative} (str $_))
|
|
169
206
|
PATTERN
|
|
@@ -205,6 +242,8 @@ module RuboCop
|
|
|
205
242
|
err_indices = err_indices.reject { |e| outdated.include?(timeline[e]) }
|
|
206
243
|
when :const_undef
|
|
207
244
|
state.undefine_const(const_name: event[:name])
|
|
245
|
+
when :include
|
|
246
|
+
state.include_module(name: event[:name])
|
|
208
247
|
when :const_assign
|
|
209
248
|
state.const_assigned(const_name: event[:name], alias_target: event[:alias_target])
|
|
210
249
|
|
data/lib/rubocop/helper/state.rb
CHANGED
|
@@ -5,11 +5,13 @@ module RuboCop
|
|
|
5
5
|
attr_accessor :defined_constants
|
|
6
6
|
attr_accessor :const_stack
|
|
7
7
|
attr_accessor :aliases
|
|
8
|
+
attr_accessor :included_modules
|
|
8
9
|
|
|
9
10
|
def initialize
|
|
10
11
|
self.defined_constants = []
|
|
11
12
|
self.const_stack = []
|
|
12
13
|
self.aliases = {}
|
|
14
|
+
self.included_modules = [] # [nesting depth, module name]
|
|
13
15
|
end
|
|
14
16
|
|
|
15
17
|
def require(file: nil)
|
|
@@ -56,6 +58,13 @@ module RuboCop
|
|
|
56
58
|
|
|
57
59
|
def undefine_const(const_name: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
58
60
|
self.const_stack.pop
|
|
61
|
+
self.included_modules.reject! { |depth, _| depth > self.const_stack.length }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def include_module(name: nil)
|
|
65
|
+
prefixes = self.const_stack.reduce([]) { |a, c| a << [a.last, c].compact.join('::') }
|
|
66
|
+
full_name = ([name] + prefixes.reverse.map { |prefix| "#{prefix}::#{name}" }).find { |n| Object.const_get(n) rescue nil }
|
|
67
|
+
self.included_modules << [self.const_stack.length, full_name || name]
|
|
59
68
|
end
|
|
60
69
|
|
|
61
70
|
def const_assigned(const_name: nil, alias_target: nil)
|
|
@@ -81,6 +90,7 @@ module RuboCop
|
|
|
81
90
|
unless local_only
|
|
82
91
|
result = Object.const_get(name) rescue nil # Defined elsewhere, top-level
|
|
83
92
|
result ||= self.defined_constants.find { |c| Object.const_get("#{c}::#{name}") rescue nil } # Defined elsewhere, nested
|
|
93
|
+
result ||= self.included_modules.map(&:last).find { |m| Object.const_get("#{m}::#{name}") rescue nil } # From an included module
|
|
84
94
|
end
|
|
85
95
|
|
|
86
96
|
result ||= self.defined_constants.find { |c| name == c } # Defined in this file, other module/class
|
|
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
27
27
|
spec.require_paths = ['lib']
|
|
28
28
|
|
|
29
|
-
spec.add_runtime_dependency 'rubocop', '>= 0
|
|
29
|
+
spec.add_runtime_dependency 'rubocop', '>= 1.0'
|
|
30
30
|
|
|
31
31
|
spec.add_development_dependency 'pry'
|
|
32
32
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubocop-require_tools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Manu Wallner
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0
|
|
18
|
+
version: '1.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: 0
|
|
25
|
+
version: '1.0'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: pry
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|