Class: ActiverecordCallbackLens::Resolver::MethodResolver
- Inherits:
-
Object
- Object
- ActiverecordCallbackLens::Resolver::MethodResolver
- Defined in:
- lib/activerecord_callback_lens/resolver/method_resolver.rb
Overview
Resolves a callback’s MethodRefNode symbol (e.g. :sync_required?) into an expanded ConditionTree.
Given a model class and a method name, MethodResolver locates the method’s source via ‘instance_method(name).source_location`, parses the file with Prism, isolates the matching DefNode, and maps its body onto a ConditionTree with the shared Parser::AstWalker. Any MethodRefNode found in that tree is then resolved recursively, so a predicate that delegates to other predicates expands into a full boolean tree.
Two guards prevent runaway recursion:
- a `visited` Set closes direct (A -> A) and indirect (A -> B -> A) cycles
- a MAX_DEPTH cap bounds otherwise-acyclic but deep chains
Known limitation: a DefNode body is a StatementsNode and the resolver treats the last statement as the effective return value (the same assumption ConditionParser makes for lambda bodies). Methods with early returns or guard clauses are therefore only partially understood and are left unexpanded where the heuristic does not apply.
Defined Under Namespace
Classes: DefLocator
Constant Summary collapse
- MAX_DEPTH =
Hard cap on recursion depth. A chain of method refs deeper than this is left unexpanded rather than followed further.
5
Class Method Summary collapse
-
.expand(definition, model_class) ⇒ Collector::CallbackDefinition
Per-definition expansion entry point.
-
.resolve(model_class, method_name) ⇒ Parser::ConditionTree::Node?
The expanded tree, or nil when the method cannot be located/parsed.
Instance Method Summary collapse
-
#expand(definition) ⇒ Collector::CallbackDefinition
Expands every MethodRefNode in the definition’s condition_tree.
-
#initialize(model_class) ⇒ MethodResolver
constructor
A new instance of MethodResolver.
-
#resolve(method_name, depth: 0, visited: Set.new) ⇒ Parser::ConditionTree::Node?
Resolves a method name into an expanded ConditionTree.
Constructor Details
#initialize(model_class) ⇒ MethodResolver
Returns a new instance of MethodResolver.
55 56 57 |
# File 'lib/activerecord_callback_lens/resolver/method_resolver.rb', line 55 def initialize(model_class) @model_class = model_class end |
Class Method Details
.expand(definition, model_class) ⇒ Collector::CallbackDefinition
Per-definition expansion entry point. Walks a CallbackDefinition’s condition_tree, resolves every MethodRefNode against the model, and returns a new definition whose tree carries populated expanded_tree fields. Bridges the resolver core and the CLI/Rake integration.
50 51 52 |
# File 'lib/activerecord_callback_lens/resolver/method_resolver.rb', line 50 def self.(definition, model_class) new(model_class).(definition) end |
.resolve(model_class, method_name) ⇒ Parser::ConditionTree::Node?
Returns the expanded tree, or nil when the method cannot be located/parsed.
38 39 40 |
# File 'lib/activerecord_callback_lens/resolver/method_resolver.rb', line 38 def self.resolve(model_class, method_name) new(model_class).resolve(method_name) end |
Instance Method Details
#expand(definition) ⇒ Collector::CallbackDefinition
Expands every MethodRefNode in the definition’s condition_tree.
A definition with no condition_tree (nil) is returned unchanged; so is a tree that contains no MethodRefNodes (expand_tree rebuilds it into a value-equal copy, leaving non-expansion output identical to v0.1).
67 68 69 70 71 72 |
# File 'lib/activerecord_callback_lens/resolver/method_resolver.rb', line 67 def (definition) return definition unless definition.condition_tree = (definition.condition_tree) definition.with(condition_tree: ) end |
#resolve(method_name, depth: 0, visited: Set.new) ⇒ Parser::ConditionTree::Node?
Resolves a method name into an expanded ConditionTree.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/activerecord_callback_lens/resolver/method_resolver.rb', line 80 def resolve(method_name, depth: 0, visited: Set.new) if depth >= MAX_DEPTH warn("[ActiverecordCallbackLens] Max resolution depth (#{MAX_DEPTH}) reached at #{method_name}") return nil end return nil if visited.include?(method_name) visited = visited.dup visited.add(method_name) node = locate_and_parse(method_name) return nil if node.nil? (node, depth: depth + 1, visited: visited) end |