Class: CallMap::DefinitionCollector
- Inherits:
-
Prism::Visitor
- Object
- Prism::Visitor
- CallMap::DefinitionCollector
- Defined in:
- lib/call_map/definition_collector.rb
Overview
The single boundary that touches Prism.
Prism node types (ClassNode / ModuleNode / DefNode ...) are referenced only here. Everything else in the codebase works with Definition, so the parser can be swapped out later by replacing just this class.
Class Method Summary collapse
-
.collect(source, path:) ⇒ Array<Definition>
Parse
sourceand return the list of definitions found in it.
Instance Method Summary collapse
- #collect(source) ⇒ Object
-
#initialize(path) ⇒ DefinitionCollector
constructor
A new instance of DefinitionCollector.
-
#visit_call_node(node) ⇒ Object
Track
private/protected/publicvisibility directives at the class-body level (bare toggle,private def foo, andprivate :foo). -
#visit_class_node(node) ⇒ Object
Called when the traversal reaches a
classdefinition. -
#visit_def_node(node) ⇒ Object
Called for every
def—def foo,def self.foo, anddef Foo.bar. -
#visit_module_node(node) ⇒ Object
Called when the traversal reaches a
moduledefinition. -
#visit_singleton_class_node(node) ⇒ Object
Called for
class << self,class << SomeConstant, andclass << obj.
Constructor Details
#initialize(path) ⇒ DefinitionCollector
Returns a new instance of DefinitionCollector.
22 23 24 25 26 27 28 29 30 31 |
# File 'lib/call_map/definition_collector.rb', line 22 def initialize(path) super() # Prism::Visitor#initialize takes no args @path = path @namespace = [] # stack of enclosing class/module names (for qualified naming) @singletons = [] # per-scope singleton owner (nil / String / :unresolved) @lexical_scopes = [] # syntactic scope stack of FULL names (mirrors Module.nesting) @visibilities = [:public] # per-scope visibility state toggled by private/protected/public @inline_visibility = nil # for the `private def foo` inline form @definitions = [] end |
Class Method Details
.collect(source, path:) ⇒ Array<Definition>
Parse source and return the list of definitions found in it.
18 19 20 |
# File 'lib/call_map/definition_collector.rb', line 18 def self.collect(source, path:) new(path).collect(source) end |
Instance Method Details
#collect(source) ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/call_map/definition_collector.rb', line 33 def collect(source) # Prism.parse returns a ParseResult; .value is the root (ProgramNode). # accept(self) starts the visitor traversal from the root. result = Prism.parse(source) @comment_lines = pure_comment_lines(source, result.comments) result.value.accept(self) @definitions end |
#visit_call_node(node) ⇒ Object
Track private / protected / public visibility directives at the
class-body level (bare toggle, private def foo, and private :foo).
82 83 84 85 86 87 88 89 90 91 |
# File 'lib/call_map/definition_collector.rb', line 82 def visit_call_node(node) directive = visibility_directive(node) return super unless directive args = node.arguments&.arguments return with_inline_visibility(directive) { super } if args&.any? && args.all?(Prism::DefNode) apply_visibility(directive, args) super end |
#visit_class_node(node) ⇒ Object
Called when the traversal reaches a class definition.
43 44 45 46 47 48 |
# File 'lib/call_map/definition_collector.rb', line 43 def visit_class_node(node) enter_namespace(node.constant_path) do @definitions << build_definition(:class, current_namespace, node, superclass: superclass_name(node)) super # descend into the class body (its methods etc.) end end |
#visit_def_node(node) ⇒ Object
Called for every def — def foo, def self.foo, and def Foo.bar.
66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/call_map/definition_collector.rb', line 66 def visit_def_node(node) info = method_kind_and_owner(node.receiver) # info is nil when the method belongs to an unresolvable receiver # (e.g. `class << obj`); such defs are skipped rather than mis-registered. # No super in either case — do not recurse into method bodies. Nested # defs inside a method are runtime-only and should not appear in the index. return unless info definition = build_definition(info[:kind], node.name.to_s, node, owner: info[:owner]) comments = leading_comments(node.location.start_line) definition.[:comments] = comments if comments.any? @definitions << definition end |
#visit_module_node(node) ⇒ Object
Called when the traversal reaches a module definition.
51 52 53 54 55 56 |
# File 'lib/call_map/definition_collector.rb', line 51 def visit_module_node(node) enter_namespace(node.constant_path) do @definitions << build_definition(:module, current_namespace, node) super end end |
#visit_singleton_class_node(node) ⇒ Object
Called for class << self, class << SomeConstant, and class << obj.
59 60 61 62 63 |
# File 'lib/call_map/definition_collector.rb', line 59 def visit_singleton_class_node(node) within_singleton(singleton_owner(node.expression)) do super end end |