class RuboCop::Cop::InternalAffairs::NodePatternGroups::ASTWalker
Walks an AST that has been processed by ‘InternalAffairs::NodePatternGroups::Processor` in order to find `node_type` and `node_sequence` nodes that can be replaced with a node group in `InternalAffairs/NodePatternGroups`.
Calling ‘ASTWalker#walk` sets `node_groups` with an array of `NodeGroup` structs that contain metadata about nodes that can be replaced, including location data. That metadata is used by the cop to register offenses and perform corrections.
Constants
- NodeGroup
-
Struct to contain data about parts of a node pattern that can be replaced
Attributes
Public Class Methods
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 30 def initialize reset! end
Public Instance Methods
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 59 def on_union(node) all_node_types = each_child_node(node, :node_type, :node_sequence).to_a each_node_group(all_node_types) do |group_name, node_types| next unless sequences_match?(node_types) node_groups << node_group_data( group_name, node, node_types, all_node_types.index(node_types.first), (node.children - node_types).any? ) end end
Search ‘union` nodes for `node_type` and `node_sequence` nodes that can be collapsed into a node group.
-
‘node_type` nodes are nodes with no further configuration (ie. `send`)
-
‘node_sequence` nodes are nodes with further configuration (ie. `(send …)`)
Each group of types that can be collapsed will have a ‘NodeGroup` record added to `node_groups`, which is then used by the cop.
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 34 def reset! @node_groups = [] end
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 42 def walk(node) return if node.nil? on_union(node) if node.type == :union node.child_nodes.each do |child| walk(child) end end
Recursively walk the AST in a depth-first manner. Only ‘union` nodes are handled further.
Private Instance Methods
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 75 def each_child_node(node, *types) return to_enum(__method__, node, *types) unless block_given? node.children.each do |child| yield child if types.empty? || types.include?(child.type) end self end
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 85 def each_node_group(types_to_check) # Find all node groups where all of the members are present in the union type_names = types_to_check.map(&:child) NODE_GROUPS.select { |_, group| group & type_names == group }.each_key do |name| nodes = get_relevant_nodes(types_to_check, name) yield name, nodes end end
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 96 def get_relevant_nodes(node_types, group_name) node_types.each_with_object([]) do |node_type, arr| next unless NODE_GROUPS[group_name].include?(node_type.child) arr << node_type end end
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 104 def node_group_data(name, union, node_types, start_index, other) NodeGroup.new( name: name, union: union, node_types: node_types, sequence?: node_types.first.type == :node_sequence, start_index: start_index, pipe: union.source_range.source['|'], other_elements?: other ) end
Source
# File lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb, line 116 def sequences_match?(types) # Ensure all given types have the same type and the same sequence # ie. `(send ...)` and `(csend ...) is a match # `(send)` and `(csend ...)` is not a match # `send` and `(csend ...)` is not a match types.each_cons(2).all? do |left, right| left.type == right.type && left.children[1..] == right.children[1..] end end