Class: Textus::CLI

Inherits:
Object
  • Object
show all
Defined in:
lib/textus/cli.rb,
lib/textus/cli/verb.rb,
lib/textus/cli/group.rb,
lib/textus/cli/runner.rb,
lib/textus/cli/verb/get.rb,
lib/textus/cli/verb/put.rb,
lib/textus/cli/group/key.rb,
lib/textus/cli/group/mcp.rb,
lib/textus/cli/verb/boot.rb,
lib/textus/cli/verb/init.rb,
lib/textus/cli/group/hook.rb,
lib/textus/cli/group/rule.rb,
lib/textus/cli/group/zone.rb,
lib/textus/cli/verb/build.rb,
lib/textus/cli/verb/fetch.rb,
lib/textus/cli/verb/hooks.rb,
lib/textus/cli/group/fetch.rb,
lib/textus/cli/verb/doctor.rb,
lib/textus/cli/group/schema.rb,
lib/textus/cli/verb/hook_run.rb,
lib/textus/cli/verb/fetch_all.rb,
lib/textus/cli/verb/mcp_serve.rb,
lib/textus/cli/verb/schema_diff.rb,
lib/textus/cli/verb/schema_init.rb,
lib/textus/cli/verb/schema_migrate.rb

Defined Under Namespace

Modules: Runner Classes: Group, Verb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(stdin:, stdout:, stderr:, cwd:) ⇒ CLI

Returns a new instance of CLI.



27
28
29
30
31
32
33
# File 'lib/textus/cli.rb', line 27

def initialize(stdin:, stdout:, stderr:, cwd:)
  @stdin = stdin
  @stdout = stdout
  @stderr = stderr
  @cwd = cwd
  @root_arg = nil
end

Class Method Details

.run(argv, stdin: $stdin, stdout: $stdout, stderr: $stderr, cwd: Dir.pwd) ⇒ Object



23
24
25
# File 'lib/textus/cli.rb', line 23

def self.run(argv, stdin: $stdin, stdout: $stdout, stderr: $stderr, cwd: Dir.pwd)
  new(stdin: stdin, stdout: stdout, stderr: stderr, cwd: cwd).run(argv)
end

.verbsObject

Auto-derived verb table. Every CLI::Verb (or Group) subclass that declares ‘command_name “X”` and has no `parent_group` is a top-level verb. Sorted alphabetically for stable help output. Adding a new verb requires only a new file declaring its `command_name`.

‘k.name` gates out anonymous (Class.new) subclasses: real verbs are always named constants (generated Gen* or hand-authored classes), so this is a no-op in production but keeps throwaway test fixtures from leaking into the registry (and tripping the reconciliation guards order-dependently).



15
16
17
18
19
20
21
# File 'lib/textus/cli.rb', line 15

def self.verbs
  Runner.install!
  Verb.descendants
      .select { |k| k.name && k.command_name && k.parent_group.nil? }
      .sort_by(&:command_name)
      .to_h { |k| [k.command_name, k] }
end

Instance Method Details

#run(argv) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/textus/cli.rb', line 35

def run(argv)
  # `--root` is a global, position-agnostic option: pull it out of argv
  # wherever it appears so it works uniformly before OR after any verb or
  # group (e.g. both `textus --root=X hook list` and
  # `textus hook list --root=X`). Without this, `order!` below only sees
  # options before the first verb token, so a trailing `--root` reached the
  # verb's own parser and raised InvalidOption (#161 F5). TEXTUS_ROOT already
  # works everywhere via Store.discover, so this brings the flag to parity.
  @root_arg = extract_root!(argv)

  # Define --version/--help ourselves so OptionParser doesn't intercept them
  # with its built-in handlers (which print "version unknown" and a bare usage
  # line, then exit before we ever reach the verb dispatch below).
  show_version = false
  show_help = false
  OptionParser.new do |o|
    o.on("--version", "-v") { show_version = true }
    o.on("--help", "-h") { show_help = true }
  end.order!(argv)

  return @stdout.puts(VERSION) || 0 if show_version
  return print_help || 0 if show_help

  verb = argv.shift
  raise UsageError.new("missing verb") if verb.nil?

  klass = self.class.verbs[verb] or raise UsageError.new("unknown verb: #{verb}")
  coerce_exit_code(dispatch(klass, argv))
rescue Textus::Error => e
  emit_error(e)
end