Class: Tapioca::Compilers::Args

Inherits:
Dsl::Compiler
  • Object
show all
Extended by:
T::Generic
Defined in:
sorbet/tapioca/compilers/args.rb

Constant Summary collapse

GLOBAL_OPTIONS =
T.let(
  Homebrew::CLI::Parser.global_options.map do |short_option, long_option, _|
    [short_option, long_option].map { "#{Homebrew::CLI::Parser.option_to_name(it)}?" }
  end.flatten.freeze, T::Array[String]
)
ConstantType =
type_member { { fixed: T.class_of(Homebrew::AbstractCommand) } }

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.comma_arrays(parser) ⇒ Array<Symbol>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



69
70
71
72
# File 'sorbet/tapioca/compilers/args.rb', line 69

def self.comma_arrays(parser)
  parser.instance_variable_get(:@non_global_processed_options)
        .filter_map { |k, v| parser.option_to_name(k).to_sym if v == :comma_array }
end

.create_args_methods(klass, parser, method_names) ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.

Parameters:



108
109
110
111
112
113
114
115
116
117
118
119
# File 'sorbet/tapioca/compilers/args.rb', line 108

def self.create_args_methods(klass, parser, method_names)
  comma_array_methods = comma_arrays(parser)
  negatable_methods = negatable_switches(parser)

  method_names.each do |method_name|
    method_name_str = method_name.to_s
    next if GLOBAL_OPTIONS.include?(method_name_str)

    return_type = get_return_type(method_name, comma_array_methods, negatable_methods)
    klass.create_method(method_name_str, return_type:)
  end
end

.gather_constants ⇒ Enumerable<T.class_of(Homebrew::AbstractCommand)>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



20
21
22
23
24
25
26
# File 'sorbet/tapioca/compilers/args.rb', line 20

def self.gather_constants
  # require all the commands to ensure the command subclasses are defined
  ["cmd", "dev-cmd"].each do |dir|
    Dir[File.join(__dir__, "../../../#{dir}", "*.rb")].each { require(it) }
  end
  Homebrew::AbstractCommand.subclasses
end

.get_return_type(method_name, comma_array_methods, negatable_methods) ⇒ String

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



95
96
97
98
99
100
101
102
103
104
105
# File 'sorbet/tapioca/compilers/args.rb', line 95

def self.get_return_type(method_name, comma_array_methods, negatable_methods)
  if comma_array_methods.include?(method_name)
    "T.nilable(T::Array[String])"
  elsif negatable_methods.include?(method_name)
    "T.nilable(T::Boolean)"
  elsif method_name.end_with?("?")
    "T::Boolean"
  else
    "T.nilable(String)"
  end
end

.negatable_switches(parser) ⇒ Array<Symbol>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

A --[no-]foo switch has a genuine "unset" state distinct from false (see CLI::Parser#disable_switch), so its accessor can return nil unless an env: always resolves it to a real boolean first. The declared --[no-] form survives verbatim in option.long, and @switch_sources already records that resolution, so this needs no new parser state.

Parameters:

Returns:



80
81
82
83
84
85
86
87
88
89
# File 'sorbet/tapioca/compilers/args.rb', line 80

def self.negatable_switches(parser)
  switch_sources = parser.instance_variable_get(:@switch_sources)

  parser.processed_options.filter_map do |_short, long, _desc, _hidden|
    next unless long&.start_with?("--[no-]")

    name = parser.option_to_name(long)
    :"#{name}?" unless switch_sources.key?(name)
  end
end

.subcommand_method_names(parser, subcommand_name) ⇒ Array<Symbol>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



57
58
59
60
61
# File 'sorbet/tapioca/compilers/args.rb', line 57

def self.subcommand_method_names(parser, subcommand_name)
  parser.args.methods(false).select do |method_name|
    subcommands_for_method(parser, method_name).include?(subcommand_name)
  end
end

.subcommands_for_method(parser, method_name) ⇒ Array<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

Returns:



64
65
66
# File 'sorbet/tapioca/compilers/args.rb', line 64

def self.subcommands_for_method(parser, method_name)
  parser.subcommands_for_option(method_name.to_s.delete_suffix("?"))
end

Instance Method Details

#decorate ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'sorbet/tapioca/compilers/args.rb', line 29

def decorate
  cmd = constant
  # This is a dummy class to make the `brew` command parsable
  return if cmd == Homebrew::Cmd::Brew

  args_class_name = cmd.args_class&.name
  raise "#{cmd} has no `Args` class; does it call `cmd_args`?" if args_class_name.nil?

  parser = cmd.parser
  # Options declared inside a `subcommand` block are defined on the shared `Args`
  # instance too, but they belong on that subcommand's own class (see `SubcommandArgs`).
  method_names = parser.args.methods(false).select do |method_name|
    self.class.subcommands_for_method(parser, method_name).empty?
  end

  # `CLI::Parser` adds `subcommand` dynamically during parsing for commands
  # that define subcommands.
  method_names << :subcommand if parser.subcommands.present? && !method_names.include?(:subcommand)

  root.create_class(args_class_name, superclass_name: "Homebrew::CLI::Args") do |klass|
    self.class.create_args_methods(klass, parser, method_names)
  end
  root.create_path(constant) do |klass|
    klass.create_method("args", return_type: args_class_name)
  end
end