class RuboCop::Cop::Ezcater::StyleDig

Use `dig` for deeply nested access.

@example

# good
my_hash.dig('foo', 'bar')
my_array.dig(0, 1)

# bad
my_hash['foo']['bar']
my_hash['foo'] && my_hash['foo']['bar']
my_array[0][1]

Constants

MSG

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/ezcater/style_dig.rb, line 39
def autocorrect(node)
  access_node = node
  source_args = [access_node.first_argument.source]
  while access_node?(access_node.children.first)
    access_node = access_node.children.first
    source_args << access_node.first_argument.source
  end
  root_node = access_node.children.first

  lambda do |corrector|
    range = Parser::Source::Range.new(node.source_range.source_buffer,
                                      root_node.source_range.end_pos,
                                      node.source_range.end_pos)
    corrector.replace(range, ".dig(#{source_args.reverse.join(', ')})")
  end
end
on_send(node) click to toggle source
# File lib/rubocop/cop/ezcater/style_dig.rb, line 30
def on_send(node)
  return unless nested_access_match(node) && !assignment?(node)

  match_node = node
  # walk to outermost access node
  match_node = match_node.parent while access_node?(match_node.parent)
  add_offense(match_node, location: :expression, message: MSG)
end

Private Instance Methods

access_node?(node) click to toggle source
# File lib/rubocop/cop/ezcater/style_dig.rb, line 62
def access_node?(node)
  node&.send_type? && node.method_name == :[] && !range?(node.first_argument)
end
assignment?(node) click to toggle source
# File lib/rubocop/cop/ezcater/style_dig.rb, line 58
def assignment?(node)
  node.parent&.assignment? && (node.parent.children.first == node)
end
range?(node) click to toggle source
# File lib/rubocop/cop/ezcater/style_dig.rb, line 66
def range?(node)
  node.irange_type? || node.erange_type?
end