Class: PinkSpoon::RbiIndex
- Inherits:
-
Object
- Object
- PinkSpoon::RbiIndex
- 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
-
#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.
-
#find_type_for_method(method_name) ⇒ Object
Returns the first RBI type that defines
method_name, scanning all indexed types. -
#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.
-
#initialize(root_path) ⇒ RbiIndex
constructor
A new instance of RbiIndex.
-
#methods_for(type, _seen = []) ⇒ Object
Returns { method_name => sig_or_def_line } for a type including all mixins.
-
#mixins_for(type) ⇒ Object
Returns the direct parent/mixin types for the given type (one level, no chain walk).
-
#params_for(type, method_name, _seen = []) ⇒ Object
Returns { param_name => type_string } for type#method, or nil.
-
#rbi_location_for(type, method_name, _seen = []) ⇒ Object
Returns { file:, line: } for the .rbi definition of type#method, or nil.
-
#return_type_for(type, method_name, _seen = []) ⇒ Object
Returns the return-type string for type#method, or nil.
-
#signature_for(type, method_name, _seen = []) ⇒ Object
Returns the sig string for type#method, or nil.
-
#types ⇒ Object
All known types (for debugging / testing).
-
#yield_type_for(type, method_name, _seen = []) ⇒ Object
Returns the yield type declared in the sig (yields(Type)), or nil.
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 29 30 |
# 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] = {} } @yields = Hash.new { |h, k| h[k] = {} } @const_locations = {} @const_resolve_cache = {} @method_type_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.
120 121 122 123 124 125 126 127 128 |
# File 'lib/pink_spoon/rbi_index.rb', line 120 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 |
#find_type_for_method(method_name) ⇒ Object
Returns the first RBI type that defines method_name, scanning all indexed types. Used as a last resort when mixin-chain lookups fail (e.g. WebMock methods not wired into RSpec::Core::ExampleGroup).
186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/pink_spoon/rbi_index.rb', line 186 def find_type_for_method(method_name) name = method_name.to_s return @method_type_cache[name] if @method_type_cache.key?(name) result = nil @sigs.each { |type, methods| result = type and break if methods.key?(name) } result ||= begin found = nil @defs.each { |type, methods| found = type and break if methods.key?(name) } found end @method_type_cache[name] = result result 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.
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/pink_spoon/rbi_index.rb', line 69 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.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/pink_spoon/rbi_index.rb', line 149 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).
112 113 114 |
# File 'lib/pink_spoon/rbi_index.rb', line 112 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.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/pink_spoon/rbi_index.rb', line 132 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.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/pink_spoon/rbi_index.rb', line 96 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.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/pink_spoon/rbi_index.rb', line 51 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.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/pink_spoon/rbi_index.rb', line 34 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 |
#types ⇒ Object
All known types (for debugging / testing).
202 |
# File 'lib/pink_spoon/rbi_index.rb', line 202 def types = @sigs.keys |
#yield_type_for(type, method_name, _seen = []) ⇒ Object
Returns the yield type declared in the sig (yields(Type)), or nil. e.g. for ‘sig { yields(WebMock::RequestSignature).returns(…) }` returns “WebMock::RequestSignature”.
168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/pink_spoon/rbi_index.rb', line 168 def yield_type_for(type, method_name, _seen = []) t = normalise(type) return nil if _seen.include?(t) direct = @yields[t][method_name.to_s] return direct if direct @mixins[t].each do |mixin| result = yield_type_for(mixin, method_name, _seen + [t]) return result if result end nil end |