Class: OKF::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/okf/cli.rb

Overview

Command-line front end: okf graph|validate|lint|loose|search|index|catalog|files|tags|types|stats|server <dir>. This is the only layer that parses argv, prints, writes files, and decides exit codes — the lib classes below it just return data. Streams are injectable for testing.

Exit codes: 0 success, 1 non-conformant / failing bundle, 2 usage error.

Constant Summary collapse

SUBCOMMANDS =

The registry umbrella's subcommands — the dispatch, and the words a flag-first invocation is checked against.

%w[set del list default rename].freeze
LINT_CATEGORIES =

Lint findings grouped for display, in category order.

{
  "Reachability" => %i[orphan not_in_index disconnected_component unlinked],
  "Backlog" => %i[missing_concept broken_index_entry],
  "Completeness" => %i[stub missing_title missing_description missing_timestamp],
  "Freshness" => %i[stale],
  "Provenance" => %i[uncited_external broken_citation],
  "Hygiene" => %i[duplicate_title unused_reference_def undefined_reference self_link]
}.freeze
WEBRICK =

Runs a Rack app under WEBrick until interrupted. Injected into the CLI so tests can drive server without opening a socket; the runner loads here (not at require time) so require "okf" and a Rails mount of the server stay light.

lambda do |app, host, port|
  require "okf/server/runner"
  OKF::Server::Runner.run(app, host: host, port: port)
end
ALL_REF =

"every registered bundle" as a ref, in its canonical spelling — what the messages say, and (normalized) what #all_ref? recognizes. Only search expands it: it is the one verb that merges across bundles, so it is the one verb for which "all" names something it can answer about. See resolve_registered for why the others refuse it outright rather than treating it as an unknown slug. Its slug half is reserved by Registry::RESERVED_SLUGS so no bundle can answer to it; a test pins the two together.

"@all"
ROW_FIELDS =

The row shape each list view emits, so --fields/--except can be checked against a name even when the result is empty. Without it the typo guard keyed off the data: --fields bogus was a usage error against a bundle with matches and silently fine against one without, which made a typo's fate depend on whether a filter happened to match. A test asserts each view's real rows carry exactly these, so the two cannot drift. Declared in emission order, so the "available:" list a typo prints reads the same as the rows themselves.

{
  "matches" => %w[id title type area tags matched score snippet],
  # Registry mode labels every row with the bundle it came from; a plain-dir
  # search has one bundle and no slug to carry. Two shapes, because the typo
  # guard checks against the *declared* one — a single shape covering both
  # would let `--fields slug` pass on a search whose rows have none, and hand
  # back an empty object per match under a count that says otherwise.
  "matches_by_ref" => %w[slug id title type area tags matched score snippet],
  "concepts" => %w[id title type description tags timestamp status backlog_ref dir area links_out links_in],
  "files" => %w[path id dir type title description],
  "directories" => %w[dir index_path present synthesized count types tags subdirs body listing],
  "bundles" => %w[slug title dir mount default missing]
}.freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(out: $stdout, err: $stderr, runner: WEBRICK) ⇒ CLI

Returns a new instance of CLI.



40
41
42
43
44
45
# File 'lib/okf/cli.rb', line 40

def initialize(out: $stdout, err: $stderr, runner: WEBRICK)
  @out = out
  @err = err
  @runner = runner
  @pretty = false
end

Class Method Details

.start(argv, out: $stdout, err: $stderr) ⇒ Object



36
37
38
# File 'lib/okf/cli.rb', line 36

def self.start(argv, out: $stdout, err: $stderr)
  new(out: out, err: err).run(argv)
end

Instance Method Details

#run(argv) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/okf/cli.rb', line 47

def run(argv)
  argv = argv.dup
  # Per-run state, reset so a reused instance never inherits the last run's
  # answer: the ref→slug memo, and the --pretty a previous argv turned on.
  @ref_slugs = {}
  @pretty = false
  # -h/--help is answered wherever a parser sees it — deep inside
  # positional_dir, where returning would only mean "usage error, exit 2".
  # Thrown here instead, so help keeps the contract every other path keeps:
  # a status this method returns. See #help_flag.
  catch(:help) do
    case (command = argv.shift)
    when "graph" then graph(argv)
    when "validate" then validate(argv)
    when "lint" then lint(argv)
    when "loose" then loose(argv)
    when "search" then search(argv)
    when "index" then index(argv)
    when "catalog" then catalog(argv)
    when "files" then files(argv)
    when "tags" then tags(argv)
    when "types" then types(argv)
    when "stats" then stats(argv)
    when "server" then server(argv)
    when "render" then render(argv)
    when "registry" then registry(argv)
    when "skill" then skill(argv)
    when "version", "--version", "-v" then @out.puts(OKF::VERSION); 0
    when "help", "--help", "-h" then usage(@out); 0
    when nil then usage(@err); 2
    else
      @err.puts "okf: unknown command '#{command}'"
      usage(@err)
      2
    end
  end
end