rubocop-rspec 1.6.0 → 1.7.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/CHANGELOG.md +22 -0
- data/README.md +23 -0
- data/Rakefile +19 -1
- data/config/default.yml +78 -15
- data/lib/rubocop-rspec.rb +19 -1
- data/lib/rubocop/cop/rspec/any_instance.rb +5 -1
- data/lib/rubocop/cop/rspec/be_eql.rb +58 -0
- data/lib/rubocop/cop/rspec/describe_class.rb +2 -3
- data/lib/rubocop/cop/rspec/describe_method.rb +4 -3
- data/lib/rubocop/cop/rspec/described_class.rb +4 -35
- data/lib/rubocop/cop/rspec/empty_example_group.rb +100 -0
- data/lib/rubocop/cop/rspec/example_length.rb +5 -2
- data/lib/rubocop/cop/rspec/example_wording.rb +5 -2
- data/lib/rubocop/cop/rspec/expect_actual.rb +79 -0
- data/lib/rubocop/cop/rspec/file_path.rb +3 -1
- data/lib/rubocop/cop/rspec/focus.rb +12 -28
- data/lib/rubocop/cop/rspec/hook_argument.rb +122 -0
- data/lib/rubocop/cop/rspec/instance_variable.rb +53 -12
- data/lib/rubocop/cop/rspec/leading_subject.rb +58 -0
- data/lib/rubocop/cop/rspec/let_setup.rb +58 -0
- data/lib/rubocop/cop/rspec/message_chain.rb +33 -0
- data/lib/rubocop/cop/rspec/message_expectation.rb +58 -0
- data/lib/rubocop/cop/rspec/multiple_describes.rb +10 -7
- data/lib/rubocop/cop/rspec/multiple_expectations.rb +89 -0
- data/lib/rubocop/cop/rspec/named_subject.rb +10 -1
- data/lib/rubocop/cop/rspec/nested_groups.rb +125 -0
- data/lib/rubocop/cop/rspec/not_to_not.rb +3 -3
- data/lib/rubocop/cop/rspec/subject_stub.rb +136 -0
- data/lib/rubocop/cop/rspec/verified_doubles.rb +4 -1
- data/lib/rubocop/rspec.rb +10 -0
- data/lib/rubocop/rspec/config_formatter.rb +33 -0
- data/lib/rubocop/rspec/description_extractor.rb +35 -0
- data/lib/rubocop/rspec/inject.rb +2 -6
- data/lib/rubocop/rspec/language.rb +73 -0
- data/lib/rubocop/rspec/language/node_pattern.rb +16 -0
- data/lib/rubocop/rspec/spec_only.rb +61 -0
- data/lib/rubocop/rspec/top_level_describe.rb +6 -0
- data/lib/rubocop/rspec/version.rb +1 -1
- data/rubocop-rspec.gemspec +1 -0
- data/spec/project/changelog_spec.rb +81 -0
- data/spec/project/default_config_spec.rb +52 -0
- data/spec/project/project_requires_spec.rb +8 -0
- data/spec/rubocop/cop/rspec/be_eql_spec.rb +59 -0
- data/spec/rubocop/cop/rspec/described_class_spec.rb +2 -2
- data/spec/rubocop/cop/rspec/empty_example_group_spec.rb +79 -0
- data/spec/rubocop/cop/rspec/example_length_spec.rb +50 -30
- data/spec/rubocop/cop/rspec/example_wording_spec.rb +21 -3
- data/spec/rubocop/cop/rspec/expect_actual_spec.rb +136 -0
- data/spec/rubocop/cop/rspec/file_path_spec.rb +48 -71
- data/spec/rubocop/cop/rspec/focus_spec.rb +1 -1
- data/spec/rubocop/cop/rspec/hook_argument_spec.rb +189 -0
- data/spec/rubocop/cop/rspec/instance_variable_spec.rb +37 -0
- data/spec/rubocop/cop/rspec/leading_subject_spec.rb +54 -0
- data/spec/rubocop/cop/rspec/let_setup_spec.rb +66 -0
- data/spec/rubocop/cop/rspec/message_chain_spec.rb +21 -0
- data/spec/rubocop/cop/rspec/message_expectation_spec.rb +63 -0
- data/spec/rubocop/cop/rspec/multiple_expectations_spec.rb +84 -0
- data/spec/rubocop/cop/rspec/nested_groups_spec.rb +55 -0
- data/spec/rubocop/cop/rspec/not_to_not_spec.rb +12 -2
- data/spec/rubocop/cop/rspec/subject_stub_spec.rb +183 -0
- data/spec/rubocop/rspec/config_formatter_spec.rb +48 -0
- data/spec/rubocop/rspec/description_extractor_spec.rb +35 -0
- data/spec/rubocop/rspec/language/selector_set_spec.rb +29 -0
- data/spec/rubocop/rspec/spec_only_spec.rb +97 -0
- data/spec/shared/rspec_only_cop_behavior.rb +68 -0
- data/spec/spec_helper.rb +13 -1
- metadata +72 -5
- data/spec/project_spec.rb +0 -115
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks if an example group does not include any tests.
|
7
|
+
#
|
8
|
+
# This cop is configurable using the `CustomIncludeMethods` option
|
9
|
+
#
|
10
|
+
# @example usage
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# describe Bacon do
|
14
|
+
# let(:bacon) { Bacon.new(chunkiness) }
|
15
|
+
# let(:chunkiness) { false }
|
16
|
+
#
|
17
|
+
# context 'extra chunky' do # flagged by rubocop
|
18
|
+
# let(:chunkiness) { true }
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# it 'is chunky' do
|
22
|
+
# expect(bacon.chunky?).to be_truthy
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# describe Bacon do
|
28
|
+
# let(:bacon) { Bacon.new(chunkiness) }
|
29
|
+
# let(:chunkiness) { false }
|
30
|
+
#
|
31
|
+
# it 'is chunky' do
|
32
|
+
# expect(bacon.chunky?).to be_truthy
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# @example configuration
|
37
|
+
#
|
38
|
+
# # .rubocop.yml
|
39
|
+
# RSpec/EmptyExampleGroup:
|
40
|
+
# CustomIncludeMethods:
|
41
|
+
# - include_tests
|
42
|
+
#
|
43
|
+
# # spec_helper.rb
|
44
|
+
# RSpec.configure do |config|
|
45
|
+
# config.alias_it_behaves_like_to(:include_tests)
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# # bacon_spec.rb
|
49
|
+
# describe Bacon do
|
50
|
+
# let(:bacon) { Bacon.new(chunkiness) }
|
51
|
+
# let(:chunkiness) { false }
|
52
|
+
#
|
53
|
+
# context 'extra chunky' do # not flagged by rubocop
|
54
|
+
# let(:chunkiness) { true }
|
55
|
+
#
|
56
|
+
# include_tests 'shared tests'
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
class EmptyExampleGroup < Cop
|
61
|
+
include RuboCop::RSpec::SpecOnly,
|
62
|
+
RuboCop::RSpec::Language,
|
63
|
+
RuboCop::RSpec::Language::NodePattern
|
64
|
+
|
65
|
+
MSG = 'Empty example group detected.'.freeze
|
66
|
+
|
67
|
+
def_node_search :contains_example?, <<-PATTERN
|
68
|
+
{
|
69
|
+
(send _ {
|
70
|
+
#{Examples::ALL.to_node_pattern}
|
71
|
+
:it_behaves_like
|
72
|
+
:it_should_behave_like
|
73
|
+
:include_context
|
74
|
+
:include_examples
|
75
|
+
} ...)
|
76
|
+
(send _ #custom_include? ...)
|
77
|
+
}
|
78
|
+
PATTERN
|
79
|
+
|
80
|
+
def on_block(node)
|
81
|
+
return unless example_group?(node) && !contains_example?(node)
|
82
|
+
|
83
|
+
add_offense(node.children.first, :expression)
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def custom_include?(method_name)
|
89
|
+
custom_include_methods.include?(method_name)
|
90
|
+
end
|
91
|
+
|
92
|
+
def custom_include_methods
|
93
|
+
cop_config
|
94
|
+
.fetch('CustomIncludeMethods', [])
|
95
|
+
.map(&:to_sym)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
+
# Checks for long examples.
|
7
|
+
#
|
6
8
|
# A long example is usually more difficult to understand. Consider
|
7
9
|
# extracting out some behaviour, e.g. with a `let` block, or a helper
|
8
10
|
# method.
|
@@ -24,8 +26,9 @@ module RuboCop
|
|
24
26
|
# expect(result).to be(true)
|
25
27
|
# end
|
26
28
|
class ExampleLength < Cop
|
27
|
-
include CodeLength
|
28
|
-
|
29
|
+
include RuboCop::RSpec::SpecOnly, CodeLength
|
30
|
+
|
31
|
+
EXAMPLE_BLOCKS = RuboCop::RSpec::Language::Examples::ALL
|
29
32
|
|
30
33
|
def on_block(node)
|
31
34
|
method, _args, _body = *node
|
@@ -3,8 +3,9 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Checks that example descriptions do not start with "should".
|
7
|
+
#
|
8
|
+
# @see http://betterspecs.org/#should
|
8
9
|
#
|
9
10
|
# The autocorrect is experimental - use with care! It can be configured
|
10
11
|
# with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only).
|
@@ -18,6 +19,8 @@ module RuboCop
|
|
18
19
|
# it 'finds nothing' do
|
19
20
|
# end
|
20
21
|
class ExampleWording < Cop
|
22
|
+
include RuboCop::RSpec::SpecOnly
|
23
|
+
|
21
24
|
MSG = 'Do not use should when describing your tests.'.freeze
|
22
25
|
|
23
26
|
def on_block(node) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/LineLength
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks for `expect(...)` calls containing literal values.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# expect(5).to eq(price)
|
11
|
+
# expect(/foo/).to eq(pattern)
|
12
|
+
# expect("John").to eq(name)
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# expect(price).to eq(5)
|
16
|
+
# expect(pattern).to eq(/foo/)
|
17
|
+
# expect(name).to eq("John")
|
18
|
+
#
|
19
|
+
class ExpectActual < Cop
|
20
|
+
include RuboCop::RSpec::SpecOnly
|
21
|
+
|
22
|
+
MSG = 'Provide the actual you are testing to `expect(...)`'.freeze
|
23
|
+
|
24
|
+
SIMPLE_LITERALS = %i(
|
25
|
+
true
|
26
|
+
false
|
27
|
+
nil
|
28
|
+
int
|
29
|
+
float
|
30
|
+
str
|
31
|
+
sym
|
32
|
+
complex
|
33
|
+
rational
|
34
|
+
regopt
|
35
|
+
).freeze
|
36
|
+
|
37
|
+
COMPLEX_LITERALS = %i(
|
38
|
+
array
|
39
|
+
hash
|
40
|
+
pair
|
41
|
+
irange
|
42
|
+
erange
|
43
|
+
regexp
|
44
|
+
).freeze
|
45
|
+
|
46
|
+
def_node_matcher :expect, '(send _ :expect $_)'
|
47
|
+
|
48
|
+
def on_send(node)
|
49
|
+
expect_literal(node) do |argument|
|
50
|
+
add_offense(argument, :expression)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# This is not implement using a NodePattern because it seems
|
57
|
+
# to not be able to match against an explicit (nil) sexp
|
58
|
+
def expect_literal(node)
|
59
|
+
return unless (argument = expect(node))
|
60
|
+
|
61
|
+
yield(argument) if literal?(argument)
|
62
|
+
end
|
63
|
+
|
64
|
+
def literal?(node)
|
65
|
+
simple_literal?(node) || complex_literal?(node)
|
66
|
+
end
|
67
|
+
|
68
|
+
def simple_literal?(node)
|
69
|
+
SIMPLE_LITERALS.include?(node.type)
|
70
|
+
end
|
71
|
+
|
72
|
+
def complex_literal?(node)
|
73
|
+
COMPLEX_LITERALS.include?(node.type) &&
|
74
|
+
node.each_child_node.all?(&method(:literal?))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
+
# Checks that spec file paths are consistent with the test subject.
|
7
|
+
#
|
6
8
|
# Checks the path of the spec file and enforces that it reflects the
|
7
9
|
# described class/module and its optionally called out method.
|
8
10
|
#
|
@@ -15,7 +17,7 @@ module RuboCop
|
|
15
17
|
# my_class_method_spec.rb # describe MyClass, '#method'
|
16
18
|
# my_class_spec.rb # describe MyClass
|
17
19
|
class FilePath < Cop
|
18
|
-
include RuboCop::RSpec::TopLevelDescribe
|
20
|
+
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::TopLevelDescribe
|
19
21
|
|
20
22
|
MESSAGE = 'Spec path should end with `%s`'.freeze
|
21
23
|
METHOD_STRING_MATCHER = /^[\#\.].+/
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
-
# Checks if
|
6
|
+
# Checks if examples are focused.
|
7
7
|
#
|
8
8
|
# @example
|
9
9
|
# # bad
|
@@ -20,36 +20,20 @@ module RuboCop
|
|
20
20
|
# describe MyClass do
|
21
21
|
# end
|
22
22
|
class Focus < Cop
|
23
|
+
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language
|
24
|
+
|
23
25
|
MSG = 'Focused spec found.'.freeze
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
:scenario
|
33
|
-
:specify
|
34
|
-
:xcontext
|
35
|
-
:xdescribe
|
36
|
-
:xexample
|
37
|
-
:xfeature
|
38
|
-
:xit
|
39
|
-
:xscenario
|
40
|
-
:xspecify
|
41
|
-
'.freeze
|
27
|
+
focusable =
|
28
|
+
ExampleGroups::GROUPS +
|
29
|
+
ExampleGroups::SKIPPED +
|
30
|
+
Examples::EXAMPLES +
|
31
|
+
Examples::SKIPPED
|
32
|
+
|
33
|
+
focused = ExampleGroups::FOCUSED + Examples::FOCUSED
|
42
34
|
|
43
|
-
|
44
|
-
|
45
|
-
:fdescribe
|
46
|
-
:fexample
|
47
|
-
:ffeature
|
48
|
-
:fit
|
49
|
-
:focus
|
50
|
-
:fscenario
|
51
|
-
:fspecify
|
52
|
-
'.freeze
|
35
|
+
FOCUSABLE_SELECTORS = focusable.to_node_pattern
|
36
|
+
FOCUSING_SELECTORS = focused.to_node_pattern
|
53
37
|
|
54
38
|
FOCUS_SYMBOL = s(:sym, :focus)
|
55
39
|
FOCUS_TRUE = s(:pair, FOCUS_SYMBOL, s(:true))
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module RSpec
|
6
|
+
# Checks the arguments passed to `before`, `around`, and `after`.
|
7
|
+
#
|
8
|
+
# This cop checks for consistent style when specifying RSpec
|
9
|
+
# hooks which run for each example. There are three supported
|
10
|
+
# styles: "implicit", "each", and "example." All styles have
|
11
|
+
# the same behavior.
|
12
|
+
#
|
13
|
+
# @example when configuration is `EnforcedStyle: implicit`
|
14
|
+
# # bad
|
15
|
+
# before(:each) do
|
16
|
+
# ...
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# before(:example) do
|
21
|
+
# ...
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# before do
|
26
|
+
# ...
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example when configuration is `EnforcedStyle: each`
|
30
|
+
# # bad
|
31
|
+
# before(:example) do
|
32
|
+
# ...
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# before do
|
37
|
+
# ...
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# before(:each) do
|
42
|
+
# ...
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @example when configuration is `EnforcedStyle: example`
|
46
|
+
# # bad
|
47
|
+
# before(:each) do
|
48
|
+
# ...
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# # bad
|
52
|
+
# before do
|
53
|
+
# ...
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# before(:example) do
|
58
|
+
# ...
|
59
|
+
# end
|
60
|
+
class HookArgument < RuboCop::Cop::Cop
|
61
|
+
include RuboCop::RSpec::Language,
|
62
|
+
RuboCop::RSpec::SpecOnly,
|
63
|
+
ConfigurableEnforcedStyle
|
64
|
+
|
65
|
+
IMPLICIT_MSG = 'Omit the default `%p` argument for RSpec hooks.'.freeze
|
66
|
+
EXPLICIT_MSG = 'Use `%p` for RSpec hooks.'.freeze
|
67
|
+
|
68
|
+
HOOKS = "{#{Hooks::ALL.to_node_pattern}}".freeze
|
69
|
+
|
70
|
+
def_node_matcher :scoped_hook, <<-PATTERN
|
71
|
+
(block $(send nil #{HOOKS} (sym ${:each :example})) ...)
|
72
|
+
PATTERN
|
73
|
+
|
74
|
+
def_node_matcher :unscoped_hook, "(block $(send nil #{HOOKS}) ...)"
|
75
|
+
|
76
|
+
def on_block(node)
|
77
|
+
hook(node) do |method_send, scope_name|
|
78
|
+
return correct_style_detected if scope_name.equal?(style)
|
79
|
+
return check_implicit(method_send) unless scope_name
|
80
|
+
|
81
|
+
style_detected(scope_name)
|
82
|
+
add_offense(method_send, :expression, explicit_message(scope_name))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def autocorrect(node)
|
87
|
+
scope = "(#{style.inspect})" unless implicit_style?
|
88
|
+
hook = "#{node.method_name}#{scope}"
|
89
|
+
|
90
|
+
lambda do |corrector|
|
91
|
+
corrector.replace(node.loc.expression, hook)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def check_implicit(method_send)
|
98
|
+
style_detected(:implicit)
|
99
|
+
return if implicit_style?
|
100
|
+
|
101
|
+
add_offense(method_send, :selector, format(EXPLICIT_MSG, style))
|
102
|
+
end
|
103
|
+
|
104
|
+
def explicit_message(scope)
|
105
|
+
if implicit_style?
|
106
|
+
format(IMPLICIT_MSG, scope)
|
107
|
+
else
|
108
|
+
format(EXPLICIT_MSG, style)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def implicit_style?
|
113
|
+
style.equal?(:implicit)
|
114
|
+
end
|
115
|
+
|
116
|
+
def hook(node, &block)
|
117
|
+
scoped_hook(node, &block) || unscoped_hook(node, &block)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -3,8 +3,12 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module RSpec
|
6
|
-
#
|
7
|
-
#
|
6
|
+
# Checks for instance variable usage in specs.
|
7
|
+
#
|
8
|
+
# This cop can be configured with the option `AssignmentOnly` which
|
9
|
+
# will configure the cop to only register offenses on instance
|
10
|
+
# variable usage if the instance variable is also assigned within
|
11
|
+
# the spec
|
8
12
|
#
|
9
13
|
# @example
|
10
14
|
# # bad
|
@@ -18,22 +22,59 @@ module RuboCop
|
|
18
22
|
# let(:foo) { [] }
|
19
23
|
# it { expect(foo).to be_empty }
|
20
24
|
# end
|
25
|
+
#
|
26
|
+
# @example with AssignmentOnly configuration
|
27
|
+
#
|
28
|
+
# # rubocop.yml
|
29
|
+
# RSpec/InstanceVariable:
|
30
|
+
# AssignmentOnly: false
|
31
|
+
#
|
32
|
+
# # bad
|
33
|
+
# describe MyClass do
|
34
|
+
# before { @foo = [] }
|
35
|
+
# it { expect(@foo).to be_empty }
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # allowed
|
39
|
+
# describe MyClass do
|
40
|
+
# it { expect(@foo).to be_empty }
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# # good
|
44
|
+
# describe MyClass do
|
45
|
+
# let(:foo) { [] }
|
46
|
+
# it { expect(foo).to be_empty }
|
47
|
+
# end
|
48
|
+
#
|
21
49
|
class InstanceVariable < Cop
|
50
|
+
include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language
|
51
|
+
|
22
52
|
MESSAGE = 'Use `let` instead of an instance variable'.freeze
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
53
|
+
|
54
|
+
EXAMPLE_GROUP_METHODS = ExampleGroups::ALL + SharedGroups::ALL
|
55
|
+
|
56
|
+
def_node_matcher :spec_group?, <<-PATTERN
|
57
|
+
(block (send _ {#{EXAMPLE_GROUP_METHODS.to_node_pattern}} ...) ...)
|
58
|
+
PATTERN
|
59
|
+
|
60
|
+
def_node_search :ivar_usage, '$(ivar $_)'
|
61
|
+
|
62
|
+
def_node_search :ivar_assigned?, '(ivasgn % ...)'
|
28
63
|
|
29
64
|
def on_block(node)
|
30
|
-
|
31
|
-
|
32
|
-
|
65
|
+
return unless spec_group?(node)
|
66
|
+
|
67
|
+
ivar_usage(node) do |ivar, name|
|
68
|
+
return if assignment_only? && !ivar_assigned?(node, name)
|
69
|
+
|
70
|
+
add_offense(ivar, :expression, MESSAGE)
|
71
|
+
end
|
33
72
|
end
|
34
73
|
|
35
|
-
|
36
|
-
|
74
|
+
private
|
75
|
+
|
76
|
+
def assignment_only?
|
77
|
+
cop_config['AssignmentOnly']
|
37
78
|
end
|
38
79
|
end
|
39
80
|
end
|