lib/rubocop/cop/rspec/instance_variable.rb in rubocop-rspec-1.6.0 vs lib/rubocop/cop/rspec/instance_variable.rb in rubocop-rspec-1.7.0

- old
+ new

@@ -1,13 +1,17 @@ # frozen_string_literal: true module RuboCop module Cop module RSpec - # When you have to assign a variable instead of using an instance - # variable, use let. + # Checks for instance variable usage in specs. # + # This cop can be configured with the option `AssignmentOnly` which + # will configure the cop to only register offenses on instance + # variable usage if the instance variable is also assigned within + # the spec + # # @example # # bad # describe MyClass do # before { @foo = [] } # it { expect(@foo).to be_empty } @@ -16,25 +20,62 @@ # # good # describe MyClass do # let(:foo) { [] } # it { expect(foo).to be_empty } # end + # + # @example with AssignmentOnly configuration + # + # # rubocop.yml + # RSpec/InstanceVariable: + # AssignmentOnly: false + # + # # bad + # describe MyClass do + # before { @foo = [] } + # it { expect(@foo).to be_empty } + # end + # + # # allowed + # describe MyClass do + # it { expect(@foo).to be_empty } + # end + # + # # good + # describe MyClass do + # let(:foo) { [] } + # it { expect(foo).to be_empty } + # end + # class InstanceVariable < Cop + include RuboCop::RSpec::SpecOnly, RuboCop::RSpec::Language + MESSAGE = 'Use `let` instead of an instance variable'.freeze - EXAMPLE_GROUP_METHODS = [ - :example_group, :describe, :context, :xdescribe, :xcontext, - :fdescribe, :fcontext, :shared_examples, :shared_context, - :share_examples_for, :shared_examples_for, :feature - ].freeze + EXAMPLE_GROUP_METHODS = ExampleGroups::ALL + SharedGroups::ALL + + def_node_matcher :spec_group?, <<-PATTERN + (block (send _ {#{EXAMPLE_GROUP_METHODS.to_node_pattern}} ...) ...) + PATTERN + + def_node_search :ivar_usage, '$(ivar $_)' + + def_node_search :ivar_assigned?, '(ivasgn % ...)' + def on_block(node) - method, _args, _body = *node - _receiver, method_name, _object = *method - @in_spec = true if EXAMPLE_GROUP_METHODS.include?(method_name) + return unless spec_group?(node) + + ivar_usage(node) do |ivar, name| + return if assignment_only? && !ivar_assigned?(node, name) + + add_offense(ivar, :expression, MESSAGE) + end end - def on_ivar(node) - add_offense(node, :expression, MESSAGE) if @in_spec + private + + def assignment_only? + cop_config['AssignmentOnly'] end end end end end