From 510781f11150ee9e3626fe39779b6beb56acd453 Mon Sep 17 00:00:00 2001 From: Daniel Vandersluis Date: Mon, 4 Nov 2024 13:16:54 -0500 Subject: [PATCH] Add `Node#type?` to reduce complexity of checking against multiple node types. --- ...ew_add_nodetype_to_reduce_complexity_of.md | 1 + lib/rubocop/ast/node.rb | 10 +++ spec/rubocop/ast/node_spec.rb | 61 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 changelog/new_add_nodetype_to_reduce_complexity_of.md 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 0081b4410..98e175465 100644 --- a/lib/rubocop/ast/node.rb +++ b/lib/rubocop/ast/node.rb @@ -154,6 +154,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 "grouped" types + # (e.g. `:boolean` for `:true` or `:false`) + 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 9d6845138..96a795078 100644 --- a/spec/rubocop/ast/node_spec.rb +++ b/spec/rubocop/ast/node_spec.rb @@ -1048,4 +1048,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