Class: Tapioca::Compilers::Args

Inherits:
Dsl::Compiler
  • Object
show all
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:



67
68
69
70
# File 'sorbet/tapioca/compilers/args.rb', line 67

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:



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

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:



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

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:



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

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:



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

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:



55
56
57
58
59
# File 'sorbet/tapioca/compilers/args.rb', line 55

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:



62
63
64
# File 'sorbet/tapioca/compilers/args.rb', line 62

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.



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

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