From 171c09846acd9519e3d7ec6b66c8d88ee7933417 Mon Sep 17 00:00:00 2001 From: Marc-Andre Lafortune Date: Mon, 8 Mar 2021 14:42:34 -0500 Subject: [PATCH] Add `SendNode#def_modifier` that returns the `def` node it modifies, or `nil` --- ...ave_sendnodedef_modifier_return_the_def.md | 1 + .../ast/node/mixin/method_dispatch_node.rb | 28 +++++++++++++++---- spec/rubocop/ast/send_node_spec.rb | 26 +++++++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 changelog/new__have_sendnodedef_modifier_return_the_def.md diff --git a/changelog/new__have_sendnodedef_modifier_return_the_def.md b/changelog/new__have_sendnodedef_modifier_return_the_def.md new file mode 100644 index 000000000..141fd7fd4 --- /dev/null +++ b/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][]) diff --git a/lib/rubocop/ast/node/mixin/method_dispatch_node.rb b/lib/rubocop/ast/node/mixin/method_dispatch_node.rb index 9a29d0d91..bb5b9b2cd 100644 --- a/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +++ b/lib/rubocop/ast/node/mixin/method_dispatch_node.rb @@ -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 diff --git a/spec/rubocop/ast/send_node_spec.rb b/spec/rubocop/ast/send_node_spec.rb index c8076e066..ef11b1374 100644 --- a/spec/rubocop/ast/send_node_spec.rb +++ b/spec/rubocop/ast/send_node_spec.rb @@ -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' }