class RuboCop::Cop::RSpec::RepeatedSubjectCall
Checks for repeated calls to subject missing that it is memoized.
@example
# bad it do subject expect { subject }.to not_change { A.count } end it do expect { subject }.to change { A.count } expect { subject }.to not_change { A.count } end # good it do expect { my_method }.to change { A.count } expect { my_method }.to not_change { A.count } end # also good it do expect { subject.a }.to change { A.count } expect { subject.b }.to not_change { A.count } end
Constants
- MSG
Public Instance Methods
on_top_level_group(node)
click to toggle source
# File lib/rubocop/cop/rspec/repeated_subject_call.rb, line 65 def on_top_level_group(node) @subjects_by_node = detect_subjects_in_scope(node) detect_offenses_in_block(node) end
Private Instance Methods
detect_offense(subject_node)
click to toggle source
# File lib/rubocop/cop/rspec/repeated_subject_call.rb, line 73 def detect_offense(subject_node) return if subject_node.chained? return if subject_node.parent.send_type? return unless (block_node = expect_block(subject_node)) add_offense(block_node) end
detect_offenses_in_block(node, subject_names = [])
click to toggle source
# File lib/rubocop/cop/rspec/repeated_subject_call.rb, line 85 def detect_offenses_in_block(node, subject_names = []) subject_names = [*subject_names, *@subjects_by_node[node]] if example?(node) return detect_offenses_in_example(node, subject_names) end node.each_child_node(:send, :def, :block, :begin) do |child| detect_offenses_in_block(child, subject_names) end end
detect_offenses_in_example(node, subject_names)
click to toggle source
# File lib/rubocop/cop/rspec/repeated_subject_call.rb, line 97 def detect_offenses_in_example(node, subject_names) return unless node.body subjects_used = Hash.new(false) subject_calls(node.body, Set[*subject_names, :subject]).each do |call| if subjects_used[call.method_name] detect_offense(call) else subjects_used[call.method_name] = true end end end
detect_subjects_in_scope(node)
click to toggle source
# File lib/rubocop/cop/rspec/repeated_subject_call.rb, line 111 def detect_subjects_in_scope(node) node.each_descendant(:block).with_object({}) do |child, h| subject?(child) do |name| outer_example_group = child.each_ancestor(:block).find do |a| example_group?(a) end (h[outer_example_group] ||= []) << name end end end
expect_block(node)
click to toggle source
# File lib/rubocop/cop/rspec/repeated_subject_call.rb, line 81 def expect_block(node) node.each_ancestor(:block).find { |block| block.method?(:expect) } end