brew/Library/Homebrew/abstract_command.rb
2024-03-15 12:46:05 -07:00

54 lines
1.5 KiB
Ruby

# typed: strong
# frozen_string_literal: true
require "command_registry"
module Homebrew
# Subclass this to implement a `brew` command. This is preferred to declaring a named function in the `Homebrew`
# module, because:
# - Each Command lives in an isolated namespace.
# - Each Command implements a defined interface.
#
# To subclass, implement a `run` method and provide a `cmd_args` block to document the command and its allowed args.
class AbstractCommand
extend T::Helpers
abstract!
class << self
sig { returns(T.nilable(T.proc.void)) }
attr_reader :parser_block
sig { returns(String) }
def command_name = T.must(name).split("::").fetch(-1).downcase
private
sig { params(block: T.nilable(T.proc.bind(CLI::Parser).void)).void }
def cmd_args(&block)
@parser_block = T.let(block, T.nilable(T.proc.void))
end
# registers subclasses for lookup by command name
sig { params(subclass: T.class_of(AbstractCommand)).void }
def inherited(subclass)
super
CommandRegistry.register(subclass)
end
end
# @note because `Args` makes use `OpenStruct`, subclasses may need to use a tapioca compiler,
# hash accessors, args.rbi, or other means to make this work with legacy commands:
sig { returns(CLI::Args) }
attr_reader :args
sig { void }
def initialize
@args = T.let(CLI::Parser.new(&self.class.parser_block).parse, CLI::Args)
end
sig { abstract.void }
def run; end
end
end