docscribe 1.4.2 → 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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +465 -130
  3. data/lib/docscribe/cli/check_for_comments.rb +183 -0
  4. data/lib/docscribe/cli/config_builder.rb +107 -53
  5. data/lib/docscribe/cli/formatters/json.rb +294 -0
  6. data/lib/docscribe/cli/formatters/sarif.rb +235 -0
  7. data/lib/docscribe/cli/formatters/text.rb +208 -0
  8. data/lib/docscribe/cli/formatters.rb +26 -0
  9. data/lib/docscribe/cli/generate.rb +45 -45
  10. data/lib/docscribe/cli/init.rb +14 -6
  11. data/lib/docscribe/cli/options.rb +190 -88
  12. data/lib/docscribe/cli/rbs_gen.rb +529 -0
  13. data/lib/docscribe/cli/run.rb +210 -152
  14. data/lib/docscribe/cli/sigs.rb +366 -0
  15. data/lib/docscribe/cli/update_types.rb +103 -0
  16. data/lib/docscribe/cli.rb +21 -13
  17. data/lib/docscribe/config/defaults.rb +5 -1
  18. data/lib/docscribe/config/emit.rb +17 -0
  19. data/lib/docscribe/config/filtering.rb +18 -25
  20. data/lib/docscribe/config/loader.rb +15 -11
  21. data/lib/docscribe/config/plugin.rb +1 -1
  22. data/lib/docscribe/config/rbs.rb +41 -9
  23. data/lib/docscribe/config/sorbet.rb +9 -12
  24. data/lib/docscribe/config/sorting.rb +1 -1
  25. data/lib/docscribe/config/template.rb +9 -1
  26. data/lib/docscribe/config/utils.rb +11 -9
  27. data/lib/docscribe/config.rb +2 -4
  28. data/lib/docscribe/infer/ast_walk.rb +1 -1
  29. data/lib/docscribe/infer/literals.rb +6 -11
  30. data/lib/docscribe/infer/names.rb +2 -3
  31. data/lib/docscribe/infer/params.rb +15 -17
  32. data/lib/docscribe/infer/raises.rb +3 -5
  33. data/lib/docscribe/infer/returns.rb +542 -140
  34. data/lib/docscribe/infer.rb +22 -23
  35. data/lib/docscribe/inline_rewriter/collector.rb +159 -164
  36. data/lib/docscribe/inline_rewriter/doc_block.rb +145 -115
  37. data/lib/docscribe/inline_rewriter/doc_builder.rb +1026 -723
  38. data/lib/docscribe/inline_rewriter/source_helpers.rb +49 -49
  39. data/lib/docscribe/inline_rewriter/tag_sorter.rb +82 -85
  40. data/lib/docscribe/inline_rewriter.rb +495 -492
  41. data/lib/docscribe/parsing.rb +29 -10
  42. data/lib/docscribe/plugin/base/collector_plugin.rb +2 -1
  43. data/lib/docscribe/plugin/base/tag_plugin.rb +0 -1
  44. data/lib/docscribe/plugin/context.rb +28 -18
  45. data/lib/docscribe/plugin/registry.rb +26 -27
  46. data/lib/docscribe/plugin/tag.rb +9 -14
  47. data/lib/docscribe/plugin.rb +17 -16
  48. data/lib/docscribe/types/provider_chain.rb +4 -2
  49. data/lib/docscribe/types/rbs/collection_loader.rb +2 -2
  50. data/lib/docscribe/types/rbs/provider.rb +60 -44
  51. data/lib/docscribe/types/rbs/type_formatter.rb +224 -83
  52. data/lib/docscribe/types/signature.rb +22 -42
  53. data/lib/docscribe/types/sorbet/base_provider.rb +24 -19
  54. data/lib/docscribe/types/sorbet/rbi_provider.rb +3 -3
  55. data/lib/docscribe/types/sorbet/source_provider.rb +3 -2
  56. data/lib/docscribe/types/yard/formatter.rb +100 -0
  57. data/lib/docscribe/types/yard/parser.rb +240 -0
  58. data/lib/docscribe/types/yard/types.rb +52 -0
  59. data/lib/docscribe/version.rb +1 -1
  60. metadata +33 -1
@@ -0,0 +1,208 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docscribe
4
+ module CLI
5
+ module Formatters
6
+ # Text output formatter preserving the original CLI output format.
7
+ class Text
8
+ # Format and print check summary.
9
+ #
10
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
11
+ # @param [Docscribe::CLI::Formatters::opts] options runtime options hash
12
+ # @return [void]
13
+ def format_check_summary(state:, options:)
14
+ puts
15
+ format_fail_paths(state, options)
16
+ format_check_status_line(state)
17
+ format_type_mismatch_paths(state, options)
18
+ format_error_paths(state)
19
+ end
20
+
21
+ # Format and print write summary.
22
+ #
23
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
24
+ # @param [Docscribe::CLI::Formatters::opts] options runtime options hash
25
+ # @return [void]
26
+ def format_write_summary(state:, options:)
27
+ puts
28
+ puts "Docscribe: updated #{state[:corrected]} file(s)" if state[:corrected].positive?
29
+ format_corrected_paths(state, options)
30
+
31
+ return unless state[:had_errors]
32
+
33
+ warn "Docscribe: #{state[:error_paths].size} file(s) had errors"
34
+ format_error_paths(state)
35
+ end
36
+
37
+ # Print files needing updates.
38
+ #
39
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
40
+ # @param [Docscribe::CLI::Formatters::opts] options runtime options hash
41
+ # @return [void]
42
+ def format_fail_paths(state, options)
43
+ state[:fail_paths].each do |p|
44
+ puts "Would update: #{p}"
45
+
46
+ next if options[:verbose] || options[:quiet]
47
+
48
+ Array(state[:fail_changes][p]).each do |change|
49
+ puts " - #{format_change_reason(change)}"
50
+ end
51
+ end
52
+ end
53
+
54
+ # Print check status line.
55
+ #
56
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
57
+ # @return [void]
58
+ def format_check_status_line(state)
59
+ checked_error = state[:error_paths].size
60
+ type_mismatch_count = state[:type_mismatch_paths].size
61
+
62
+ if all_fine?(state, checked_error, type_mismatch_count)
63
+ puts "Docscribe: OK (#{state[:checked_ok]} files checked)"
64
+ elsif mismatch_only?(state, checked_error)
65
+ puts "Docscribe: OK (#{state[:checked_ok]} files checked, #{type_mismatch_count} with type mismatches)"
66
+ else
67
+ puts failure_line(state, type_mismatch_count, checked_error)
68
+ end
69
+ end
70
+
71
+ # Print type mismatch warnings.
72
+ #
73
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
74
+ # @param [Docscribe::CLI::Formatters::opts] options runtime options hash
75
+ # @return [void]
76
+ def format_type_mismatch_paths(state, options)
77
+ return if options[:quiet]
78
+ return unless options[:verbose] || options[:explain]
79
+
80
+ state[:type_mismatch_paths].each do |p|
81
+ warn "Type mismatches: #{p}"
82
+ Array(state[:type_mismatch_changes][p]).each do |change|
83
+ warn " - #{format_change_reason(change)}"
84
+ end
85
+ end
86
+ end
87
+
88
+ # Print updated file paths.
89
+ #
90
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
91
+ # @param [Docscribe::CLI::Formatters::opts] options runtime options hash
92
+ # @return [void]
93
+ def format_corrected_paths(state, options)
94
+ state[:corrected_paths].each do |p|
95
+ puts "Updated: #{p}"
96
+
97
+ next if options[:verbose] || options[:quiet]
98
+
99
+ Array(state[:corrected_changes][p]).each do |change|
100
+ puts " - #{format_change_reason(change)}"
101
+ end
102
+ end
103
+ end
104
+
105
+ # Print error file messages.
106
+ #
107
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
108
+ # @return [void]
109
+ def format_error_paths(state)
110
+ return if state[:error_paths].empty?
111
+
112
+ warn ''
113
+ state[:error_paths].each do |p|
114
+ warn "Error processing: #{p}"
115
+ warn " #{state[:error_messages][p]}" if state[:error_messages][p]
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ # Check if all files passed.
122
+ #
123
+ # @private
124
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
125
+ # @param [Integer] checked_error count of error files
126
+ # @param [Integer] type_mismatch_count count of type mismatches
127
+ # @return [Boolean]
128
+ def all_fine?(state, checked_error, type_mismatch_count)
129
+ state[:checked_fail].zero? && checked_error.zero? && type_mismatch_count.zero?
130
+ end
131
+
132
+ # Check only type mismatches.
133
+ #
134
+ # @private
135
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
136
+ # @param [Integer] checked_error count of error files
137
+ # @return [Boolean]
138
+ def mismatch_only?(state, checked_error)
139
+ state[:checked_fail].zero? && checked_error.zero?
140
+ end
141
+
142
+ # Build failure status line.
143
+ #
144
+ # @private
145
+ # @param [Docscribe::CLI::Formatters::state] state formatter state hash
146
+ # @param [Integer] type_mismatch_count count of type mismatches
147
+ # @param [Integer] checked_error count of error files
148
+ # @return [String]
149
+ def failure_line(state, type_mismatch_count, checked_error)
150
+ parts = ["#{state[:checked_fail]} need updates"]
151
+ parts << "#{type_mismatch_count} type mismatches" if type_mismatch_count.positive?
152
+ parts << "#{checked_error} errors"
153
+ parts << "#{state[:checked_ok]} ok"
154
+ "Docscribe: FAILED (#{parts.join(', ')})"
155
+ end
156
+
157
+ # Format change reason string.
158
+ #
159
+ # @private
160
+ # @param [Docscribe::CLI::Formatters::change] change change info hash
161
+ # @return [String]
162
+ def format_change_reason(change)
163
+ line = change_line_suffix(change)
164
+ method = change_method_suffix(change)
165
+
166
+ return "unsorted tags#{line}" if change[:type] == :unsorted_tags
167
+ return "#{change[:message]}#{method}#{line}" if direct_message_change?(change)
168
+
169
+ "#{change[:message] || change[:type].to_s.tr('_', ' ')}#{method}#{line}"
170
+ end
171
+
172
+ # Build change line suffix.
173
+ #
174
+ # @private
175
+ # @param [Docscribe::CLI::Formatters::change] change change info hash
176
+ # @return [String]
177
+ def change_line_suffix(change)
178
+ change[:line] ? " at line #{change[:line]}" : ''
179
+ end
180
+
181
+ # Build change method suffix.
182
+ #
183
+ # @private
184
+ # @param [Docscribe::CLI::Formatters::change] change change info hash
185
+ # @return [String]
186
+ def change_method_suffix(change)
187
+ change[:method] ? " for #{change[:method]}" : ''
188
+ end
189
+
190
+ # Check direct message type.
191
+ #
192
+ # @private
193
+ # @param [Docscribe::CLI::Formatters::change] change change info hash
194
+ # @return [Boolean]
195
+ def direct_message_change?(change)
196
+ %i[
197
+ missing_param
198
+ missing_return
199
+ missing_raise
200
+ missing_visibility
201
+ missing_module_function_note
202
+ insert_full_doc_block
203
+ ].include?(change[:type])
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docscribe
4
+ module CLI
5
+ # Factory for output formatters.
6
+ module Formatters
7
+ # Select formatter by format type.
8
+ #
9
+ # @param [Docscribe::CLI::Formatters::format] format output format symbol
10
+ # @raise [ArgumentError]
11
+ # @return [Docscribe::CLI::Formatters::Text, Docscribe::CLI::Formatters::Json, Docscribe::CLI::Formatters::Sarif]
12
+ def self.for(format)
13
+ case format
14
+ when :text then Text.new
15
+ when :json then Json.new
16
+ when :sarif then Sarif.new
17
+ else raise ArgumentError, "Unknown format: #{format}"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ require_relative 'formatters/text'
25
+ require_relative 'formatters/json'
26
+ require_relative 'formatters/sarif'
@@ -34,8 +34,7 @@ module Docscribe
34
34
  class << self
35
35
  # Run the `generate` subcommand.
36
36
  #
37
- # @param [Array<String>] argv
38
- # @raise [OptionParser::InvalidOption]
37
+ # @param [Array<String>] argv command line arguments
39
38
  # @return [Integer] exit code
40
39
  def run(argv)
41
40
  opts, parser = parse_generate_options(argv)
@@ -54,9 +53,9 @@ module Docscribe
54
53
  # Parse options for the generate subcommand.
55
54
  #
56
55
  # @private
57
- # @param [Array<String>] argv
56
+ # @param [Array<String>] argv command line arguments
58
57
  # @raise [OptionParser::InvalidOption]
59
- # @return [Array(Hash, OptionParser)]
58
+ # @return [(Hash<Symbol, Object>, OptionParser)]
60
59
  def parse_generate_options(argv)
61
60
  opts = { output: nil, stdout: false, help: false }
62
61
  parser = build_option_parser(opts)
@@ -74,8 +73,8 @@ module Docscribe
74
73
  # Extract plugin_type and class_name from remaining argv.
75
74
  #
76
75
  # @private
77
- # @param [Array<String>] argv
78
- # @return [Array(String, String)]
76
+ # @param [Array<String>] argv command line arguments
77
+ # @return [(String?, String?)]
79
78
  def extract_generate_args(argv)
80
79
  [argv.shift, argv.shift]
81
80
  end
@@ -83,9 +82,9 @@ module Docscribe
83
82
  # Validate generate arguments and return exit code on failure.
84
83
  #
85
84
  # @private
86
- # @param [String, nil] plugin_type
87
- # @param [String, nil] class_name
88
- # @param [OptionParser] parser
85
+ # @param [String?] plugin_type 'tag' or 'collector'
86
+ # @param [String?] class_name CamelCase plugin class name
87
+ # @param [OptionParser] parser option parser instance
89
88
  # @return [Integer, nil] exit code or nil if valid
90
89
  def validate_generate_args(plugin_type, class_name, parser)
91
90
  return 1 unless args_provided?(plugin_type, class_name, parser)
@@ -98,9 +97,9 @@ module Docscribe
98
97
  # Render plugin boilerplate for the given type and class name.
99
98
  #
100
99
  # @private
101
- # @param [String] plugin_type 'tag' or 'collector'
102
- # @param [String] class_name CamelCase plugin class name
103
- # @return [String]
100
+ # @param [String?] plugin_type 'tag' or 'collector'
101
+ # @param [String?] class_name CamelCase plugin class name
102
+ # @return [String?]
104
103
  def render(plugin_type, class_name)
105
104
  case plugin_type
106
105
  when 'tag' then tag_template(class_name)
@@ -111,7 +110,7 @@ module Docscribe
111
110
  # Template for a TagPlugin.
112
111
  #
113
112
  # @private
114
- # @param [String] class_name
113
+ # @param [String?] class_name CamelCase plugin class name
115
114
  # @return [String]
116
115
  def tag_template(class_name)
117
116
  <<~RUBY
@@ -169,7 +168,7 @@ module Docscribe
169
168
  # Template for a CollectorPlugin.
170
169
  #
171
170
  # @private
172
- # @param [String] class_name
171
+ # @param [String?] class_name CamelCase plugin class name
173
172
  # @return [String]
174
173
  def collector_template(class_name)
175
174
  <<~RUBY
@@ -237,10 +236,10 @@ module Docscribe
237
236
  # Write generated plugin to a file or print to STDOUT based on options.
238
237
  #
239
238
  # @private
240
- # @param [String] content generated plugin source code
241
- # @param [String] plugin_type 'tag' or 'collector'
242
- # @param [String] class_name CamelCase plugin class name
243
- # @param [Hash] opts parsed options hash
239
+ # @param [String?] content generated plugin source code
240
+ # @param [String?] plugin_type 'tag' or 'collector'
241
+ # @param [String?] class_name CamelCase plugin class name
242
+ # @param [Hash<Symbol, Object>] opts parsed options hash
244
243
  # @return [Integer] exit code
245
244
  def dispatch_output(content, plugin_type, class_name, opts)
246
245
  if opts[:stdout]
@@ -254,10 +253,10 @@ module Docscribe
254
253
  # Write the generated content to a file.
255
254
  #
256
255
  # @private
257
- # @param [String] content
258
- # @param [String] plugin_type
259
- # @param [String] class_name
260
- # @param [String] output_dir
256
+ # @param [String?] content file content to write
257
+ # @param [String?] plugin_type 'tag' or 'collector'
258
+ # @param [String?] class_name CamelCase plugin class name
259
+ # @param [String?] output_dir output directory path
261
260
  # @return [Integer] exit code
262
261
  def write_plugin(content, plugin_type:, class_name:, output_dir:)
263
262
  path = plugin_path(class_name, output_dir)
@@ -272,7 +271,7 @@ module Docscribe
272
271
  # Build the OptionParser for the generate subcommand.
273
272
  #
274
273
  # @private
275
- # @param [Hash] opts mutable parsed options hash
274
+ # @param [Hash<Symbol, Object>] opts mutable parsed options hash
276
275
  # @return [OptionParser]
277
276
  def build_option_parser(opts)
278
277
  OptionParser.new do |opt|
@@ -302,8 +301,8 @@ module Docscribe
302
301
  # Register the --output option on the OptionParser.
303
302
  #
304
303
  # @private
305
- # @param [OptionParser] opt
306
- # @param [Hash] opts mutable parsed options hash
304
+ # @param [OptionParser] opt option parser instance
305
+ # @param [Hash<Symbol, Object>] opts mutable parsed options hash
307
306
  # @return [void]
308
307
  def register_output_option(opt, opts)
309
308
  opt.on('--output DIR', 'Directory to write the plugin file (default: .)') { |v| opts[:output] = v }
@@ -312,8 +311,8 @@ module Docscribe
312
311
  # Register the --stdout option on the OptionParser.
313
312
  #
314
313
  # @private
315
- # @param [OptionParser] opt
316
- # @param [Hash] opts mutable parsed options hash
314
+ # @param [OptionParser] opt option parser instance
315
+ # @param [Hash<Symbol, Object>] opts mutable parsed options hash
317
316
  # @return [void]
318
317
  def register_stdout_option(opt, opts)
319
318
  opt.on('--stdout', 'Print the generated plugin to STDOUT instead of writing a file') { opts[:stdout] = true }
@@ -322,11 +321,12 @@ module Docscribe
322
321
  # Register the -h/--help option on the OptionParser.
323
322
  #
324
323
  # @private
325
- # @param [OptionParser] opt
326
- # @param [Hash] opts mutable parsed options hash
324
+ # @param [OptionParser] opt option parser instance
325
+ # @param [Hash<Symbol, Object>] opts mutable parsed options hash
327
326
  # @return [void]
328
327
  def register_help_option(opt, opts)
329
328
  opt.on('-h', '--help', 'Show this help') do
329
+ puts opt
330
330
  opts[:help] = true
331
331
  end
332
332
  end
@@ -334,9 +334,9 @@ module Docscribe
334
334
  # Validate that both plugin_type and class_name arguments were provided.
335
335
  #
336
336
  # @private
337
- # @param [String, nil] plugin_type plugin type argument
338
- # @param [String, nil] class_name plugin class name argument
339
- # @param [OptionParser] parser
337
+ # @param [String?] plugin_type plugin type argument
338
+ # @param [String?] class_name plugin class name argument
339
+ # @param [OptionParser] parser option parser instance
340
340
  # @return [Boolean]
341
341
  def args_provided?(plugin_type, class_name, parser)
342
342
  return true if plugin_type && class_name
@@ -349,7 +349,7 @@ module Docscribe
349
349
  # Validate that the plugin type is one of the recognized types.
350
350
  #
351
351
  # @private
352
- # @param [String] plugin_type plugin type to validate
352
+ # @param [String?] plugin_type plugin type to validate
353
353
  # @return [Boolean]
354
354
  def known_type?(plugin_type)
355
355
  return true if PLUGIN_TYPES.include?(plugin_type)
@@ -361,7 +361,7 @@ module Docscribe
361
361
  # Validate that the class name is a valid Ruby constant name.
362
362
  #
363
363
  # @private
364
- # @param [String] class_name class name to validate
364
+ # @param [String?] class_name class name to validate
365
365
  # @return [Boolean]
366
366
  def valid_name?(class_name)
367
367
  return true if valid_constant?(class_name)
@@ -373,7 +373,7 @@ module Docscribe
373
373
  # Check whether a string is a valid Ruby constant name.
374
374
  #
375
375
  # @private
376
- # @param [String] str
376
+ # @param [String?] str string constant to validate
377
377
  # @return [Boolean]
378
378
  def valid_constant?(str)
379
379
  !!(str =~ /\A[A-Z][A-Za-z0-9]*(?:::[A-Z][A-Za-z0-9]*)*\z/)
@@ -382,8 +382,8 @@ module Docscribe
382
382
  # Build the file path for the generated plugin.
383
383
  #
384
384
  # @private
385
- # @param [String] class_name CamelCase plugin class name
386
- # @param [String] output_dir output directory
385
+ # @param [String?] class_name CamelCase plugin class name
386
+ # @param [String?] output_dir output directory
387
387
  # @return [String] full file path
388
388
  def plugin_path(class_name, output_dir)
389
389
  File.join(output_dir || '.', "#{underscore(class_name || '')}.rb")
@@ -392,7 +392,7 @@ module Docscribe
392
392
  # Convert CamelCase to snake_case for file naming.
393
393
  #
394
394
  # @private
395
- # @param [String] str
395
+ # @param [String] str CamelCase string to convert
396
396
  # @return [String]
397
397
  def underscore(str)
398
398
  str
@@ -416,9 +416,9 @@ module Docscribe
416
416
  # Create the output directory and write the plugin file.
417
417
  #
418
418
  # @private
419
- # @param [String] output_dir output directory path
419
+ # @param [String?] output_dir output directory path
420
420
  # @param [String] path full plugin file path
421
- # @param [String] content file content to write
421
+ # @param [String?] content file content to write
422
422
  # @return [void]
423
423
  def write_to_file(output_dir, path, content)
424
424
  require 'fileutils'
@@ -429,7 +429,7 @@ module Docscribe
429
429
  # Print the creation message and next steps after generating a plugin.
430
430
  #
431
431
  # @private
432
- # @param [String] plugin_type 'tag' or 'collector'
432
+ # @param [String?] plugin_type 'tag' or 'collector'
433
433
  # @param [String] path file path of the created plugin
434
434
  # @return [void]
435
435
  def print_created(plugin_type, path)
@@ -441,8 +441,8 @@ module Docscribe
441
441
  # Print registration instructions after file creation.
442
442
  #
443
443
  # @private
444
- # @param [String] plugin_type
445
- # @param [String] path
444
+ # @param [String?] plugin_type 'tag' or 'collector'
445
+ # @param [String] path file path
446
446
  # @return [String]
447
447
  def next_steps(plugin_type, path)
448
448
  format(NEXT_STEPS_TEMPLATE,
@@ -464,8 +464,8 @@ module Docscribe
464
464
  # Generate an implementation hint string for the given plugin type.
465
465
  #
466
466
  # @private
467
- # @param [String] plugin_type 'tag' or 'collector'
468
- # @return [String] hint text
467
+ # @param [String?] plugin_type 'tag' or 'collector'
468
+ # @return [String, nil] hint text
469
469
  def generate_implement_hint(plugin_type)
470
470
  case plugin_type
471
471
  when 'tag'
@@ -7,6 +7,14 @@ module Docscribe
7
7
  module CLI
8
8
  # Generate starter Docscribe configuration.
9
9
  module Init
10
+ BANNER = <<~TEXT
11
+ Usage: docscribe init [options]
12
+
13
+ Generate a starter docscribe.yml configuration file.
14
+
15
+ Options:
16
+ TEXT
17
+
10
18
  class << self
11
19
  # Create or print a starter Docscribe configuration file.
12
20
  #
@@ -37,8 +45,8 @@ module Docscribe
37
45
  # Parse CLI options for `docscribe init`.
38
46
  #
39
47
  # @private
40
- # @param [Array<String>] argv
41
- # @return [Hash] parsed options
48
+ # @param [Array<String>] argv command-line arguments for `docscribe init`
49
+ # @return [Hash<Symbol, Object>] parsed options
42
50
  def parse_init_options(argv)
43
51
  opts = default_init_options
44
52
  build_init_parser(opts).parse!(argv)
@@ -48,7 +56,7 @@ module Docscribe
48
56
  # Return the default options hash for the init command.
49
57
  #
50
58
  # @private
51
- # @return [Hash]
59
+ # @return [Hash<Symbol, String, Boolean>]
52
60
  def default_init_options
53
61
  { config: 'docscribe.yml', force: false, stdout: false, help: false }
54
62
  end
@@ -56,11 +64,11 @@ module Docscribe
56
64
  # Build and return an OptionParser for the init command.
57
65
  #
58
66
  # @private
59
- # @param [Hash] opts options hash that the parser populates
67
+ # @param [Hash<Symbol, Object>] opts options hash that the parser populates
60
68
  # @return [OptionParser]
61
69
  def build_init_parser(opts)
62
70
  OptionParser.new do |o|
63
- o.banner = 'Usage: docscribe init [options]'
71
+ o.banner = BANNER
64
72
  o.on('--config PATH', 'Where to write the config (default: docscribe.yml)') { |v| opts[:config] = v }
65
73
  o.on('-f', '--force', 'Overwrite if the file already exists') { opts[:force] = true }
66
74
  o.on('--stdout', 'Print config template to STDOUT instead of writing a file') { opts[:stdout] = true }
@@ -74,7 +82,7 @@ module Docscribe
74
82
  # Write the config template to a file.
75
83
  #
76
84
  # @private
77
- # @param [Hash] opts parsed options
85
+ # @param [Hash<Symbol, Object>] opts parsed options
78
86
  # @param [String] yaml config template content
79
87
  # @return [Integer] exit code
80
88
  def write_init_config(opts, yaml)