diff --git a/changelog/new_add_nodetype_to_reduce_complexity_of.md b/changelog/new_add_nodetype_to_reduce_complexity_of.md new file mode 100644 index 000000000..9105963b2 --- /dev/null +++ b/changelog/new_add_nodetype_to_reduce_complexity_of.md @@ -0,0 +1 @@ +* [#329](https://github.com/rubocop/rubocop-ast/pull/329): Add `Node#type?` to reduce complexity of checking against multiple node types. ([@dvandersluis][]) diff --git a/lib/rubocop/ast/node.rb b/lib/rubocop/ast/node.rb index 9b0a51c2d..0b3b8f33c 100644 --- a/lib/rubocop/ast/node.rb +++ b/lib/rubocop/ast/node.rb @@ -152,6 +152,16 @@ def initialize(type, children = EMPTY_CHILDREN, properties = EMPTY_PROPERTIES) end end + # Determine if the node is one of several node types in a single query + # Allows specific single node types, as well as `TYPE_GROUP` keys to + # specify a group of nodes. + def type?(*types) + return true if types.include?(type) + + group_type = GROUP_FOR_TYPE[type] + !group_type.nil? && types.include?(group_type) + end + (Parser::Meta::NODE_TYPES - [:send]).each do |node_type| method_name = "#{node_type.to_s.gsub(/\W/, '')}_type?" class_eval <<~RUBY, __FILE__, __LINE__ + 1 diff --git a/spec/rubocop/ast/node_spec.rb b/spec/rubocop/ast/node_spec.rb index 2b7d43b12..2b0172b00 100644 --- a/spec/rubocop/ast/node_spec.rb +++ b/spec/rubocop/ast/node_spec.rb @@ -986,4 +986,65 @@ class << expr end end end + + describe '#type?' do + let(:src) do + <<~RUBY + foo.bar + RUBY + end + + context 'when it is one of the given types' do + it 'is true' do + expect(node).to be_type(:send, :const, :lvar) + end + end + + context 'when it is not one of the given types' do + it 'is false' do + expect(node).not_to be_type(:if, :while, :until) + end + end + + context 'when given :argument with an `arg` node' do + let(:src) { 'foo { |>> var <<| } ' } + + it 'is true' do + arg_node = ast.procarg0_type? ? ast.child_nodes.first : node + expect(arg_node).to be_type(:argument) + end + end + + context 'when given :boolean with an `true` node' do + let(:src) { 'true' } + + it 'is true' do + expect(node).to be_type(:boolean) + end + end + + context 'when given :numeric with an `int` node' do + let(:src) { '42' } + + it 'is true' do + expect(node).to be_type(:numeric) + end + end + + context 'when given :range with an `irange` node' do + let(:src) { '1..3' } + + it 'is true' do + expect(node).to be_type(:range) + end + end + + context 'when given :call with an `send` node' do + let(:src) { 'foo.bar' } + + it 'is true' do + expect(node).to be_type(:call) + end + end + end end