Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add AST::InPatternNode node #183

Merged
merged 1 commit into from May 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/new_add_ast_in_pattern_node.md
@@ -0,0 +1 @@
* [#183](https://github.com/rubocop-hq/rubocop-ast/pull/183): Add `AST::InPatternNode` node. ([@koic][])
1 change: 1 addition & 0 deletions lib/rubocop/ast.rb
Expand Up @@ -53,6 +53,7 @@
require_relative 'ast/node/float_node'
require_relative 'ast/node/hash_node'
require_relative 'ast/node/if_node'
require_relative 'ast/node/in_pattern_node'
require_relative 'ast/node/index_node'
require_relative 'ast/node/indexasgn_node'
require_relative 'ast/node/int_node'
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop/ast/builder.rb
Expand Up @@ -49,6 +49,7 @@ class Builder < Parser::Builders::Default
float: FloatNode,
hash: HashNode,
if: IfNode,
in_pattern: InPatternNode,
int: IntNode,
index: IndexNode,
indexasgn: IndexasgnNode,
Expand Down
4 changes: 2 additions & 2 deletions lib/rubocop/ast/node/case_match_node.rb
Expand Up @@ -24,9 +24,9 @@ def each_in_pattern(&block)
self
end

# Returns an array of all the when branches in the `case` statement.
# Returns an array of all the `in` pattern branches in the `case` statement.
#
# @return [Array<Node>] an array of `in_pattern` nodes
# @return [Array<InPatternNode>] an array of `in_pattern` nodes
def in_pattern_branches
node_parts[1...-1]
end
Expand Down
31 changes: 31 additions & 0 deletions lib/rubocop/ast/node/in_pattern_node.rb
@@ -0,0 +1,31 @@
# frozen_string_literal: true

module RuboCop
module AST
# A node extension for `in` nodes. This will be used in place of a plain
# node when the builder constructs the AST, making its methods available
# to all `in` nodes within RuboCop.
class InPatternNode < Node
# Returns the index of the `in` branch within the `case` statement.
#
# @return [Integer] the index of the `in` branch
def branch_index
parent.in_pattern_branches.index(self)
end

# Checks whether the `in` node has a `then` keyword.
#
# @return [Boolean] whether the `in` node has a `then` keyword
def then?
loc.begin&.is?('then')
end

# Returns the body of the `in` node.
#
# @return [Node, nil] the body of the `in` node
def body
node_parts[-1]
end
end
end
end
79 changes: 79 additions & 0 deletions spec/rubocop/ast/in_pattern_node_spec.rb
@@ -0,0 +1,79 @@
# frozen_string_literal: true

RSpec.describe RuboCop::AST::InPatternNode do
context 'when using Ruby 2.7 or newer', :ruby27 do
let(:in_pattern_node) { parse_source(source).ast.children[1] }

describe '.new' do
let(:source) do
['case condition',
'in [42] then foo',
'end'].join("\n")
end

it { expect(in_pattern_node).to be_a(described_class) }
end

describe '#then?' do
context 'with a then keyword' do
let(:source) do
['case condition',
'in [42] then foo',
'end'].join("\n")
end

it { expect(in_pattern_node).to be_then }
end

context 'without a then keyword' do
let(:source) do
['case condition',
'in [42]',
' foo',
'end'].join("\n")
end

it { expect(in_pattern_node).not_to be_then }
end
end

describe '#body' do
context 'with a then keyword' do
let(:source) do
['case condition',
'in [42] then :foo',
'end'].join("\n")
end

it { expect(in_pattern_node.body).to be_sym_type }
end

context 'without a then keyword' do
let(:source) do
['case condition',
'in [42]',
' [:foo, :bar]',
'end'].join("\n")
end

it { expect(in_pattern_node.body).to be_array_type }
end
end

describe '#branch_index' do
let(:source) do
['case condition',
'in [42] then 1',
'in [43] then 2',
'in [44] then 3',
'end'].join("\n")
end

let(:in_patterns) { parse_source(source).ast.children[1...-1] }

it { expect(in_patterns[0].branch_index).to eq(0) }
it { expect(in_patterns[1].branch_index).to eq(1) }
it { expect(in_patterns[2].branch_index).to eq(2) }
end
end
end