Class: Docscribe::InlineRewriter::Collector

Inherits:
Parser::AST::Processor
  • Object
show all
Defined in:
lib/docscribe/inline_rewriter/collector.rb

Overview

AST walker that collects documentation insertion targets.

This is where Docscribe models Ruby scoping and visibility semantics so the doc generator can:

  • know whether a method is an instance method or class/module method (‘#` vs `.`)

  • add ‘@private` / `@protected` tags when appropriate

  • know the container name (‘A::B`) to show in `+A::B#foo+`

In addition to ‘private` / `protected` / `public` handling, Collector supports:

  • ‘module_function` inside modules

  • ‘extend self` inside modules

  • receiver-based containers (‘def Foo.bar`, `class << Foo`)

  • Sorbet-aware anchoring for methods with leading ‘sig` declarations

Defined Under Namespace

Classes: AttrInsertion, Insertion, VisibilityCtx

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(buffer) ⇒ Collector

Create a collector for the given source buffer.

Parameters:

  • buffer (Parser::Source::Buffer)

    source buffer for anchor location lookups



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/docscribe/inline_rewriter/collector.rb', line 165

def initialize(buffer)
  super()
  @buffer = buffer
  @insertions = []
  @attr_insertions = []
  @name_stack = []

  # Track module-level state across reopened modules within the same file pass.
  # Example:
  #   module M; extend self; end
  #   module M; def foo; end; end  # => should still document foo as M.foo
  #
  # @type [Hash{String=>Hash}]
  @module_states = {} # { "M" => { extend_self: true } }
end

Instance Attribute Details

#attr_insertionsObject (readonly)

Returns the value of attribute attr_insertions.



159
160
161
# File 'lib/docscribe/inline_rewriter/collector.rb', line 159

def attr_insertions
  @attr_insertions
end

#insertionsObject (readonly)

Returns the value of attribute insertions.



155
156
157
# File 'lib/docscribe/inline_rewriter/collector.rb', line 155

def insertions
  @insertions
end

Instance Method Details

#on_casgn(node) ⇒ Parser::AST::Node

Process a constant assignment (e.g. ‘FOO = …` or `Foo::BAR = …`).

If the value is a ‘Struct.new` call, extracts attribute insertions first. Then continues processing child nodes.

Parameters:

  • node (Parser::AST::Node)

    a ‘:casgn` node

Returns:

  • (Parser::AST::Node)

    the original node



236
237
238
239
240
241
242
243
244
# File 'lib/docscribe/inline_rewriter/collector.rb', line 236

def on_casgn(node)
  return node if process_struct_casgn(node)

  node.children.each do |child|
    process(child) if child.is_a?(Parser::AST::Node)
  end

  node
end

#on_class(node) ⇒ Parser::AST::Node

Enter a class body and collect documentation targets from its contents.

Parameters:

  • node (Parser::AST::Node)

Returns:

  • (Parser::AST::Node)


185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/docscribe/inline_rewriter/collector.rb', line 185

def on_class(node)
  cname_node, super_node, body = *node
  @name_stack.push(const_name(cname_node))

  ctx = VisibilityCtx.new
  ctx.container_is_module = false

  process_struct_class(node, super_node)
  process_body(body, ctx)

  @name_stack.pop
  node
end

#on_def(node) ⇒ Parser::AST::Node

Enter a top-level method definition and collect it as a documentation target.

Top-level methods implicitly belong to Object. This handler ensures that def foo declared outside of any class or module is still picked up by the collector.

Parameters:

  • node (Parser::AST::Node)

Returns:

  • (Parser::AST::Node)


254
255
256
257
258
259
260
261
# File 'lib/docscribe/inline_rewriter/collector.rb', line 254

def on_def(node)
  return node unless @name_stack.empty?

  ctx = VisibilityCtx.new
  ctx.container_is_module = false
  process_stmt(node, ctx)
  node
end

#on_defs(node) ⇒ Parser::AST::Node

Enter a top-level singleton method definition and collect it as a documentation target.

Handles the case of def self.foo declared at the top level, outside of any class or module body.

Parameters:

  • node (Parser::AST::Node)

Returns:

  • (Parser::AST::Node)


270
271
272
273
274
275
276
277
# File 'lib/docscribe/inline_rewriter/collector.rb', line 270

def on_defs(node)
  return node unless @name_stack.empty?

  ctx = VisibilityCtx.new
  ctx.container_is_module = false
  process_stmt(node, ctx)
  node
end

#on_module(node) ⇒ Parser::AST::Node

Enter a module body and collect documentation targets from its contents.

This also carries ‘extend self` state across reopened modules in the same file.

Parameters:

  • node (Parser::AST::Node)

Returns:

  • (Parser::AST::Node)


206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/docscribe/inline_rewriter/collector.rb', line 206

def on_module(node)
  cname_node, body = *node
  @name_stack.push(const_name(cname_node))

  container = current_container

  ctx = VisibilityCtx.new
  ctx.container_is_module = true
  ctx.extend_self = !!@module_states.dig(container, :extend_self)

  process_body(body, ctx)

  # If `extend self` is active for this module, document all instance defs as module methods (M.foo).
  if ctx.extend_self
    promote_extend_self_container(container: container)
    @module_states[container] ||= {}
    @module_states[container][:extend_self] = true
  end

  @name_stack.pop
  node
end