docscribe 1.4.1 → 1.5.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 +588 -104
- data/lib/docscribe/cli/check_for_comments.rb +183 -0
- data/lib/docscribe/cli/config_builder.rb +180 -36
- data/lib/docscribe/cli/formatters/json.rb +294 -0
- data/lib/docscribe/cli/formatters/sarif.rb +235 -0
- data/lib/docscribe/cli/formatters/text.rb +208 -0
- data/lib/docscribe/cli/formatters.rb +26 -0
- data/lib/docscribe/cli/generate.rb +296 -125
- data/lib/docscribe/cli/init.rb +58 -14
- data/lib/docscribe/cli/options.rb +410 -133
- data/lib/docscribe/cli/rbs_gen.rb +529 -0
- data/lib/docscribe/cli/run.rb +503 -189
- data/lib/docscribe/cli/sigs.rb +366 -0
- data/lib/docscribe/cli/update_types.rb +103 -0
- data/lib/docscribe/cli.rb +35 -9
- data/lib/docscribe/config/defaults.rb +16 -12
- data/lib/docscribe/config/emit.rb +18 -0
- data/lib/docscribe/config/filtering.rb +37 -31
- data/lib/docscribe/config/loader.rb +20 -13
- data/lib/docscribe/config/plugin.rb +2 -1
- data/lib/docscribe/config/rbs.rb +68 -27
- data/lib/docscribe/config/sorbet.rb +40 -17
- data/lib/docscribe/config/sorting.rb +2 -1
- data/lib/docscribe/config/template.rb +10 -1
- data/lib/docscribe/config/utils.rb +12 -9
- data/lib/docscribe/config.rb +3 -4
- data/lib/docscribe/infer/ast_walk.rb +1 -1
- data/lib/docscribe/infer/constants.rb +15 -0
- data/lib/docscribe/infer/literals.rb +39 -26
- data/lib/docscribe/infer/names.rb +24 -16
- data/lib/docscribe/infer/params.rb +57 -13
- data/lib/docscribe/infer/raises.rb +23 -15
- data/lib/docscribe/infer/returns.rb +784 -199
- data/lib/docscribe/infer.rb +28 -28
- data/lib/docscribe/inline_rewriter/collector.rb +816 -430
- data/lib/docscribe/inline_rewriter/doc_block.rb +323 -150
- data/lib/docscribe/inline_rewriter/doc_builder.rb +1837 -648
- data/lib/docscribe/inline_rewriter/source_helpers.rb +119 -71
- data/lib/docscribe/inline_rewriter/tag_sorter.rb +165 -107
- data/lib/docscribe/inline_rewriter.rb +1144 -727
- data/lib/docscribe/parsing.rb +29 -10
- data/lib/docscribe/plugin/base/collector_plugin.rb +3 -3
- data/lib/docscribe/plugin/base/tag_plugin.rb +1 -2
- data/lib/docscribe/plugin/context.rb +28 -18
- data/lib/docscribe/plugin/registry.rb +49 -23
- data/lib/docscribe/plugin/tag.rb +9 -14
- data/lib/docscribe/plugin.rb +54 -22
- data/lib/docscribe/types/provider_chain.rb +4 -2
- data/lib/docscribe/types/rbs/collection_loader.rb +2 -3
- data/lib/docscribe/types/rbs/provider.rb +127 -62
- data/lib/docscribe/types/rbs/type_formatter.rb +286 -77
- data/lib/docscribe/types/signature.rb +22 -42
- data/lib/docscribe/types/sorbet/base_provider.rb +51 -27
- data/lib/docscribe/types/sorbet/rbi_provider.rb +3 -3
- data/lib/docscribe/types/sorbet/source_provider.rb +3 -2
- data/lib/docscribe/types/yard/formatter.rb +100 -0
- data/lib/docscribe/types/yard/parser.rb +240 -0
- data/lib/docscribe/types/yard/types.rb +52 -0
- data/lib/docscribe/version.rb +1 -1
- metadata +34 -2
|
@@ -18,413 +18,685 @@ module Docscribe
|
|
|
18
18
|
module DocBuilder
|
|
19
19
|
module_function
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
21
|
+
PARAM_TYPE_COLLECTORS = {
|
|
22
|
+
arg: lambda { |arg_node, param_types, external_sig, config|
|
|
23
|
+
collect_param_type(
|
|
24
|
+
arg_node,
|
|
25
|
+
param_types,
|
|
26
|
+
external_sig,
|
|
27
|
+
config,
|
|
28
|
+
infer_name: nil
|
|
29
|
+
)
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
optarg: lambda { |arg_node, param_types, external_sig, config|
|
|
33
|
+
collect_optarg_param_type(
|
|
34
|
+
arg_node,
|
|
35
|
+
param_types,
|
|
36
|
+
external_sig,
|
|
37
|
+
config,
|
|
38
|
+
infer_name: nil
|
|
39
|
+
)
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
kwarg: lambda { |arg_node, param_types, external_sig, config|
|
|
43
|
+
collect_param_type(
|
|
44
|
+
arg_node,
|
|
45
|
+
param_types,
|
|
46
|
+
external_sig,
|
|
47
|
+
config,
|
|
48
|
+
infer_name: ->(param_name) { "#{param_name}:" }
|
|
49
|
+
)
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
kwoptarg: lambda { |arg_node, param_types, external_sig, config|
|
|
53
|
+
collect_optarg_param_type(
|
|
54
|
+
arg_node,
|
|
55
|
+
param_types,
|
|
56
|
+
external_sig,
|
|
57
|
+
config,
|
|
58
|
+
infer_name: ->(param_name) { "#{param_name}:" }
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
}.freeze
|
|
62
|
+
|
|
63
|
+
# Build
|
|
64
|
+
#
|
|
65
|
+
# @note module_function: defines #build (visibility: private)
|
|
66
|
+
# @param [Object] insertion the collected method insertion object
|
|
67
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
68
|
+
# @param [Object] opts additional keyword options forwarded to doc_setup
|
|
35
69
|
# @raise [StandardError]
|
|
36
|
-
# @return [String, nil]
|
|
37
|
-
|
|
70
|
+
# @return [String, nil] if StandardError
|
|
71
|
+
# @return [nil] if StandardError
|
|
72
|
+
def build(insertion, config:, **opts)
|
|
73
|
+
setup = doc_setup(insertion, config: config, **opts)
|
|
74
|
+
return nil unless setup
|
|
75
|
+
|
|
76
|
+
build_unsafe(insertion, config: config, setup: setup, **opts)
|
|
77
|
+
rescue StandardError => e
|
|
78
|
+
debug_warn(e, insertion: insertion, name: '(unknown)', phase: 'DocBuilder.build')
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Build merge additions
|
|
83
|
+
#
|
|
84
|
+
# @note module_function: defines #build_merge_additions (visibility: private)
|
|
85
|
+
# @param [Object] insertion the collected method insertion object
|
|
86
|
+
# @param [Array<String>] existing_lines existing doc comment lines being merged
|
|
87
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
88
|
+
# @param [Object] options additional keyword options forwarded to downstream methods
|
|
89
|
+
# @raise [StandardError]
|
|
90
|
+
# @return [String, nil] if StandardError
|
|
91
|
+
# @return [nil] if StandardError
|
|
92
|
+
def build_merge_additions(insertion, existing_lines:, config:, **options)
|
|
93
|
+
setup = doc_setup(insertion, config: config, **options)
|
|
94
|
+
return '' unless setup
|
|
95
|
+
|
|
96
|
+
info = parse_existing_doc_tags(existing_lines)
|
|
97
|
+
merge_dest_lines(existing_lines, setup: setup, insertion: insertion, config: config, info: info,
|
|
98
|
+
param_types: options[:param_types])
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
debug_warn(e, insertion: insertion, name: setup&.dig(:name) || '(unknown)',
|
|
101
|
+
phase: 'DocBuilder.build_merge_additions')
|
|
102
|
+
nil
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Build missing merge result
|
|
106
|
+
#
|
|
107
|
+
# @note module_function: defines #build_missing_merge_result (visibility: private)
|
|
108
|
+
# @param [Object] insertion the collected method insertion object
|
|
109
|
+
# @param [Array<String>] existing_lines existing doc comment lines being merged
|
|
110
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
111
|
+
# @param [Object] options additional keyword options forwarded to downstream methods
|
|
112
|
+
# @raise [StandardError]
|
|
113
|
+
# @return [Hash<Symbol, Object>] if StandardError
|
|
114
|
+
# @return [Hash] if StandardError
|
|
115
|
+
def build_missing_merge_result(insertion, existing_lines:, config:, **options)
|
|
116
|
+
setup = doc_setup(insertion, config: config, **options)
|
|
117
|
+
return { lines: [], reasons: [] } unless setup
|
|
118
|
+
|
|
119
|
+
info = parse_existing_doc_tags(existing_lines)
|
|
120
|
+
collect_all_missing(setup, info, insertion, config, options)
|
|
121
|
+
rescue StandardError => e
|
|
122
|
+
debug_warn(e, insertion: insertion, name: setup&.dig(:name) || '(unknown)',
|
|
123
|
+
phase: 'DocBuilder.build_missing_merge_result')
|
|
124
|
+
{ lines: [], reasons: [] }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Doc setup
|
|
128
|
+
#
|
|
129
|
+
# @note module_function: defines #doc_setup (visibility: private)
|
|
130
|
+
# @param [Object] insertion the collected method insertion object
|
|
131
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
132
|
+
# @param [Object] opts additional options
|
|
133
|
+
# @return [Hash<Symbol, Object>, nil]
|
|
134
|
+
def doc_setup(insertion, config:, **opts)
|
|
38
135
|
node = insertion.node
|
|
39
136
|
name = SourceHelpers.node_name(node)
|
|
40
137
|
return nil unless name
|
|
41
138
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
139
|
+
setup = extract_base_setup(insertion, name)
|
|
140
|
+
resolve_doc_setup!(setup, node, name, config, opts)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Build unsafe
|
|
144
|
+
#
|
|
145
|
+
# @note module_function: defines #build_unsafe (visibility: private)
|
|
146
|
+
# @param [Object] insertion the collected method insertion object
|
|
147
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
148
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with name, normal_type, scope, visibility
|
|
149
|
+
# @param [Object] opts additional options including infer_default, fallback_type, treat_options_keyword_as_hash
|
|
150
|
+
# @return [String]
|
|
151
|
+
def build_unsafe(insertion, config:, setup:, **opts)
|
|
152
|
+
_, pl, rt = build_param_and_raise_info(setup, config, opts)
|
|
153
|
+
lines = build_doc_lines(setup, config: config, insertion: insertion, params_lines: pl, raise_types: rt,
|
|
154
|
+
override_tags: opts[:override_tags],
|
|
155
|
+
return_description: opts[:return_description],
|
|
156
|
+
description: opts[:description])
|
|
157
|
+
lines.map { |l| "#{l}\n" }.join
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Build param and raise info
|
|
161
|
+
#
|
|
162
|
+
# @note module_function: defines #build_param_and_raise_info (visibility: private)
|
|
163
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with name, normal_type, scope, visibility
|
|
164
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
165
|
+
# @param [Hash<Symbol, Object>] opts additional options including
|
|
166
|
+
# @return [(Hash<String, String>, nil, Array<String>, nil, Array<String>)]
|
|
167
|
+
def build_param_and_raise_info(setup, config, opts)
|
|
168
|
+
pt = opts[:param_types] || build_param_types_from_node(setup[:node], external_sig: setup[:external_sig],
|
|
169
|
+
config: config)
|
|
170
|
+
pl = if config.emit_param_tags?
|
|
171
|
+
build_params_lines(setup[:node], setup[:indent], external_sig: setup[:external_sig], config: config,
|
|
172
|
+
param_types_override: pt,
|
|
173
|
+
param_descriptions: opts[:param_descriptions])
|
|
174
|
+
end
|
|
175
|
+
rt = config.emit_raise_tags? ? Docscribe::Infer.infer_raises_from_node(setup[:node]) : [] #: Array[String]
|
|
176
|
+
[pt, pl, rt]
|
|
177
|
+
end
|
|
47
178
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
179
|
+
# Resolve doc setup
|
|
180
|
+
#
|
|
181
|
+
# @note module_function: defines #resolve_doc_setup! (visibility: private)
|
|
182
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with name, normal_type, scope, visibility
|
|
183
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
184
|
+
# @param [Symbol] name the method name string
|
|
185
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
186
|
+
# @param [Hash<Symbol, Object>] opts additional options including
|
|
187
|
+
# @return [Hash<Symbol, Object>]
|
|
188
|
+
def resolve_doc_setup!(setup, node, name, config, opts)
|
|
189
|
+
external_sig = resolve_external_sig(setup[:container], setup[:scope], name, opts[:signature_provider])
|
|
190
|
+
returns_spec = compute_returns_spec(node, config, opts[:param_types], opts[:core_rbs_provider])
|
|
191
|
+
normal_type = opts[:return_type_override] || external_sig&.return_type || returns_spec[:normal]
|
|
192
|
+
|
|
193
|
+
setup.merge(
|
|
194
|
+
external_sig: external_sig,
|
|
195
|
+
normal_type: normal_type,
|
|
196
|
+
rescue_specs: returns_spec[:rescues] || []
|
|
52
197
|
)
|
|
198
|
+
end
|
|
53
199
|
|
|
54
|
-
|
|
55
|
-
|
|
200
|
+
# Extract base setup
|
|
201
|
+
#
|
|
202
|
+
# @note module_function: defines #extract_base_setup (visibility: private)
|
|
203
|
+
# @param [Object] insertion the collected method insertion object
|
|
204
|
+
# @param [Symbol] name the method name string
|
|
205
|
+
# @return [Hash<Symbol, Object>]
|
|
206
|
+
def extract_base_setup(insertion, name)
|
|
207
|
+
n = insertion.node
|
|
208
|
+
{ node: n, name: name, indent: SourceHelpers.line_indent(n), scope: insertion.scope,
|
|
209
|
+
visibility: insertion.visibility, container: insertion.container,
|
|
210
|
+
method_symbol: insertion.scope == :instance ? '#' : '.' }
|
|
211
|
+
end
|
|
56
212
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
213
|
+
# Resolve external sig
|
|
214
|
+
#
|
|
215
|
+
# @note module_function: defines #resolve_external_sig (visibility: private)
|
|
216
|
+
# @param [String] container method container name
|
|
217
|
+
# @param [Symbol] scope method scope symbol
|
|
218
|
+
# @param [Symbol] name the method name string
|
|
219
|
+
# @param [Docscribe::Types::ProviderChain, nil] signature_provider external sig provider
|
|
220
|
+
# @return [Docscribe::Types::MethodSignature, nil]
|
|
221
|
+
def resolve_external_sig(container, scope, name, signature_provider)
|
|
222
|
+
signature_provider&.signature_for(container: container, scope: scope, name: name)
|
|
223
|
+
end
|
|
61
224
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
225
|
+
# Compute returns spec
|
|
226
|
+
#
|
|
227
|
+
# @note module_function: defines #compute_returns_spec (visibility: private)
|
|
228
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
229
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
230
|
+
# @param [Hash<String, String>, nil] param_types hash accumulating parameter name-to-type mappings
|
|
231
|
+
# @param [Object] core_rbs_provider RBS type provider
|
|
232
|
+
# @return [Hash<Symbol, Object>]
|
|
233
|
+
def compute_returns_spec(node, config, param_types, core_rbs_provider)
|
|
234
|
+
Docscribe::Infer.returns_spec_from_node(
|
|
235
|
+
node, fallback_type: config.fallback_type, nil_as_optional: config.nil_as_optional?,
|
|
236
|
+
param_types: param_types, core_rbs_provider: core_rbs_provider
|
|
68
237
|
)
|
|
238
|
+
end
|
|
69
239
|
|
|
70
|
-
|
|
71
|
-
|
|
240
|
+
# Parse existing doc tags
|
|
241
|
+
#
|
|
242
|
+
# @note module_function: defines #parse_existing_doc_tags (visibility: private)
|
|
243
|
+
# @param [Array<String>] lines existing doc comment lines
|
|
244
|
+
# @return [Hash<Symbol, Object>] parsed tag info
|
|
245
|
+
def parse_existing_doc_tags(lines)
|
|
246
|
+
init = init_parse_info
|
|
247
|
+
tags_started = false
|
|
248
|
+
joined_lines = join_multiline_tags(Array(lines))
|
|
249
|
+
joined_lines.each_with_object(init) do |line, info|
|
|
250
|
+
extract_all_comment_tags(line, info)
|
|
251
|
+
tags_started = parse_existing_tag_line(line, info, tags_started)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
72
254
|
|
|
73
|
-
|
|
255
|
+
# Join @param/@return/@raise tag lines where the type bracket spans multiple lines.
|
|
256
|
+
#
|
|
257
|
+
# @note module_function: defines #join_multiline_tags (visibility: private)
|
|
258
|
+
# @param [Array<String>] lines doc comment lines
|
|
259
|
+
# @return [Array<String>]
|
|
260
|
+
def join_multiline_tags(lines)
|
|
261
|
+
result = [] #: Array[String]
|
|
262
|
+
i = 0
|
|
263
|
+
i = consume_tag_or_copy(lines, i, result) while i < lines.length
|
|
264
|
+
result
|
|
265
|
+
end
|
|
74
266
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
267
|
+
# Consume tag line or copy verbatim
|
|
268
|
+
#
|
|
269
|
+
# @note module_function: defines #consume_tag_or_copy (visibility: private)
|
|
270
|
+
# @param [Array<String>] lines doc comment lines
|
|
271
|
+
# @param [Integer] idx current line index
|
|
272
|
+
# @param [Array<String>] result result accumulator array
|
|
273
|
+
# @return [Integer]
|
|
274
|
+
def consume_tag_or_copy(lines, idx, result)
|
|
275
|
+
if (c = lines[idx].sub(/^\s*#\s*/, '')) =~ /^@(param|return|raise)\s+\[/ && unbalanced_bracket?(c)
|
|
276
|
+
buffer, consumed = join_tag_continuations(lines, idx)
|
|
277
|
+
result << "# #{buffer}"
|
|
278
|
+
idx + consumed
|
|
279
|
+
else
|
|
280
|
+
result << lines[idx]
|
|
281
|
+
idx + 1
|
|
78
282
|
end
|
|
283
|
+
end
|
|
79
284
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
285
|
+
# Join continuation lines for a multi-line tag type bracket.
|
|
286
|
+
#
|
|
287
|
+
# @note module_function: defines #join_tag_continuations (visibility: private)
|
|
288
|
+
# @param [Array<String>] lines all doc comment lines
|
|
289
|
+
# @param [Integer] start index of the @param/@return/@raise line
|
|
290
|
+
# @return [(String, Integer)] joined content and number of lines consumed
|
|
291
|
+
def join_tag_continuations(lines, start)
|
|
292
|
+
buffer = +lines[start].sub(/^\s*#\s*/, '').dup
|
|
293
|
+
i = start + 1
|
|
294
|
+
while i < lines.length
|
|
295
|
+
continuation = lines[i].sub(/^\s*#[ \t]/, '')
|
|
296
|
+
break unless continuation.start_with?(' ')
|
|
297
|
+
|
|
298
|
+
buffer << continuation.rstrip
|
|
299
|
+
i += 1
|
|
300
|
+
break unless unbalanced_bracket?(buffer)
|
|
83
301
|
end
|
|
302
|
+
[buffer, i - start]
|
|
303
|
+
end
|
|
84
304
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
305
|
+
# Check if bracket depth is positive (an opening `[` is unclosed).
|
|
306
|
+
#
|
|
307
|
+
# @note module_function: defines #unbalanced_bracket? (visibility: private)
|
|
308
|
+
# @param [String] str string to check
|
|
309
|
+
# @return [Boolean]
|
|
310
|
+
def unbalanced_bracket?(str)
|
|
311
|
+
depth = 0
|
|
312
|
+
str.each_char do |c|
|
|
313
|
+
depth += 1 if c == '['
|
|
314
|
+
depth -= 1 if c == ']'
|
|
92
315
|
end
|
|
316
|
+
depth.positive?
|
|
317
|
+
end
|
|
93
318
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
319
|
+
# Parse a single doc comment line for tag info.
|
|
320
|
+
#
|
|
321
|
+
# @note module_function: defines #parse_existing_tag_line (visibility: private)
|
|
322
|
+
# @param [String] line the doc comment line
|
|
323
|
+
# @param [Hash<Symbol, Object>] info mutable parse info accumulator
|
|
324
|
+
# @param [Boolean] tags_started whether @tags have been seen
|
|
325
|
+
# @return [Boolean] updated tags_started
|
|
326
|
+
def parse_existing_tag_line(line, info, tags_started)
|
|
327
|
+
content = line.sub(/^\s*# ?/, '').rstrip
|
|
328
|
+
if content.start_with?('@')
|
|
329
|
+
tags_started = true.tap { track_last_tag(content, info) }
|
|
330
|
+
start_note_tag(line, info) if content.start_with?('@note ')
|
|
331
|
+
elsif tags_started && info[:last_tag]
|
|
332
|
+
append_note_continuation(line, info).tap { append_tag_continuation(content, info) }
|
|
333
|
+
else
|
|
334
|
+
info[:description] << content
|
|
104
335
|
end
|
|
336
|
+
tags_started
|
|
337
|
+
end
|
|
105
338
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
339
|
+
# Start a note tag
|
|
340
|
+
#
|
|
341
|
+
# @note module_function: defines #start_note_tag (visibility: private)
|
|
342
|
+
# @param [String] line doc comment line
|
|
343
|
+
# @param [Hash<Symbol, Object>] info parse info hash
|
|
344
|
+
# @return [void]
|
|
345
|
+
def start_note_tag(line, info)
|
|
346
|
+
return if line.match?(/^\s*#\s*@note\s+module_function:/)
|
|
109
347
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
end
|
|
115
|
-
plugin_tags = Docscribe::Plugin.run_tag_plugins(build_plugin_context(insertion, normal_type: normal_type))
|
|
116
|
-
plugin_tags.concat(Array(override_tags)) if override_tags
|
|
348
|
+
empty = [] #: Array[String]
|
|
349
|
+
info[:note_lines] << empty
|
|
350
|
+
info[:note_lines].last << line.chomp
|
|
351
|
+
end
|
|
117
352
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
353
|
+
# Append note continuation lines
|
|
354
|
+
#
|
|
355
|
+
# @note module_function: defines #append_note_continuation (visibility: private)
|
|
356
|
+
# @param [String] line doc comment line
|
|
357
|
+
# @param [Hash<Symbol, Object>] info parse info hash
|
|
358
|
+
# @return [Object]
|
|
359
|
+
def append_note_continuation(line, info)
|
|
360
|
+
return unless info[:last_tag] == :note && info[:note_lines].any?
|
|
361
|
+
|
|
362
|
+
info[:note_lines].last << line.chomp
|
|
123
363
|
end
|
|
124
364
|
|
|
125
|
-
#
|
|
126
|
-
# doc-like block.
|
|
365
|
+
# Init parse info
|
|
127
366
|
#
|
|
128
|
-
#
|
|
367
|
+
# @note module_function: defines #init_parse_info (visibility: private)
|
|
368
|
+
# @return [Hash<Symbol, Object>]
|
|
369
|
+
def init_parse_info
|
|
370
|
+
{
|
|
371
|
+
param_names: {}, param_types: {}, param_descriptions: {},
|
|
372
|
+
raise_types: {}, plugin_tags: {},
|
|
373
|
+
has_return: false, return_type: nil, return_description: nil,
|
|
374
|
+
has_private: false, has_protected: false, has_module_function_note: false,
|
|
375
|
+
description: [],
|
|
376
|
+
last_tag: nil, last_param: nil,
|
|
377
|
+
note_lines: []
|
|
378
|
+
}
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Merge dest lines
|
|
129
382
|
#
|
|
130
|
-
# @note module_function:
|
|
131
|
-
# @param [
|
|
132
|
-
# @param [
|
|
133
|
-
# @param [Docscribe::Config] config
|
|
134
|
-
# @param [Object, nil] signature_provider
|
|
135
|
-
# @param [nil] core_rbs_provider Param documentation.
|
|
136
|
-
# @param [nil] param_types Param documentation.
|
|
137
|
-
# @param [nil] return_type_override Param documentation.
|
|
138
|
-
# @raise [StandardError]
|
|
383
|
+
# @note module_function: defines #merge_dest_lines (visibility: private)
|
|
384
|
+
# @param [Array<String>] existing_lines existing doc comment lines to merge into
|
|
385
|
+
# @param [Object] ctx merge context hash (setup, insertion, config, info, param_types)
|
|
139
386
|
# @return [String, nil]
|
|
140
|
-
def
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
name = SourceHelpers.node_name(node)
|
|
144
|
-
return '' unless name
|
|
387
|
+
def merge_dest_lines(existing_lines, **ctx)
|
|
388
|
+
merge_lines_with_context(existing_lines, **ctx)
|
|
389
|
+
end
|
|
145
390
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
391
|
+
# Merge lines with context
|
|
392
|
+
#
|
|
393
|
+
# @note module_function: defines #merge_lines_with_context (visibility: private)
|
|
394
|
+
# @param [Array<String>] existing_lines existing doc comment lines being merged
|
|
395
|
+
# @param [Object] ctx merge context (setup, insertion, config, info, param_types)
|
|
396
|
+
# @return [String]
|
|
397
|
+
def merge_lines_with_context(existing_lines, **ctx)
|
|
398
|
+
s = ctx[:setup]
|
|
399
|
+
i = s[:indent]
|
|
400
|
+
config = ctx[:config]
|
|
401
|
+
info = ctx[:info]
|
|
402
|
+
base_ary = build_initial_line_ary(existing_lines, i)
|
|
403
|
+
line_ary = merge_all_tag_lines(base_ary, s: s, i: i, config: config, info: info,
|
|
404
|
+
insertion: ctx[:insertion], param_types: ctx[:param_types])
|
|
405
|
+
useful = line_ary.reject { |l| l.strip == '#' }
|
|
406
|
+
return '' if useful.empty?
|
|
150
407
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
scope: scope,
|
|
154
|
-
name: name
|
|
155
|
-
)
|
|
408
|
+
line_ary.map { |l| "#{l}\n" }.join
|
|
409
|
+
end
|
|
156
410
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
411
|
+
# Build initial line ary
|
|
412
|
+
#
|
|
413
|
+
# @note module_function: defines #build_initial_line_ary (visibility: private)
|
|
414
|
+
# @param [Array<String>] existing_lines existing doc comment lines being merged
|
|
415
|
+
# @param [String] indent indentation string for the doc line
|
|
416
|
+
# @return [Array<String>]
|
|
417
|
+
def build_initial_line_ary(existing_lines, indent)
|
|
418
|
+
existing_lines.any? && existing_lines.last.strip != '#' ? ["#{indent}#"] : []
|
|
419
|
+
end
|
|
164
420
|
|
|
165
|
-
|
|
166
|
-
|
|
421
|
+
# Merge all tag lines
|
|
422
|
+
#
|
|
423
|
+
# @note module_function: defines #merge_all_tag_lines (visibility: private)
|
|
424
|
+
# @param [Array<String>] base_ary initial line array
|
|
425
|
+
# @param [Object] ctx context hash with setup, config, info, insertion, param_types
|
|
426
|
+
# @return [Array<String>]
|
|
427
|
+
def merge_all_tag_lines(base_ary, **ctx)
|
|
428
|
+
line_ary = base_ary.dup
|
|
429
|
+
merge_tag_lines_core(line_ary, ctx)
|
|
430
|
+
line_ary.concat(merge_rescue_return_lines(ctx[:i], ctx[:s][:rescue_specs], ctx[:config], ctx[:info]))
|
|
431
|
+
line_ary
|
|
432
|
+
end
|
|
167
433
|
|
|
168
|
-
|
|
169
|
-
|
|
434
|
+
# Merge tag lines core
|
|
435
|
+
#
|
|
436
|
+
# @note module_function: defines #merge_tag_lines_core (visibility: private)
|
|
437
|
+
# @param [Array<String>] line_ary output line array
|
|
438
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
439
|
+
# @return [void]
|
|
440
|
+
def merge_tag_lines_core(line_ary, ctx)
|
|
441
|
+
append_merge_tag_lines(line_ary, ctx)
|
|
442
|
+
merge_return_line(line_ary, ctx[:i], ctx[:s], ctx[:config], ctx[:info])
|
|
443
|
+
end
|
|
170
444
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
445
|
+
# Append merge tag lines
|
|
446
|
+
#
|
|
447
|
+
# @note module_function: defines #append_merge_tag_lines (visibility: private)
|
|
448
|
+
# @param [Array<String>] line_ary output line array
|
|
449
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
450
|
+
# @return [void]
|
|
451
|
+
def append_merge_tag_lines(line_ary, ctx)
|
|
452
|
+
line_ary.concat(build_all_merge_tags(ctx))
|
|
453
|
+
end
|
|
178
454
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
455
|
+
# Build all merge tags
|
|
456
|
+
#
|
|
457
|
+
# @note module_function: defines #build_all_merge_tags (visibility: private)
|
|
458
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
459
|
+
# @return [Array<String>]
|
|
460
|
+
def build_all_merge_tags(ctx)
|
|
461
|
+
i = ctx[:i]
|
|
462
|
+
s = ctx[:s]
|
|
463
|
+
c = ctx[:config]
|
|
464
|
+
info = ctx[:info]
|
|
465
|
+
[merge_visibility_tag_lines(i, s[:visibility], c, info),
|
|
466
|
+
merge_module_function_note_lines(i, ctx[:insertion], s[:name], info),
|
|
467
|
+
merge_param_lines(s[:node], i, config: c, external_sig: s[:external_sig],
|
|
468
|
+
param_types: ctx[:param_types], info: info),
|
|
469
|
+
merge_raise_tag_lines(s[:node], i, c, info)].flatten
|
|
470
|
+
end
|
|
184
471
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
472
|
+
# Merge return line
|
|
473
|
+
#
|
|
474
|
+
# @note module_function: defines #merge_return_line (visibility: private)
|
|
475
|
+
# @param [Array<String>] line_ary output line array
|
|
476
|
+
# @param [String] indent indentation string for doc comment lines
|
|
477
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with node, name, types, scope
|
|
478
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
479
|
+
# @param [Hash<Symbol, Object>] info parse info hash to update with visibility flags
|
|
480
|
+
# @return [void]
|
|
481
|
+
def merge_return_line(line_ary, indent, setup, config, info)
|
|
482
|
+
emit_ret = config.emit_return_tag?(setup[:scope], setup[:visibility])
|
|
483
|
+
ret_line = merge_return_tag_line(indent, setup[:normal_type], config: config, scope: setup[:scope],
|
|
484
|
+
visibility: setup[:visibility], info: info)
|
|
190
485
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
end
|
|
486
|
+
line_ary << ret_line if emit_ret && ret_line
|
|
487
|
+
end
|
|
194
488
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
489
|
+
# Collect all missing
|
|
490
|
+
#
|
|
491
|
+
# @note module_function: defines #collect_all_missing (visibility: private)
|
|
492
|
+
# @param [Hash<Symbol, Object>] setup resolved setup hash with node, name, indent, types
|
|
493
|
+
# @param [Hash<Symbol, Object>] info parsed existing doc tag information
|
|
494
|
+
# @param [Object] insertion the collected method insertion object
|
|
495
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
496
|
+
# @param [Hash<Symbol, Object>] options additional options hash forwarded to missing collector
|
|
497
|
+
# @return [Hash<Symbol, Object>]
|
|
498
|
+
def collect_all_missing(setup, info, insertion, config, options)
|
|
499
|
+
s = setup
|
|
500
|
+
ctx = { node: s[:node], indent: s[:indent], config: config, external_sig: s[:external_sig],
|
|
501
|
+
info: info, strategy: options[:strategy], scope: s[:scope], visibility: s[:visibility],
|
|
502
|
+
normal_type: s[:normal_type], rescue_specs: s[:rescue_specs], insertion: insertion,
|
|
503
|
+
param_types: options[:param_types], override_tags: options[:override_tags] }
|
|
504
|
+
collect_missing_all(ctx)
|
|
505
|
+
end
|
|
201
506
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
507
|
+
# Collect missing all
|
|
508
|
+
#
|
|
509
|
+
# @note module_function: defines #collect_missing_all (visibility: private)
|
|
510
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
511
|
+
# @return [Hash<Symbol, Object>]
|
|
512
|
+
def collect_missing_all(ctx)
|
|
513
|
+
lines = [] #: Array[String]
|
|
514
|
+
reasons = [] #: Array[Hash[Symbol, untyped]]
|
|
515
|
+
collect_missing_visibility!(lines, reasons, **ctx)
|
|
516
|
+
collect_missing_module_function_note!(lines, reasons, **ctx)
|
|
517
|
+
collect_missing_params!(lines, reasons, **ctx)
|
|
518
|
+
collect_missing_raises!(lines, reasons, **ctx)
|
|
519
|
+
collect_missing_return!(lines, reasons, **ctx)
|
|
520
|
+
collect_missing_rescue_returns!(lines, reasons, **ctx)
|
|
521
|
+
collect_missing_plugin_tags!(lines, reasons, **ctx)
|
|
522
|
+
{ lines: lines, reasons: reasons }
|
|
523
|
+
end
|
|
205
524
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
525
|
+
# Extract param info
|
|
526
|
+
#
|
|
527
|
+
# @note module_function: defines #extract_all_comment_tags (visibility: private)
|
|
528
|
+
# @param [String] line single comment line
|
|
529
|
+
# @param [Hash<Symbol, Object>] info parse info hash
|
|
530
|
+
# @return [void]
|
|
531
|
+
def extract_all_comment_tags(line, info)
|
|
532
|
+
extract_param_info(line, info[:param_names], info[:param_types], info[:param_descriptions])
|
|
533
|
+
extract_return_info(line, info)
|
|
534
|
+
extract_visibility_info(line, info)
|
|
535
|
+
extract_raise_info(line, info[:raise_types])
|
|
536
|
+
extract_plugin_info(line, info[:plugin_tags])
|
|
537
|
+
end
|
|
211
538
|
|
|
212
|
-
|
|
213
|
-
|
|
539
|
+
# Extract param info from tag line
|
|
540
|
+
#
|
|
541
|
+
# @note module_function: defines #extract_param_info (visibility: private)
|
|
542
|
+
# @param [String] line a single doc comment line to parse
|
|
543
|
+
# @param [Hash<String, Boolean>] param_names hash tracking existing @param names
|
|
544
|
+
# @param [Hash<String, String>] param_types hash tracking existing @param types
|
|
545
|
+
# @param [Hash<String, String>, nil] param_descriptions param descriptions hash
|
|
546
|
+
# @return [void]
|
|
547
|
+
def extract_param_info(line, param_names, param_types, param_descriptions = nil)
|
|
548
|
+
return unless (pname = extract_param_name_from_param_line(line))
|
|
214
549
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
550
|
+
param_names[pname] = true
|
|
551
|
+
ptype = extract_param_type_from_param_line(line)
|
|
552
|
+
return unless ptype
|
|
553
|
+
|
|
554
|
+
param_types[pname] = ptype
|
|
555
|
+
return unless param_descriptions
|
|
556
|
+
|
|
557
|
+
desc = extract_param_description(line)
|
|
558
|
+
param_descriptions[pname] = desc if desc
|
|
219
559
|
end
|
|
220
560
|
|
|
221
|
-
#
|
|
561
|
+
# Extract return info
|
|
222
562
|
#
|
|
223
|
-
#
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
-
#
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
# @param [Array<String>] existing_lines
|
|
230
|
-
# @param [Docscribe::Config] config
|
|
231
|
-
# @param [Object, nil] signature_provider
|
|
232
|
-
# @param [nil] core_rbs_provider Param documentation.
|
|
233
|
-
# @param [nil] param_types Param documentation.
|
|
234
|
-
# @param [nil] strategy Param documentation.
|
|
235
|
-
# @param [nil] return_type_override Param documentation.
|
|
236
|
-
# @param [nil] override_tags Param documentation.
|
|
237
|
-
# @raise [StandardError]
|
|
238
|
-
# @return [Hash]
|
|
239
|
-
def build_missing_merge_result(insertion, existing_lines:, config:, signature_provider: nil,
|
|
240
|
-
core_rbs_provider: nil, param_types: nil, strategy: nil, return_type_override: nil, override_tags: nil)
|
|
241
|
-
node = insertion.node
|
|
242
|
-
name = SourceHelpers.node_name(node)
|
|
243
|
-
return { lines: [], reasons: [] } unless name
|
|
244
|
-
|
|
245
|
-
indent = SourceHelpers.line_indent(node)
|
|
246
|
-
info = parse_existing_doc_tags(existing_lines)
|
|
247
|
-
scope = insertion.scope
|
|
248
|
-
visibility = insertion.visibility
|
|
563
|
+
# @note module_function: defines #extract_return_info (visibility: private)
|
|
564
|
+
# @param [String] line a single doc comment line to parse
|
|
565
|
+
# @param [Hash<Symbol, Object>] info parse info hash to update with return data
|
|
566
|
+
# @return [void]
|
|
567
|
+
def extract_return_info(line, info)
|
|
568
|
+
return unless line.match?(/^\s*#\s*@return\b/)
|
|
249
569
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
name: name
|
|
254
|
-
)
|
|
570
|
+
info[:has_return] = true
|
|
571
|
+
content = line.sub(/^\s*#\s*/, '')
|
|
572
|
+
return unless (m = content.match(/@return\s+/))
|
|
255
573
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
param_types: param_types,
|
|
261
|
-
core_rbs_provider: core_rbs_provider
|
|
262
|
-
)
|
|
574
|
+
return_type, return_desc = parse_return_rest(m.post_match)
|
|
575
|
+
info[:return_type] = return_type if return_type
|
|
576
|
+
info[:return_description] = return_desc if return_desc
|
|
577
|
+
end
|
|
263
578
|
|
|
264
|
-
|
|
265
|
-
|
|
579
|
+
# Parse return type from rest string
|
|
580
|
+
#
|
|
581
|
+
# @note module_function: defines #parse_return_rest (visibility: private)
|
|
582
|
+
# @param [String] rest remaining tag content
|
|
583
|
+
# @return [(String, String, nil), nil]
|
|
584
|
+
def parse_return_rest(rest)
|
|
585
|
+
return unless rest[0] == '['
|
|
266
586
|
|
|
267
|
-
|
|
268
|
-
reasons = []
|
|
587
|
+
type_end = find_matching_close_bracket(rest) or return
|
|
269
588
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
elsif visibility == :protected && !info[:has_protected]
|
|
275
|
-
lines << "#{indent}# @protected\n"
|
|
276
|
-
reasons << { type: :missing_visibility, message: 'missing @protected' }
|
|
277
|
-
end
|
|
278
|
-
end
|
|
589
|
+
return_type = rest[1...type_end] #: String
|
|
590
|
+
desc = rest[(type_end + 1)..]&.strip
|
|
591
|
+
[return_type, desc&.empty? ? nil : desc]
|
|
592
|
+
end
|
|
279
593
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
all_params&.each do |pl|
|
|
291
|
-
pname = extract_param_name_from_param_line(pl)
|
|
292
|
-
next unless pname
|
|
293
|
-
|
|
294
|
-
if !info[:param_names].include?(pname)
|
|
295
|
-
lines << "#{pl}\n"
|
|
296
|
-
reasons << { type: :missing_param, message: "missing @param #{pname}", extra: { param: pname } }
|
|
297
|
-
elsif external_sig && info[:param_types][pname]
|
|
298
|
-
new_type = extract_param_type_from_param_line(pl)
|
|
299
|
-
if new_type && info[:param_types][pname] != new_type
|
|
300
|
-
lines << "#{pl}\n" unless strategy == :safe
|
|
301
|
-
reasons << {
|
|
302
|
-
type: :updated_param,
|
|
303
|
-
message: "updated @param #{pname} from #{info[:param_types][pname]} to #{new_type}",
|
|
304
|
-
extra: { param: pname }
|
|
305
|
-
}
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
end
|
|
309
|
-
end
|
|
594
|
+
# Extract all comment tags from line
|
|
595
|
+
#
|
|
596
|
+
# @note module_function: defines #track_last_tag (visibility: private)
|
|
597
|
+
# @param [String] content
|
|
598
|
+
# @param [Hash<Symbol, Object>] info parse info hash
|
|
599
|
+
# @return [void]
|
|
600
|
+
def track_last_tag(content, info)
|
|
601
|
+
tag = content.match(/@(\w+)/)&.[](1)&.to_sym
|
|
602
|
+
info[:last_tag] = tag
|
|
603
|
+
return unless tag == :param
|
|
310
604
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
missing = inferred.reject { |rt| existing[rt] }
|
|
605
|
+
pname = extract_param_name_from_param_line(content)
|
|
606
|
+
info[:last_param] = pname if pname
|
|
607
|
+
end
|
|
315
608
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
609
|
+
# Append continuation to current tag
|
|
610
|
+
#
|
|
611
|
+
# @note module_function: defines #append_tag_continuation (visibility: private)
|
|
612
|
+
# @param [String] content tag continuation text
|
|
613
|
+
# @param [Hash<Symbol, Object>] info parse info hash
|
|
614
|
+
# @return [void]
|
|
615
|
+
def append_tag_continuation(content, info)
|
|
616
|
+
text = content.strip
|
|
617
|
+
return if text.empty?
|
|
321
618
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
reasons << { type: :missing_return, message: 'missing @return' }
|
|
326
|
-
elsif external_sig && info[:return_type] && info[:return_type] != normal_type
|
|
327
|
-
lines << "#{indent}# @return [#{normal_type}]\n" unless strategy == :safe
|
|
328
|
-
reasons << {
|
|
329
|
-
type: :updated_return,
|
|
330
|
-
message: "updated @return from #{info[:return_type]} to #{normal_type}"
|
|
331
|
-
}
|
|
332
|
-
end
|
|
333
|
-
end
|
|
619
|
+
append_to_return_description(text, info) if info[:last_tag] == :return
|
|
620
|
+
append_to_param_description(text, info) if info[:last_tag] == :param
|
|
621
|
+
end
|
|
334
622
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
623
|
+
# Append text to return description
|
|
624
|
+
#
|
|
625
|
+
# @note module_function: defines #append_to_return_description (visibility: private)
|
|
626
|
+
# @param [String] text text to append
|
|
627
|
+
# @param [Hash<Symbol, Object>] info parse info hash
|
|
628
|
+
# @return [void]
|
|
629
|
+
def append_to_return_description(text, info)
|
|
630
|
+
if info[:return_description]
|
|
631
|
+
info[:return_description] += "\n#{text}"
|
|
632
|
+
else
|
|
633
|
+
info[:return_description] = text
|
|
343
634
|
end
|
|
344
|
-
|
|
345
|
-
plugin_tags.concat(Array(override_tags)) if override_tags
|
|
635
|
+
end
|
|
346
636
|
|
|
347
|
-
|
|
348
|
-
|
|
637
|
+
# Append text to param description
|
|
638
|
+
#
|
|
639
|
+
# @note module_function: defines #append_to_param_description (visibility: private)
|
|
640
|
+
# @param [String] text text to append
|
|
641
|
+
# @param [Hash<Symbol, Object>] info parse info hash
|
|
642
|
+
# @return [void]
|
|
643
|
+
def append_to_param_description(text, info)
|
|
644
|
+
pname = info[:last_param]
|
|
645
|
+
return unless pname
|
|
349
646
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
647
|
+
if info[:param_descriptions][pname]
|
|
648
|
+
info[:param_descriptions][pname] += "\n#{text}"
|
|
649
|
+
else
|
|
650
|
+
info[:param_descriptions][pname] = text
|
|
353
651
|
end
|
|
354
|
-
{ lines: lines, reasons: reasons }
|
|
355
|
-
rescue StandardError => e
|
|
356
|
-
debug_warn(e, insertion: insertion, name: name || '(unknown)', phase: 'DocBuilder.build_missing_merge_result')
|
|
357
|
-
{ lines: [], reasons: [] }
|
|
358
652
|
end
|
|
359
653
|
|
|
360
|
-
#
|
|
654
|
+
# Extract visibility info
|
|
361
655
|
#
|
|
362
|
-
#
|
|
363
|
-
#
|
|
364
|
-
#
|
|
365
|
-
# @
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
has_return = false
|
|
372
|
-
return_type = nil
|
|
373
|
-
has_private = false
|
|
374
|
-
has_protected = false
|
|
375
|
-
has_module_function_note = false
|
|
376
|
-
raise_types = {}
|
|
377
|
-
plugin_tags = {}
|
|
378
|
-
|
|
379
|
-
Array(lines).each do |line|
|
|
380
|
-
if (m = line.match(/^\s*#\s*@(\w+)\b/))
|
|
381
|
-
plugin_tags[m[1]] = true
|
|
382
|
-
end
|
|
383
|
-
if (pname = extract_param_name_from_param_line(line))
|
|
384
|
-
param_names[pname] = true
|
|
385
|
-
if (type_match = line.match(/@param\s+\[([^\]]+)\]\s+\S+/) || line.match(/@param\s+\S+\s+\[([^\]]+)\]/))
|
|
386
|
-
param_types[pname] = type_match[1]
|
|
387
|
-
end
|
|
388
|
-
end
|
|
656
|
+
# @note module_function: defines #extract_visibility_info (visibility: private)
|
|
657
|
+
# @param [String] line a single doc comment line to parse
|
|
658
|
+
# @param [Hash<Symbol, Object>] info parse info hash to update with visibility flags
|
|
659
|
+
# @return [void]
|
|
660
|
+
def extract_visibility_info(line, info)
|
|
661
|
+
info[:has_private] ||= line.match?(/^\s*#\s*@private\b/)
|
|
662
|
+
info[:has_protected] ||= line.match?(/^\s*#\s*@protected\b/)
|
|
663
|
+
info[:has_module_function_note] ||= line.match?(/^\s*#\s*@note\s+module_function:/)
|
|
664
|
+
end
|
|
389
665
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
666
|
+
# Extract raise info
|
|
667
|
+
#
|
|
668
|
+
# @note module_function: defines #extract_raise_info (visibility: private)
|
|
669
|
+
# @param [String] line a single doc comment line to parse
|
|
670
|
+
# @param [Hash<String, Boolean>] raise_types hash tracking existing @raise types
|
|
671
|
+
# @return [void]
|
|
672
|
+
def extract_raise_info(line, raise_types)
|
|
673
|
+
extract_raise_types_from_line(line).each { |t| raise_types[t || ''] = true }
|
|
674
|
+
end
|
|
399
675
|
|
|
400
|
-
|
|
401
|
-
|
|
676
|
+
# Extract plugin info
|
|
677
|
+
#
|
|
678
|
+
# @note module_function: defines #extract_plugin_info (visibility: private)
|
|
679
|
+
# @param [String] line a single doc comment line to parse
|
|
680
|
+
# @param [Hash<String, Boolean>] plugin_tags hash tracking existing plugin tag names
|
|
681
|
+
# @return [void]
|
|
682
|
+
def extract_plugin_info(line, plugin_tags)
|
|
683
|
+
return unless (m = line.match(/^\s*#\s*@(\w+)\b/))
|
|
402
684
|
|
|
403
|
-
|
|
404
|
-
param_names: param_names,
|
|
405
|
-
param_types: param_types,
|
|
406
|
-
has_return: has_return,
|
|
407
|
-
return_type: return_type,
|
|
408
|
-
raise_types: raise_types,
|
|
409
|
-
has_private: has_private,
|
|
410
|
-
has_protected: has_protected,
|
|
411
|
-
has_module_function_note: has_module_function_note,
|
|
412
|
-
plugin_tags: plugin_tags
|
|
413
|
-
}
|
|
685
|
+
plugin_tags[m[1] || ''] = true
|
|
414
686
|
end
|
|
415
687
|
|
|
416
|
-
# Extract
|
|
688
|
+
# Extract raise types from line
|
|
417
689
|
#
|
|
418
|
-
# @note module_function:
|
|
690
|
+
# @note module_function: defines #extract_raise_types_from_line (visibility: private)
|
|
419
691
|
# @param [String] line a `@raise` doc line
|
|
420
692
|
# @raise [StandardError]
|
|
421
|
-
# @return [String, nil]
|
|
422
|
-
# @return [Array] if StandardError
|
|
693
|
+
# @return [Array<String, nil>] if StandardError
|
|
694
|
+
# @return [Array] if StandardError
|
|
423
695
|
def extract_raise_types_from_line(line)
|
|
424
696
|
return [] unless line.match?(/^\s*#\s*@raise\b/)
|
|
425
697
|
|
|
426
698
|
if (m = line.match(/^\s*#\s*@raise\s*\[([^\]]+)\]/))
|
|
427
|
-
parse_raise_bracket_list(m[1])
|
|
699
|
+
parse_raise_bracket_list(m[1]) # steep:ignore ArgumentTypeMismatch
|
|
428
700
|
elsif (m = line.match(/^\s*#\s*@raise\s+([A-Z]\w*(?:::[A-Z]\w*)*)/))
|
|
429
701
|
[m[1]]
|
|
430
702
|
else
|
|
@@ -434,361 +706,1311 @@ module Docscribe
|
|
|
434
706
|
[]
|
|
435
707
|
end
|
|
436
708
|
|
|
437
|
-
# Parse
|
|
709
|
+
# Parse raise bracket list
|
|
438
710
|
#
|
|
439
|
-
# @note module_function:
|
|
440
|
-
# @param [String]
|
|
441
|
-
# @return [Array<String
|
|
442
|
-
def parse_raise_bracket_list(
|
|
443
|
-
|
|
711
|
+
# @note module_function: defines #parse_raise_bracket_list (visibility: private)
|
|
712
|
+
# @param [String] str comma-separated exception names string from @raise brackets
|
|
713
|
+
# @return [Array<String>] the exception names or nil
|
|
714
|
+
def parse_raise_bracket_list(str)
|
|
715
|
+
str.to_s.split(',').map(&:strip).reject(&:empty?)
|
|
444
716
|
end
|
|
445
717
|
|
|
446
|
-
# Build
|
|
718
|
+
# Build param types from node
|
|
447
719
|
#
|
|
448
|
-
# @note module_function:
|
|
449
|
-
# @private
|
|
720
|
+
# @note module_function: defines #build_param_types_from_node (visibility: private)
|
|
450
721
|
# @param [Parser::AST::Node] node def or defs node
|
|
451
|
-
# @param [
|
|
452
|
-
# @param [Docscribe::Config] config
|
|
453
|
-
# @return [Hash
|
|
722
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external signature if available
|
|
723
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
724
|
+
# @return [Hash<String, String>, nil]
|
|
454
725
|
def build_param_types_from_node(node, external_sig:, config:)
|
|
455
|
-
return
|
|
726
|
+
return unless node
|
|
456
727
|
|
|
457
|
-
args =
|
|
458
|
-
|
|
459
|
-
when :def then node.children[1]
|
|
460
|
-
when :defs then node.children[2]
|
|
461
|
-
end
|
|
728
|
+
args = extract_args_from_node(node)
|
|
729
|
+
return unless args
|
|
462
730
|
|
|
463
|
-
|
|
731
|
+
param_types = {} #: Hash[String, String]
|
|
732
|
+
collect_all_param_types(args, param_types, external_sig, config)
|
|
733
|
+
param_types.empty? ? nil : param_types
|
|
734
|
+
end
|
|
464
735
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
pname, default = *a
|
|
482
|
-
pname = pname.to_s
|
|
483
|
-
default_src = default&.loc&.expression&.source
|
|
484
|
-
ty = external_sig&.param_types&.[](pname) ||
|
|
485
|
-
Infer.infer_param_type(
|
|
486
|
-
pname,
|
|
487
|
-
default_src,
|
|
488
|
-
fallback_type: config.fallback_type,
|
|
489
|
-
treat_options_keyword_as_hash: config.treat_options_keyword_as_hash?
|
|
490
|
-
)
|
|
491
|
-
param_types[pname] = ty
|
|
492
|
-
|
|
493
|
-
when :kwarg
|
|
494
|
-
pname = a.children.first.to_s
|
|
495
|
-
ty = external_sig&.param_types&.[](pname) ||
|
|
496
|
-
Infer.infer_param_type(
|
|
497
|
-
"#{pname}:",
|
|
498
|
-
nil,
|
|
499
|
-
fallback_type: config.fallback_type,
|
|
500
|
-
treat_options_keyword_as_hash: config.treat_options_keyword_as_hash?
|
|
501
|
-
)
|
|
502
|
-
param_types[pname] = ty
|
|
503
|
-
|
|
504
|
-
when :kwoptarg
|
|
505
|
-
pname, default = *a
|
|
506
|
-
pname = pname.to_s
|
|
507
|
-
default_src = default&.loc&.expression&.source
|
|
508
|
-
ty = external_sig&.param_types&.[](pname) ||
|
|
509
|
-
Infer.infer_param_type(
|
|
510
|
-
"#{pname}:",
|
|
511
|
-
default_src,
|
|
512
|
-
fallback_type: config.fallback_type,
|
|
513
|
-
treat_options_keyword_as_hash: config.treat_options_keyword_as_hash?
|
|
514
|
-
)
|
|
515
|
-
param_types[pname] = ty
|
|
736
|
+
# Collect all param types
|
|
737
|
+
#
|
|
738
|
+
# @note module_function: defines #collect_all_param_types (visibility: private)
|
|
739
|
+
# @param [Parser::AST::Node] args arguments AST node
|
|
740
|
+
# @param [Hash<String, String>] param_types hash accumulating parameter name-to-type mappings
|
|
741
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
742
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
743
|
+
# @return [void]
|
|
744
|
+
def collect_all_param_types(args, param_types, external_sig, config)
|
|
745
|
+
# Pre-seed param_types with positional (unnamed) RBS types so that
|
|
746
|
+
# collectors can keep them when external_sig lacks param names.
|
|
747
|
+
positional = Array(external_sig&.positional_types)
|
|
748
|
+
(args.children || []).each_with_index do |a, idx|
|
|
749
|
+
if (ptype = positional[idx])
|
|
750
|
+
pname = a.children.first
|
|
751
|
+
param_types[pname.to_s] = ptype if pname
|
|
516
752
|
end
|
|
753
|
+
collector = PARAM_TYPE_COLLECTORS[a.type]
|
|
754
|
+
collector&.call(a, param_types, external_sig, config)
|
|
517
755
|
end
|
|
756
|
+
end
|
|
518
757
|
|
|
519
|
-
|
|
758
|
+
# Collect param type
|
|
759
|
+
#
|
|
760
|
+
# @note module_function: defines #collect_param_type (visibility: private)
|
|
761
|
+
# @param [Parser::AST::Node] arg_node AST node for the required/keyword argument
|
|
762
|
+
# @param [Hash<String, String>] param_types hash accumulating parameter name-to-type mappings
|
|
763
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
764
|
+
# @param [Docscribe::Config] config Docscribe configuration for fallback type options
|
|
765
|
+
# @param [Proc, nil] infer_name lambda to transform parameter name for inference
|
|
766
|
+
# @return [void]
|
|
767
|
+
def collect_param_type(arg_node, param_types, external_sig, config, infer_name:)
|
|
768
|
+
pname = arg_node.children.first.to_s
|
|
769
|
+
param_types[pname] ||= begin
|
|
770
|
+
infer_pname = resolve_infer_name(pname, infer_name)
|
|
771
|
+
external_sig&.param_types&.[](pname) ||
|
|
772
|
+
Infer.infer_param_type(infer_pname, nil,
|
|
773
|
+
fallback_type: config.fallback_type,
|
|
774
|
+
treat_options_keyword_as_hash: config.treat_options_keyword_as_hash?)
|
|
775
|
+
end
|
|
520
776
|
end
|
|
521
777
|
|
|
522
|
-
#
|
|
778
|
+
# Collect optarg param type
|
|
523
779
|
#
|
|
524
|
-
#
|
|
780
|
+
# @note module_function: defines #collect_optarg_param_type (visibility: private)
|
|
781
|
+
# @param [Parser::AST::Node] arg_node AST node for the optional/keyword optional argument
|
|
782
|
+
# @param [Hash<String, String>] param_types hash accumulating parameter name-to-type mappings
|
|
783
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
784
|
+
# @param [Docscribe::Config] config Docscribe configuration for fallback type options
|
|
785
|
+
# @param [Proc, nil] infer_name lambda to transform parameter name for inference
|
|
786
|
+
# @return [void]
|
|
787
|
+
def collect_optarg_param_type(arg_node, param_types, external_sig, config, infer_name:)
|
|
788
|
+
pname, default = *arg_node
|
|
789
|
+
pname = pname.to_s
|
|
790
|
+
param_types[pname] ||= begin
|
|
791
|
+
default_src = source_from_node(default)
|
|
792
|
+
infer_pname = resolve_infer_name(pname, infer_name)
|
|
793
|
+
external_sig&.param_types&.[](pname) ||
|
|
794
|
+
Infer.infer_param_type(infer_pname, default_src,
|
|
795
|
+
fallback_type: config.fallback_type,
|
|
796
|
+
treat_options_keyword_as_hash: config.treat_options_keyword_as_hash?)
|
|
797
|
+
end
|
|
798
|
+
end
|
|
799
|
+
|
|
800
|
+
# Merge visibility tag lines
|
|
525
801
|
#
|
|
526
|
-
# @note module_function:
|
|
527
|
-
# @param [
|
|
528
|
-
# @param [
|
|
529
|
-
# @param [Docscribe::
|
|
530
|
-
# @param [
|
|
531
|
-
# @
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
fallback_type = config.fallback_type
|
|
535
|
-
treat_options_keyword_as_hash = config.treat_options_keyword_as_hash?
|
|
536
|
-
param_tag_style = config.param_tag_style
|
|
537
|
-
param_documentation = config.include_param_documentation? ? config.param_documentation : ''
|
|
538
|
-
|
|
539
|
-
args =
|
|
540
|
-
case node.type
|
|
541
|
-
when :def then node.children[1]
|
|
542
|
-
when :defs then node.children[2]
|
|
543
|
-
end
|
|
802
|
+
# @note module_function: defines #merge_visibility_tag_lines (visibility: private)
|
|
803
|
+
# @param [String] indent indentation string for the doc line
|
|
804
|
+
# @param [Symbol] visibility method visibility symbol
|
|
805
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
806
|
+
# @param [Hash<Symbol, Object>] info parse info hash to update with visibility flags
|
|
807
|
+
# @return [Array<String>]
|
|
808
|
+
def merge_visibility_tag_lines(indent, visibility, config, info)
|
|
809
|
+
return [] unless config.emit_visibility_tags?
|
|
544
810
|
|
|
545
|
-
|
|
811
|
+
if visibility == :private && !info[:has_private]
|
|
812
|
+
["#{indent}# @private"]
|
|
813
|
+
elsif visibility == :protected && !info[:has_protected]
|
|
814
|
+
["#{indent}# @protected"]
|
|
815
|
+
else
|
|
816
|
+
[]
|
|
817
|
+
end
|
|
818
|
+
end
|
|
546
819
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
fallback_type: fallback_type,
|
|
559
|
-
treat_options_keyword_as_hash: treat_options_keyword_as_hash
|
|
560
|
-
)
|
|
561
|
-
params << format_param_tag(indent, pname, ty, param_documentation, style: param_tag_style)
|
|
562
|
-
|
|
563
|
-
when :optarg
|
|
564
|
-
pname, default = *a
|
|
565
|
-
pname = pname.to_s
|
|
566
|
-
default_src = default&.loc&.expression&.source
|
|
567
|
-
ty = external_sig&.param_types&.[](pname) ||
|
|
568
|
-
override_param_type_for(pname, param_types_override) ||
|
|
569
|
-
Infer.infer_param_type(
|
|
570
|
-
pname,
|
|
571
|
-
default_src,
|
|
572
|
-
fallback_type: fallback_type,
|
|
573
|
-
treat_options_keyword_as_hash: treat_options_keyword_as_hash
|
|
574
|
-
)
|
|
575
|
-
params << format_param_tag(indent, pname, ty, param_documentation, style: param_tag_style)
|
|
576
|
-
|
|
577
|
-
hash_option_pairs(default).each do |pair|
|
|
578
|
-
key_node, value_node = pair.children
|
|
579
|
-
option_key = option_key_name(key_node)
|
|
580
|
-
option_type = Infer::Literals.type_from_literal(value_node, fallback_type: fallback_type)
|
|
581
|
-
option_default = node_default_literal(value_node)
|
|
582
|
-
|
|
583
|
-
line = "#{indent}# @option #{pname} [#{option_type}] :#{option_key}"
|
|
584
|
-
line += " (#{option_default})" if option_default
|
|
585
|
-
line += ' Option documentation.'
|
|
586
|
-
params << line
|
|
587
|
-
end
|
|
588
|
-
|
|
589
|
-
when :kwarg
|
|
590
|
-
pname = a.children.first.to_s
|
|
591
|
-
ty = external_sig&.param_types&.[](pname) ||
|
|
592
|
-
override_param_type_for(pname, param_types_override) ||
|
|
593
|
-
Infer.infer_param_type(
|
|
594
|
-
"#{pname}:",
|
|
595
|
-
nil,
|
|
596
|
-
fallback_type: fallback_type,
|
|
597
|
-
treat_options_keyword_as_hash: treat_options_keyword_as_hash
|
|
598
|
-
)
|
|
599
|
-
params << format_param_tag(indent, pname, ty, param_documentation, style: param_tag_style)
|
|
600
|
-
|
|
601
|
-
when :kwoptarg
|
|
602
|
-
pname, default = *a
|
|
603
|
-
pname = pname.to_s
|
|
604
|
-
default_src = default&.loc&.expression&.source
|
|
605
|
-
ty = external_sig&.param_types&.[](pname) ||
|
|
606
|
-
override_param_type_for(pname, param_types_override) ||
|
|
607
|
-
Infer.infer_param_type(
|
|
608
|
-
"#{pname}:",
|
|
609
|
-
default_src,
|
|
610
|
-
fallback_type: fallback_type,
|
|
611
|
-
treat_options_keyword_as_hash: treat_options_keyword_as_hash
|
|
612
|
-
)
|
|
613
|
-
params << format_param_tag(indent, pname, ty, param_documentation, style: param_tag_style)
|
|
614
|
-
|
|
615
|
-
when :restarg
|
|
616
|
-
pname = (a.children.first || 'args').to_s
|
|
617
|
-
ty =
|
|
618
|
-
if external_sig&.rest_positional&.element_type
|
|
619
|
-
"Array<#{external_sig.rest_positional.element_type}>"
|
|
620
|
-
else
|
|
621
|
-
override_param_type_for(pname, param_types_override) ||
|
|
622
|
-
Infer.infer_param_type(
|
|
623
|
-
"*#{pname}",
|
|
624
|
-
nil,
|
|
625
|
-
fallback_type: fallback_type,
|
|
626
|
-
treat_options_keyword_as_hash: treat_options_keyword_as_hash
|
|
627
|
-
)
|
|
628
|
-
end
|
|
629
|
-
params << format_param_tag(indent, pname, ty, param_documentation, style: param_tag_style)
|
|
630
|
-
|
|
631
|
-
when :kwrestarg
|
|
632
|
-
pname = (a.children.first || 'kwargs').to_s
|
|
633
|
-
ty = external_sig&.rest_keywords&.type ||
|
|
634
|
-
override_param_type_for(pname, param_types_override) ||
|
|
635
|
-
Infer.infer_param_type(
|
|
636
|
-
"**#{pname}",
|
|
637
|
-
nil,
|
|
638
|
-
fallback_type: fallback_type,
|
|
639
|
-
treat_options_keyword_as_hash: treat_options_keyword_as_hash
|
|
640
|
-
)
|
|
641
|
-
params << format_param_tag(indent, pname, ty, param_documentation, style: param_tag_style)
|
|
642
|
-
|
|
643
|
-
when :blockarg
|
|
644
|
-
pname = (a.children.first || 'block').to_s
|
|
645
|
-
ty = external_sig&.param_types&.[](pname) ||
|
|
646
|
-
override_param_type_for(pname, param_types_override) ||
|
|
647
|
-
Infer.infer_param_type(
|
|
648
|
-
"&#{pname}",
|
|
649
|
-
nil,
|
|
650
|
-
fallback_type: fallback_type,
|
|
651
|
-
treat_options_keyword_as_hash: treat_options_keyword_as_hash
|
|
652
|
-
)
|
|
653
|
-
params << format_param_tag(indent, pname, ty, param_documentation, style: param_tag_style)
|
|
654
|
-
|
|
655
|
-
when :forward_arg
|
|
656
|
-
# skip
|
|
657
|
-
end
|
|
820
|
+
# Merge module function note lines
|
|
821
|
+
#
|
|
822
|
+
# @note module_function: defines #merge_module_function_note_lines (visibility: private)
|
|
823
|
+
# @param [String] indent indentation string for the doc line
|
|
824
|
+
# @param [Object] insertion the collected method insertion object
|
|
825
|
+
# @param [String] name the method name string
|
|
826
|
+
# @param [Hash<Symbol, Object>] info parse info hash to update with visibility flags
|
|
827
|
+
# @return [Array<String>]
|
|
828
|
+
def merge_module_function_note_lines(indent, insertion, name, info)
|
|
829
|
+
unless insertion.respond_to?(:module_function) && insertion.module_function && !info[:has_module_function_note]
|
|
830
|
+
return []
|
|
658
831
|
end
|
|
659
832
|
|
|
660
|
-
|
|
833
|
+
included_vis = insertion.included_instance_visibility || :private
|
|
834
|
+
["#{indent}# @note module_function: defines ##{name} (visibility: #{included_vis})"]
|
|
661
835
|
end
|
|
662
836
|
|
|
663
|
-
#
|
|
837
|
+
# Merge param lines
|
|
664
838
|
#
|
|
665
|
-
# @note module_function:
|
|
666
|
-
# @param [
|
|
667
|
-
# @param [
|
|
668
|
-
# @
|
|
669
|
-
|
|
670
|
-
|
|
839
|
+
# @note module_function: defines #merge_param_lines (visibility: private)
|
|
840
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
841
|
+
# @param [String] indent indentation string for the doc line
|
|
842
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
843
|
+
# @param [Object] opts additional options including external_sig, param_types, info
|
|
844
|
+
# @return [Array<String>]
|
|
845
|
+
def merge_param_lines(node, indent, config:, **opts)
|
|
846
|
+
return [] unless config.emit_param_tags?
|
|
671
847
|
|
|
672
|
-
|
|
673
|
-
|
|
848
|
+
all_params = build_params_lines(node, indent, external_sig: opts[:external_sig], config: config,
|
|
849
|
+
param_types_override: opts[:param_types])
|
|
850
|
+
return [] unless all_params
|
|
851
|
+
|
|
852
|
+
info = opts[:info]
|
|
853
|
+
all_params.each_with_object([]) do |pl, result|
|
|
854
|
+
pname = extract_param_name_from_param_line(pl)
|
|
855
|
+
next if pname.nil? || info[:param_names].include?(pname)
|
|
856
|
+
|
|
857
|
+
result << pl
|
|
858
|
+
end
|
|
674
859
|
end
|
|
675
860
|
|
|
676
|
-
#
|
|
861
|
+
# Merge raise tag lines
|
|
677
862
|
#
|
|
678
|
-
# @note module_function:
|
|
679
|
-
# @param [
|
|
680
|
-
# @param [String]
|
|
681
|
-
# @param [
|
|
682
|
-
# @param [
|
|
683
|
-
# @
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
doc = documentation.to_s.strip
|
|
687
|
-
type = type.to_s
|
|
688
|
-
|
|
689
|
-
line = case style.to_s
|
|
690
|
-
when 'name_type'
|
|
691
|
-
"#{indent}# @param #{name} [#{type}]"
|
|
692
|
-
else
|
|
693
|
-
"#{indent}# @param [#{type}] #{name}"
|
|
694
|
-
end
|
|
863
|
+
# @note module_function: defines #merge_raise_tag_lines (visibility: private)
|
|
864
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
865
|
+
# @param [String] indent indentation string for the doc line
|
|
866
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
867
|
+
# @param [Hash<Symbol, Object>] info parse info hash to update with visibility flags
|
|
868
|
+
# @return [Array<String>]
|
|
869
|
+
def merge_raise_tag_lines(node, indent, config, info)
|
|
870
|
+
return [] unless config.emit_raise_tags?
|
|
695
871
|
|
|
696
|
-
|
|
872
|
+
inferred = Docscribe::Infer.infer_raises_from_node(node)
|
|
873
|
+
existing = info[:raise_types] || {}
|
|
874
|
+
inferred.reject { |rt| existing[rt] }
|
|
875
|
+
.map { |rt| "#{indent}# @raise [#{rt}]" }
|
|
697
876
|
end
|
|
698
877
|
|
|
699
|
-
#
|
|
878
|
+
# Merge return tag line
|
|
700
879
|
#
|
|
701
|
-
# @note module_function:
|
|
702
|
-
# @param [
|
|
703
|
-
# @
|
|
704
|
-
|
|
705
|
-
|
|
880
|
+
# @note module_function: defines #merge_return_tag_line (visibility: private)
|
|
881
|
+
# @param [String] indent indentation string for the doc line
|
|
882
|
+
# @param [String] normal_type resolved return type
|
|
883
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
884
|
+
# @param [Object] opts additional options including scope, visibility, info
|
|
885
|
+
# @return [String, nil]
|
|
886
|
+
def merge_return_tag_line(indent, normal_type, config:, **opts)
|
|
887
|
+
return unless config.emit_return_tag?(opts[:scope], opts[:visibility])
|
|
888
|
+
return if opts[:info][:has_return]
|
|
706
889
|
|
|
707
|
-
|
|
890
|
+
"#{indent}# @return [#{normal_type}]"
|
|
708
891
|
end
|
|
709
892
|
|
|
710
|
-
#
|
|
893
|
+
# Merge rescue return lines
|
|
711
894
|
#
|
|
712
|
-
# @note module_function:
|
|
713
|
-
# @param [
|
|
714
|
-
# @
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
895
|
+
# @note module_function: defines #merge_rescue_return_lines (visibility: private)
|
|
896
|
+
# @param [String] indent indentation string for the doc line
|
|
897
|
+
# @param [Array<(Array<String>, String)>] rescue_specs rescue type specs
|
|
898
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
899
|
+
# @param [Hash<Symbol, Object>] info parse info hash to update with visibility flags
|
|
900
|
+
# @return [Array<String>]
|
|
901
|
+
def merge_rescue_return_lines(indent, rescue_specs, config, info)
|
|
902
|
+
return [] unless config.emit_rescue_conditional_returns?
|
|
903
|
+
return [] if info[:has_return]
|
|
904
|
+
|
|
905
|
+
rescue_specs.map do |exceptions, rtype|
|
|
906
|
+
"#{indent}# @return [#{rtype}] if #{exceptions.join(', ')}"
|
|
721
907
|
end
|
|
722
908
|
end
|
|
723
909
|
|
|
724
|
-
#
|
|
910
|
+
# Collect missing visibility
|
|
725
911
|
#
|
|
726
|
-
# @note module_function:
|
|
727
|
-
# @param [
|
|
728
|
-
# @
|
|
729
|
-
|
|
730
|
-
|
|
912
|
+
# @note module_function: defines #collect_missing_visibility! (visibility: private)
|
|
913
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
914
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
915
|
+
# @param [Object] ctx merged context hash with info and indent
|
|
916
|
+
# @return [void]
|
|
917
|
+
def collect_missing_visibility!(lines, reasons, **ctx)
|
|
918
|
+
return unless ctx[:config].emit_visibility_tags?
|
|
919
|
+
|
|
920
|
+
add_missing_private(lines, reasons, ctx)
|
|
921
|
+
add_missing_protected(lines, reasons, ctx)
|
|
731
922
|
end
|
|
732
923
|
|
|
733
|
-
#
|
|
924
|
+
# Add missing private
|
|
734
925
|
#
|
|
735
|
-
#
|
|
926
|
+
# @note module_function: defines #add_missing_private (visibility: private)
|
|
927
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
928
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
929
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
930
|
+
# @return [void]
|
|
931
|
+
def add_missing_private(lines, reasons, ctx)
|
|
932
|
+
return unless ctx[:visibility] == :private && !ctx[:info][:has_private]
|
|
933
|
+
|
|
934
|
+
lines << "#{ctx[:indent]}# @private\n"
|
|
935
|
+
reasons << { type: :missing_visibility, message: 'missing @private' }
|
|
936
|
+
end
|
|
937
|
+
|
|
938
|
+
# Add missing protected
|
|
736
939
|
#
|
|
737
|
-
# @note module_function:
|
|
940
|
+
# @note module_function: defines #add_missing_protected (visibility: private)
|
|
941
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
942
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
943
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
944
|
+
# @return [void]
|
|
945
|
+
def add_missing_protected(lines, reasons, ctx)
|
|
946
|
+
return unless ctx[:visibility] == :protected && !ctx[:info][:has_protected]
|
|
947
|
+
|
|
948
|
+
lines << "#{ctx[:indent]}# @protected\n"
|
|
949
|
+
reasons << { type: :missing_visibility, message: 'missing @protected' }
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
# Collect missing module function note
|
|
953
|
+
#
|
|
954
|
+
# @note module_function: defines #collect_missing_module_function_note! (visibility: private)
|
|
955
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
956
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
957
|
+
# @param [Object] ctx merged context hash with info and indent
|
|
958
|
+
# @return [void]
|
|
959
|
+
def collect_missing_module_function_note!(lines, reasons, **ctx)
|
|
960
|
+
insertion = ctx[:insertion]
|
|
961
|
+
unless insertion.respond_to?(:module_function) && insertion.module_function &&
|
|
962
|
+
!ctx[:info][:has_module_function_note]
|
|
963
|
+
return
|
|
964
|
+
end
|
|
965
|
+
|
|
966
|
+
included_vis = insertion.included_instance_visibility || :private
|
|
967
|
+
lines << "#{ctx[:indent]}# @note module_function: defines ##{ctx[:name]} (visibility: #{included_vis})\n"
|
|
968
|
+
reasons << { type: :missing_module_function_note, message: 'missing module_function note' }
|
|
969
|
+
end
|
|
970
|
+
|
|
971
|
+
# Collect missing params
|
|
972
|
+
#
|
|
973
|
+
# @note module_function: defines #collect_missing_params! (visibility: private)
|
|
974
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
975
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
976
|
+
# @param [Object] ctx merged context hash with info and indent
|
|
977
|
+
# @return [void]
|
|
978
|
+
def collect_missing_params!(lines, reasons, **ctx)
|
|
979
|
+
return unless ctx[:config].emit_param_tags?
|
|
980
|
+
|
|
981
|
+
all_params = build_params_lines(ctx[:node], ctx[:indent],
|
|
982
|
+
external_sig: ctx[:external_sig], config: ctx[:config],
|
|
983
|
+
param_types_override: ctx[:param_types])
|
|
984
|
+
return unless all_params
|
|
985
|
+
|
|
986
|
+
all_params.each { |pl| collect_param_from_line(pl, lines, reasons, ctx) }
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
# Collect param from line
|
|
990
|
+
#
|
|
991
|
+
# @note module_function: defines #collect_param_from_line (visibility: private)
|
|
992
|
+
# @param [String] param_line a single @param tag line to evaluate
|
|
993
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
994
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
995
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with build parameters
|
|
996
|
+
# @return [void]
|
|
997
|
+
def collect_param_from_line(param_line, lines, reasons, ctx)
|
|
998
|
+
pname = extract_param_name_from_param_line(param_line)
|
|
999
|
+
return unless pname
|
|
1000
|
+
|
|
1001
|
+
if !ctx[:info][:param_names].include?(pname)
|
|
1002
|
+
lines << "#{param_line}\n"
|
|
1003
|
+
reasons << { type: :missing_param, message: "missing @param #{pname}", extra: { param: pname } }
|
|
1004
|
+
elsif ctx[:external_sig] && ctx[:info][:param_types][pname]
|
|
1005
|
+
collect_updated_param(param_line, pname, lines, reasons, ctx)
|
|
1006
|
+
end
|
|
1007
|
+
end
|
|
1008
|
+
|
|
1009
|
+
# Collect updated param
|
|
1010
|
+
#
|
|
1011
|
+
# @note module_function: defines #collect_updated_param (visibility: private)
|
|
1012
|
+
# @param [String] param_line a single @param tag line to evaluate
|
|
1013
|
+
# @param [String] pname the parameter name string
|
|
1014
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1015
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
1016
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with build parameters
|
|
1017
|
+
# @return [void]
|
|
1018
|
+
def collect_updated_param(param_line, pname, lines, reasons, ctx)
|
|
1019
|
+
new_type = extract_param_type_from_param_line(param_line)
|
|
1020
|
+
return unless new_type && ctx[:info][:param_types][pname] != new_type
|
|
1021
|
+
|
|
1022
|
+
lines << "#{param_line}\n" unless ctx[:strategy] == :safe
|
|
1023
|
+
reasons << {
|
|
1024
|
+
type: :updated_param,
|
|
1025
|
+
message: "updated @param #{pname} from #{ctx[:info][:param_types][pname]} to #{new_type}",
|
|
1026
|
+
extra: { param: pname }
|
|
1027
|
+
}
|
|
1028
|
+
end
|
|
1029
|
+
|
|
1030
|
+
# Build params lines
|
|
1031
|
+
#
|
|
1032
|
+
# @note module_function: defines #build_params_lines (visibility: private)
|
|
1033
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
1034
|
+
# @param [String] indent indentation string for the doc line
|
|
1035
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1036
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1037
|
+
# @param [Hash] kwargs additional keyword args including insertion, params_lines, raise_types, override_tags
|
|
1038
|
+
# @return [Array<String>, nil]
|
|
1039
|
+
def build_params_lines(node, indent, external_sig:, config:, **kwargs)
|
|
1040
|
+
args = extract_args_from_node(node)
|
|
1041
|
+
return nil unless args
|
|
1042
|
+
|
|
1043
|
+
build_all_param_lines(args, indent, config, external_sig: external_sig, **kwargs)
|
|
1044
|
+
end
|
|
1045
|
+
|
|
1046
|
+
# Build all param lines
|
|
1047
|
+
#
|
|
1048
|
+
# @note module_function: defines #build_all_param_lines (visibility: private)
|
|
1049
|
+
# @param [Parser::AST::Node] args arguments AST node
|
|
1050
|
+
# @param [String] indent indentation string for the doc line
|
|
1051
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1052
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1053
|
+
# @param [Object] kwargs additional keyword args including insertion, params_lines, raise_types, override_tags
|
|
1054
|
+
# @return [Array<String>, nil]
|
|
1055
|
+
def build_all_param_lines(args, indent, config, external_sig: nil, **kwargs)
|
|
1056
|
+
param_lines = [] #: Array[String]
|
|
1057
|
+
params = (args.children || []).each_with_object(param_lines) do |a, p|
|
|
1058
|
+
p.concat(build_param_line(a, indent, external_sig, kwargs[:param_types_override],
|
|
1059
|
+
skip_anonymous_block_params: config.skip_anonymous_block_params?,
|
|
1060
|
+
fallback_type: config.fallback_type,
|
|
1061
|
+
treat_options_keyword_as_hash: config.treat_options_keyword_as_hash?,
|
|
1062
|
+
param_documentation: param_doc_for_arg(a, kwargs, config),
|
|
1063
|
+
param_tag_style: config.param_tag_style))
|
|
1064
|
+
end
|
|
1065
|
+
params.empty? ? nil : params
|
|
1066
|
+
end
|
|
1067
|
+
|
|
1068
|
+
# Get param doc for argument
|
|
1069
|
+
#
|
|
1070
|
+
# @note module_function: defines #param_doc_for_arg (visibility: private)
|
|
1071
|
+
# @param [Parser::AST::Node] arg individual argument node
|
|
1072
|
+
# @param [Hash<Symbol, Object>] kwargs keyword args hash
|
|
1073
|
+
# @param [Docscribe::Config] config doc configuration
|
|
1074
|
+
# @return [String]
|
|
1075
|
+
def param_doc_for_arg(arg, kwargs, config)
|
|
1076
|
+
(kwargs[:param_descriptions] || {})[param_name_from_arg(arg)] ||
|
|
1077
|
+
(config.include_param_documentation? ? config.param_documentation : '')
|
|
1078
|
+
end
|
|
1079
|
+
|
|
1080
|
+
# Build doc lines
|
|
1081
|
+
#
|
|
1082
|
+
# @note module_function: defines #build_doc_lines (visibility: private)
|
|
1083
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with indent, name, types, scope
|
|
1084
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1085
|
+
# @param [Object] kwargs additional keyword args including insertion, params_lines, raise_types, override_tags
|
|
1086
|
+
# @return [Array<String>]
|
|
1087
|
+
def build_doc_lines(setup, config:, **kwargs)
|
|
1088
|
+
i = setup[:indent]
|
|
1089
|
+
assemble_doc_lines(i, setup, config: config, insertion: kwargs[:insertion],
|
|
1090
|
+
params_lines: kwargs[:params_lines],
|
|
1091
|
+
raise_types: kwargs[:raise_types], override_tags: kwargs[:override_tags],
|
|
1092
|
+
return_description: kwargs[:return_description],
|
|
1093
|
+
description: kwargs[:description])
|
|
1094
|
+
end
|
|
1095
|
+
|
|
1096
|
+
# Assemble doc lines
|
|
1097
|
+
#
|
|
1098
|
+
# @note module_function: defines #assemble_doc_lines (visibility: private)
|
|
1099
|
+
# @param [String] indent indent
|
|
1100
|
+
# @param [Hash<Symbol, Object>] setup setup
|
|
1101
|
+
# @param [Object] ctx context hash with config, insertion, params_lines, raise_types, override_tags
|
|
1102
|
+
# @return [Array<String>]
|
|
1103
|
+
def assemble_doc_lines(indent, setup, **ctx)
|
|
1104
|
+
line_ary = build_header_lines(
|
|
1105
|
+
indent,
|
|
1106
|
+
config: ctx[:config],
|
|
1107
|
+
container: setup[:container], method_symbol: setup[:method_symbol], name: setup[:name],
|
|
1108
|
+
normal_type: setup[:normal_type]
|
|
1109
|
+
)
|
|
1110
|
+
|
|
1111
|
+
append_assemble_body_lines(line_ary, indent, setup, ctx)
|
|
1112
|
+
line_ary
|
|
1113
|
+
end
|
|
1114
|
+
|
|
1115
|
+
# Append assemble body lines
|
|
1116
|
+
#
|
|
1117
|
+
# @note module_function: defines #append_assemble_body_lines (visibility: private)
|
|
1118
|
+
# @param [Array<String>] line_ary output line array
|
|
1119
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1120
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with name, types, scope
|
|
1121
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
1122
|
+
# @return [void]
|
|
1123
|
+
def append_assemble_body_lines(line_ary, indent, setup, ctx)
|
|
1124
|
+
line_ary.concat(build_all_body_tags(indent, setup, ctx))
|
|
1125
|
+
end
|
|
1126
|
+
|
|
1127
|
+
# Build all body tags
|
|
1128
|
+
#
|
|
1129
|
+
# @note module_function: defines #build_all_body_tags (visibility: private)
|
|
1130
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1131
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with name, types, scope
|
|
1132
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
1133
|
+
# @return [Array<String>]
|
|
1134
|
+
def build_all_body_tags(indent, setup, ctx)
|
|
1135
|
+
result = core_body_tags(indent, setup, ctx)
|
|
1136
|
+
result.insert(4, ctx[:params_lines]) if ctx[:params_lines]
|
|
1137
|
+
result.flatten
|
|
1138
|
+
end
|
|
1139
|
+
|
|
1140
|
+
# Core body tags
|
|
1141
|
+
#
|
|
1142
|
+
# @note module_function: defines #core_body_tags (visibility: private)
|
|
1143
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1144
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with name, types, scope
|
|
1145
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
1146
|
+
# @return [Array<Object>]
|
|
1147
|
+
def core_body_tags(indent, setup, ctx)
|
|
1148
|
+
config, insertion = ctx.values_at(:config, :insertion)
|
|
1149
|
+
[
|
|
1150
|
+
defaults_and_visibility(indent, config, setup[:scope], setup[:visibility], description: ctx[:description]),
|
|
1151
|
+
build_module_function_note_lines(indent, insertion, setup[:name]),
|
|
1152
|
+
ctx.dig(:info, :note_lines) || [],
|
|
1153
|
+
build_raise_tag_lines(indent, ctx[:raise_types], config),
|
|
1154
|
+
build_return_line_if_needed(indent, setup, config, ctx),
|
|
1155
|
+
build_rescue_return_lines(indent, setup[:rescue_specs], config),
|
|
1156
|
+
build_plugin_tag_lines(insertion, indent, setup[:normal_type], ctx[:override_tags])
|
|
1157
|
+
]
|
|
1158
|
+
end
|
|
1159
|
+
|
|
1160
|
+
# Defaults and visibility
|
|
1161
|
+
#
|
|
1162
|
+
# @note module_function: defines #defaults_and_visibility (visibility: private)
|
|
1163
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1164
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1165
|
+
# @param [Symbol] scope method scope symbol
|
|
1166
|
+
# @param [Symbol] visibility method visibility symbol
|
|
1167
|
+
# @param [Array<String>, nil] description optional description lines
|
|
1168
|
+
# @return [Array<String>]
|
|
1169
|
+
def defaults_and_visibility(indent, config, scope, visibility, description: nil)
|
|
1170
|
+
[
|
|
1171
|
+
build_default_msg_lines(indent, config, scope, visibility, description: description),
|
|
1172
|
+
build_visibility_tag_lines(indent, visibility, config)
|
|
1173
|
+
].flatten
|
|
1174
|
+
end
|
|
1175
|
+
|
|
1176
|
+
# Build return line if needed
|
|
1177
|
+
#
|
|
1178
|
+
# @note module_function: defines #build_return_line_if_needed (visibility: private)
|
|
1179
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1180
|
+
# @param [Hash<Symbol, Object>] setup method setup hash with name, normal_type, scope, visibility
|
|
1181
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1182
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
1183
|
+
# @return [Array<String>]
|
|
1184
|
+
def build_return_line_if_needed(indent, setup, config, ctx)
|
|
1185
|
+
ret_line = build_return_tag_line(indent, setup[:normal_type], config, setup[:scope], setup[:visibility])
|
|
1186
|
+
rd = ctx[:return_description]
|
|
1187
|
+
if ret_line && rd && !rd.empty?
|
|
1188
|
+
lines = rd.split("\n")
|
|
1189
|
+
ret_line = +"#{ret_line} #{lines.first}"
|
|
1190
|
+
lines[1..]&.each { |l| ret_line << "\n#{indent}# #{l}" }
|
|
1191
|
+
end
|
|
1192
|
+
ret_line ? [ret_line] : []
|
|
1193
|
+
end
|
|
1194
|
+
|
|
1195
|
+
# Extract args from node
|
|
1196
|
+
#
|
|
1197
|
+
# @note module_function: defines #extract_args_from_node (visibility: private)
|
|
1198
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
1199
|
+
# @return [Parser::AST::Node, nil]
|
|
1200
|
+
def extract_args_from_node(node)
|
|
1201
|
+
case node.type
|
|
1202
|
+
when :def then node.children[1]
|
|
1203
|
+
when :defs then node.children[2]
|
|
1204
|
+
end
|
|
1205
|
+
end
|
|
1206
|
+
|
|
1207
|
+
# Build param line
|
|
1208
|
+
#
|
|
1209
|
+
# @note module_function: defines #build_param_line (visibility: private)
|
|
1210
|
+
# @param [Parser::AST::Node] arg_node AST node for the argument
|
|
1211
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1212
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1213
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1214
|
+
# @param [Object] opts additional options for param formatting (fallback_type, param_tag_style, etc.)
|
|
1215
|
+
# @return [Array<String>]
|
|
1216
|
+
def build_param_line(arg_node, indent, external_sig, param_types_override, **opts)
|
|
1217
|
+
method_name = :"build_#{arg_node.type}_line"
|
|
1218
|
+
if respond_to?(method_name, true)
|
|
1219
|
+
return [] if arg_node.type == :blockarg && opts[:skip_anonymous_block_params] && arg_node.children.first.nil?
|
|
1220
|
+
|
|
1221
|
+
return [send(method_name, arg_node, indent, external_sig, param_types_override, **opts)]
|
|
1222
|
+
end
|
|
1223
|
+
|
|
1224
|
+
method_name = :"build_#{arg_node.type}_lines"
|
|
1225
|
+
if respond_to?(method_name, true)
|
|
1226
|
+
return send(method_name, arg_node, indent, external_sig, param_types_override, **opts)
|
|
1227
|
+
end
|
|
1228
|
+
|
|
1229
|
+
[]
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1232
|
+
# Build header lines
|
|
1233
|
+
#
|
|
1234
|
+
# @note module_function: defines #build_header_lines (visibility: private)
|
|
1235
|
+
# @param [String] indent indentation string for the doc line
|
|
1236
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1237
|
+
# @param [Object] opts additional options including container, method_symbol, name, normal_type
|
|
1238
|
+
# @return [Array<String>]
|
|
1239
|
+
def build_header_lines(indent, config:, **opts)
|
|
1240
|
+
if config.emit_header?
|
|
1241
|
+
c = opts[:container]
|
|
1242
|
+
ms = opts[:method_symbol]
|
|
1243
|
+
n = opts[:name]
|
|
1244
|
+
nt = opts[:normal_type]
|
|
1245
|
+
["#{indent}# +#{c}#{ms}#{n}+ -> #{nt}", "#{indent}#"]
|
|
1246
|
+
else
|
|
1247
|
+
[]
|
|
1248
|
+
end
|
|
1249
|
+
end
|
|
1250
|
+
|
|
1251
|
+
# Build default msg lines
|
|
1252
|
+
#
|
|
1253
|
+
# @note module_function: defines #build_default_msg_lines (visibility: private)
|
|
1254
|
+
# @param [String] indent indentation string for the doc line
|
|
1255
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1256
|
+
# @param [Symbol] scope method scope symbol
|
|
1257
|
+
# @param [Symbol] visibility method visibility symbol
|
|
1258
|
+
# @param [Array<String>, nil] description optional description lines
|
|
1259
|
+
# @return [Array<String>]
|
|
1260
|
+
def build_default_msg_lines(indent, config, scope, visibility, description: nil)
|
|
1261
|
+
if description&.any?
|
|
1262
|
+
result = description.map { |line| line.empty? ? "#{indent}#" : "#{indent}# #{line}" }
|
|
1263
|
+
result << "#{indent}#" unless result.last == "#{indent}#"
|
|
1264
|
+
result
|
|
1265
|
+
elsif config.include_default_message?
|
|
1266
|
+
["#{indent}# #{config.default_message(scope, visibility)}", "#{indent}#"]
|
|
1267
|
+
else
|
|
1268
|
+
[]
|
|
1269
|
+
end
|
|
1270
|
+
end
|
|
1271
|
+
|
|
1272
|
+
# Build visibility tag lines
|
|
1273
|
+
#
|
|
1274
|
+
# @note module_function: defines #build_visibility_tag_lines (visibility: private)
|
|
1275
|
+
# @param [String] indent indentation string for the doc line
|
|
1276
|
+
# @param [Symbol] visibility method visibility symbol
|
|
1277
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1278
|
+
# @return [Array<String>]
|
|
1279
|
+
def build_visibility_tag_lines(indent, visibility, config)
|
|
1280
|
+
return [] unless config.emit_visibility_tags?
|
|
1281
|
+
|
|
1282
|
+
case visibility
|
|
1283
|
+
when :private then ["#{indent}# @private"]
|
|
1284
|
+
when :protected then ["#{indent}# @protected"]
|
|
1285
|
+
else []
|
|
1286
|
+
end
|
|
1287
|
+
end
|
|
1288
|
+
|
|
1289
|
+
# Build module function note lines
|
|
1290
|
+
#
|
|
1291
|
+
# @note module_function: defines #build_module_function_note_lines (visibility: private)
|
|
1292
|
+
# @param [String] indent indentation string for the doc line
|
|
1293
|
+
# @param [Object] insertion the collected method insertion object
|
|
1294
|
+
# @param [String] name the method name string
|
|
1295
|
+
# @return [Array<String>]
|
|
1296
|
+
def build_module_function_note_lines(indent, insertion, name)
|
|
1297
|
+
return [] unless insertion.respond_to?(:module_function) && insertion.module_function
|
|
1298
|
+
|
|
1299
|
+
included_vis =
|
|
1300
|
+
if insertion.respond_to?(:included_instance_visibility) && insertion.included_instance_visibility
|
|
1301
|
+
insertion.included_instance_visibility
|
|
1302
|
+
else
|
|
1303
|
+
:private
|
|
1304
|
+
end
|
|
1305
|
+
|
|
1306
|
+
["#{indent}# @note module_function: defines ##{name} (visibility: #{included_vis})"]
|
|
1307
|
+
end
|
|
1308
|
+
|
|
1309
|
+
# Build raise tag lines
|
|
1310
|
+
#
|
|
1311
|
+
# @note module_function: defines #build_raise_tag_lines (visibility: private)
|
|
1312
|
+
# @param [String] indent indentation string for the doc line
|
|
1313
|
+
# @param [Array<String>] raise_types hash tracking existing @raise types
|
|
1314
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1315
|
+
# @return [Array<String>]
|
|
1316
|
+
def build_raise_tag_lines(indent, raise_types, config)
|
|
1317
|
+
return [] unless config.emit_raise_tags?
|
|
1318
|
+
|
|
1319
|
+
raise_types.map { |rt| "#{indent}# @raise [#{rt}]" }
|
|
1320
|
+
end
|
|
1321
|
+
|
|
1322
|
+
# Build return tag line
|
|
1323
|
+
#
|
|
1324
|
+
# @note module_function: defines #build_return_tag_line (visibility: private)
|
|
1325
|
+
# @param [String] indent indentation string for the doc line
|
|
1326
|
+
# @param [String] normal_type resolved return type
|
|
1327
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1328
|
+
# @param [Symbol] scope method scope symbol
|
|
1329
|
+
# @param [Symbol] visibility method visibility symbol
|
|
1330
|
+
# @return [String, nil]
|
|
1331
|
+
def build_return_tag_line(indent, normal_type, config, scope, visibility)
|
|
1332
|
+
return unless config.emit_return_tag?(scope, visibility)
|
|
1333
|
+
|
|
1334
|
+
"#{indent}# @return [#{normal_type}]"
|
|
1335
|
+
end
|
|
1336
|
+
|
|
1337
|
+
# Build rescue return lines
|
|
1338
|
+
#
|
|
1339
|
+
# @note module_function: defines #build_rescue_return_lines (visibility: private)
|
|
1340
|
+
# @param [String] indent indentation string for the doc line
|
|
1341
|
+
# @param [Array<(Array<String>, String)>] rescue_specs rescue type specs
|
|
1342
|
+
# @param [Docscribe::Config] config Docscribe configuration object
|
|
1343
|
+
# @return [Array<String>]
|
|
1344
|
+
def build_rescue_return_lines(indent, rescue_specs, config)
|
|
1345
|
+
return [] unless config.emit_rescue_conditional_returns?
|
|
1346
|
+
|
|
1347
|
+
rescue_specs.map do |exceptions, rtype|
|
|
1348
|
+
"#{indent}# @return [#{rtype}] if #{exceptions.join(', ')}"
|
|
1349
|
+
end
|
|
1350
|
+
end
|
|
1351
|
+
|
|
1352
|
+
# Build plugin tag lines
|
|
1353
|
+
#
|
|
1354
|
+
# @note module_function: defines #build_plugin_tag_lines (visibility: private)
|
|
1355
|
+
# @param [Object] insertion the collected method insertion object
|
|
1356
|
+
# @param [String] indent indentation string for the doc line
|
|
1357
|
+
# @param [String] normal_type resolved return type
|
|
1358
|
+
# @param [Array<Object>, nil] override_tags plugin tag overrides
|
|
1359
|
+
# @return [Array<String>]
|
|
1360
|
+
def build_plugin_tag_lines(insertion, indent, normal_type, override_tags)
|
|
1361
|
+
plugin_tags = Docscribe::Plugin.run_tag_plugins(build_plugin_context(insertion, normal_type: normal_type))
|
|
1362
|
+
plugin_tags.concat(Array(override_tags)) if override_tags
|
|
1363
|
+
render_plugin_tags(plugin_tags, indent)
|
|
1364
|
+
end
|
|
1365
|
+
|
|
1366
|
+
# Build arg line
|
|
1367
|
+
#
|
|
1368
|
+
# @note module_function: defines #build_arg_line (visibility: private)
|
|
1369
|
+
# @param [Parser::AST::Node] arg_node AST node for the required argument
|
|
1370
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1371
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1372
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1373
|
+
# @param [Object] opts additional options for param formatting
|
|
1374
|
+
# @return [String]
|
|
1375
|
+
def build_arg_line(arg_node, indent, external_sig, param_types_override, **opts)
|
|
1376
|
+
pname = arg_node.children.first.to_s
|
|
1377
|
+
ty = lookup_param_type(external_sig, param_types_override, pname, pname,
|
|
1378
|
+
infer_default: nil,
|
|
1379
|
+
fallback_type: opts[:fallback_type],
|
|
1380
|
+
treat_options_keyword_as_hash: opts[:treat_options_keyword_as_hash])
|
|
1381
|
+
format_param_tag(indent, pname, ty, opts[:param_documentation], style: opts[:param_tag_style])
|
|
1382
|
+
end
|
|
1383
|
+
|
|
1384
|
+
# Build optarg lines
|
|
1385
|
+
#
|
|
1386
|
+
# @note module_function: defines #build_optarg_lines (visibility: private)
|
|
1387
|
+
# @param [Parser::AST::Node] arg_node AST node for the optional argument
|
|
1388
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1389
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1390
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1391
|
+
# @param [Object] opts additional options for param formatting
|
|
1392
|
+
# @return [Array<String>]
|
|
1393
|
+
def build_optarg_lines(arg_node, indent, external_sig, param_types_override, **opts)
|
|
1394
|
+
pname, default = *arg_node
|
|
1395
|
+
pname = pname.to_s
|
|
1396
|
+
ty = optarg_type(pname, default, external_sig, param_types_override, opts)
|
|
1397
|
+
lines = [format_param_tag(indent, pname, ty, opts[:param_documentation], style: opts[:param_tag_style])]
|
|
1398
|
+
|
|
1399
|
+
append_option_lines(lines, default, indent, pname, opts[:fallback_type])
|
|
1400
|
+
lines
|
|
1401
|
+
end
|
|
1402
|
+
|
|
1403
|
+
# Optarg type
|
|
1404
|
+
#
|
|
1405
|
+
# @note module_function: defines #optarg_type (visibility: private)
|
|
1406
|
+
# @param [String] pname the parameter name to look up
|
|
1407
|
+
# @param [Parser::AST::Node] default default value node
|
|
1408
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1409
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1410
|
+
# @param [Hash<Symbol, Object>] opts additional options including
|
|
1411
|
+
# @return [String]
|
|
1412
|
+
def optarg_type(pname, default, external_sig, param_types_override, opts)
|
|
1413
|
+
default_src = source_from_node(default)
|
|
1414
|
+
lookup_param_type(external_sig, param_types_override, pname, pname,
|
|
1415
|
+
infer_default: default_src,
|
|
1416
|
+
fallback_type: opts[:fallback_type],
|
|
1417
|
+
treat_options_keyword_as_hash: opts[:treat_options_keyword_as_hash])
|
|
1418
|
+
end
|
|
1419
|
+
|
|
1420
|
+
# Source from node
|
|
1421
|
+
#
|
|
1422
|
+
# @note module_function: defines #source_from_node (visibility: private)
|
|
1423
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
1424
|
+
# @return [String, nil]
|
|
1425
|
+
def source_from_node(node)
|
|
1426
|
+
loc = node&.loc
|
|
1427
|
+
loc&.expression&.source
|
|
1428
|
+
end
|
|
1429
|
+
|
|
1430
|
+
# Resolve infer name
|
|
1431
|
+
#
|
|
1432
|
+
# @note module_function: defines #resolve_infer_name (visibility: private)
|
|
1433
|
+
# @param [String] pname the parameter name to look up
|
|
1434
|
+
# @param [Proc, nil] infer_name parameter name string or transformed version for inference
|
|
1435
|
+
# @return [String]
|
|
1436
|
+
def resolve_infer_name(pname, infer_name)
|
|
1437
|
+
infer_name ? infer_name.call(pname) : pname
|
|
1438
|
+
end
|
|
1439
|
+
|
|
1440
|
+
# Build kwarg line
|
|
1441
|
+
#
|
|
1442
|
+
# @note module_function: defines #build_kwarg_line (visibility: private)
|
|
1443
|
+
# @param [Parser::AST::Node] arg_node AST node for the keyword argument
|
|
1444
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1445
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1446
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1447
|
+
# @param [Object] opts additional options for param formatting
|
|
1448
|
+
# @return [String]
|
|
1449
|
+
def build_kwarg_line(arg_node, indent, external_sig, param_types_override, **opts)
|
|
1450
|
+
pname = arg_node.children.first.to_s
|
|
1451
|
+
ty = lookup_param_type(external_sig, param_types_override, pname, "#{pname}:",
|
|
1452
|
+
infer_default: nil,
|
|
1453
|
+
fallback_type: opts[:fallback_type],
|
|
1454
|
+
treat_options_keyword_as_hash: opts[:treat_options_keyword_as_hash])
|
|
1455
|
+
format_param_tag(indent, pname, ty, opts[:param_documentation], style: opts[:param_tag_style])
|
|
1456
|
+
end
|
|
1457
|
+
|
|
1458
|
+
# Build kwoptarg line
|
|
1459
|
+
#
|
|
1460
|
+
# @note module_function: defines #build_kwoptarg_line (visibility: private)
|
|
1461
|
+
# @param [Parser::AST::Node] arg_node AST node for the optional keyword argument
|
|
1462
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1463
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1464
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1465
|
+
# @param [Object] opts additional options for param formatting
|
|
1466
|
+
# @return [String]
|
|
1467
|
+
def build_kwoptarg_line(arg_node, indent, external_sig, param_types_override, **opts)
|
|
1468
|
+
pname, default = *arg_node
|
|
1469
|
+
pname = pname.to_s
|
|
1470
|
+
default_loc = default&.loc
|
|
1471
|
+
default_src = default_loc&.expression&.source
|
|
1472
|
+
ty = lookup_param_type(external_sig, param_types_override, pname, "#{pname}:",
|
|
1473
|
+
infer_default: default_src,
|
|
1474
|
+
fallback_type: opts[:fallback_type],
|
|
1475
|
+
treat_options_keyword_as_hash: opts[:treat_options_keyword_as_hash])
|
|
1476
|
+
format_param_tag(indent, pname, ty, opts[:param_documentation], style: opts[:param_tag_style])
|
|
1477
|
+
end
|
|
1478
|
+
|
|
1479
|
+
# Build restarg line
|
|
1480
|
+
#
|
|
1481
|
+
# @note module_function: defines #build_restarg_line (visibility: private)
|
|
1482
|
+
# @param [Parser::AST::Node] arg_node AST node for the rest argument (*args)
|
|
1483
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1484
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1485
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1486
|
+
# @param [Object] opts additional options for param formatting
|
|
1487
|
+
# @return [String]
|
|
1488
|
+
def build_restarg_line(arg_node, indent, external_sig, param_types_override, **opts)
|
|
1489
|
+
pname = (arg_node.children.first || 'args').to_s
|
|
1490
|
+
rest_pos = external_sig&.rest_positional
|
|
1491
|
+
ty = if rest_pos&.element_type
|
|
1492
|
+
"Array<#{rest_pos.element_type}>"
|
|
1493
|
+
else
|
|
1494
|
+
lookup_param_type_by_infer(param_types_override, pname, "*#{pname}",
|
|
1495
|
+
opts[:fallback_type], opts[:treat_options_keyword_as_hash])
|
|
1496
|
+
end
|
|
1497
|
+
format_param_tag(indent, pname, ty, opts[:param_documentation], style: opts[:param_tag_style])
|
|
1498
|
+
end
|
|
1499
|
+
|
|
1500
|
+
# Build kwrestarg line
|
|
1501
|
+
#
|
|
1502
|
+
# @note module_function: defines #build_kwrestarg_line (visibility: private)
|
|
1503
|
+
# @param [Parser::AST::Node] arg_node AST node for the keyword rest argument (**kwargs)
|
|
1504
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1505
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1506
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1507
|
+
# @param [Object] opts additional options for param formatting
|
|
1508
|
+
# @return [String]
|
|
1509
|
+
def build_kwrestarg_line(arg_node, indent, external_sig, param_types_override, **opts)
|
|
1510
|
+
pname = (arg_node.children.first || 'kwargs').to_s
|
|
1511
|
+
ty = external_sig&.rest_keywords&.type ||
|
|
1512
|
+
lookup_param_type_by_infer(param_types_override, pname, "**#{pname}",
|
|
1513
|
+
opts[:fallback_type], opts[:treat_options_keyword_as_hash])
|
|
1514
|
+
format_param_tag(indent, pname, ty, opts[:param_documentation], style: opts[:param_tag_style])
|
|
1515
|
+
end
|
|
1516
|
+
|
|
1517
|
+
# Build blockarg line
|
|
1518
|
+
#
|
|
1519
|
+
# @note module_function: defines #build_blockarg_line (visibility: private)
|
|
1520
|
+
# @param [Parser::AST::Node] arg_node AST node for the block argument (&block)
|
|
1521
|
+
# @param [String] indent indentation string for doc comment lines
|
|
1522
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1523
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1524
|
+
# @param [Object] opts additional options for param formatting
|
|
1525
|
+
# @return [String]
|
|
1526
|
+
def build_blockarg_line(arg_node, indent, external_sig, param_types_override, **opts)
|
|
1527
|
+
pname = (arg_node.children.first || 'block').to_s
|
|
1528
|
+
ty = lookup_param_type(external_sig, param_types_override, pname, "&#{pname}",
|
|
1529
|
+
infer_default: nil,
|
|
1530
|
+
fallback_type: opts[:fallback_type],
|
|
1531
|
+
treat_options_keyword_as_hash: opts[:treat_options_keyword_as_hash])
|
|
1532
|
+
format_param_tag(indent, pname, ty, opts[:param_documentation], style: opts[:param_tag_style])
|
|
1533
|
+
end
|
|
1534
|
+
|
|
1535
|
+
# Lookup param type
|
|
1536
|
+
#
|
|
1537
|
+
# @note module_function: defines #lookup_param_type (visibility: private)
|
|
1538
|
+
# @param [Docscribe::Types::MethodSignature, nil] external_sig external method signature for type overrides
|
|
1539
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1540
|
+
# @param [String] pname the parameter name string
|
|
1541
|
+
# @param [String] infer_name parameter name string or transformed version for inference
|
|
1542
|
+
# @param [Object] opts additional options including infer_default, fallback_type, treat_options_keyword_as_hash
|
|
1543
|
+
# @return [String]
|
|
1544
|
+
def lookup_param_type(external_sig, param_types_override, pname, infer_name, **opts)
|
|
1545
|
+
external_sig&.param_types&.[](pname) ||
|
|
1546
|
+
override_param_type_for(pname, param_types_override) ||
|
|
1547
|
+
Infer.infer_param_type(infer_name, opts[:infer_default],
|
|
1548
|
+
fallback_type: opts[:fallback_type],
|
|
1549
|
+
treat_options_keyword_as_hash: opts[:treat_options_keyword_as_hash])
|
|
1550
|
+
end
|
|
1551
|
+
|
|
1552
|
+
# Lookup param type by infer
|
|
1553
|
+
#
|
|
1554
|
+
# @note module_function: defines #lookup_param_type_by_infer (visibility: private)
|
|
1555
|
+
# @param [Hash<String, String>, nil] param_types_override map of parameter name to override type
|
|
1556
|
+
# @param [String] pname the parameter name string
|
|
1557
|
+
# @param [String] infer_name parameter name string or transformed version for inference
|
|
1558
|
+
# @param [String] fallback_type default type string when inference fails
|
|
1559
|
+
# @param [Boolean, nil] treat_options_keyword_as_hash whether to treat options keyword as Hash type
|
|
1560
|
+
# @return [String]
|
|
1561
|
+
def lookup_param_type_by_infer(param_types_override, pname, infer_name, fallback_type,
|
|
1562
|
+
treat_options_keyword_as_hash)
|
|
1563
|
+
override_param_type_for(pname, param_types_override) ||
|
|
1564
|
+
Infer.infer_param_type(infer_name, nil,
|
|
1565
|
+
fallback_type: fallback_type,
|
|
1566
|
+
treat_options_keyword_as_hash: treat_options_keyword_as_hash || false)
|
|
1567
|
+
end
|
|
1568
|
+
|
|
1569
|
+
# Format param tag
|
|
1570
|
+
#
|
|
1571
|
+
# @note module_function: defines #format_param_tag (visibility: private)
|
|
1572
|
+
# @param [String] indent indentation string for the doc line
|
|
1573
|
+
# @param [String] name the parameter name
|
|
1574
|
+
# @param [String] type the parameter type string
|
|
1575
|
+
# @param [String] documentation optional documentation text appended to the tag
|
|
1576
|
+
# @param [Symbol, String] style param tag style (:type_name or :name_type)
|
|
1577
|
+
# @return [String]
|
|
1578
|
+
def format_param_tag(indent, name, type, documentation, style:)
|
|
1579
|
+
doc = documentation.to_s.strip
|
|
1580
|
+
type = type.to_s
|
|
1581
|
+
line = build_param_tag_base(indent, name, type, style)
|
|
1582
|
+
doc.empty? ? line : append_param_doc(line, doc, indent)
|
|
1583
|
+
end
|
|
1584
|
+
|
|
1585
|
+
# Build param tag base string
|
|
1586
|
+
#
|
|
1587
|
+
# @note module_function: defines #build_param_tag_base (visibility: private)
|
|
1588
|
+
# @param [String] indent indentation string
|
|
1589
|
+
# @param [String] name parameter name
|
|
1590
|
+
# @param [String] type parameter type string
|
|
1591
|
+
# @param [String, Symbol] style tag style symbol
|
|
1592
|
+
# @return [String]
|
|
1593
|
+
def build_param_tag_base(indent, name, type, style)
|
|
1594
|
+
case style.to_s
|
|
1595
|
+
when 'name_type' then "#{indent}# @param #{name} [#{type}]"
|
|
1596
|
+
else "#{indent}# @param [#{type}] #{name}"
|
|
1597
|
+
end
|
|
1598
|
+
end
|
|
1599
|
+
|
|
1600
|
+
# Append param doc text
|
|
1601
|
+
#
|
|
1602
|
+
# @note module_function: defines #append_param_doc (visibility: private)
|
|
1603
|
+
# @param [String] line existing param tag line
|
|
1604
|
+
# @param [String] doc documentation text
|
|
1605
|
+
# @param [String] indent indentation string
|
|
1606
|
+
# @return [String]
|
|
1607
|
+
def append_param_doc(line, doc, indent)
|
|
1608
|
+
parts = doc.split("\n")
|
|
1609
|
+
result = +"#{line} #{parts.first}"
|
|
1610
|
+
parts[1..]&.each { |l| result << "\n#{indent}# #{l}" }
|
|
1611
|
+
result
|
|
1612
|
+
end
|
|
1613
|
+
|
|
1614
|
+
# Append option lines
|
|
1615
|
+
#
|
|
1616
|
+
# @note module_function: defines #append_option_lines (visibility: private)
|
|
1617
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1618
|
+
# @param [Parser::AST::Node] default default value node
|
|
1619
|
+
# @param [String] indent indentation string for the doc line
|
|
1620
|
+
# @param [String] pname the parameter name to look up
|
|
1621
|
+
# @param [String] fallback_type default type string when inference fails
|
|
1622
|
+
# @return [void]
|
|
1623
|
+
def append_option_lines(lines, default, indent, pname, fallback_type)
|
|
1624
|
+
hash_option_pairs(default).each do |pair|
|
|
1625
|
+
lines << build_option_line(pair, indent, pname, fallback_type)
|
|
1626
|
+
end
|
|
1627
|
+
end
|
|
1628
|
+
|
|
1629
|
+
# Hash option pairs
|
|
1630
|
+
#
|
|
1631
|
+
# @note module_function: defines #hash_option_pairs (visibility: private)
|
|
1632
|
+
# @param [Parser::AST::Node] node AST node for the default value, expected to be :hash type
|
|
1633
|
+
# @return [Array<Parser::AST::Node>]
|
|
1634
|
+
def hash_option_pairs(node)
|
|
1635
|
+
return [] unless node&.type == :hash
|
|
1636
|
+
|
|
1637
|
+
node.children.select { |child| child.is_a?(Parser::AST::Node) && child.type == :pair }
|
|
1638
|
+
end
|
|
1639
|
+
|
|
1640
|
+
# Build option line
|
|
1641
|
+
#
|
|
1642
|
+
# @note module_function: defines #build_option_line (visibility: private)
|
|
1643
|
+
# @param [Parser::AST::Node] pair AST pair node containing key and value
|
|
1644
|
+
# @param [String] indent indentation string for the doc line
|
|
1645
|
+
# @param [String] pname the parent parameter name for @option scope
|
|
1646
|
+
# @param [String] fallback_type default type string when inference fails
|
|
1647
|
+
# @return [String]
|
|
1648
|
+
def build_option_line(pair, indent, pname, fallback_type)
|
|
1649
|
+
key_node, value_node = pair.children
|
|
1650
|
+
option_key = option_key_name(key_node)
|
|
1651
|
+
option_type = Infer::Literals.type_from_literal(value_node, fallback_type: fallback_type)
|
|
1652
|
+
option_default = node_default_literal(value_node)
|
|
1653
|
+
|
|
1654
|
+
line = "#{indent}# @option #{pname} [#{option_type}] :#{option_key}"
|
|
1655
|
+
line += " (#{option_default})" if option_default
|
|
1656
|
+
line += ' Description of this option.'
|
|
1657
|
+
line
|
|
1658
|
+
end
|
|
1659
|
+
|
|
1660
|
+
# Option key name
|
|
1661
|
+
#
|
|
1662
|
+
# @note module_function: defines #option_key_name (visibility: private)
|
|
1663
|
+
# @param [Parser::AST::Node] key_node AST node for the hash key (:sym or :str type)
|
|
1664
|
+
# @return [String]
|
|
1665
|
+
def option_key_name(key_node)
|
|
1666
|
+
case key_node&.type
|
|
1667
|
+
when :sym, :str
|
|
1668
|
+
key_node.children.first.to_s
|
|
1669
|
+
else
|
|
1670
|
+
expression = key_node&.loc&.expression
|
|
1671
|
+
expression&.source.to_s.sub(/\A:/, '')
|
|
1672
|
+
end
|
|
1673
|
+
end
|
|
1674
|
+
|
|
1675
|
+
# Node default literal
|
|
1676
|
+
#
|
|
1677
|
+
# @note module_function: defines #node_default_literal (visibility: private)
|
|
1678
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
1679
|
+
# @return [String, nil]
|
|
1680
|
+
def node_default_literal(node)
|
|
1681
|
+
expression = node&.loc&.expression
|
|
1682
|
+
expression&.source
|
|
1683
|
+
end
|
|
1684
|
+
|
|
1685
|
+
# Override param type for
|
|
1686
|
+
#
|
|
1687
|
+
# @note module_function: defines #override_param_type_for (visibility: private)
|
|
1688
|
+
# @param [String] pname the parameter name to look up
|
|
1689
|
+
# @param [Hash<Object, Object>, nil] override_map hash map of parameter name to override type
|
|
1690
|
+
# @return [String, nil]
|
|
1691
|
+
def override_param_type_for(pname, override_map)
|
|
1692
|
+
return nil unless override_map
|
|
1693
|
+
|
|
1694
|
+
key = pname.to_s
|
|
1695
|
+
override_map[key] || override_map[:"#{key}"] || override_map["#{key}:"] || override_map[:"#{key}:"]
|
|
1696
|
+
end
|
|
1697
|
+
|
|
1698
|
+
# Extract param description
|
|
1699
|
+
#
|
|
1700
|
+
# @note module_function: defines #extract_param_description (visibility: private)
|
|
1701
|
+
# @param [String] line a `@param` tag line
|
|
1702
|
+
# @return [String, nil]
|
|
1703
|
+
def extract_param_description(line)
|
|
1704
|
+
after = param_rest_after_type(line)
|
|
1705
|
+
return nil unless after
|
|
1706
|
+
|
|
1707
|
+
parts = after.split(/\s+/, 2)
|
|
1708
|
+
parts[1] if parts.length > 1 && !parts[1].empty?
|
|
1709
|
+
end
|
|
1710
|
+
|
|
1711
|
+
# Extract everything after the type bracket in a @param line.
|
|
1712
|
+
#
|
|
1713
|
+
# @note module_function: defines #param_rest_after_type (visibility: private)
|
|
1714
|
+
# @param [String] line a @param doc line
|
|
1715
|
+
# @return [String?] the text after the closing `]`, or nil
|
|
1716
|
+
def param_rest_after_type(line)
|
|
1717
|
+
content = line.sub(/^\s*#\s*/, '')
|
|
1718
|
+
if (m = content.match(/@param\s+(\S+\s+)?\[/))
|
|
1719
|
+
brace_end = m.end(0) #: Integer
|
|
1720
|
+
rest = content[(brace_end - 1)..] #: String
|
|
1721
|
+
type_end = find_matching_close_bracket(rest)
|
|
1722
|
+
return rest[(type_end + 1)..]&.strip if type_end
|
|
1723
|
+
end
|
|
1724
|
+
nil
|
|
1725
|
+
end
|
|
1726
|
+
ARG_DEFAULT_NAMES = { restarg: 'args', kwrestarg: 'kwargs', blockarg: 'block' }.freeze
|
|
1727
|
+
|
|
1728
|
+
# Param name from arg
|
|
1729
|
+
#
|
|
1730
|
+
# @note module_function: defines #param_name_from_arg (visibility: private)
|
|
1731
|
+
# @param [Parser::AST::Node] arg_node AST node for the block argument (&block)
|
|
1732
|
+
# @return [String, nil]
|
|
1733
|
+
def param_name_from_arg(arg_node)
|
|
1734
|
+
return nil if arg_node.type == :forward_arg
|
|
1735
|
+
|
|
1736
|
+
(arg_node.children.first || ARG_DEFAULT_NAMES[arg_node.type] || '').to_s
|
|
1737
|
+
end
|
|
1738
|
+
|
|
1739
|
+
# Extract param name from param line
|
|
1740
|
+
#
|
|
1741
|
+
# @note module_function: defines #extract_param_name_from_param_line (visibility: private)
|
|
738
1742
|
# @param [String] line a `@param` doc line
|
|
739
1743
|
# @return [String, nil] the parameter name or nil
|
|
740
1744
|
def extract_param_name_from_param_line(line)
|
|
741
|
-
|
|
742
|
-
|
|
1745
|
+
content = line.sub(/^\s*#\s*/, '')
|
|
1746
|
+
if (m = content.match(/@param\s+(\S+)\s+\[/))
|
|
1747
|
+
return m[1]
|
|
1748
|
+
elsif (m = content.match(/@param\s+\[/))
|
|
1749
|
+
name_end = m.end(0) #: Integer
|
|
1750
|
+
rest = content[(name_end - 1)..] #: String
|
|
1751
|
+
type_end = find_matching_close_bracket(rest)
|
|
1752
|
+
return name_after_type_bracket(rest, type_end) if type_end
|
|
1753
|
+
end
|
|
743
1754
|
|
|
744
1755
|
nil
|
|
745
1756
|
end
|
|
746
1757
|
|
|
747
|
-
#
|
|
1758
|
+
# Extract name after type bracket
|
|
748
1759
|
#
|
|
749
|
-
# @note module_function:
|
|
750
|
-
# @param [
|
|
751
|
-
# @
|
|
1760
|
+
# @note module_function: defines #name_after_type_bracket (visibility: private)
|
|
1761
|
+
# @param [String] rest tag content after bracket
|
|
1762
|
+
# @param [Integer] type_end closing bracket position
|
|
1763
|
+
# @return [String?]
|
|
1764
|
+
def name_after_type_bracket(rest, type_end)
|
|
1765
|
+
rest[(type_end + 1)..].to_s.strip.split(/\s+/).first
|
|
1766
|
+
end
|
|
1767
|
+
|
|
1768
|
+
# Extract param type from param line
|
|
1769
|
+
#
|
|
1770
|
+
# @note module_function: defines #extract_param_type_from_param_line (visibility: private)
|
|
1771
|
+
# @param [String] line a `@param` tag line
|
|
1772
|
+
# @return [String, nil]
|
|
752
1773
|
def extract_param_type_from_param_line(line)
|
|
753
|
-
|
|
754
|
-
|
|
1774
|
+
content = line.sub(/^\s*#\s*/, '')
|
|
1775
|
+
if (m = content.match(/@param\s+(\S+\s+)?\[/))
|
|
1776
|
+
name_end = m.end(0) #: Integer
|
|
1777
|
+
rest = content[(name_end - 1)..] #: String
|
|
1778
|
+
type_end = find_matching_close_bracket(rest)
|
|
1779
|
+
return rest[1...type_end] if type_end
|
|
1780
|
+
end
|
|
1781
|
+
nil
|
|
1782
|
+
end
|
|
1783
|
+
|
|
1784
|
+
# Find matching close bracket
|
|
1785
|
+
#
|
|
1786
|
+
# @note module_function: defines #find_matching_close_bracket (visibility: private)
|
|
1787
|
+
# @param [String] str string to scan
|
|
1788
|
+
# @return [Integer, nil]
|
|
1789
|
+
def find_matching_close_bracket(str)
|
|
1790
|
+
depth = 0
|
|
1791
|
+
str.each_char.with_index do |c, i|
|
|
1792
|
+
case c
|
|
1793
|
+
when '[' then depth += 1
|
|
1794
|
+
when ']'
|
|
1795
|
+
depth -= 1
|
|
1796
|
+
return i if depth.zero?
|
|
1797
|
+
end
|
|
1798
|
+
end
|
|
1799
|
+
nil
|
|
1800
|
+
end
|
|
1801
|
+
|
|
1802
|
+
# Collect missing raises
|
|
1803
|
+
#
|
|
1804
|
+
# @note module_function: defines #collect_missing_raises! (visibility: private)
|
|
1805
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1806
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
1807
|
+
# @param [Object] ctx merged context hash with info and indent
|
|
1808
|
+
# @return [void]
|
|
1809
|
+
def collect_missing_raises!(lines, reasons, **ctx)
|
|
1810
|
+
return unless ctx[:config].emit_raise_tags?
|
|
1811
|
+
|
|
1812
|
+
inferred = Docscribe::Infer.infer_raises_from_node(ctx[:node])
|
|
1813
|
+
existing = ctx[:info][:raise_types] || {}
|
|
1814
|
+
missing = inferred.reject { |rt| existing[rt] }
|
|
1815
|
+
|
|
1816
|
+
missing.each do |rt|
|
|
1817
|
+
lines << "#{ctx[:indent]}# @raise [#{rt}]\n"
|
|
1818
|
+
reasons << { type: :missing_raise, message: "missing @raise [#{rt}]", extra: { raise_type: rt } }
|
|
755
1819
|
end
|
|
756
1820
|
end
|
|
757
1821
|
|
|
758
|
-
#
|
|
1822
|
+
# Collect missing return
|
|
759
1823
|
#
|
|
760
|
-
# @note module_function
|
|
761
|
-
# @
|
|
762
|
-
# @param [
|
|
1824
|
+
# @note module_function: defines #collect_missing_return! (visibility: private)
|
|
1825
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1826
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
1827
|
+
# @param [Object] ctx merged context hash with info and indent
|
|
1828
|
+
# @return [void]
|
|
1829
|
+
def collect_missing_return!(lines, reasons, **ctx)
|
|
1830
|
+
return unless ctx[:config].emit_return_tag?(ctx[:scope], ctx[:visibility])
|
|
1831
|
+
|
|
1832
|
+
if !ctx[:info][:has_return]
|
|
1833
|
+
record_missing_return(lines, reasons, ctx)
|
|
1834
|
+
elsif return_type_changed?(ctx)
|
|
1835
|
+
record_updated_return(lines, reasons, ctx)
|
|
1836
|
+
end
|
|
1837
|
+
end
|
|
1838
|
+
|
|
1839
|
+
# Record missing return
|
|
1840
|
+
#
|
|
1841
|
+
# @note module_function: defines #record_missing_return (visibility: private)
|
|
1842
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1843
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
1844
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with normal_type and indent
|
|
1845
|
+
# @return [void]
|
|
1846
|
+
def record_missing_return(lines, reasons, ctx)
|
|
1847
|
+
lines << "#{ctx[:indent]}# @return [#{ctx[:normal_type]}]\n"
|
|
1848
|
+
reasons << { type: :missing_return, message: 'missing @return' }
|
|
1849
|
+
end
|
|
1850
|
+
|
|
1851
|
+
# Record updated return
|
|
1852
|
+
#
|
|
1853
|
+
# @note module_function: defines #record_updated_return (visibility: private)
|
|
1854
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1855
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
1856
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with normal_type and info
|
|
1857
|
+
# @return [void]
|
|
1858
|
+
def record_updated_return(lines, reasons, ctx)
|
|
1859
|
+
lines << "#{ctx[:indent]}# @return [#{ctx[:normal_type]}]\n" unless ctx[:strategy] == :safe
|
|
1860
|
+
reasons << { type: :updated_return,
|
|
1861
|
+
message: "updated @return from #{ctx[:info][:return_type]} to #{ctx[:normal_type]}" }
|
|
1862
|
+
end
|
|
1863
|
+
|
|
1864
|
+
# Return type changed
|
|
1865
|
+
#
|
|
1866
|
+
# @note module_function: defines #return_type_changed? (visibility: private)
|
|
1867
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with external_sig, info, and normal_type
|
|
1868
|
+
# @return [Boolean]
|
|
1869
|
+
def return_type_changed?(ctx)
|
|
1870
|
+
ctx[:external_sig] && ctx[:info][:return_type] && ctx[:info][:return_type] != ctx[:normal_type]
|
|
1871
|
+
end
|
|
1872
|
+
|
|
1873
|
+
# Collect missing rescue returns
|
|
1874
|
+
#
|
|
1875
|
+
# @note module_function: defines #collect_missing_rescue_returns! (visibility: private)
|
|
1876
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1877
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
1878
|
+
# @param [Object] ctx merged context hash with info and indent
|
|
1879
|
+
# @return [void]
|
|
1880
|
+
def collect_missing_rescue_returns!(lines, reasons, **ctx)
|
|
1881
|
+
return unless ctx[:config].emit_rescue_conditional_returns?
|
|
1882
|
+
return if ctx[:info][:has_return]
|
|
1883
|
+
|
|
1884
|
+
ctx[:rescue_specs].each do |exceptions, rtype|
|
|
1885
|
+
lines << "#{ctx[:indent]}# @return [#{rtype}] if #{exceptions.join(', ')}\n"
|
|
1886
|
+
reasons << {
|
|
1887
|
+
type: :missing_return,
|
|
1888
|
+
message: "missing conditional @return for #{exceptions.join(', ')}"
|
|
1889
|
+
}
|
|
1890
|
+
end
|
|
1891
|
+
end
|
|
1892
|
+
|
|
1893
|
+
# Collect missing plugin tags
|
|
1894
|
+
#
|
|
1895
|
+
# @note module_function: defines #collect_missing_plugin_tags! (visibility: private)
|
|
1896
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1897
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
1898
|
+
# @param [Object] ctx merged context hash with info and indent
|
|
1899
|
+
# @return [void]
|
|
1900
|
+
def collect_missing_plugin_tags!(lines, reasons, **ctx)
|
|
1901
|
+
plugin_tags = Docscribe::Plugin.run_tag_plugins(build_plugin_context(ctx[:insertion],
|
|
1902
|
+
normal_type: ctx[:normal_type]))
|
|
1903
|
+
plugin_tags.concat(Array(ctx[:override_tags])) if ctx[:override_tags]
|
|
1904
|
+
|
|
1905
|
+
plugin_tags.each { |tag| record_plugin_tag(tag, lines, reasons, ctx) }
|
|
1906
|
+
end
|
|
1907
|
+
|
|
1908
|
+
# Record plugin tag
|
|
1909
|
+
#
|
|
1910
|
+
# @note module_function: defines #record_plugin_tag (visibility: private)
|
|
1911
|
+
# @param [Object] tag plugin tag object to render and record
|
|
1912
|
+
# @param [Array<String>] lines array of output doc lines being accumulated
|
|
1913
|
+
# @param [Array<Hash<Symbol, Object>>] reasons array of reason hashes for --explain output
|
|
1914
|
+
# @param [Hash<Symbol, Object>] ctx merged context hash with info and indent
|
|
1915
|
+
# @return [void]
|
|
1916
|
+
def record_plugin_tag(tag, lines, reasons, ctx)
|
|
1917
|
+
return if ctx[:info][:plugin_tags]&.[](tag.name)
|
|
1918
|
+
|
|
1919
|
+
rendered = render_plugin_tags([tag], ctx[:indent]).first
|
|
1920
|
+
lines << "#{rendered}\n"
|
|
1921
|
+
reasons << { type: :missing_plugin_tag, message: "missing @#{tag.name}" }
|
|
1922
|
+
end
|
|
1923
|
+
|
|
1924
|
+
# Debug warn
|
|
1925
|
+
#
|
|
1926
|
+
# @note module_function: defines #debug_warn (visibility: private)
|
|
1927
|
+
# @param [StandardError] error the error that occurred
|
|
1928
|
+
# @param [Object] insertion the method insertion being processed
|
|
1929
|
+
# @param [String] name the method name
|
|
1930
|
+
# @param [String] phase the processing phase
|
|
1931
|
+
# @return [void]
|
|
1932
|
+
def debug_warn(error, insertion:, name:, phase:)
|
|
1933
|
+
return unless debug?
|
|
1934
|
+
|
|
1935
|
+
where = build_debug_location(insertion, name)
|
|
1936
|
+
warn "Docscribe DEBUG: #{phase} failed at #{where}: #{error.class}: #{error.message}"
|
|
1937
|
+
end
|
|
1938
|
+
|
|
1939
|
+
# Build debug location
|
|
1940
|
+
#
|
|
1941
|
+
# @note module_function: defines #build_debug_location (visibility: private)
|
|
1942
|
+
# @param [Object] insertion the collected method insertion object
|
|
1943
|
+
# @param [String] name the method name string
|
|
1944
|
+
# @return [String]
|
|
1945
|
+
def build_debug_location(insertion, name)
|
|
1946
|
+
return name.to_s unless insertion
|
|
1947
|
+
|
|
1948
|
+
expr = insertion.node.loc.expression
|
|
1949
|
+
buf = expr.source_buffer.name
|
|
1950
|
+
sym = insertion.scope == :class ? '.' : '#'
|
|
1951
|
+
ctr = insertion.container || 'Object'
|
|
1952
|
+
+"#{buf}:#{expr.line} #{ctr}#{sym}#{name}"
|
|
1953
|
+
end
|
|
1954
|
+
|
|
1955
|
+
# Debug
|
|
1956
|
+
#
|
|
1957
|
+
# @note module_function: defines #debug? (visibility: private)
|
|
1958
|
+
# @return [Boolean]
|
|
1959
|
+
def debug?
|
|
1960
|
+
ENV['DOCSCRIBE_DEBUG'] == '1'
|
|
1961
|
+
end
|
|
1962
|
+
|
|
1963
|
+
# Build plugin context
|
|
1964
|
+
#
|
|
1965
|
+
# @note module_function: defines #build_plugin_context (visibility: private)
|
|
1966
|
+
# @param [Object] insertion the collected method insertion object
|
|
763
1967
|
# @param [String] normal_type resolved return type
|
|
764
|
-
# @
|
|
765
|
-
# @return [Docscribe::Plugin::Context]
|
|
1968
|
+
# @return [Object]
|
|
766
1969
|
def build_plugin_context(insertion, normal_type:)
|
|
767
1970
|
node = insertion.node
|
|
768
|
-
source =
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
''
|
|
772
|
-
end
|
|
1971
|
+
source = safe_node_source(node)
|
|
1972
|
+
new_plugin_context(insertion, node, source, normal_type)
|
|
1973
|
+
end
|
|
773
1974
|
|
|
1975
|
+
# New plugin context
|
|
1976
|
+
#
|
|
1977
|
+
# @note module_function: defines #new_plugin_context (visibility: private)
|
|
1978
|
+
# @param [Object] insertion the collected method insertion object
|
|
1979
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
1980
|
+
# @param [String] source method source text
|
|
1981
|
+
# @param [String] normal_type resolved return type
|
|
1982
|
+
# @return [Object]
|
|
1983
|
+
def new_plugin_context(insertion, node, source, normal_type)
|
|
774
1984
|
Docscribe::Plugin::Context.new(
|
|
775
1985
|
node: node,
|
|
776
1986
|
container: insertion.container,
|
|
777
1987
|
scope: insertion.scope,
|
|
778
1988
|
visibility: insertion.visibility,
|
|
779
|
-
method_name: SourceHelpers.node_name(node),
|
|
1989
|
+
method_name: SourceHelpers.node_name(node), #: Symbol
|
|
780
1990
|
inferred_params: {},
|
|
781
1991
|
inferred_return: normal_type,
|
|
782
1992
|
source: source
|
|
783
1993
|
)
|
|
784
1994
|
end
|
|
785
1995
|
|
|
786
|
-
#
|
|
1996
|
+
# Safe node source
|
|
1997
|
+
#
|
|
1998
|
+
# @note module_function: defines #safe_node_source (visibility: private)
|
|
1999
|
+
# @param [Parser::AST::Node] node AST node whose source text to extract
|
|
2000
|
+
# @raise [StandardError]
|
|
2001
|
+
# @return [String] if StandardError
|
|
2002
|
+
# @return [String] if StandardError
|
|
2003
|
+
def safe_node_source(node)
|
|
2004
|
+
node.loc.expression.source
|
|
2005
|
+
rescue StandardError
|
|
2006
|
+
''
|
|
2007
|
+
end
|
|
2008
|
+
|
|
2009
|
+
# Render plugin tags
|
|
787
2010
|
#
|
|
788
|
-
# @note module_function
|
|
789
|
-
# @
|
|
790
|
-
# @param [
|
|
791
|
-
# @param [String] indent
|
|
2011
|
+
# @note module_function: defines #render_plugin_tags (visibility: private)
|
|
2012
|
+
# @param [Array<Object>] tags plugin tag objects
|
|
2013
|
+
# @param [String] indent indentation string for the doc line
|
|
792
2014
|
# @return [Array<String>]
|
|
793
2015
|
def render_plugin_tags(tags, indent)
|
|
794
2016
|
tags.map do |tag|
|
|
@@ -797,39 +2019,6 @@ module Docscribe
|
|
|
797
2019
|
"#{indent}# @#{tag.name}#{type_part}#{text_part}"
|
|
798
2020
|
end
|
|
799
2021
|
end
|
|
800
|
-
|
|
801
|
-
# Print a debug warning for a failed doc build phase.
|
|
802
|
-
#
|
|
803
|
-
# @note module_function: when included, also defines #debug_warn (instance visibility: private)
|
|
804
|
-
# @param [StandardError] e the error that occurred
|
|
805
|
-
# @param [Collector::Insertion] insertion the method insertion being processed
|
|
806
|
-
# @param [String] name the method name
|
|
807
|
-
# @param [String] phase the processing phase
|
|
808
|
-
# @return [void]
|
|
809
|
-
def debug_warn(e, insertion:, name:, phase:)
|
|
810
|
-
return unless debug?
|
|
811
|
-
|
|
812
|
-
node = insertion&.node
|
|
813
|
-
buf_name = node&.loc&.expression&.source_buffer&.name || '(unknown)'
|
|
814
|
-
line = node&.loc&.expression&.line
|
|
815
|
-
scope = insertion&.scope
|
|
816
|
-
method_symbol = scope == :class ? '.' : '#'
|
|
817
|
-
container = insertion&.container || 'Object'
|
|
818
|
-
|
|
819
|
-
where = +buf_name.to_s
|
|
820
|
-
where << ":#{line}" if line
|
|
821
|
-
where << " #{container}#{method_symbol}#{name}"
|
|
822
|
-
|
|
823
|
-
warn "Docscribe DEBUG: #{phase} failed at #{where}: #{e.class}: #{e.message}"
|
|
824
|
-
end
|
|
825
|
-
|
|
826
|
-
# Check whether debug mode is enabled.
|
|
827
|
-
#
|
|
828
|
-
# @note module_function: when included, also defines #debug? (instance visibility: private)
|
|
829
|
-
# @return [Boolean]
|
|
830
|
-
def debug?
|
|
831
|
-
ENV['DOCSCRIBE_DEBUG'] == '1'
|
|
832
|
-
end
|
|
833
2022
|
end
|
|
834
2023
|
end
|
|
835
2024
|
end
|