Module: Snoot::CLI
- Defined in:
- lib/snoot/cli.rb,
lib/snoot/cli/event.rb,
lib/snoot/cli/pipeline.rb
Overview
The CLI surface. cli.rb owns the surface entry points: argv-shape entry (.run – UsageErrorExit), in-process entry (.run_invoked), the surface constants (banners, exit codes, the default path set), and the IO emitter helpers (emit_warnings, emit_failure, emit_nothing_to_report, format_report). The event values (RunInvoked, ReportEmitted) live in cli/event.rb; the Pipeline value lives in cli/pipeline.rb. .run consults BANNERS for –version, –help, and -h, rejects unknown flags with exit 64, and otherwise threads argv through .run_invoked, mapping the terminal outcome to an EXIT_CODES integer.
The two entry points return deliberately different shapes. .run is the POSIX boundary: argv -> Integer, consumed by ‘exit Snoot::CLI.run(ARGV)` in exe/snoot. .run_invoked is the in-process boundary: Set<Path> -> [Run, Array of event values], used by tests and any library embedding that needs the full event list. Internally .run calls .run_invoked and projects Run#outcome through EXIT_CODES, so the integer is a lossy view of the Run; callers that need the Run, the events, or both must use .run_invoked.
Defined Under Namespace
Classes: Pipeline, ReportEmitted, RunInvoked
Constant Summary collapse
- NOTHING_TO_REPORT =
"nothing to report -- no findings above snoot's significance floor\n"- DEFAULT_PATHS =
Set[Snoot::Path.new(raw: ".")].freeze
- USAGE =
<<~HELP snoot - single-finding reek/flog/flay reporter Usage: snoot [paths...] snoot --version snoot --help With no path arguments, snoot scans the current directory. Exit codes: 0 nothing to report 1 one finding rendered 2 analyser failure 64 usage error Example: snoot lib/ HELP
- EXIT_CODES =
{ finding_rendered: 1, nothing_to_report: 0, analysis_failed: 2, usage_error: 64 }.freeze
- BANNERS =
{ %w[--version] => "snoot #{Snoot::VERSION}\n", %w[-h --help] => USAGE }.freeze
Class Method Summary collapse
- .build_paths(argv) ⇒ Object
- .collect_events(paths, pipeline) ⇒ Object
- .emit_failure(run, stderr) ⇒ Object
- .emit_nothing_to_report(stdout) ⇒ Object
- .emit_report(run, smells, pipeline:) ⇒ Object
- .emit_warnings(analyse_events, stderr) ⇒ Object
- .events_for_outcome(run, smells, pipeline:) ⇒ Object
- .format_report(sections) ⇒ Object
- .lookup_banner(argv) ⇒ Object
- .run(argv, pipeline: Pipeline.default) ⇒ Object
- .run_invoked(paths, pipeline: Pipeline.default) ⇒ Object
- .run_pipeline(argv, pipeline:) ⇒ Object
- .unknown_flag?(argv) ⇒ Boolean
- .write_and_return(io, message, code) ⇒ Object
Class Method Details
.build_paths(argv) ⇒ Object
113 114 115 |
# File 'lib/snoot/cli.rb', line 113 def build_paths(argv) argv.each_with_object(Set[]) { |raw, set| set << Path.new(raw: raw) } end |
.collect_events(paths, pipeline) ⇒ Object
122 123 124 125 126 127 128 129 |
# File 'lib/snoot/cli.rb', line 122 def collect_events(paths, pipeline) AnalyseRun.invoke(paths, orchestration: pipeline.orchestration) => { run:, events: analyse_events, smells: } emit_warnings(analyse_events, pipeline.stderr) events = [RunInvoked.new(paths: paths), *analyse_events, *events_for_outcome(run, smells, pipeline: pipeline)] [run, events] end |
.emit_failure(run, stderr) ⇒ Object
67 68 69 70 71 |
# File 'lib/snoot/cli.rb', line 67 def emit_failure(run, stderr) failure = run.failure stderr.write("analysis failed (#{failure.analyser}): #{failure.}\n") [] end |
.emit_nothing_to_report(stdout) ⇒ Object
62 63 64 65 |
# File 'lib/snoot/cli.rb', line 62 def emit_nothing_to_report(stdout) stdout.write(NOTHING_TO_REPORT) [] end |
.emit_report(run, smells, pipeline:) ⇒ Object
140 141 142 143 144 145 |
# File 'lib/snoot/cli.rb', line 140 def emit_report(run, smells, pipeline:) RenderReport.invoke(run, smells: smells, orchestration: pipeline.orchestration) => { sections:, finding: } pipeline.stdout.write(format_report(sections)) ReportEmitted.new(run: run, finding: finding, sections: sections) end |
.emit_warnings(analyse_events, stderr) ⇒ Object
73 74 75 76 77 78 79 |
# File 'lib/snoot/cli.rb', line 73 def emit_warnings(analyse_events, stderr) analyse_events.each do |event| next unless event.is_a?(AnalyseRun::SkippedDocLessSmellWarned) stderr.write("warning: skipping doc-less smell type '#{event.smell_type.name}'\n") end end |
.events_for_outcome(run, smells, pipeline:) ⇒ Object
131 132 133 134 135 136 137 138 |
# File 'lib/snoot/cli.rb', line 131 def events_for_outcome(run, smells, pipeline:) case run.outcome when :finding_rendered then [emit_report(run, smells, pipeline: pipeline)] when :nothing_to_report then emit_nothing_to_report(pipeline.stdout) when :analysis_failed then emit_failure(run, pipeline.stderr) else [] end end |
.format_report(sections) ⇒ Object
81 82 83 |
# File 'lib/snoot/cli.rb', line 81 def format_report(sections) "#{sections.values.join("\n\n")}\n" end |
.lookup_banner(argv) ⇒ Object
93 94 95 96 97 |
# File 'lib/snoot/cli.rb', line 93 def (argv) return nil unless argv.length == 1 BANNERS.find { |flags, _| flags.include?(argv.first) }&.last end |
.run(argv, pipeline: Pipeline.default) ⇒ Object
85 86 87 88 89 90 91 |
# File 'lib/snoot/cli.rb', line 85 def run(argv, pipeline: Pipeline.default) = (argv) return write_and_return(pipeline.stdout, , 0) if return write_and_return(pipeline.stderr, USAGE, EXIT_CODES.fetch(:usage_error)) if unknown_flag?(argv) run_pipeline(argv, pipeline: pipeline) end |
.run_invoked(paths, pipeline: Pipeline.default) ⇒ Object
117 118 119 120 |
# File 'lib/snoot/cli.rb', line 117 def run_invoked(paths, pipeline: Pipeline.default) paths = DEFAULT_PATHS if paths.empty? collect_events(paths, pipeline) end |
.run_pipeline(argv, pipeline:) ⇒ Object
108 109 110 111 |
# File 'lib/snoot/cli.rb', line 108 def run_pipeline(argv, pipeline:) run, _events = run_invoked(build_paths(argv), pipeline: pipeline) EXIT_CODES.fetch(run.outcome) end |
.unknown_flag?(argv) ⇒ Boolean
104 105 106 |
# File 'lib/snoot/cli.rb', line 104 def unknown_flag?(argv) argv.any? { |arg| arg.start_with?("-") } end |
.write_and_return(io, message, code) ⇒ Object
99 100 101 102 |
# File 'lib/snoot/cli.rb', line 99 def write_and_return(io, , code) io.write() code end |