Module: Docscribe::CLI::Run
- Defined in:
- lib/docscribe/cli/run.rb
Overview
Execute Docscribe from parsed CLI options.
This module handles:
- config loading and CLI overrides
- stdin mode
- file expansion / filtering
- inspect vs write behavior
- process exit status
Constant Summary collapse
- INITIAL_RUN_STATE =
{ changed: false, had_errors: false, checked_ok: 0, checked_fail: 0, corrected: 0, corrected_paths: [], #: Array[String] corrected_changes: {}, #: Hash[String, untyped] fail_paths: [], #: Array[String] fail_changes: {}, #: Hash[String, untyped] error_paths: [], #: Array[String] error_messages: {}, #: Hash[String, String] type_mismatch_paths: [], #: Array[String] type_mismatch_changes: {}, #: Hash[String, untyped] total: 0, processed: 0 }.freeze
- CLI_OVERRIDE_KEYS =
%i[ keep_descriptions no_boilerplate include exclude include_file exclude_file rbs rbs_collection sig_dirs sorbet rbi_dirs ].freeze
Class Method Summary collapse
-
.all_fine?(state, checked_error, type_mismatch_count) ⇒ Boolean
Whether no failures, errors, or type mismatches occurred.
-
.append_expanded_path(files, path) ⇒ void
Append a file or recursively expand a directory into the files array.
- .build_config(options) ⇒ Docscribe::Config
-
.build_failure_line(state, type_mismatch_count, checked_error) ⇒ String
Build the human-readable failure summary line for check output.
- .build_light_config(options) ⇒ Docscribe::Config
-
.change_line_suffix(change) ⇒ String
Format the line number suffix for a change reason string.
-
.change_method_suffix(change) ⇒ String
Format the method name suffix for a change reason string.
-
.core_rbs_provider_for(conf) ⇒ Docscribe::Types::RBS::Provider?
Return the core RBS provider from the config if available.
-
.direct_message_change?(change) ⇒ Boolean
Whether a change type uses its own :message field directly as the reason.
-
.dispatch_server_result(result, file_changes, path, **ctx) ⇒ void
Dispatch the server result to check or write handler.
-
.ensure_server_running!(config_path: nil) ⇒ void
Ensure the server daemon is running, auto-starting if necessary.
-
.expand_paths(args) ⇒ Array<String>
Expand CLI path arguments into a sorted list of Ruby files.
- .extract_cli_overrides(options) ⇒ Hash<String, Object>
-
.filtered_paths(argv, conf) ⇒ Array<String>
Expand CLI path arguments and filter through config file patterns.
-
.format_change_reason(change) ⇒ String
Format a structured change record into human-readable CLI output.
-
.handle_via_server_check(path, file_changes:, display_path:, options:, state:) ⇒ void
Handle a check result from the server.
-
.mismatch_only?(state, checked_error) ⇒ Boolean
Whether type mismatches exist but no failures or errors.
-
.no_files_found ⇒ Integer
Warn and return exit code when no matching files were found.
-
.print_check_status_line(state) ⇒ void
Print the check-mode status line.
-
.print_corrected_paths(state, options) ⇒ void
Print corrected paths from write-mode summary (stdout).
-
.print_error_paths(state) ⇒ void
Print error paths from check summary.
-
.print_fail_paths(state, options) ⇒ void
Print fail paths from check summary (stdout).
-
.print_type_mismatch_paths(state, options) ⇒ void
Print type mismatch paths from check summary.
-
.print_write_summary(state:, options:) ⇒ void
Print the write-mode summary (files corrected, errors).
-
.process_one_file_via_server(client, path, options:, pwd:, state:) ⇒ void
Process a single file via the server client.
-
.report_check_failure(display_path, file_changes, options) ⇒ void
Report a check failure with verbose or compact output.
-
.run(options:, argv:) ⇒ Integer
Run Docscribe for files or STDIN using the selected mode and strategy.
-
.run_files(options:, conf:, paths:) ⇒ Integer
Process file paths in inspect or write mode.
-
.run_files_via_server(client, paths, options) ⇒ Integer
Run files through the server client with progress tracking.
-
.run_stdin(options:, conf:) ⇒ Integer
Rewrite code from STDIN using the selected strategy and print the result.
- .run_via_server(options:, argv:) ⇒ Integer
- .send_server_request(client, path, options) ⇒ Hash<String, Object>?
-
.server_error(path, state, message) ⇒ void
Record a server error in the shared state and print an indicator.
-
.stdin_rewrite_result(options, conf) ⇒ Hash<Symbol, Object>
Rewrite STDIN input and return the result report.
-
.symbolize_change(change) ⇒ Docscribe::CLI::Formatters::change
Convert server response change (string keys) to formatter-compatible change (symbol keys).
-
.update_check_failure_state(path, file_changes, state) ⇒ void
Update shared state after a check failure.
-
.write_server_result(result, file_changes, display_path:, options:, state:) ⇒ void
Handle a server write-mode result.
Class Method Details
.all_fine?(state, checked_error, type_mismatch_count) ⇒ Boolean
Whether no failures, errors, or type mismatches occurred.
840 841 842 |
# File 'lib/docscribe/cli/run.rb', line 840 def all_fine?(state, checked_error, type_mismatch_count) state[:checked_fail].zero? && checked_error.zero? && type_mismatch_count.zero? end |
.append_expanded_path(files, path) ⇒ void
This method returns an undefined value.
Append a file or recursively expand a directory into the files array.
360 361 362 363 364 365 366 367 368 |
# File 'lib/docscribe/cli/run.rb', line 360 def (files, path) if File.directory?(path) files.concat(Dir.glob(File.join(path, '**', '*.rb'))) elsif File.file?(path) files << path else warn "Skipping missing path: #{path}" end end |
.build_config(options) ⇒ Docscribe::Config
112 113 114 115 116 117 |
# File 'lib/docscribe/cli/run.rb', line 112 def build_config() conf = Docscribe::Config.load([:config]) conf = Docscribe::CLI::ConfigBuilder.build(conf, ) conf.load_plugins! conf end |
.build_failure_line(state, type_mismatch_count, checked_error) ⇒ String
Build the human-readable failure summary line for check output.
859 860 861 862 863 864 865 |
# File 'lib/docscribe/cli/run.rb', line 859 def build_failure_line(state, type_mismatch_count, checked_error) parts = ["#{state[:checked_fail]} need updates"] parts << "#{type_mismatch_count} type mismatches" if type_mismatch_count.positive? parts << "#{checked_error} errors" parts << "#{state[:checked_ok]} ok" "Docscribe: FAILED (#{parts.join(', ')})" end |
.build_light_config(options) ⇒ Docscribe::Config
121 122 123 124 |
# File 'lib/docscribe/cli/run.rb', line 121 def build_light_config() conf = Docscribe::Config.load([:config]) Docscribe::CLI::ConfigBuilder.build(conf, ) end |
.change_line_suffix(change) ⇒ String
Format the line number suffix for a change reason string.
937 938 939 |
# File 'lib/docscribe/cli/run.rb', line 937 def change_line_suffix(change) change[:line] ? " at line #{change[:line]}" : '' end |
.change_method_suffix(change) ⇒ String
Format the method name suffix for a change reason string.
945 946 947 |
# File 'lib/docscribe/cli/run.rb', line 945 def change_method_suffix(change) change[:method] ? " for #{change[:method]}" : '' end |
.core_rbs_provider_for(conf) ⇒ Docscribe::Types::RBS::Provider?
Return the core RBS provider from the config if available.
161 162 163 |
# File 'lib/docscribe/cli/run.rb', line 161 def core_rbs_provider_for(conf) conf.respond_to?(:core_rbs_provider) ? conf.core_rbs_provider : nil end |
.direct_message_change?(change) ⇒ Boolean
Whether a change type uses its own :message field directly as the reason.
953 954 955 956 957 958 959 960 961 962 |
# File 'lib/docscribe/cli/run.rb', line 953 def (change) %i[ missing_param missing_return missing_raise missing_visibility missing_module_function_note insert_full_doc_block ].include?(change[:type]) end |
.dispatch_server_result(result, file_changes, path, **ctx) ⇒ void
This method returns an undefined value.
Dispatch the server result to check or write handler.
246 247 248 249 250 251 252 253 254 255 |
# File 'lib/docscribe/cli/run.rb', line 246 def dispatch_server_result(result, file_changes, path, **ctx) if ctx[:options][:mode] == :check handle_via_server_check(path, file_changes: file_changes, display_path: ctx[:display_path], options: ctx[:options], state: ctx[:state]) else write_server_result(result, file_changes, display_path: ctx[:display_path], options: ctx[:options], state: ctx[:state]) end end |
.ensure_server_running!(config_path: nil) ⇒ void
This method returns an undefined value.
Ensure the server daemon is running, auto-starting if necessary.
186 187 188 |
# File 'lib/docscribe/cli/run.rb', line 186 def ensure_server_running!(config_path: nil) Docscribe::Server.ensure_running!(config_path: config_path) end |
.expand_paths(args) ⇒ Array<String>
Expand CLI path arguments into a sorted list of Ruby files.
Directories are expanded recursively to **/*.rb.
If no arguments are provided, the current directory is used.
344 345 346 347 348 349 350 351 352 353 |
# File 'lib/docscribe/cli/run.rb', line 344 def (args) files = [] #: Array[String] args = ['.'] if args.empty? args.each do |path| (files, path) end files.uniq.sort end |
.extract_cli_overrides(options) ⇒ Hash<String, Object>
402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/docscribe/cli/run.rb', line 402 def extract_cli_overrides() overrides = .slice(*CLI_OVERRIDE_KEYS) acc = {} #: Hash[String, untyped] overrides.each do |k, v| next if v.nil? || v == false next if v.is_a?(Array) && v.empty? acc[k.to_s] = v end acc end |
.filtered_paths(argv, conf) ⇒ Array<String>
Expand CLI path arguments and filter through config file patterns.
170 171 172 |
# File 'lib/docscribe/cli/run.rb', line 170 def filtered_paths(argv, conf) (argv).select { |path| conf.process_file?(path) } end |
.format_change_reason(change) ⇒ String
Format a structured change record into human-readable CLI output.
923 924 925 926 927 928 929 930 931 |
# File 'lib/docscribe/cli/run.rb', line 923 def format_change_reason(change) line = change_line_suffix(change) method = change_method_suffix(change) return "unsorted tags#{line}" if change[:type] == :unsorted_tags return "#{change[:message]}#{method}#{line}" if (change) "#{change[:message] || change[:type].to_s.tr('_', ' ')}#{method}#{line}" end |
.handle_via_server_check(path, file_changes:, display_path:, options:, state:) ⇒ void
This method returns an undefined value.
Handle a check result from the server.
284 285 286 287 288 289 290 291 292 |
# File 'lib/docscribe/cli/run.rb', line 284 def handle_via_server_check(path, file_changes:, display_path:, options:, state:) if file_changes.empty? state[:checked_ok] += 1 return log_check_verdict('OK', display_path, ) end report_check_failure(display_path, file_changes, ) update_check_failure_state(path, file_changes, state) end |
.mismatch_only?(state, checked_error) ⇒ Boolean
Whether type mismatches exist but no failures or errors.
849 850 851 |
# File 'lib/docscribe/cli/run.rb', line 849 def mismatch_only?(state, checked_error) state[:checked_fail].zero? && checked_error.zero? end |
.no_files_found ⇒ Integer
Warn and return exit code when no matching files were found.
177 178 179 180 |
# File 'lib/docscribe/cli/run.rb', line 177 def no_files_found warn 'No files found. Pass files or directories (e.g. `docscribe lib`).' 2 end |
.print_check_status_line(state) ⇒ void
This method returns an undefined value.
Print the check-mode status line.
821 822 823 824 825 826 827 828 829 830 831 832 |
# File 'lib/docscribe/cli/run.rb', line 821 def print_check_status_line(state) checked_error = state[:error_paths].size type_mismatch_count = state[:type_mismatch_paths].size if all_fine?(state, checked_error, type_mismatch_count) puts "Docscribe: OK (#{state[:checked_ok]} files checked)" elsif mismatch_only?(state, checked_error) puts "Docscribe: OK (#{state[:checked_ok]} files checked, #{type_mismatch_count} with type mismatches)" else puts build_failure_line(state, type_mismatch_count, checked_error) end end |
.print_corrected_paths(state, options) ⇒ void
This method returns an undefined value.
Print corrected paths from write-mode summary (stdout).
Skips explanations when --verbose showed them inline per-file.
907 908 909 910 911 912 913 914 915 916 917 |
# File 'lib/docscribe/cli/run.rb', line 907 def print_corrected_paths(state, ) state[:corrected_paths].each do |p| puts "Updated: #{p}" next if [:verbose] || [:quiet] Array(state[:corrected_changes][p]).each do |change| puts " - #{format_change_reason(change)}" end end end |
.print_error_paths(state) ⇒ void
This method returns an undefined value.
Print error paths from check summary.
968 969 970 971 972 973 974 975 976 |
# File 'lib/docscribe/cli/run.rb', line 968 def print_error_paths(state) return if state[:error_paths].empty? warn '' state[:error_paths].each do |p| warn "Error processing: #{p}" warn " #{state[:error_messages][p]}" if state[:error_messages][p] end end |
.print_fail_paths(state, options) ⇒ void
This method returns an undefined value.
Print fail paths from check summary (stdout).
Skips explanations when --verbose showed them inline per-file.
805 806 807 808 809 810 811 812 813 814 815 |
# File 'lib/docscribe/cli/run.rb', line 805 def print_fail_paths(state, ) state[:fail_paths].each do |p| puts "Would update: #{p}" next if [:verbose] || [:quiet] Array(state[:fail_changes][p]).each do |change| puts " - #{format_change_reason(change)}" end end end |
.print_type_mismatch_paths(state, options) ⇒ void
This method returns an undefined value.
Print type mismatch paths from check summary.
872 873 874 875 876 877 878 879 880 881 882 |
# File 'lib/docscribe/cli/run.rb', line 872 def print_type_mismatch_paths(state, ) return if [:quiet] return unless [:verbose] || [:explain] state[:type_mismatch_paths].each do |p| warn "Type mismatches: #{p}" Array(state[:type_mismatch_changes][p]).each do |change| warn " - #{format_change_reason(change)}" end end end |
.print_write_summary(state:, options:) ⇒ void
This method returns an undefined value.
Print the write-mode summary (files corrected, errors).
889 890 891 892 893 894 895 896 897 898 |
# File 'lib/docscribe/cli/run.rb', line 889 def print_write_summary(state:, options:) puts puts "Docscribe: updated #{state[:corrected]} file(s)" if state[:corrected].positive? print_corrected_paths(state, ) return unless state[:had_errors] warn "Docscribe: #{state[:error_paths].size} file(s) had errors" print_error_paths(state) end |
.process_one_file_via_server(client, path, options:, pwd:, state:) ⇒ void
This method returns an undefined value.
Process a single file via the server client.
198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/docscribe/cli/run.rb', line 198 def process_one_file_via_server(client, path, options:, pwd:, state:) display_path = display_path_for(path, pwd: pwd) report_progress(state, , display_path) response = send_server_request(client, path, ) return server_error(path, state, 'Server unreachable') unless response return server_error(path, state, response['error']['message']) if response['error'] result = response['result'] file_changes = (result['changes'] || []).map { |c| symbolize_change(c) } dispatch_server_result(result, file_changes, path, display_path: display_path, options: , state: state) end |
.report_check_failure(display_path, file_changes, options) ⇒ void
This method returns an undefined value.
Report a check failure with verbose or compact output.
300 301 302 303 304 305 306 307 |
# File 'lib/docscribe/cli/run.rb', line 300 def report_check_failure(display_path, file_changes, ) if [:verbose] warn("FAIL #{display_path}") print_check_explanations(file_changes) else $stderr.print('F') end end |
.run(options:, argv:) ⇒ Integer
Run Docscribe for files or STDIN using the selected mode and strategy.
Modes:
- :check => inspect what the selected strategy would change
- :write => apply the selected strategy in place
- :stdin => rewrite STDIN and print to STDOUT
Strategies:
- :safe => merge/add/normalize non-destructively
- :aggressive => rebuild existing doc blocks
59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/docscribe/cli/run.rb', line 59 def run(options:, argv:) return run_via_server(options: , argv: argv) if [:server] require 'docscribe/inline_rewriter' conf = build_config() return run_stdin(options: , conf: conf) if [:mode] == :stdin paths = filtered_paths(argv, conf) return no_files_found unless paths.any? run_files(options: , conf: conf, paths: paths) end |
.run_files(options:, conf:, paths:) ⇒ Integer
Process file paths in inspect or write mode.
In inspect mode:
- prints progress/status
- exits non-zero if any file would change or if any errors occurred
In write mode:
- rewrites changed files in place
- exits non-zero only if errors occurred
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/docscribe/cli/run.rb', line 384 def run_files(options:, conf:, paths:) $stdout.sync = true state = initial_run_state state[:total] = paths.size pwd = Pathname.pwd paths.each do |path| process_one_file(path, options: , conf: conf, pwd: pwd, state: state) end finalize_run(, state) run_exit_code(, state) end |
.run_files_via_server(client, paths, options) ⇒ Integer
Run files through the server client with progress tracking.
98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/docscribe/cli/run.rb', line 98 def run_files_via_server(client, paths, ) $stdout.sync = true state = initial_run_state state[:total] = paths.size pwd = Pathname.pwd paths.each do |path| process_one_file_via_server(client, path, options: , pwd: pwd, state: state) end finalize_run(, state) run_exit_code(, state) end |
.run_stdin(options:, conf:) ⇒ Integer
Rewrite code from STDIN using the selected strategy and print the result.
134 135 136 137 138 139 140 |
# File 'lib/docscribe/cli/run.rb', line 134 def run_stdin(options:, conf:) puts stdin_rewrite_result(, conf)[:output] 0 rescue StandardError => e warn "Docscribe: Error processing stdin: #{e.class}: #{e.}" 1 end |
.run_via_server(options:, argv:) ⇒ Integer
78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/docscribe/cli/run.rb', line 78 def run_via_server(options:, argv:) require 'docscribe/server' conf = build_light_config() ensure_server_running!(config_path: conf.config_path) client = Docscribe::Server::Client.new(config_path: conf.config_path) paths = filtered_paths(argv, conf) return no_files_found unless paths.any? run_files_via_server(client, paths, ) rescue RuntimeError => e warn e. 1 end |
.send_server_request(client, path, options) ⇒ Hash<String, Object>?
215 216 217 218 219 220 221 222 223 224 |
# File 'lib/docscribe/cli/run.rb', line 215 def send_server_request(client, path, ) method_name = [:mode] == :write ? :fix : :check strategy = [:strategy].to_s cli_overrides = extract_cli_overrides() if cli_overrides.empty? client.send(method_name, file: path, strategy: strategy) else client.send(method_name, file: path, strategy: strategy, cli_overrides: cli_overrides) end end |
.server_error(path, state, message) ⇒ void
This method returns an undefined value.
Record a server error in the shared state and print an indicator.
232 233 234 235 236 237 |
# File 'lib/docscribe/cli/run.rb', line 232 def server_error(path, state, ) state[:had_errors] = true state[:error_paths] << path state[:error_messages][path] = $stderr.print('E') end |
.stdin_rewrite_result(options, conf) ⇒ Hash<Symbol, Object>
Rewrite STDIN input and return the result report.
147 148 149 150 151 152 153 154 155 |
# File 'lib/docscribe/cli/run.rb', line 147 def stdin_rewrite_result(, conf) Docscribe::InlineRewriter.rewrite_with_report( $stdin.read, strategy: [:strategy], config: conf, core_rbs_provider: core_rbs_provider_for(conf), file: '(stdin)' ) end |
.symbolize_change(change) ⇒ Docscribe::CLI::Formatters::change
Convert server response change (string keys) to formatter-compatible change (symbol keys).
327 328 329 330 331 332 333 334 335 |
# File 'lib/docscribe/cli/run.rb', line 327 def symbolize_change(change) { type: change['type'].to_sym, file: change['file'], line: change['line'], method: change['method'], message: change['message'] } end |
.update_check_failure_state(path, file_changes, state) ⇒ void
This method returns an undefined value.
Update shared state after a check failure.
315 316 317 318 319 320 |
# File 'lib/docscribe/cli/run.rb', line 315 def update_check_failure_state(path, file_changes, state) state[:checked_fail] += 1 state[:changed] = true state[:fail_paths] << path state[:fail_changes][path] = file_changes end |
.write_server_result(result, file_changes, display_path:, options:, state:) ⇒ void
This method returns an undefined value.
Handle a server write-mode result.
265 266 267 268 269 270 271 272 273 274 |
# File 'lib/docscribe/cli/run.rb', line 265 def write_server_result(result, file_changes, display_path:, options:, state:) if result['changed'] state[:corrected] += 1 state[:corrected_paths] << display_path state[:corrected_changes][display_path] = file_changes log_check_verdict('CHANGED', display_path, ) else log_check_verdict('OK', display_path, ) end end |