Module: ActiverecordCallbackLens::Parser::AstWalker

Defined in:
lib/activerecord_callback_lens/parser/ast_walker.rb

Overview

Maps a Prism boolean AST (‘&&`, `||`, `!`, predicate calls) onto the ConditionTree node types. Shared by ConditionParser (lambda bodies) and MethodResolver (method bodies) so the two stay in lockstep.

The walker recognises the same boolean vocabulary the v0.1 ConditionParser established:

- StatementsNode  -> the last statement is the effective return value
- ParenthesesNode -> transparent; walk the inner body
- AndNode/OrNode  -> AndNode/OrNode combinators (nil operands dropped)
- CallNode `!`    -> NotNode wrapping the negated receiver
- CallNode        -> PredicateNode for the called method name
- anything else    -> nil (unresolvable)

Class Method Summary collapse

Class Method Details

.combinator(klass, node) ⇒ ConditionTree::Node

Builds an And/Or combinator from a binary Prism node, walking both sides and dropping any unresolved (nil) operand.

Parameters:

  • klass (Class)

    ConditionTree::AndNode or ConditionTree::OrNode

  • node (Prism::AndNode, Prism::OrNode)

Returns:



46
47
48
# File 'lib/activerecord_callback_lens/parser/ast_walker.rb', line 46

def combinator(klass, node)
  klass.new(children: [walk(node.left), walk(node.right)].compact)
end

.negate(node) ⇒ ConditionTree::NotNode?

Parameters:

Returns:



52
53
54
55
56
# File 'lib/activerecord_callback_lens/parser/ast_walker.rb', line 52

def negate(node)
  return nil if node.nil?

  ConditionTree::NotNode.new(child: node)
end

.walk(node) ⇒ ConditionTree::Node?

Recursively maps a Prism boolean AST onto ConditionTree nodes.

Parameters:

  • node (Prism::Node, nil)

Returns:



28
29
30
31
32
33
34
35
36
37
38
# File 'lib/activerecord_callback_lens/parser/ast_walker.rb', line 28

def walk(node)
  case node
  in Prism::StatementsNode then walk(node.body.last)
  in Prism::ParenthesesNode then walk(node.body)
  in Prism::AndNode then combinator(ConditionTree::AndNode, node)
  in Prism::OrNode then combinator(ConditionTree::OrNode, node)
  in Prism::CallNode if node.name == :! then negate(walk(node.receiver))
  in Prism::CallNode then ConditionTree::PredicateNode.new(name: node.name.to_s)
  else nil
  end
end