Class: PinkSpoon::RbiIndex::RbiVisitor

Inherits:
Prism::Visitor
  • Object
show all
Defined in:
lib/pink_spoon/rbi_index.rb

Overview


Prism AST visitor that walks RBI files and extracts:

- sig+def pairs (entries)
- extend/include calls (mixins)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(comment_map = {}) ⇒ RbiVisitor

Returns a new instance of RbiVisitor.



203
204
205
206
207
208
209
# File 'lib/pink_spoon/rbi_index.rb', line 203

def initialize(comment_map = {})
  @entries     = []
  @mixins      = Hash.new { |h, k| h[k] = [] }
  @scope       = []
  @pending_sig = nil
  @comment_map = comment_map
end

Instance Attribute Details

#entriesObject (readonly)

Returns the value of attribute entries.



201
202
203
# File 'lib/pink_spoon/rbi_index.rb', line 201

def entries
  @entries
end

#mixinsObject (readonly)

Returns the value of attribute mixins.



201
202
203
# File 'lib/pink_spoon/rbi_index.rb', line 201

def mixins
  @mixins
end

Instance Method Details

#visit_call_node(node) ⇒ Object



227
228
229
230
231
232
233
234
# File 'lib/pink_spoon/rbi_index.rb', line 227

def visit_call_node(node)
  if node.name == :sig && node.receiver.nil?
    @pending_sig = node.slice
  elsif (node.name == :extend || node.name == :include) && node.receiver.nil?
    record_mixins(node)
  end
  super
end

#visit_class_node(node) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
# File 'lib/pink_spoon/rbi_index.rb', line 215

def visit_class_node(node)
  push_scope(node.constant_path) do
    # Record superclass as a parent so method lookups walk the chain.
    if node.superclass
      type   = @scope.join("::")
      parent = const_path_to_string(node.superclass).delete_prefix("::")
      @mixins[type] << parent unless @mixins[type].include?(parent)
    end
    super
  end
end

#visit_def_node(node) ⇒ Object



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/pink_spoon/rbi_index.rb', line 236

def visit_def_node(node)
  method_name  = node.name.to_s
  sig          = @pending_sig
  @pending_sig = nil

  # Build a plain def line even when no Sorbet sig exists.
  # e.g. "def init_label_set(labels)"
  params    = node.parameters&.slice
  def_line  = params ? "def #{method_name}(#{params})" : "def #{method_name}"

  # Check for a "# source://" comment on the line immediately before this def.
  preceding = @comment_map[node.location.start_line - 1]
  source    = preceding&.match?(/# source:\/\//) ? preceding : nil

  @entries << {
    type:        @scope.join("::"),
    method:      method_name,
    sig:         sig,
    def_line:    def_line,
    return_type: sig ? extract_return_type(sig) : nil,
    params:      sig ? extract_params(sig) : {},
    source:      source,
    line:        node.location.start_line,
  }

  super
end

#visit_module_node(node) ⇒ Object



211
212
213
# File 'lib/pink_spoon/rbi_index.rb', line 211

def visit_module_node(node)
  push_scope(node.constant_path) { super }
end