class RuboCop::Cop::Layout::SpaceAroundKeyword

Checks the spacing around the keywords.

@example

# bad
something 'test'do|x|
end

while(something)
end

something = 123if test

# good
something 'test' do |x|
end

while (something)
end

something = 123 if test

Constants

ACCEPT_LEFT_PAREN
ACCEPT_LEFT_SQUARE_BRACKET
ACCEPT_NAMESPACE_OPERATOR
DO
MSG_AFTER
MSG_BEFORE
NAMESPACE_OPERATOR
SAFE_NAVIGATION

Public Instance Methods

on_and(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 40
def on_and(node)
  check(node, [:operator].freeze) if node.keyword?
end
on_block(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 44
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
  check(node, %i[begin end].freeze)
end
on_break(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 48
def on_break(node)
  check(node, [:keyword].freeze)
end
on_case(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 52
def on_case(node)
  check(node, %i[keyword else].freeze)
end
on_case_match(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 56
def on_case_match(node)
  check(node, %i[keyword else].freeze)
end
on_defined?(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 156
def on_defined?(node)
  check(node, [:keyword].freeze)
end
on_ensure(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 60
def on_ensure(node)
  check(node, [:keyword].freeze)
end
on_for(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 64
def on_for(node)
  check(node, %i[begin end].freeze)
end
on_if(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 68
def on_if(node)
  check(node, %i[keyword else begin end].freeze, 'then')
end
on_if_guard(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 72
def on_if_guard(node)
  check(node, [:keyword].freeze)
end
on_in_pattern(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 76
def on_in_pattern(node)
  check(node, [:keyword].freeze)
end
on_kwbegin(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 80
def on_kwbegin(node)
  check(node, %i[begin end].freeze, nil)
end
on_match_pattern(node) click to toggle source

Handle one-line pattern matching syntax (‘in`) with `Parser::Ruby27`.

# File lib/rubocop/cop/layout/space_around_keyword.rb, line 85
def on_match_pattern(node)
  return if target_ruby_version >= 3.0

  check(node, [:operator].freeze)
end
on_match_pattern_p(node) click to toggle source

Handle one-line pattern matching syntax (‘in`) with `Parser::Ruby30`.

# File lib/rubocop/cop/layout/space_around_keyword.rb, line 92
def on_match_pattern_p(node)
  check(node, [:operator].freeze)
end
on_next(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 96
def on_next(node)
  check(node, [:keyword].freeze)
end
on_or(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 100
def on_or(node)
  check(node, [:operator].freeze) if node.keyword?
end
on_postexe(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 104
def on_postexe(node)
  check(node, [:keyword].freeze)
end
on_preexe(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 108
def on_preexe(node)
  check(node, [:keyword].freeze)
end
on_resbody(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 112
def on_resbody(node)
  check(node, [:keyword].freeze)
end
on_rescue(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 116
def on_rescue(node)
  check(node, [:else].freeze)
end
on_return(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 120
def on_return(node)
  check(node, [:keyword].freeze)
end
on_send(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 124
def on_send(node)
  check(node, [:selector].freeze) if node.prefix_not?
end
on_super(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 128
def on_super(node)
  check(node, [:keyword].freeze)
end
on_unless_guard(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 136
def on_unless_guard(node)
  check(node, [:keyword].freeze)
end
on_until(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 140
def on_until(node)
  check(node, %i[begin end keyword].freeze)
end
on_when(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 144
def on_when(node)
  check(node, [:keyword].freeze)
end
on_while(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 148
def on_while(node)
  check(node, %i[begin end keyword].freeze)
end
on_yield(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 152
def on_yield(node)
  check(node, [:keyword].freeze)
end
on_zsuper(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 132
def on_zsuper(node)
  check(node, [:keyword].freeze)
end

Private Instance Methods

accept_left_parenthesis?(range) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 235
def accept_left_parenthesis?(range)
  ACCEPT_LEFT_PAREN.include?(range.source)
end
accept_left_square_bracket?(range) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 239
def accept_left_square_bracket?(range)
  ACCEPT_LEFT_SQUARE_BRACKET.include?(range.source)
end
accept_namespace_operator?(range) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 243
def accept_namespace_operator?(range)
  ACCEPT_NAMESPACE_OPERATOR == range.source
end
accepted_opening_delimiter?(range, char) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 228
def accepted_opening_delimiter?(range, char)
  return true unless char

  (accept_left_square_bracket?(range) && char == '[') ||
    (accept_left_parenthesis?(range) && char == '(')
end
check(node, locations, begin_keyword = DO) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 162
def check(node, locations, begin_keyword = DO)
  locations.each do |loc|
    next unless node.loc.respond_to?(loc)

    range = node.loc.public_send(loc)
    next unless range

    case loc
    when :begin then check_begin(node, range, begin_keyword)
    when :end then check_end(node, range, begin_keyword)
    else check_keyword(node, range)
    end
  end
end
check_begin(node, range, begin_keyword) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 177
def check_begin(node, range, begin_keyword)
  return if begin_keyword && !range.is?(begin_keyword)

  check_keyword(node, range)
end
check_end(node, range, begin_keyword) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 183
def check_end(node, range, begin_keyword)
  return if begin_keyword == DO && !do?(node)
  return unless space_before_missing?(range)

  add_offense(range, message: format(MSG_BEFORE, range: range.source)) do |corrector|
    corrector.insert_before(range, ' ')
  end
end
check_keyword(node, range) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 196
def check_keyword(node, range)
  if space_before_missing?(range) && !preceded_by_operator?(node, range)
    add_offense(range, message: format(MSG_BEFORE, range: range.source)) do |corrector|
      corrector.insert_before(range, ' ')
    end
  end

  return unless space_after_missing?(range)

  add_offense(range, message: format(MSG_AFTER, range: range.source)) do |corrector|
    corrector.insert_after(range, ' ')
  end
end
do?(node) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 192
def do?(node)
  node.loc.begin&.is?(DO)
end
namespace_operator?(range, pos) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 251
def namespace_operator?(range, pos)
  range.source_buffer.source[pos, 2].start_with?(NAMESPACE_OPERATOR)
end
preceded_by_operator?(node, _range) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 255
def preceded_by_operator?(node, _range)
  # regular dotted method calls bind more tightly than operators
  # so we need to climb up the AST past them
  node.each_ancestor do |ancestor|
    return true if ancestor.and_type? || ancestor.or_type?
    return false unless ancestor.send_type?
    return true if ancestor.operator_method?
  end
  false
end
safe_navigation_call?(range, pos) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 247
def safe_navigation_call?(range, pos)
  range.source_buffer.source[pos, 2].start_with?(SAFE_NAVIGATION)
end
space_after_missing?(range) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 217
def space_after_missing?(range)
  pos = range.end_pos
  char = range.source_buffer.source[pos]

  return false if accepted_opening_delimiter?(range, char)
  return false if safe_navigation_call?(range, pos)
  return false if accept_namespace_operator?(range) && namespace_operator?(range, pos)

  !/[\s;,#\\)}\].]/.match?(char)
end
space_before_missing?(range) click to toggle source
# File lib/rubocop/cop/layout/space_around_keyword.rb, line 210
def space_before_missing?(range)
  pos = range.begin_pos - 1
  return false if pos.negative?

  !/[\s(|{\[;,*=]/.match?(range.source_buffer.source[pos])
end