module RuboCop::AST::NodePattern::Macros
def def_node_matcher(method_name, pattern_str)
If the node matches, and no block is provided, the new method will
yield to the block (passing any captures as block arguments).
If the node matches, and a block is provided, the new method will
The new method will return nil if the node does not match
Define a method which applies a pattern to an AST node
def def_node_matcher(method_name, pattern_str) compiler = Compiler.new(pattern_str, 'node') src = "def #{method_name}(node = self" \ "#{compiler.emit_trailing_params});" \ "#{compiler.emit_method_code};end" location = caller_locations(1, 1).first class_eval(src, location.path, location.lineno) end
def def_node_search(method_name, pattern_str)
as soon as it finds a descendant which matches. Otherwise, it will
If the method name ends with '?', the new method will return `true`
checking whether any of them match the provided pattern
Define a method which recurses over the descendants of an AST node,
def def_node_search(method_name, pattern_str) compiler = Compiler.new(pattern_str, 'node') called_from = caller(1..1).first.split(':') if method_name.to_s.end_with?('?') node_search_first(method_name, compiler, called_from) else node_search_all(method_name, compiler, called_from) end end
def node_search(method_name, compiler, on_match, prelude, called_from)
def node_search(method_name, compiler, on_match, prelude, called_from) src = node_search_body(method_name, compiler.emit_trailing_params, prelude, compiler.match_code, on_match) filename, lineno = *called_from class_eval(src, filename, lineno.to_i) end
def node_search_all(method_name, compiler, called_from)
def node_search_all(method_name, compiler, called_from) yield_code = compiler.emit_yield_capture('node') prelude = "return enum_for(:#{method_name}, node0" \ "#{compiler.emit_trailing_params}) unless block_given?" node_search(method_name, compiler, yield_code, prelude, called_from) end
def node_search_body(method_name, trailing_params, prelude, match_code,
def node_search_body(method_name, trailing_params, prelude, match_code, on_match) <<~RUBY def #{method_name}(node0#{trailing_params}) #{prelude} node0.each_node do |node| if #{match_code} #{on_match} end end nil end RUBY end
def node_search_first(method_name, compiler, called_from)
def node_search_first(method_name, compiler, called_from) node_search(method_name, compiler, 'return true', '', called_from) end