docscribe 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +692 -180
- data/exe/docscribe +2 -74
- data/lib/docscribe/cli/config_builder.rb +62 -0
- data/lib/docscribe/cli/init.rb +58 -0
- data/lib/docscribe/cli/options.rb +204 -0
- data/lib/docscribe/cli/run.rb +415 -0
- data/lib/docscribe/cli.rb +31 -0
- data/lib/docscribe/config/defaults.rb +71 -0
- data/lib/docscribe/config/emit.rb +126 -0
- data/lib/docscribe/config/filtering.rb +160 -0
- data/lib/docscribe/config/loader.rb +59 -0
- data/lib/docscribe/config/rbs.rb +51 -0
- data/lib/docscribe/config/sorbet.rb +87 -0
- data/lib/docscribe/config/sorting.rb +23 -0
- data/lib/docscribe/config/template.rb +176 -0
- data/lib/docscribe/config/utils.rb +102 -0
- data/lib/docscribe/config.rb +20 -230
- data/lib/docscribe/infer/ast_walk.rb +28 -0
- data/lib/docscribe/infer/constants.rb +11 -0
- data/lib/docscribe/infer/literals.rb +55 -0
- data/lib/docscribe/infer/names.rb +43 -0
- data/lib/docscribe/infer/params.rb +62 -0
- data/lib/docscribe/infer/raises.rb +68 -0
- data/lib/docscribe/infer/returns.rb +171 -0
- data/lib/docscribe/infer.rb +110 -259
- data/lib/docscribe/inline_rewriter/collector.rb +845 -0
- data/lib/docscribe/inline_rewriter/doc_block.rb +383 -0
- data/lib/docscribe/inline_rewriter/doc_builder.rb +605 -0
- data/lib/docscribe/inline_rewriter/source_helpers.rb +228 -0
- data/lib/docscribe/inline_rewriter/tag_sorter.rb +244 -0
- data/lib/docscribe/inline_rewriter.rb +604 -425
- data/lib/docscribe/parsing.rb +120 -0
- data/lib/docscribe/types/provider_chain.rb +37 -0
- data/lib/docscribe/types/rbs/provider.rb +213 -0
- data/lib/docscribe/types/rbs/type_formatter.rb +132 -0
- data/lib/docscribe/types/signature.rb +65 -0
- data/lib/docscribe/types/sorbet/base_provider.rb +217 -0
- data/lib/docscribe/types/sorbet/rbi_provider.rb +35 -0
- data/lib/docscribe/types/sorbet/source_provider.rb +25 -0
- data/lib/docscribe/version.rb +1 -1
- data/lib/docscribe.rb +1 -0
- metadata +85 -17
- data/.rspec +0 -3
- data/.rubocop.yml +0 -11
- data/.rubocop_todo.yml +0 -73
- data/CODE_OF_CONDUCT.md +0 -84
- data/Gemfile +0 -6
- data/Gemfile.lock +0 -73
- data/Rakefile +0 -12
- data/rakelib/docs.rake +0 -73
- data/stingray_docs_internal.gemspec +0 -41
|
@@ -1,532 +1,711 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require '
|
|
4
|
-
require '
|
|
3
|
+
require 'ast'
|
|
4
|
+
require 'parser/deprecation'
|
|
5
|
+
require 'parser/source/buffer'
|
|
6
|
+
require 'parser/source/range'
|
|
7
|
+
require 'parser/source/tree_rewriter'
|
|
8
|
+
|
|
9
|
+
require 'docscribe/config'
|
|
10
|
+
require 'docscribe/parsing'
|
|
11
|
+
|
|
12
|
+
require 'docscribe/inline_rewriter/source_helpers'
|
|
13
|
+
require 'docscribe/inline_rewriter/doc_builder'
|
|
14
|
+
require 'docscribe/inline_rewriter/collector'
|
|
15
|
+
require 'docscribe/inline_rewriter/doc_block'
|
|
5
16
|
|
|
6
17
|
module Docscribe
|
|
18
|
+
# Raised when source cannot be parsed before rewriting.
|
|
19
|
+
class ParseError < StandardError; end
|
|
20
|
+
|
|
21
|
+
# Rewrite Ruby source to insert or update inline YARD-style documentation.
|
|
22
|
+
#
|
|
23
|
+
# Supported strategies:
|
|
24
|
+
# - `:safe`
|
|
25
|
+
# - insert missing docs
|
|
26
|
+
# - merge into existing doc-like blocks
|
|
27
|
+
# - normalize configured sortable tags
|
|
28
|
+
# - preserve existing prose and directives where possible
|
|
29
|
+
# - `:aggressive`
|
|
30
|
+
# - replace existing doc blocks with freshly generated docs
|
|
31
|
+
#
|
|
32
|
+
# Compatibility note:
|
|
33
|
+
# - `merge: true` maps to `strategy: :safe`
|
|
34
|
+
# - `rewrite: true` maps to `strategy: :aggressive`
|
|
7
35
|
module InlineRewriter
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
class << self
|
|
37
|
+
# Rewrite source and return only the rewritten output string.
|
|
38
|
+
#
|
|
39
|
+
# This is the main convenience entry point for library usage.
|
|
40
|
+
#
|
|
41
|
+
# @param [String] code Ruby source
|
|
42
|
+
# @param [Symbol, nil] strategy :safe or :aggressive
|
|
43
|
+
# @param [Boolean, nil] rewrite compatibility alias for aggressive strategy
|
|
44
|
+
# @param [Boolean, nil] merge compatibility alias for safe strategy
|
|
45
|
+
# @param [Docscribe::Config, nil] config config object (defaults to loaded config)
|
|
46
|
+
# @param [String] file source name used for parser locations/debugging
|
|
47
|
+
# @return [String]
|
|
48
|
+
def insert_comments(code, strategy: nil, rewrite: nil, merge: nil, config: nil, file: '(inline)')
|
|
49
|
+
strategy = normalize_strategy(strategy: strategy, rewrite: rewrite, merge: merge)
|
|
50
|
+
|
|
51
|
+
rewrite_with_report(
|
|
52
|
+
code,
|
|
53
|
+
strategy: strategy,
|
|
54
|
+
config: config,
|
|
55
|
+
file: file
|
|
56
|
+
)[:output]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Rewrite source and return both output and structured change information.
|
|
60
|
+
#
|
|
61
|
+
# The result hash includes:
|
|
62
|
+
# - `:output` => rewritten source
|
|
63
|
+
# - `:changes` => structured change records used by CLI explanation output
|
|
64
|
+
#
|
|
65
|
+
# @param [String] code Ruby source
|
|
66
|
+
# @param [Symbol, nil] strategy :safe or :aggressive
|
|
67
|
+
# @param [Boolean, nil] rewrite compatibility alias for aggressive strategy
|
|
68
|
+
# @param [Boolean, nil] merge compatibility alias for safe strategy
|
|
69
|
+
# @param [Docscribe::Config, nil] config config object (defaults to loaded config)
|
|
70
|
+
# @param [String] file source name used for parser locations/debugging
|
|
71
|
+
# @raise [Docscribe::ParseError]
|
|
72
|
+
# @return [Hash]
|
|
73
|
+
def rewrite_with_report(code, strategy: nil, rewrite: nil, merge: nil, config: nil, file: '(inline)')
|
|
74
|
+
strategy = normalize_strategy(strategy: strategy, rewrite: rewrite, merge: merge)
|
|
75
|
+
validate_strategy!(strategy)
|
|
76
|
+
|
|
77
|
+
buffer = Parser::Source::Buffer.new(file.to_s, source: code)
|
|
78
|
+
ast = Docscribe::Parsing.parse_buffer(buffer)
|
|
79
|
+
raise Docscribe::ParseError, "Failed to parse #{file}" unless ast
|
|
80
|
+
|
|
81
|
+
config ||= Docscribe::Config.load
|
|
82
|
+
signature_provider = build_signature_provider(config, code, file.to_s)
|
|
83
|
+
|
|
84
|
+
collector = Docscribe::InlineRewriter::Collector.new(buffer)
|
|
85
|
+
collector.process(ast)
|
|
86
|
+
|
|
87
|
+
method_insertions = collector.insertions
|
|
88
|
+
attr_insertions = collector.respond_to?(:attr_insertions) ? collector.attr_insertions : []
|
|
89
|
+
|
|
90
|
+
all = method_insertions.map { |i| [:method, i] } + attr_insertions.map { |i| [:attr, i] }
|
|
91
|
+
|
|
92
|
+
rewriter = Parser::Source::TreeRewriter.new(buffer)
|
|
93
|
+
merge_inserts = Hash.new { |h, k| h[k] = [] }
|
|
94
|
+
changes = []
|
|
95
|
+
|
|
96
|
+
all.sort_by { |(_kind, ins)| ins.node.loc.expression.begin_pos }
|
|
97
|
+
.reverse_each do |kind, ins|
|
|
98
|
+
case kind
|
|
99
|
+
when :method
|
|
100
|
+
apply_method_insertion!(
|
|
101
|
+
rewriter: rewriter,
|
|
102
|
+
buffer: buffer,
|
|
103
|
+
insertion: ins,
|
|
104
|
+
config: config,
|
|
105
|
+
signature_provider: signature_provider,
|
|
106
|
+
strategy: strategy,
|
|
107
|
+
changes: changes,
|
|
108
|
+
file: file.to_s
|
|
109
|
+
)
|
|
110
|
+
when :attr
|
|
111
|
+
apply_attr_insertion!(
|
|
112
|
+
rewriter: rewriter,
|
|
113
|
+
buffer: buffer,
|
|
114
|
+
insertion: ins,
|
|
115
|
+
config: config,
|
|
116
|
+
signature_provider: signature_provider,
|
|
117
|
+
strategy: strategy,
|
|
118
|
+
merge_inserts: merge_inserts
|
|
119
|
+
)
|
|
39
120
|
end
|
|
40
|
-
elsif already_has_doc_immediately_above?(buffer, bol_range.begin_pos)
|
|
41
|
-
# Skip if a doc already exists immediately above
|
|
42
|
-
next
|
|
43
121
|
end
|
|
44
122
|
|
|
45
|
-
|
|
46
|
-
next unless doc && !doc.empty?
|
|
123
|
+
apply_merge_inserts!(rewriter: rewriter, buffer: buffer, merge_inserts: merge_inserts)
|
|
47
124
|
|
|
48
|
-
rewriter.
|
|
125
|
+
{ output: rewriter.process, changes: changes }
|
|
49
126
|
end
|
|
50
127
|
|
|
51
|
-
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# +Docscribe::InlineRewriter.line_start_range+ -> Range
|
|
55
|
-
#
|
|
56
|
-
# Method documentation.
|
|
57
|
-
#
|
|
58
|
-
# @param [Object] buffer Param documentation.
|
|
59
|
-
# @param [Object] node Param documentation.
|
|
60
|
-
# @return [Range]
|
|
61
|
-
def self.line_start_range(buffer, node)
|
|
62
|
-
start_pos = node.loc.expression.begin_pos
|
|
63
|
-
src = buffer.source
|
|
64
|
-
bol = src.rindex("\n", start_pos - 1) || -1
|
|
65
|
-
Parser::Source::Range.new(buffer, bol + 1, bol + 1)
|
|
66
|
-
end
|
|
128
|
+
private
|
|
67
129
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
130
|
+
# Normalize strategy inputs, including compatibility booleans.
|
|
131
|
+
#
|
|
132
|
+
# Precedence:
|
|
133
|
+
# - explicit `strategy`
|
|
134
|
+
# - `rewrite: true` => `:aggressive`
|
|
135
|
+
# - `merge: true` => `:safe`
|
|
136
|
+
# - default => `:safe`
|
|
137
|
+
#
|
|
138
|
+
# @private
|
|
139
|
+
# @param [Symbol, nil] strategy
|
|
140
|
+
# @param [Boolean, nil] rewrite
|
|
141
|
+
# @param [Boolean, nil] merge
|
|
142
|
+
# @return [Symbol]
|
|
143
|
+
def normalize_strategy(strategy:, rewrite:, merge:)
|
|
144
|
+
return strategy if strategy
|
|
145
|
+
return :aggressive if rewrite
|
|
146
|
+
return :safe if merge
|
|
147
|
+
|
|
148
|
+
:safe
|
|
80
149
|
end
|
|
81
|
-
end
|
|
82
150
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
# Find def line index
|
|
94
|
-
def_line_idx = src[0...def_bol_pos].count("\n")
|
|
95
|
-
i = def_line_idx - 1
|
|
96
|
-
|
|
97
|
-
# Walk up and skip blank lines directly above def
|
|
98
|
-
i -= 1 while i >= 0 && lines[i].strip.empty?
|
|
99
|
-
# Now if the nearest non-blank line isn't a comment, nothing to remove
|
|
100
|
-
return nil unless i >= 0 && lines[i] =~ /^\s*#/
|
|
101
|
-
|
|
102
|
-
# Find the start of the contiguous comment block
|
|
103
|
-
start_idx = i
|
|
104
|
-
start_idx -= 1 while start_idx >= 0 && lines[start_idx] =~ /^\s*#/
|
|
105
|
-
start_idx += 1
|
|
106
|
-
|
|
107
|
-
# End position is at def_bol_pos; start position is BOL of start_idx
|
|
108
|
-
# Compute absolute buffer positions
|
|
109
|
-
# Position of BOL for start_idx:
|
|
110
|
-
start_pos = 0
|
|
111
|
-
if start_idx.positive?
|
|
112
|
-
# Sum lengths of all preceding lines
|
|
113
|
-
start_pos = lines[0...start_idx].join.length
|
|
151
|
+
# Validate a normalized rewrite strategy.
|
|
152
|
+
#
|
|
153
|
+
# @private
|
|
154
|
+
# @param [Symbol] strategy
|
|
155
|
+
# @raise [ArgumentError]
|
|
156
|
+
# @return [void]
|
|
157
|
+
def validate_strategy!(strategy)
|
|
158
|
+
return if %i[safe aggressive].include?(strategy)
|
|
159
|
+
|
|
160
|
+
raise ArgumentError, "Unknown strategy: #{strategy.inspect}"
|
|
114
161
|
end
|
|
115
162
|
|
|
116
|
-
|
|
117
|
-
|
|
163
|
+
# Apply one method insertion according to the selected strategy.
|
|
164
|
+
#
|
|
165
|
+
# Safe strategy:
|
|
166
|
+
# - merge into existing doc-like blocks when present
|
|
167
|
+
# - otherwise insert a full doc block non-destructively
|
|
168
|
+
#
|
|
169
|
+
# Aggressive strategy:
|
|
170
|
+
# - remove the existing doc block (if any)
|
|
171
|
+
# - insert a fresh regenerated block
|
|
172
|
+
#
|
|
173
|
+
# @private
|
|
174
|
+
# @param [Parser::Source::TreeRewriter] rewriter
|
|
175
|
+
# @param [Parser::Source::Buffer] buffer
|
|
176
|
+
# @param [Docscribe::InlineRewriter::Collector::Insertion] insertion
|
|
177
|
+
# @param [Docscribe::Config] config
|
|
178
|
+
# @param [Object, nil] signature_provider
|
|
179
|
+
# @param [Symbol] strategy
|
|
180
|
+
# @param [Array<Hash>] changes structured change records
|
|
181
|
+
# @param [String] file
|
|
182
|
+
# @return [void]
|
|
183
|
+
def apply_method_insertion!(rewriter:, buffer:, insertion:, config:, signature_provider:, strategy:, changes:,
|
|
184
|
+
file:)
|
|
185
|
+
name = SourceHelpers.node_name(insertion.node)
|
|
186
|
+
|
|
187
|
+
return unless config.process_method?(
|
|
188
|
+
container: insertion.container,
|
|
189
|
+
scope: insertion.scope,
|
|
190
|
+
visibility: insertion.visibility,
|
|
191
|
+
name: name
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
anchor_bol_range, = method_bol_ranges(buffer, insertion)
|
|
195
|
+
|
|
196
|
+
case strategy
|
|
197
|
+
when :aggressive
|
|
198
|
+
if (range = method_comment_block_removal_range(buffer, insertion))
|
|
199
|
+
rewriter.remove(range)
|
|
200
|
+
end
|
|
118
201
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
202
|
+
doc = build_method_doc(insertion, config: config, signature_provider: signature_provider)
|
|
203
|
+
return if doc.nil? || doc.empty?
|
|
204
|
+
|
|
205
|
+
rewriter.insert_before(anchor_bol_range, doc)
|
|
206
|
+
|
|
207
|
+
add_change(
|
|
208
|
+
changes,
|
|
209
|
+
type: :insert_full_doc_block,
|
|
210
|
+
insertion: insertion,
|
|
211
|
+
file: file,
|
|
212
|
+
message: 'missing docs'
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
when :safe
|
|
216
|
+
info = method_doc_comment_info(buffer, insertion)
|
|
217
|
+
|
|
218
|
+
if info
|
|
219
|
+
merge_result = build_missing_method_merge_result(
|
|
220
|
+
insertion,
|
|
221
|
+
existing_lines: info[:doc_lines],
|
|
222
|
+
config: config,
|
|
223
|
+
signature_provider: signature_provider
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
missing_lines = merge_result[:lines]
|
|
227
|
+
reason_specs = merge_result[:reasons] || []
|
|
228
|
+
|
|
229
|
+
sorted_existing_doc_lines = Docscribe::InlineRewriter::DocBlock.merge(
|
|
230
|
+
info[:doc_lines],
|
|
231
|
+
missing_lines: [],
|
|
232
|
+
sort_tags: config.sort_tags?,
|
|
233
|
+
tag_order: config.tag_order
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
merged_doc_lines = Docscribe::InlineRewriter::DocBlock.merge(
|
|
237
|
+
info[:doc_lines],
|
|
238
|
+
missing_lines: missing_lines,
|
|
239
|
+
sort_tags: config.sort_tags?,
|
|
240
|
+
tag_order: config.tag_order
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
existing_order_changed = sorted_existing_doc_lines != info[:doc_lines]
|
|
244
|
+
new_block = (info[:preserved_lines] + merged_doc_lines).join
|
|
245
|
+
old_block = info[:lines].join
|
|
246
|
+
|
|
247
|
+
if new_block != old_block
|
|
248
|
+
range = Parser::Source::Range.new(buffer, info[:start_pos], info[:end_pos])
|
|
249
|
+
rewriter.replace(range, new_block)
|
|
250
|
+
|
|
251
|
+
reason_specs.each do |reason|
|
|
252
|
+
add_change(
|
|
253
|
+
changes,
|
|
254
|
+
type: reason[:type],
|
|
255
|
+
insertion: insertion,
|
|
256
|
+
file: file,
|
|
257
|
+
message: reason[:message],
|
|
258
|
+
extra: reason[:extra] || {}
|
|
259
|
+
)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
if existing_order_changed
|
|
263
|
+
add_change(
|
|
264
|
+
changes,
|
|
265
|
+
type: :unsorted_tags,
|
|
266
|
+
insertion: insertion,
|
|
267
|
+
file: file,
|
|
268
|
+
message: 'unsorted tags'
|
|
269
|
+
)
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
return
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
doc = build_method_doc(insertion, config: config, signature_provider: signature_provider)
|
|
277
|
+
return if doc.nil? || doc.empty?
|
|
136
278
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
# @return [nil] if StandardError
|
|
147
|
-
def self.build_doc_for_node(_buffer, insertion, config)
|
|
148
|
-
node = insertion.node
|
|
149
|
-
indent = ' ' * node.loc.expression.column
|
|
150
|
-
|
|
151
|
-
name =
|
|
152
|
-
case node.type
|
|
153
|
-
when :def then node.children[0]
|
|
154
|
-
when :defs then node.children[1]
|
|
279
|
+
rewriter.insert_before(anchor_bol_range, doc)
|
|
280
|
+
|
|
281
|
+
add_change(
|
|
282
|
+
changes,
|
|
283
|
+
type: :insert_full_doc_block,
|
|
284
|
+
insertion: insertion,
|
|
285
|
+
file: file,
|
|
286
|
+
message: 'missing docs'
|
|
287
|
+
)
|
|
155
288
|
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Append a structured change record.
|
|
292
|
+
#
|
|
293
|
+
# @private
|
|
294
|
+
# @param [Array<Hash>] changes
|
|
295
|
+
# @param [Symbol] type
|
|
296
|
+
# @param [Docscribe::InlineRewriter::Collector::Insertion] insertion
|
|
297
|
+
# @param [String] file
|
|
298
|
+
# @param [String] message
|
|
299
|
+
# @param [Integer, nil] line
|
|
300
|
+
# @param [Hash] extra
|
|
301
|
+
# @return [void]
|
|
302
|
+
def add_change(changes, type:, insertion:, file:, message:, line: nil, extra: {})
|
|
303
|
+
changes << {
|
|
304
|
+
type: type,
|
|
305
|
+
file: file,
|
|
306
|
+
line: line || method_line_for(insertion),
|
|
307
|
+
method: method_id_for(insertion),
|
|
308
|
+
message: message
|
|
309
|
+
}.merge(extra)
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
# Build a printable method identifier from a collected insertion.
|
|
313
|
+
#
|
|
314
|
+
# @private
|
|
315
|
+
# @param [Docscribe::InlineRewriter::Collector::Insertion] insertion
|
|
316
|
+
# @return [String]
|
|
317
|
+
def method_id_for(insertion)
|
|
318
|
+
name = SourceHelpers.node_name(insertion.node)
|
|
319
|
+
"#{insertion.container}#{insertion.scope == :instance ? '#' : '.'}#{name}"
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# Apply one attribute insertion according to the selected strategy.
|
|
323
|
+
#
|
|
324
|
+
# @private
|
|
325
|
+
# @param [Parser::Source::TreeRewriter] rewriter
|
|
326
|
+
# @param [Parser::Source::Buffer] buffer
|
|
327
|
+
# @param [Docscribe::InlineRewriter::Collector::AttrInsertion] insertion
|
|
328
|
+
# @param [Docscribe::Config] config
|
|
329
|
+
# @param [Object, nil] signature_provider
|
|
330
|
+
# @param [Symbol] strategy
|
|
331
|
+
# @param [Hash] merge_inserts
|
|
332
|
+
# @return [void]
|
|
333
|
+
def apply_attr_insertion!(rewriter:, buffer:, insertion:, config:, signature_provider:, strategy:, merge_inserts:)
|
|
334
|
+
return unless config.respond_to?(:emit_attributes?) && config.emit_attributes?
|
|
335
|
+
return unless attribute_allowed?(config, insertion)
|
|
336
|
+
|
|
337
|
+
bol_range = SourceHelpers.line_start_range(buffer, insertion.node)
|
|
338
|
+
|
|
339
|
+
case strategy
|
|
340
|
+
when :aggressive
|
|
341
|
+
if (range = SourceHelpers.comment_block_removal_range(buffer, bol_range.begin_pos))
|
|
342
|
+
rewriter.remove(range)
|
|
343
|
+
end
|
|
156
344
|
|
|
157
|
-
|
|
158
|
-
|
|
345
|
+
doc = build_attr_doc_for_node(
|
|
346
|
+
insertion,
|
|
347
|
+
config: config,
|
|
348
|
+
signature_provider: signature_provider
|
|
349
|
+
)
|
|
350
|
+
return if doc.nil? || doc.empty?
|
|
159
351
|
|
|
160
|
-
|
|
161
|
-
container = insertion.container
|
|
352
|
+
rewriter.insert_before(bol_range, doc)
|
|
162
353
|
|
|
163
|
-
|
|
164
|
-
|
|
354
|
+
when :safe
|
|
355
|
+
info = SourceHelpers.doc_comment_block_info(buffer, bol_range.begin_pos)
|
|
165
356
|
|
|
166
|
-
|
|
167
|
-
|
|
357
|
+
if info
|
|
358
|
+
additions = build_attr_merge_additions(
|
|
359
|
+
insertion,
|
|
360
|
+
existing_lines: info[:lines],
|
|
361
|
+
config: config,
|
|
362
|
+
signature_provider: signature_provider
|
|
363
|
+
)
|
|
168
364
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
rescue_specs = spec[:rescues]
|
|
365
|
+
if additions && !additions.empty?
|
|
366
|
+
merge_inserts[info[:end_pos]] << [insertion.node.loc.expression.begin_pos, additions]
|
|
367
|
+
end
|
|
173
368
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
lines << "#{indent}# +#{container}#{method_symbol}#{name}+ -> #{normal_type}"
|
|
177
|
-
lines << "#{indent}#"
|
|
178
|
-
end
|
|
369
|
+
return
|
|
370
|
+
end
|
|
179
371
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
372
|
+
doc = build_attr_doc_for_node(
|
|
373
|
+
insertion,
|
|
374
|
+
config: config,
|
|
375
|
+
signature_provider: signature_provider
|
|
376
|
+
)
|
|
377
|
+
return if doc.nil? || doc.empty?
|
|
183
378
|
|
|
184
|
-
|
|
185
|
-
case visibility
|
|
186
|
-
when :private then lines << "#{indent}# @private"
|
|
187
|
-
when :protected then lines << "#{indent}# @protected"
|
|
379
|
+
rewriter.insert_before(bol_range, doc)
|
|
188
380
|
end
|
|
189
381
|
end
|
|
190
382
|
|
|
191
|
-
|
|
383
|
+
# Apply aggregated merge inserts at shared end positions.
|
|
384
|
+
#
|
|
385
|
+
# Used primarily for attribute merge behavior where multiple additions may target the same block end.
|
|
386
|
+
#
|
|
387
|
+
# @private
|
|
388
|
+
# @param [Parser::Source::TreeRewriter] rewriter
|
|
389
|
+
# @param [Parser::Source::Buffer] buffer
|
|
390
|
+
# @param [Hash{Integer=>Array<(Integer,String)>}] merge_inserts
|
|
391
|
+
# @return [void]
|
|
392
|
+
def apply_merge_inserts!(rewriter:, buffer:, merge_inserts:)
|
|
393
|
+
sep_re = /^\s*#\s*\r?\n$/
|
|
192
394
|
|
|
193
|
-
|
|
395
|
+
merge_inserts.keys.sort.reverse_each do |end_pos|
|
|
396
|
+
chunks = merge_inserts[end_pos]
|
|
397
|
+
next if chunks.empty?
|
|
194
398
|
|
|
195
|
-
|
|
399
|
+
chunks = chunks.sort_by { |(sort_key, _s)| sort_key }
|
|
196
400
|
|
|
197
|
-
|
|
198
|
-
rescue_specs.each do |(exceptions, rtype)|
|
|
199
|
-
ex_display = exceptions.join(', ')
|
|
200
|
-
lines << "#{indent}# @return [#{rtype}] if #{ex_display}"
|
|
201
|
-
end
|
|
202
|
-
end
|
|
401
|
+
out_lines = []
|
|
203
402
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
nil
|
|
207
|
-
end
|
|
403
|
+
chunks.each do |(_k, chunk)|
|
|
404
|
+
next if chunk.nil? || chunk.empty?
|
|
208
405
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
params = []
|
|
225
|
-
(args.children || []).each do |a|
|
|
226
|
-
case a.type
|
|
227
|
-
when :arg
|
|
228
|
-
name = a.children.first.to_s
|
|
229
|
-
ty = Infer.infer_param_type(name, nil)
|
|
230
|
-
params << "#{indent}# @param [#{ty}] #{name} Param documentation."
|
|
231
|
-
when :optarg
|
|
232
|
-
name, default = *a
|
|
233
|
-
ty = Infer.infer_param_type(name.to_s, default&.loc&.expression&.source)
|
|
234
|
-
params << "#{indent}# @param [#{ty}] #{name} Param documentation."
|
|
235
|
-
when :kwarg
|
|
236
|
-
name = "#{a.children.first}:"
|
|
237
|
-
ty = Infer.infer_param_type(name, nil)
|
|
238
|
-
pname = name.sub(/:$/, '')
|
|
239
|
-
params << "#{indent}# @param [#{ty}] #{pname} Param documentation."
|
|
240
|
-
when :kwoptarg
|
|
241
|
-
name, default = *a
|
|
242
|
-
name = "#{name}:"
|
|
243
|
-
ty = Infer.infer_param_type(name, default&.loc&.expression&.source)
|
|
244
|
-
pname = name.sub(/:$/, '')
|
|
245
|
-
params << "#{indent}# @param [#{ty}] #{pname} Param documentation."
|
|
246
|
-
when :restarg
|
|
247
|
-
name = "*#{a.children.first}"
|
|
248
|
-
ty = Infer.infer_param_type(name, nil)
|
|
249
|
-
pname = a.children.first.to_s
|
|
250
|
-
params << "#{indent}# @param [#{ty}] #{pname} Param documentation."
|
|
251
|
-
when :kwrestarg
|
|
252
|
-
name = "**#{a.children.first || 'kwargs'}"
|
|
253
|
-
ty = Infer.infer_param_type(name, nil)
|
|
254
|
-
pname = (a.children.first || 'kwargs').to_s
|
|
255
|
-
params << "#{indent}# @param [#{ty}] #{pname} Param documentation."
|
|
256
|
-
when :blockarg
|
|
257
|
-
name = "&#{a.children.first}"
|
|
258
|
-
ty = Infer.infer_param_type(name, nil)
|
|
259
|
-
pname = a.children.first.to_s
|
|
260
|
-
params << "#{indent}# @param [#{ty}] #{pname} Param documentation."
|
|
261
|
-
when :forward_arg
|
|
262
|
-
# Ruby 3 '...' forwarding; skip
|
|
406
|
+
lines = chunk.lines
|
|
407
|
+
seps = []
|
|
408
|
+
seps << lines.shift while !lines.empty? && lines.first.match?(sep_re)
|
|
409
|
+
|
|
410
|
+
sep = seps.first
|
|
411
|
+
out_lines << sep if sep && (out_lines.empty? || !out_lines.last.match?(sep_re))
|
|
412
|
+
out_lines.concat(lines)
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
text = out_lines.join
|
|
416
|
+
next if text.empty?
|
|
417
|
+
|
|
418
|
+
range = Parser::Source::Range.new(buffer, end_pos, end_pos)
|
|
419
|
+
rewriter.insert_before(range, text)
|
|
263
420
|
end
|
|
264
421
|
end
|
|
265
|
-
params.empty? ? nil : params
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
class VisibilityCtx
|
|
269
|
-
attr_accessor :default_instance_vis, :default_class_vis, :inside_sclass
|
|
270
|
-
attr_reader :explicit_instance, :explicit_class
|
|
271
422
|
|
|
272
|
-
#
|
|
423
|
+
# Build plain-text merge additions for an attribute doc block.
|
|
273
424
|
#
|
|
274
|
-
#
|
|
275
|
-
#
|
|
276
|
-
# @
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
425
|
+
# @private
|
|
426
|
+
# @param [Docscribe::InlineRewriter::Collector::AttrInsertion] ins
|
|
427
|
+
# @param [Array<String>] existing_lines
|
|
428
|
+
# @param [Docscribe::Config] config
|
|
429
|
+
# @param [Object] signature_provider Param documentation.
|
|
430
|
+
# @raise [StandardError]
|
|
431
|
+
# @return [String, nil]
|
|
432
|
+
def build_attr_merge_additions(ins, existing_lines:, config:, signature_provider:)
|
|
433
|
+
indent = SourceHelpers.line_indent(ins.node)
|
|
434
|
+
param_tag_style = config.param_tag_style
|
|
435
|
+
existing = existing_attr_names(existing_lines)
|
|
436
|
+
missing = ins.names.reject { |name_sym| existing[name_sym.to_s] }
|
|
437
|
+
return '' if missing.empty?
|
|
438
|
+
|
|
439
|
+
lines = []
|
|
440
|
+
lines << "#{indent}#" if existing_lines.any? && existing_lines.last.strip != '#'
|
|
441
|
+
|
|
442
|
+
missing.each_with_index do |name_sym, idx|
|
|
443
|
+
attr_name = name_sym.to_s
|
|
444
|
+
mode = ins.access.to_s
|
|
445
|
+
attr_type = attribute_type(ins, name_sym, config, signature_provider: signature_provider)
|
|
446
|
+
|
|
447
|
+
lines << "#{indent}# @!attribute [#{mode}] #{attr_name}"
|
|
448
|
+
|
|
449
|
+
if config.emit_visibility_tags?
|
|
450
|
+
lines << "#{indent}# @private" if ins.visibility == :private
|
|
451
|
+
lines << "#{indent}# @protected" if ins.visibility == :protected
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
lines << "#{indent}# @return [#{attr_type}]" if %i[r rw].include?(ins.access)
|
|
455
|
+
if %i[w rw].include?(ins.access)
|
|
456
|
+
lines << format_attribute_param_tag(indent, 'value', attr_type, style: param_tag_style)
|
|
457
|
+
end
|
|
458
|
+
lines << "#{indent}#" if idx < missing.length - 1
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
lines.map { |l| "#{l}\n" }.join
|
|
462
|
+
rescue StandardError
|
|
463
|
+
nil
|
|
283
464
|
end
|
|
284
465
|
|
|
285
|
-
#
|
|
466
|
+
# Extract already documented attribute names from existing `@!attribute` lines.
|
|
286
467
|
#
|
|
287
|
-
#
|
|
288
|
-
#
|
|
289
|
-
# @return [
|
|
290
|
-
def
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
468
|
+
# @private
|
|
469
|
+
# @param [Array<String>] lines
|
|
470
|
+
# @return [Hash{String=>Boolean}]
|
|
471
|
+
def existing_attr_names(lines)
|
|
472
|
+
names = {}
|
|
473
|
+
|
|
474
|
+
Array(lines).each do |line|
|
|
475
|
+
if (m = line.match(/^\s*#\s*@!attribute\b(?:\s+\[[^\]]+\])?\s+(\S+)/))
|
|
476
|
+
names[m[1]] = true
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
names
|
|
298
481
|
end
|
|
299
|
-
end
|
|
300
482
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
483
|
+
# Decide whether an attribute macro should be emitted according to method filters.
|
|
484
|
+
#
|
|
485
|
+
# @private
|
|
486
|
+
# @param [Docscribe::Config] config
|
|
487
|
+
# @param [Docscribe::InlineRewriter::Collector::AttrInsertion] ins
|
|
488
|
+
# @return [Boolean]
|
|
489
|
+
def attribute_allowed?(config, ins)
|
|
490
|
+
ins.names.any? do |name_sym|
|
|
491
|
+
ok = false
|
|
492
|
+
|
|
493
|
+
if %i[r rw].include?(ins.access)
|
|
494
|
+
ok ||= config.process_method?(
|
|
495
|
+
container: ins.container,
|
|
496
|
+
scope: ins.scope,
|
|
497
|
+
visibility: ins.visibility,
|
|
498
|
+
name: name_sym
|
|
499
|
+
)
|
|
500
|
+
end
|
|
304
501
|
|
|
305
|
-
|
|
502
|
+
if %i[w rw].include?(ins.access)
|
|
503
|
+
ok ||= config.process_method?(
|
|
504
|
+
container: ins.container,
|
|
505
|
+
scope: ins.scope,
|
|
506
|
+
visibility: ins.visibility,
|
|
507
|
+
name: :"#{name_sym}="
|
|
508
|
+
)
|
|
509
|
+
end
|
|
306
510
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
# Method documentation.
|
|
310
|
-
#
|
|
311
|
-
# @param [Object] buffer Param documentation.
|
|
312
|
-
# @return [Object]
|
|
313
|
-
def initialize(buffer)
|
|
314
|
-
super()
|
|
315
|
-
@buffer = buffer
|
|
316
|
-
@insertions = []
|
|
317
|
-
@name_stack = [] # e.g., ['Demo']
|
|
511
|
+
ok
|
|
512
|
+
end
|
|
318
513
|
end
|
|
319
514
|
|
|
320
|
-
#
|
|
515
|
+
# Build a full `@!attribute` documentation block for one attribute insertion.
|
|
321
516
|
#
|
|
322
|
-
#
|
|
323
|
-
#
|
|
324
|
-
# @param [
|
|
325
|
-
# @
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
517
|
+
# @private
|
|
518
|
+
# @param [Docscribe::InlineRewriter::Collector::AttrInsertion] ins
|
|
519
|
+
# @param [Docscribe::Config] config
|
|
520
|
+
# @param [Object] signature_provider Param documentation.
|
|
521
|
+
# @raise [StandardError]
|
|
522
|
+
# @return [String, nil]
|
|
523
|
+
def build_attr_doc_for_node(ins, config:, signature_provider:)
|
|
524
|
+
indent = SourceHelpers.line_indent(ins.node)
|
|
525
|
+
param_tag_style = config.param_tag_style
|
|
526
|
+
lines = []
|
|
527
|
+
|
|
528
|
+
ins.names.each_with_index do |name_sym, idx|
|
|
529
|
+
attr_name = name_sym.to_s
|
|
530
|
+
mode = ins.access.to_s
|
|
531
|
+
attr_type = attribute_type(ins, name_sym, config, signature_provider: signature_provider)
|
|
532
|
+
|
|
533
|
+
lines << "#{indent}# @!attribute [#{mode}] #{attr_name}"
|
|
534
|
+
|
|
535
|
+
if config.emit_visibility_tags?
|
|
536
|
+
lines << "#{indent}# @private" if ins.visibility == :private
|
|
537
|
+
lines << "#{indent}# @protected" if ins.visibility == :protected
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
lines << "#{indent}# @return [#{attr_type}]" if %i[r rw].include?(ins.access)
|
|
541
|
+
if %i[w rw].include?(ins.access)
|
|
542
|
+
lines << format_attribute_param_tag(indent, 'value', attr_type, style: param_tag_style)
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
lines << "#{indent}#" if idx < ins.names.length - 1
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
lines.map { |l| "#{l}\n" }.join
|
|
549
|
+
rescue StandardError
|
|
550
|
+
nil
|
|
333
551
|
end
|
|
334
552
|
|
|
335
|
-
# +Docscribe::InlineRewriter::Collector#on_module+ -> Object
|
|
336
|
-
#
|
|
337
553
|
# Method documentation.
|
|
338
554
|
#
|
|
339
|
-
# @
|
|
340
|
-
# @
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
555
|
+
# @private
|
|
556
|
+
# @param [Object] indent Param documentation.
|
|
557
|
+
# @param [Object] name Param documentation.
|
|
558
|
+
# @param [Object] type Param documentation.
|
|
559
|
+
# @param [Object] style Param documentation.
|
|
560
|
+
# @return [String]
|
|
561
|
+
def format_attribute_param_tag(indent, name, type, style:)
|
|
562
|
+
type = type.to_s
|
|
563
|
+
|
|
564
|
+
case style.to_s
|
|
565
|
+
when 'name_type'
|
|
566
|
+
"#{indent}# @param #{name} [#{type}]"
|
|
567
|
+
else
|
|
568
|
+
"#{indent}# @param [#{type}] #{name}"
|
|
569
|
+
end
|
|
348
570
|
end
|
|
349
571
|
|
|
350
|
-
#
|
|
572
|
+
# Determine the attribute type for one attr name.
|
|
351
573
|
#
|
|
352
|
-
#
|
|
574
|
+
# Prefers the RBS reader signature when available; otherwise falls back to the config fallback type.
|
|
353
575
|
#
|
|
354
|
-
# @
|
|
355
|
-
# @
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
576
|
+
# @private
|
|
577
|
+
# @param [Docscribe::InlineRewriter::Collector::AttrInsertion] ins
|
|
578
|
+
# @param [Symbol] name_sym
|
|
579
|
+
# @param [Docscribe::Config] config
|
|
580
|
+
# @param [Object] signature_provider Param documentation.
|
|
581
|
+
# @raise [StandardError]
|
|
582
|
+
# @return [String]
|
|
583
|
+
def attribute_type(ins, name_sym, config, signature_provider:)
|
|
584
|
+
ty = config.fallback_type
|
|
585
|
+
return ty unless signature_provider
|
|
586
|
+
|
|
587
|
+
reader_sig = signature_provider.signature_for(container: ins.container, scope: ins.scope, name: name_sym)
|
|
588
|
+
reader_sig&.return_type || ty
|
|
589
|
+
rescue StandardError
|
|
590
|
+
config.fallback_type
|
|
359
591
|
end
|
|
360
592
|
|
|
361
|
-
# +Docscribe::InlineRewriter::Collector#on_defs+ -> Object
|
|
362
|
-
#
|
|
363
593
|
# Method documentation.
|
|
364
594
|
#
|
|
365
|
-
# @
|
|
595
|
+
# @private
|
|
596
|
+
# @param [Object] config Param documentation.
|
|
597
|
+
# @param [Object] code Param documentation.
|
|
598
|
+
# @param [Object] file Param documentation.
|
|
599
|
+
# @raise [StandardError]
|
|
366
600
|
# @return [Object]
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
601
|
+
# @return [Object?] if StandardError
|
|
602
|
+
def build_signature_provider(config, code, file)
|
|
603
|
+
if config.respond_to?(:signature_provider_for)
|
|
604
|
+
config.signature_provider_for(source: code, file: file)
|
|
605
|
+
elsif config.respond_to?(:signature_provider)
|
|
606
|
+
config.signature_provider
|
|
607
|
+
elsif config.respond_to?(:rbs_provider)
|
|
608
|
+
config.rbs_provider
|
|
609
|
+
end
|
|
610
|
+
rescue StandardError
|
|
611
|
+
config.respond_to?(:rbs_provider) ? config.rbs_provider : nil
|
|
370
612
|
end
|
|
371
613
|
|
|
372
|
-
private
|
|
373
|
-
|
|
374
|
-
# +Docscribe::InlineRewriter::Collector#process_stmt+ -> Object
|
|
375
|
-
#
|
|
376
614
|
# Method documentation.
|
|
377
615
|
#
|
|
378
616
|
# @private
|
|
379
|
-
# @param [Object]
|
|
380
|
-
# @param [Object]
|
|
617
|
+
# @param [Object] insertion Param documentation.
|
|
618
|
+
# @param [Object] config Param documentation.
|
|
619
|
+
# @param [Object] signature_provider Param documentation.
|
|
381
620
|
# @return [Object]
|
|
382
|
-
def
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
if ctx.inside_sclass
|
|
389
|
-
vis = ctx.explicit_class[name] || ctx.default_class_vis
|
|
390
|
-
scope = :class
|
|
391
|
-
else
|
|
392
|
-
vis = ctx.explicit_instance[name] || ctx.default_instance_vis
|
|
393
|
-
scope = :instance
|
|
394
|
-
end
|
|
395
|
-
@insertions << Insertion.new(node, scope, vis, current_container)
|
|
396
|
-
|
|
397
|
-
when :defs
|
|
398
|
-
_, name, _args, _body = *node
|
|
399
|
-
vis = ctx.explicit_class[name] || ctx.default_class_vis
|
|
400
|
-
@insertions << Insertion.new(node, :class, vis, current_container)
|
|
401
|
-
|
|
402
|
-
when :sclass
|
|
403
|
-
recv, body = *node
|
|
404
|
-
inner_ctx = ctx.dup
|
|
405
|
-
inner_ctx.inside_sclass = self_node?(recv)
|
|
406
|
-
inner_ctx.default_class_vis = :public
|
|
407
|
-
process_body(body, inner_ctx)
|
|
408
|
-
|
|
409
|
-
when :send
|
|
410
|
-
process_visibility_send(node, ctx)
|
|
411
|
-
|
|
412
|
-
else
|
|
413
|
-
process(node)
|
|
414
|
-
end
|
|
621
|
+
def build_method_doc(insertion, config:, signature_provider:)
|
|
622
|
+
DocBuilder.build(
|
|
623
|
+
insertion,
|
|
624
|
+
config: config,
|
|
625
|
+
signature_provider: signature_provider
|
|
626
|
+
)
|
|
415
627
|
end
|
|
416
628
|
|
|
417
|
-
# +Docscribe::InlineRewriter::Collector#process_visibility_send+ -> Object
|
|
418
|
-
#
|
|
419
629
|
# Method documentation.
|
|
420
630
|
#
|
|
421
631
|
# @private
|
|
422
|
-
# @param [Object]
|
|
423
|
-
# @param [Object]
|
|
632
|
+
# @param [Object] insertion Param documentation.
|
|
633
|
+
# @param [Object] existing_lines Param documentation.
|
|
634
|
+
# @param [Object] config Param documentation.
|
|
635
|
+
# @param [Object] signature_provider Param documentation.
|
|
424
636
|
# @return [Object]
|
|
425
|
-
def
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
ctx.default_class_vis = meth
|
|
433
|
-
else
|
|
434
|
-
ctx.default_instance_vis = meth
|
|
435
|
-
end
|
|
436
|
-
else
|
|
437
|
-
# explicit list: affects current def-target
|
|
438
|
-
args.each do |arg|
|
|
439
|
-
sym = extract_name_sym(arg)
|
|
440
|
-
next unless sym
|
|
441
|
-
|
|
442
|
-
if ctx.inside_sclass
|
|
443
|
-
ctx.explicit_class[sym] = meth
|
|
444
|
-
else
|
|
445
|
-
ctx.explicit_instance[sym] = meth
|
|
446
|
-
end
|
|
447
|
-
|
|
448
|
-
target = ctx.inside_sclass ? 'class' : 'instance'
|
|
449
|
-
if args.empty?
|
|
450
|
-
puts "[vis] bare #{meth} -> default_#{target}_vis=#{meth}"
|
|
451
|
-
else
|
|
452
|
-
puts "[vis] explicit #{meth} -> #{target} names=#{args.map { |a| extract_name_sym(a) }.inspect}"
|
|
453
|
-
end
|
|
454
|
-
end
|
|
455
|
-
end
|
|
637
|
+
def build_missing_method_merge_result(insertion, existing_lines:, config:, signature_provider:)
|
|
638
|
+
DocBuilder.build_missing_merge_result(
|
|
639
|
+
insertion,
|
|
640
|
+
existing_lines: existing_lines,
|
|
641
|
+
config: config,
|
|
642
|
+
signature_provider: signature_provider
|
|
643
|
+
)
|
|
456
644
|
end
|
|
457
645
|
|
|
458
|
-
# +Docscribe::InlineRewriter::Collector#extract_name_sym+ -> Object
|
|
459
|
-
#
|
|
460
646
|
# Method documentation.
|
|
461
647
|
#
|
|
462
648
|
# @private
|
|
463
|
-
# @param [Object]
|
|
649
|
+
# @param [Object] buffer Param documentation.
|
|
650
|
+
# @param [Object] insertion Param documentation.
|
|
464
651
|
# @return [Object]
|
|
465
|
-
def
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
652
|
+
def method_doc_comment_info(buffer, insertion)
|
|
653
|
+
anchor_bol_range, def_bol_range = method_bol_ranges(buffer, insertion)
|
|
654
|
+
|
|
655
|
+
SourceHelpers.doc_comment_block_info(buffer, anchor_bol_range.begin_pos) ||
|
|
656
|
+
SourceHelpers.doc_comment_block_info(buffer, def_bol_range.begin_pos)
|
|
470
657
|
end
|
|
471
658
|
|
|
472
|
-
# +Docscribe::InlineRewriter::Collector#self_node?+ -> Object
|
|
473
|
-
#
|
|
474
659
|
# Method documentation.
|
|
475
660
|
#
|
|
476
661
|
# @private
|
|
477
|
-
# @param [Object]
|
|
662
|
+
# @param [Object] buffer Param documentation.
|
|
663
|
+
# @param [Object] insertion Param documentation.
|
|
478
664
|
# @return [Object]
|
|
479
|
-
def
|
|
480
|
-
|
|
665
|
+
def method_comment_block_removal_range(buffer, insertion)
|
|
666
|
+
anchor_bol_range, def_bol_range = method_bol_ranges(buffer, insertion)
|
|
667
|
+
|
|
668
|
+
SourceHelpers.comment_block_removal_range(buffer, anchor_bol_range.begin_pos) ||
|
|
669
|
+
SourceHelpers.comment_block_removal_range(buffer, def_bol_range.begin_pos)
|
|
481
670
|
end
|
|
482
671
|
|
|
483
|
-
# +Docscribe::InlineRewriter::Collector#current_container+ -> Object
|
|
484
|
-
#
|
|
485
672
|
# Method documentation.
|
|
486
673
|
#
|
|
487
674
|
# @private
|
|
488
|
-
# @
|
|
489
|
-
|
|
490
|
-
|
|
675
|
+
# @param [Object] buffer Param documentation.
|
|
676
|
+
# @param [Object] insertion Param documentation.
|
|
677
|
+
# @return [Array]
|
|
678
|
+
def method_bol_ranges(buffer, insertion)
|
|
679
|
+
anchor_node = anchor_node_for(insertion)
|
|
680
|
+
[
|
|
681
|
+
SourceHelpers.line_start_range(buffer, anchor_node),
|
|
682
|
+
SourceHelpers.line_start_range(buffer, insertion.node)
|
|
683
|
+
]
|
|
491
684
|
end
|
|
492
685
|
|
|
493
|
-
# +Docscribe::InlineRewriter::Collector#const_name+ -> Object
|
|
494
|
-
#
|
|
495
686
|
# Method documentation.
|
|
496
687
|
#
|
|
497
688
|
# @private
|
|
498
|
-
# @param [Object]
|
|
689
|
+
# @param [Object] insertion Param documentation.
|
|
690
|
+
# @raise [StandardError]
|
|
499
691
|
# @return [Object]
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
scope, name = *node
|
|
506
|
-
scope_name = scope ? const_name(scope) : nil
|
|
507
|
-
[scope_name, name].compact.join('::')
|
|
508
|
-
when :cbase
|
|
509
|
-
'' # leading ::
|
|
510
|
-
else
|
|
511
|
-
node.loc.expression.source # fallback
|
|
512
|
-
end
|
|
692
|
+
# @return [Object] if StandardError
|
|
693
|
+
def method_line_for(insertion)
|
|
694
|
+
anchor_node_for(insertion).loc.expression.line
|
|
695
|
+
rescue StandardError
|
|
696
|
+
insertion.node.loc.expression.line
|
|
513
697
|
end
|
|
514
698
|
|
|
515
|
-
# +Docscribe::InlineRewriter::Collector#process_body+ -> Object
|
|
516
|
-
#
|
|
517
699
|
# Method documentation.
|
|
518
700
|
#
|
|
519
701
|
# @private
|
|
520
|
-
# @param [Object]
|
|
521
|
-
# @param [Object] ctx Param documentation.
|
|
702
|
+
# @param [Object] insertion Param documentation.
|
|
522
703
|
# @return [Object]
|
|
523
|
-
def
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
if body.type == :begin
|
|
527
|
-
body.children.each { |child| process_stmt(child, ctx) }
|
|
704
|
+
def anchor_node_for(insertion)
|
|
705
|
+
if insertion.respond_to?(:anchor_node) && insertion.anchor_node
|
|
706
|
+
insertion.anchor_node
|
|
528
707
|
else
|
|
529
|
-
|
|
708
|
+
insertion.node
|
|
530
709
|
end
|
|
531
710
|
end
|
|
532
711
|
end
|