Module: Docscribe::InlineRewriter

Defined in:
lib/docscribe/inline_rewriter.rb,
lib/docscribe/inline_rewriter/collector.rb,
lib/docscribe/inline_rewriter/doc_block.rb,
lib/docscribe/inline_rewriter/tag_sorter.rb,
lib/docscribe/inline_rewriter/doc_builder.rb,
lib/docscribe/inline_rewriter/source_helpers.rb

Overview

Rewrite Ruby source to insert or update inline YARD-style documentation.

Supported strategies:

  • :safe
    • insert missing docs
    • merge into existing doc-like blocks
    • normalize configured sortable tags
    • preserve existing prose and directives where possible
  • :aggressive
    • replace existing doc blocks with freshly generated docs

Compatibility note:

  • merge: true maps to strategy: :safe
  • rewrite: true maps to strategy: :aggressive

Defined Under Namespace

Modules: DocBlock, DocBuilder, SourceHelpers, TagSorter Classes: Collector

Class Method Summary collapse

Class Method Details

.build_rewrite_pipeline(buffer, ast) ⇒ Docscribe::InlineRewriter::pipeline

Build rewrite pipeline

Parameters:

  • buffer (Parser::Source::Buffer)

    the source buffer being rewritten

  • ast (Parser::AST::Node)

    the parsed AST of the source code

Returns:

  • (Docscribe::InlineRewriter::pipeline)


76
77
78
79
80
81
82
83
84
85
86
# File 'lib/docscribe/inline_rewriter.rb', line 76

def build_rewrite_pipeline(buffer, ast)
  all = collect_insertions(buffer, ast)
  method_overrides_by_pos = {} #: Hash[Integer, untyped]
  all = deduplicate_insertions(all, method_overrides_by_pos: method_overrides_by_pos)
  rewriter = Parser::Source::TreeRewriter.new(buffer) # steep:ignore
  merge_inserts = Hash.new { |h, k| h[k] = [] } #: Hash[Integer, untyped]
  changes = [] #: Array[untyped]

  { all: all, method_overrides_by_pos: method_overrides_by_pos, rewriter: rewriter,
    merge_inserts: merge_inserts, changes: changes }
end

.dispatch_attr_insertion(ins, pipeline, buffer, **options) ⇒ void

This method returns an undefined value.

Dispatch attr insertion

Parameters:

  • ins (Docscribe::InlineRewriter::Collector::AttrInsertion)

    the attribute insertion object

  • pipeline (Docscribe::InlineRewriter::pipeline)

    the pipeline hash with rewriter, insertions, and tracking state

  • buffer (Parser::Source::Buffer)

    the source buffer

  • options (Hash)

    the full keyword options hash



195
196
197
198
199
200
201
# File 'lib/docscribe/inline_rewriter.rb', line 195

def dispatch_attr_insertion(ins, pipeline, buffer, **options)
  apply_attr_insertion!(
    rewriter: pipeline[:rewriter], buffer: buffer, insertion: ins,
    config: options[:config], signature_provider: options[:signature_provider],
    strategy: options[:strategy], merge_inserts: pipeline[:merge_inserts]
  )
end

.dispatch_method_insertion(ins, pipeline, buffer, **options) ⇒ void

This method returns an undefined value.

Dispatch method insertion

Parameters:

  • ins (Docscribe::InlineRewriter::Collector::Insertion)

    the attribute insertion object

  • pipeline (Docscribe::InlineRewriter::pipeline)

    the pipeline hash with rewriter, insertions, and tracking state

  • buffer (Parser::Source::Buffer)

    the source buffer

  • options (Hash)

    the full keyword options hash



175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/docscribe/inline_rewriter.rb', line 175

def dispatch_method_insertion(ins, pipeline, buffer, **options)
  pos = plugin_insertion_pos(:method, ins)
  method_override = pipeline[:method_overrides_by_pos][pos]

  apply_method_insertion!(
    rewriter: pipeline[:rewriter], buffer: buffer, insertion: ins,
    config: options[:config], signature_provider: options[:signature_provider],
    core_rbs_provider: options[:core_rbs_provider], strategy: options[:strategy],
    changes: pipeline[:changes], file: options[:file],
    method_override: method_override
  )
end

.dispatch_plugin_insertion(ins, pipeline, buffer, **options) ⇒ void

This method returns an undefined value.

Dispatch plugin insertion

Parameters:

  • ins (Docscribe::InlineRewriter::pluginInsertion)

    the attribute insertion object

  • pipeline (Docscribe::InlineRewriter::pipeline)

    the pipeline hash with rewriter, insertions, and tracking state

  • buffer (Parser::Source::Buffer)

    the source buffer

  • options (Hash)

    the full keyword options hash



210
211
212
213
214
215
# File 'lib/docscribe/inline_rewriter.rb', line 210

def dispatch_plugin_insertion(ins, pipeline, buffer, **options)
  apply_plugin_insertion!(
    rewriter: pipeline[:rewriter], buffer: buffer, insertion: ins,
    strategy: options[:strategy], config: options[:config]
  )
end

.dispatch_rewrite_insertions(pipeline, buffer, **options) ⇒ void

This method returns an undefined value.

Dispatch rewrite insertions

Parameters:

  • pipeline (Docscribe::InlineRewriter::pipeline)

    the pipeline hash with rewriter, insertions, and tracking state

  • buffer (Parser::Source::Buffer)

    the source buffer being rewritten

  • options (Hash)

    additional kwargs (config, signature_provider, core_rbs_provider, strategy, file)



94
95
96
97
98
99
100
101
# File 'lib/docscribe/inline_rewriter.rb', line 94

def dispatch_rewrite_insertions(pipeline, buffer, **options)
  pipeline[:all].sort_by { |(kind, ins)| plugin_insertion_pos(kind, ins) }
                .reverse_each do |kind, ins|
    dispatch_single_insertion(kind, ins, pipeline, buffer, **options)
  end

  apply_merge_inserts!(rewriter: pipeline[:rewriter], buffer: buffer, merge_inserts: pipeline[:merge_inserts])
end

.dispatch_single_insertion(kind, ins, pipeline, buffer, **options) ⇒ void, Object

Dispatch a single insertion, isolating per-method failures.

A crash while documenting one method (e.g., unexpected AST shape) must not discard warnings for the rest of the file: the error is reported to stderr and the remaining insertions still apply.

Parameters:

  • kind (Symbol)

    insertion kind (:method, :attr, :plugin)

  • ins (Object)

    the insertion object

  • pipeline (Docscribe::InlineRewriter::pipeline)

    the pipeline hash with rewriter, insertions, and tracking state

  • buffer (Parser::Source::Buffer)

    the source buffer being rewritten

  • options (Hash)

    additional kwargs (config, signature_provider, core_rbs_provider, strategy, file)

Returns:

  • (void)
  • (Object)

    if StandardError

Raises:

  • (StandardError)


117
118
119
120
121
122
123
124
# File 'lib/docscribe/inline_rewriter.rb', line 117

def dispatch_single_insertion(kind, ins, pipeline, buffer, **options)
  method_name = :"dispatch_#{kind}_insertion"
  return unless respond_to?(method_name, true)

  send(method_name, ins, pipeline, buffer, **options)
rescue StandardError => e
  warn_insertion_error(kind, ins, options[:file], e)
end

.insert_comments(code, strategy: nil, rewrite: nil, merge: nil, **options) ⇒ String

Insert comments

Parameters:

  • code (String)

    Ruby source

  • strategy (Symbol?) (defaults to: nil)

    :safe or :aggressive

  • rewrite (Boolean?) (defaults to: nil)

    compatibility alias for aggressive strategy

  • merge (Boolean?) (defaults to: nil)

    compatibility alias for safe strategy

  • options (Hash)

    additional keyword arguments forwarded to rewrite_with_report

Returns:

  • (String)


45
46
47
48
49
# File 'lib/docscribe/inline_rewriter.rb', line 45

def insert_comments(code, strategy: nil, rewrite: nil, merge: nil, **options)
  strategy = normalize_strategy(strategy: strategy, rewrite: rewrite, merge: merge)

  rewrite_with_report(code, strategy: strategy, **options)[:output]
end

.insertion_label(kind, ins) ⇒ String

Human-readable label for an insertion used in skip warnings.

Parameters:

  • kind (Symbol)

    insertion kind (:method, :attr, :plugin)

  • ins (Object)

    the insertion object

Returns:

  • (String)

    label like "method foo at line 12"



142
143
144
145
146
147
148
# File 'lib/docscribe/inline_rewriter.rb', line 142

def insertion_label(kind, ins)
  node = insertion_node(ins)
  name = node ? SourceHelpers.node_name(node) : nil
  line = node_line(node)
  label = name ? "#{kind} #{name}" : kind.to_s
  line ? "#{label} at line #{line}" : label
end

.insertion_node(ins) ⇒ Parser::AST::Node?

Extract the AST node from an insertion when available.

Parameters:

  • ins (Object)

    the insertion object

Returns:

  • (Parser::AST::Node, nil)

    the node or nil



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

def insertion_node(ins)
  ins.respond_to?(:node) ? ins.node : nil
end

.node_line(node) ⇒ Integer?

Source line of a node expression when available.

Parameters:

  • node (Parser::AST::Node, nil)

    an AST node

Returns:

  • (Integer, nil)

    1-based line number or nil



162
163
164
165
166
# File 'lib/docscribe/inline_rewriter.rb', line 162

def node_line(node)
  loc = node&.loc
  expr = loc&.expression
  expr&.line
end

.rewrite_with_report(code, strategy: nil, rewrite: nil, merge: nil, **options) ⇒ Hash<Symbol, String, Array<Docscribe::InlineRewriter::changeRecord>>

Rewrite with report

Parameters:

  • code (String)

    Ruby source

  • strategy (Symbol?) (defaults to: nil)

    :safe or :aggressive

  • rewrite (Boolean?) (defaults to: nil)

    compatibility alias for aggressive strategy

  • merge (Boolean?) (defaults to: nil)

    compatibility alias for safe strategy

  • options (Hash)

    additional keyword arguments forwarded to downstream helpers

Returns:

  • (Hash<Symbol, String, Array<Docscribe::InlineRewriter::changeRecord>>)


59
60
61
62
63
64
65
66
67
68
69
# File 'lib/docscribe/inline_rewriter.rb', line 59

def rewrite_with_report(code, strategy: nil, rewrite: nil, merge: nil, **options)
  strategy = normalize_strategy(strategy: strategy, rewrite: rewrite, merge: merge)
  validate_strategy!(strategy)
  parsed = setup_rewrite_env(code, options)
  pipeline = build_rewrite_pipeline(parsed[:buffer], parsed[:ast])
  dispatch_rewrite_insertions(pipeline, parsed[:buffer],
                              config: parsed[:config], signature_provider: parsed[:signature_provider],
                              core_rbs_provider: parsed[:core_rbs_provider], strategy: strategy,
                              file: parsed[:file])
  { output: pipeline[:rewriter].process, changes: pipeline[:changes] }
end

.warn_insertion_error(kind, ins, file, error) ⇒ void

This method returns an undefined value.

Report a skipped insertion to stderr without interrupting the rewrite.

Parameters:

  • kind (Symbol)

    insertion kind (:method, :attr, :plugin)

  • ins (Object)

    the insertion object

  • file (String, nil)

    the file being rewritten

  • error (StandardError)

    the rescued error



133
134
135
# File 'lib/docscribe/inline_rewriter.rb', line 133

def warn_insertion_error(kind, ins, file, error)
  warn "Docscribe: skipping #{insertion_label(kind, ins)} in #{file}: #{error.class}: #{error.message}"
end