Class: PinkSpoon::RbiIndex

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

Overview

Parses every sorbet/rbi/*/.rbi file in the project and builds:

@sigs[type][method]   → sig string
@types[type][method]  → return type string
@mixins[type]         → [mixin_type, ...] from extend/include calls

Type keys are fully qualified with “::” prefix normalised away. Lookups walk the mixin chain so Hesiod.register_gauge resolves even though the method is defined on Hesiod::Gauge (which Hesiod extends).

Defined Under Namespace

Classes: RbiVisitor

Instance Method Summary collapse

Constructor Details

#initialize(root_path) ⇒ RbiIndex

Returns a new instance of RbiIndex.



16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/pink_spoon/rbi_index.rb', line 16

def initialize(root_path)
  @root_path       = root_path
  @sigs            = Hash.new { |h, k| h[k] = {} }
  @types           = Hash.new { |h, k| h[k] = {} }
  @defs            = Hash.new { |h, k| h[k] = {} }
  @sources         = Hash.new { |h, k| h[k] = {} }
  @locations       = Hash.new { |h, k| h[k] = {} }
  @mixins          = Hash.new { |h, k| h[k] = [] }
  @params          = Hash.new { |h, k| h[k] = {} }
  @const_locations     = {}
  @const_resolve_cache = {}
  build
end

Instance Method Details

#const_source_for(type) ⇒ Object

Returns { file:, line: } pointing at the real gem source for a constant, resolved from the “# source://” comment in the RBI file, or nil. Resolution is deferred to call time and nil results are not cached so transient Bundler state changes don’t permanently break lookups.



118
119
120
121
122
123
124
125
126
# File 'lib/pink_spoon/rbi_index.rb', line 118

def const_source_for(type)
  raw = @const_locations[normalise(type)]
  return nil unless raw
  cached = @const_resolve_cache[raw]
  return cached if cached
  loc = resolve_source_uri(raw)
  @const_resolve_cache[raw] = loc if loc
  loc
end

#hover_content_for(type, method_name, _seen = []) ⇒ Object

Returns markdown hover content for type#method, or nil if we know nothing about the method at all. Prefers the Sorbet sig; falls back to the plain def line so callers always get something useful.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/pink_spoon/rbi_index.rb', line 67

def hover_content_for(type, method_name, _seen = [])
  t = normalise(type)
  return nil if _seen.include?(t)

  sig      = @sigs[t][method_name.to_s]
  def_line = @defs[t][method_name.to_s]
  source   = @sources[t][method_name.to_s]

  if sig || def_line
    parts = []
    parts << source   if source
    parts << sig      if sig
    parts << def_line if def_line
    body = parts.join("\n")
    return "**`#{t}##{method_name}`** _(via RBI)_\n\n```ruby\n#{body}\n```"
  end

  @mixins[t].each do |mixin|
    result = hover_content_for(mixin, method_name, _seen + [t])
    return result if result
  end

  nil
end

#methods_for(type, _seen = []) ⇒ Object

Returns { method_name => sig_or_def_line } for a type including all mixins. Used by the completion listener to enumerate available methods.



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/pink_spoon/rbi_index.rb', line 147

def methods_for(type, _seen = [])
  t = normalise(type)
  return {} if _seen.include?(t)

  result = {}
  @mixins[t].each do |mixin|
    result.merge!(methods_for(mixin, _seen + [t]))
  end

  @defs[t].each do |method, def_line|
    result[method] = @sigs[t][method] || def_line
  end

  result
end

#mixins_for(type) ⇒ Object

Returns the direct parent/mixin types for the given type (one level, no chain walk).



110
111
112
# File 'lib/pink_spoon/rbi_index.rb', line 110

def mixins_for(type)
  @mixins[normalise(type)].dup
end

#params_for(type, method_name, _seen = []) ⇒ Object

Returns { param_name => type_string } for type#method, or nil. Follows the mixin chain.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/pink_spoon/rbi_index.rb', line 130

def params_for(type, method_name, _seen = [])
  t = normalise(type)
  return nil if _seen.include?(t)

  direct = @params[t][method_name.to_s]
  return direct if direct && !direct.empty?

  @mixins[t].each do |mixin|
    result = params_for(mixin, method_name, _seen + [t])
    return result if result && !result.empty?
  end

  nil
end

#rbi_location_for(type, method_name, _seen = []) ⇒ Object

Returns { file:, line: } for the .rbi definition of type#method, or nil. Follows extend/include/superclass chain when not found directly.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/pink_spoon/rbi_index.rb', line 94

def rbi_location_for(type, method_name, _seen = [])
  t = normalise(type)
  return nil if _seen.include?(t)

  loc = @locations[t][method_name.to_s]
  return loc if loc

  @mixins[t].each do |mixin|
    result = rbi_location_for(mixin, method_name, _seen + [t])
    return result if result
  end

  nil
end

#return_type_for(type, method_name, _seen = []) ⇒ Object

Returns the return-type string for type#method, or nil. Follows extend/include chain when not found directly.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/pink_spoon/rbi_index.rb', line 49

def return_type_for(type, method_name, _seen = [])
  t = normalise(type)
  return nil if _seen.include?(t)

  direct = @types[t][method_name.to_s]
  return direct if direct

  @mixins[t].each do |mixin|
    result = return_type_for(mixin, method_name, _seen + [t])
    return result if result
  end

  nil
end

#signature_for(type, method_name, _seen = []) ⇒ Object

Returns the sig string for type#method, or nil. Follows extend/include chain when not found directly.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/pink_spoon/rbi_index.rb', line 32

def signature_for(type, method_name, _seen = [])
  t = normalise(type)
  return nil if _seen.include?(t)

  direct = @sigs[t][method_name.to_s]
  return direct if direct

  @mixins[t].each do |mixin|
    result = signature_for(mixin, method_name, _seen + [t])
    return result if result
  end

  nil
end

#typesObject

All known types (for debugging / testing).



164
# File 'lib/pink_spoon/rbi_index.rb', line 164

def types = @sigs.keys