class RuboCop::Cop::RSpec::ReceiveMessages
Checks for multiple messages stubbed on the same object.
@safety
The autocorrection is marked as unsafe, because it may change the order of stubs. This in turn may cause e.g. variables to be called before they are defined.
@example
# bad before do allow(Service).to receive(:foo).and_return(bar) allow(Service).to receive(:baz).and_return(qux) end # good before do allow(Service).to receive_messages(foo: bar, baz: qux) end # good - ignore same message before do allow(Service).to receive(:foo).and_return(bar) allow(Service).to receive(:foo).and_return(qux) end
Constants
- MSG
Public Instance Methods
on_begin(node)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 63 def on_begin(node) repeated_receive_message(node).each do |item, repeated_lines, args| next if repeated_lines.empty? register_offense(item, repeated_lines, args) end end
Private Instance Methods
add_repeated_lines_and_arguments(items)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 83 def add_repeated_lines_and_arguments(items) uniq_items = uniq_items(items) repeated_lines = uniq_items.map(&:first_line) uniq_items.map do |item| [item, repeated_lines - [item.first_line], arguments(uniq_items)] end end
arguments(items)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 100 def arguments(items) items.map do |item| receive_and_return_argument(item) do |receive_arg, return_arg| "#{normalize_receive_arg(receive_arg)}: " \ "#{normalize_return_arg(return_arg)}" end end end
heredoc_or_splat?(node)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 150 def heredoc_or_splat?(node) ((node.str_type? || node.dstr_type?) && node.heredoc?) || node.splat_type? end
item_range_by_whole_lines(item)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 146 def item_range_by_whole_lines(item) range_by_whole_lines(item.source_range, include_final_newline: true) end
message(repeated_lines)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 135 def message(repeated_lines) format(MSG, loc: repeated_lines) end
normalize_receive_arg(receive_arg)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 109 def normalize_receive_arg(receive_arg) if requires_quotes?(receive_arg) "'#{receive_arg}'" else receive_arg end end
normalize_return_arg(return_arg)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 117 def normalize_return_arg(return_arg) if return_arg.hash_type? && !return_arg.braces? "{ #{return_arg.source} }" else return_arg.source end end
register_offense(item, repeated_lines, args)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 125 def register_offense(item, repeated_lines, args) add_offense(item, message: message(repeated_lines)) do |corrector| if item.loc.line > repeated_lines.max replace_to_receive_messages(corrector, item, args) else corrector.remove(item_range_by_whole_lines(item)) end end end
repeated_receive_message(node)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 73 def repeated_receive_message(node) node .children .select { |child| allow_receive_message?(child) } .group_by { |child| allow_argument(child) } .values .reject(&:one?) .flat_map { |items| add_repeated_lines_and_arguments(items) } end
replace_to_receive_messages(corrector, item, args)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 139 def replace_to_receive_messages(corrector, item, args) receive_node(item) do |node| corrector.replace(node, "receive_messages(#{args.join(', ')})") end end
requires_quotes?(value)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 155 def requires_quotes?(value) value.match?(/^:".*?"|=$|^\W+$/) end
uniq_items(items)
click to toggle source
# File lib/rubocop/cop/rspec/receive_messages.rb, line 91 def uniq_items(items) items.select do |item| items.none? do |i| receive_arg(item).first == receive_arg(i).first && !same_line?(item, i) end end end