Module: RubyLLM::Toolbox::RubyOutline::RipperBackend

Defined in:
lib/ruby_llm/toolbox/ruby_outline.rb

Overview

— Ripper backend (stdlib) ——————————————

Class Method Summary collapse

Class Method Details

.const_name(node) ⇒ Object



155
156
157
158
159
160
161
162
163
164
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 155

def const_name(node)
  case node && node[0]
  when :const_ref, :top_const_ref, :var_ref
    simple_name(node[1])
  when :const_path_ref # Foo::Bar
    "#{const_name(node[1])}::#{simple_name(node[2])}"
  else
    simple_name(node)
  end
end

.dispatch(node, depth, acc) ⇒ Object



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 118

def dispatch(node, depth, acc)
  case node[0]
  when :program
    walk(node[1], depth, acc)
  when :class
    acc << Entry.new(kind: :class, name: const_name(node[1]), line: line_of(node[1]), depth: depth)
    walk(node[3], depth + 1, acc) # bodystmt
  when :module
    acc << Entry.new(kind: :module, name: const_name(node[1]), line: line_of(node[1]), depth: depth)
    walk(node[2], depth + 1, acc)
  when :sclass # class << self
    acc << Entry.new(kind: :singleton_class, name: "<< #{simple_name(node[1])}", line: line_of(node), depth: depth)
    walk(node[2], depth + 1, acc)
  when :def
    acc << Entry.new(kind: :method, name: ident_name(node[1]), line: line_of(node[1]), depth: depth)
  when :defs # def self.x / def Recv.x
    name = "#{simple_name(node[1])}.#{ident_name(node[3])}"
    acc << Entry.new(kind: :method, name: name, line: line_of(node[3]), depth: depth)
  when :bodystmt
    walk(node[1], depth, acc)
  when :assign
    handle_assign(node, depth, acc)
  else
    node[1..].each { |child| walk(child, depth, acc) }
  end
end

.extract(source) ⇒ Object

Raises:



99
100
101
102
103
104
105
106
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 99

def extract(source)
  sexp = Ripper.sexp(source.to_s)
  raise ParseError, "source is not valid Ruby (syntax error)" if sexp.nil?

  acc = []
  walk(sexp, 0, acc)
  acc
end

.find_name_leaf(node) ⇒ Object



200
201
202
203
204
205
206
207
208
209
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 200

def find_name_leaf(node)
  return nil unless node.is_a?(Array)
  return node if %i[@const @ident @kw].include?(node[0])

  node.each do |child|
    found = find_name_leaf(child)
    return found if found
  end
  nil
end

.handle_assign(node, depth, acc) ⇒ Object



145
146
147
148
149
150
151
152
153
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 145

def handle_assign(node, depth, acc)
  target = node[1]
  return unless target.is_a?(Array) && target[0] == :var_field

  field = target[1]
  return unless field.is_a?(Array) && field[0] == :@const

  acc << Entry.new(kind: :constant, name: field[1], line: field[2]&.first, depth: depth)
end

.ident_name(node) ⇒ Object



179
180
181
182
183
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 179

def ident_name(node)
  return node.to_s unless node.is_a?(Array)

  node[0] == :@ident || node[0] == :@const || node[0] == :@kw ? node[1].to_s : simple_name(node)
end

.line_of(node) ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 185

def line_of(node)
  return nil unless node.is_a?(Array)

  if node.size == 3 && node[2].is_a?(Array) && node[2].size == 2 &&
     node[2][0].is_a?(Integer) && node[0].is_a?(Symbol)
    return node[2][0]
  end

  node.each do |child|
    line = line_of(child)
    return line if line
  end
  nil
end

.simple_name(node) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 166

def simple_name(node)
  return node.to_s unless node.is_a?(Array)

  case node[0]
  when :@const, :@ident, :@ivar, :@gvar, :@kw then node[1].to_s
  when :const_ref, :var_ref, :var_field then simple_name(node[1])
  when :const_path_ref then "#{simple_name(node[1])}::#{simple_name(node[2])}"
  else
    leaf = find_name_leaf(node)
    leaf ? leaf[1].to_s : "?"
  end
end

.walk(node, depth, acc) ⇒ Object



108
109
110
111
112
113
114
115
116
# File 'lib/ruby_llm/toolbox/ruby_outline.rb', line 108

def walk(node, depth, acc)
  return unless node.is_a?(Array)

  if node[0].is_a?(Symbol)
    dispatch(node, depth, acc)
  else
    node.each { |child| walk(child, depth, acc) }
  end
end