Skip to content

Commit

Permalink
Add SendNode#def_modifier that returns the def node it modifies, …
Browse files Browse the repository at this point in the history
…or `nil`
  • Loading branch information
marcandre committed May 26, 2021
1 parent 2c85e6a commit 171c098
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 5 deletions.
1 change: 1 addition & 0 deletions changelog/new__have_sendnodedef_modifier_return_the_def.md
@@ -0,0 +1 @@
* [#171](https://github.com/rubocop-hq/rubocop-ast/pull/171): Add `SendNode#def_modifier` that returns the `def` node it modifies, or `nil`. ([@marcandre][])
28 changes: 23 additions & 5 deletions lib/rubocop/ast/node/mixin/method_dispatch_node.rb
Expand Up @@ -165,16 +165,34 @@ def arithmetic_operation?
ARITHMETIC_OPERATORS.include?(method_name)
end

# Checks if this node is part of a chain of `def` modifiers.
# Checks if this node is part of a chain of `def` or `defs` modifiers.
#
# @example
#
# private def foo; end
#
# @return [Boolean] whether the dispatched method is a `def` modifier
def def_modifier?
send_type? &&
adjacent_def_modifier? || each_child_node(:send).any?(&:def_modifier?)
# @return wether the `def|defs` node is a modifier or not.
# See also `def_modifier` that returns the node or `nil`
def def_modifier?(node = self)
!!def_modifier(node)
end

# Checks if this node is part of a chain of `def` or `defs` modifiers.
#
# @example
#
# private def foo; end
#
# @return [Node | nil] returns the `def|defs` node this is a modifier for,
# or `nil` if it isn't a def modifier
def def_modifier(node = self)
arg = node.children[2]

return unless node.send_type? && node.receiver.nil? && arg.is_a?(::AST::Node)

return arg if arg.def_type? || arg.defs_type?

def_modifier(arg)
end

# Checks whether this is a lambda. Some versions of parser parses
Expand Down
26 changes: 26 additions & 0 deletions spec/rubocop/ast/send_node_spec.rb
Expand Up @@ -1122,6 +1122,32 @@ def bar
end
end

describe '#def_modifier' do
context 'with a prefixed def modifier' do
let(:source) { 'foo def bar; end' }

it { expect(send_node.def_modifier.method_name).to eq(:bar) }
end

context 'with several prefixed def modifiers' do
let(:source) { 'foo bar baz def qux; end' }

it { expect(send_node.def_modifier.method_name).to eq(:qux) }
end

context 'with a block containing a method definition' do
let(:source) { 'foo bar { baz def qux; end }' }

it { expect(send_node.def_modifier).to be_nil }
end

context 'with call with no argument' do
let(:source) { 'foo' }

it { expect(send_node.def_modifier).to be_nil }
end
end

describe '#negation_method?' do
context 'with prefix `not`' do
let(:source) { 'not foo' }
Expand Down

0 comments on commit 171c098

Please sign in to comment.