Class: Rigor::ModuleGraph::VisibilityMap
- Inherits:
-
Object
- Object
- Rigor::ModuleGraph::VisibilityMap
- Defined in:
- lib/rigor/module_graph/visibility_map.rb
Overview
Pre-walks a Prism tree once and records each DefNode‘s effective visibility based on the running public / protected / private marker calls inside its enclosing class / module body.
The Analyzer’s per-node rules can then look up a visibility in O(1) without re-walking the surrounding body. Built once per file by the plugin’s node_file_context hook.
Limitations (acknowledged):
-
private :foo (explicit symbol form) is ignored; only the bare keyword that flips the running visibility is honoured. The bare form covers ~90% of Ruby; the symbol form mostly shows up in DSL-generated method blocks.
-
private_class_methodand singleton-class blocks (+class << self+) are not interpreted. -
Methods inside a
classinside a method body (rare) stay atpublic.
Constant Summary collapse
- VISIBILITY_MARKERS =
%i[public protected private].freeze
Class Method Summary collapse
- .bare_marker?(call_node) ⇒ Boolean
- .build(root) ⇒ VisibilityMap
- .walk_body(class_or_module, map) ⇒ Object
- .walk_top_level(node, map) ⇒ Object
Instance Method Summary collapse
-
#initialize ⇒ VisibilityMap
constructor
A new instance of VisibilityMap.
- #record(node, visibility) ⇒ Object
- #visibility_for(node) ⇒ Object
Constructor Details
#initialize ⇒ VisibilityMap
Returns a new instance of VisibilityMap.
29 30 31 |
# File 'lib/rigor/module_graph/visibility_map.rb', line 29 def initialize @table = {}.compare_by_identity end |
Class Method Details
.bare_marker?(call_node) ⇒ Boolean
80 81 82 83 |
# File 'lib/rigor/module_graph/visibility_map.rb', line 80 def self.(call_node) call_node.receiver.nil? && (call_node.arguments.nil? || call_node.arguments.arguments.empty?) end |
.build(root) ⇒ VisibilityMap
35 36 37 38 39 |
# File 'lib/rigor/module_graph/visibility_map.rb', line 35 def self.build(root) map = new walk_top_level(root, map) if root map end |
.walk_body(class_or_module, map) ⇒ Object
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/rigor/module_graph/visibility_map.rb', line 61 def self.walk_body(class_or_module, map) body = class_or_module.body statements = body.respond_to?(:body) ? Array(body.body) : [] current = "public" statements.each do |stmt| case stmt when Prism::CallNode if VISIBILITY_MARKERS.include?(stmt.name) && (stmt) current = stmt.name.to_s end when Prism::DefNode map.record(stmt, current) when Prism::ClassNode, Prism::ModuleNode walk_body(stmt, map) end end end |
.walk_top_level(node, map) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/rigor/module_graph/visibility_map.rb', line 45 def self.walk_top_level(node, map) return unless node.is_a?(Prism::Node) # The top level is a module-like scope; defs there read as # public. Modules nested below get their own pass with the # visibility reset to public. case node when Prism::ProgramNode walk_top_level(node.statements, map) when Prism::StatementsNode node.body.each { |child| walk_top_level(child, map) } when Prism::ClassNode, Prism::ModuleNode walk_body(node, map) end end |
Instance Method Details
#record(node, visibility) ⇒ Object
85 86 87 |
# File 'lib/rigor/module_graph/visibility_map.rb', line 85 def record(node, visibility) @table[node] = visibility end |
#visibility_for(node) ⇒ Object
41 42 43 |
# File 'lib/rigor/module_graph/visibility_map.rb', line 41 def visibility_for(node) @table[node] end |