class RuboCop::Cop::RSpec::ExampleWording

Checks for common mistakes in example descriptions.

This cop will correct docstrings that begin with ‘should’ and ‘it’. This cop will also look for insufficient examples and call them out.

@see betterspecs.org/#should

The autocorrect is experimental - use with care! It can be configured with CustomTransform (e.g. have => has) and IgnoredWords (e.g. only).

Use the DisallowedExamples setting to prevent unclear or insufficient descriptions. Please note that this config will not be treated as case sensitive.

@example

# bad
it 'should find nothing' do
end

it 'will find nothing' do
end

# good
it 'finds nothing' do
end

@example

# bad
it 'it does things' do
end

# good
it 'does things' do
end

@example ‘DisallowedExamples: [’works’]‘ (default)

# bad
it 'works' do
end

# good
it 'marks the task as done' do
end

Constants

IT_PREFIX
MSG_INSUFFICIENT_DESCRIPTION
MSG_IT
MSG_SHOULD
MSG_WILL
SHOULD_PREFIX
WILL_PREFIX

Public Instance Methods

on_block(node) click to toggle source

rubocop:disable Metrics/MethodLength

# File lib/rubocop/cop/rspec/example_wording.rb, line 71
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
  it_description(node) do |description_node, message|
    if message.match?(SHOULD_PREFIX)
      add_wording_offense(description_node, MSG_SHOULD)
    elsif message.match?(WILL_PREFIX)
      add_wording_offense(description_node, MSG_WILL)
    elsif message.match?(IT_PREFIX)
      add_wording_offense(description_node, MSG_IT)
    elsif insufficient_docstring?(description_node)
      add_offense(docstring(description_node),
                  message: MSG_INSUFFICIENT_DESCRIPTION)
    end
  end
end

Private Instance Methods

add_wording_offense(node, message) click to toggle source

rubocop:enable Metrics/MethodLength

# File lib/rubocop/cop/rspec/example_wording.rb, line 89
def add_wording_offense(node, message)
  docstring = docstring(node)

  add_offense(docstring, message: message) do |corrector|
    next if node.heredoc?

    corrector.replace(docstring, replacement_text(node))
  end
end
custom_transform() click to toggle source
# File lib/rubocop/cop/rspec/example_wording.rb, line 136
def custom_transform
  cop_config.fetch('CustomTransform', {})
end
docstring(node) click to toggle source
# File lib/rubocop/cop/rspec/example_wording.rb, line 99
def docstring(node)
  expr = node.source_range

  Parser::Source::Range.new(
    expr.source_buffer,
    expr.begin_pos + 1,
    expr.end_pos - 1
  )
end
ignored_words() click to toggle source
# File lib/rubocop/cop/rspec/example_wording.rb, line 140
def ignored_words
  cop_config.fetch('IgnoredWords', [])
end
insufficient_docstring?(description_node) click to toggle source
# File lib/rubocop/cop/rspec/example_wording.rb, line 144
def insufficient_docstring?(description_node)
  insufficient_examples.include?(preprocess(text(description_node)))
end
insufficient_examples() click to toggle source
# File lib/rubocop/cop/rspec/example_wording.rb, line 148
def insufficient_examples
  examples = cop_config.fetch('DisallowedExamples', [])
  examples.map! { |example| preprocess(example) }
end
preprocess(message) click to toggle source
# File lib/rubocop/cop/rspec/example_wording.rb, line 153
def preprocess(message)
  message.strip.squeeze(' ').downcase
end
replacement_text(node) click to toggle source
# File lib/rubocop/cop/rspec/example_wording.rb, line 109
def replacement_text(node)
  text = text(node)

  if text.match?(SHOULD_PREFIX) || text.match?(WILL_PREFIX)
    RuboCop::RSpec::Wording.new(
      text,
      ignore:  ignored_words,
      replace: custom_transform
    ).rewrite
  else
    text.sub(IT_PREFIX, '')
  end
end
text(node) click to toggle source

Recursive processing is required to process nested dstr nodes that is the case for -separated multiline strings with interpolation.

# File lib/rubocop/cop/rspec/example_wording.rb, line 125
def text(node)
  case node.type
  when :dstr
    node.node_parts.map { |child_node| text(child_node) }.join
  when :str
    node.value
  when :begin
    node.source
  end
end