cli-kit 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,27 +7,23 @@ module CLI
7
7
  module Args
8
8
  class Parser
9
9
  class Node
10
- extend T::Sig
11
-
12
- sig { void }
10
+ #: -> void
13
11
  def initialize
14
12
  end
15
13
 
16
- sig { params(other: T.untyped).returns(T::Boolean) }
14
+ #: (untyped other) -> bool
17
15
  def ==(other)
18
16
  self.class == other.class
19
17
  end
20
18
 
21
19
  class Option < Node
22
- extend T::Sig
23
-
24
- sig { returns(String) }
20
+ #: String
25
21
  attr_reader :name
26
22
 
27
- sig { returns(String) }
23
+ #: String
28
24
  attr_reader :value
29
25
 
30
- sig { params(name: String, value: String).void }
26
+ #: (String name, String value) -> void
31
27
  def initialize(name, value)
32
28
  @name = name
33
29
  @value = value
@@ -35,12 +31,12 @@ module CLI
35
31
  end
36
32
  private_class_method(:new) # don't instantiate this class directly
37
33
 
38
- sig { returns(String) }
34
+ #: -> String
39
35
  def inspect
40
36
  "#<#{self.class.name} #{@name}=#{@value}>"
41
37
  end
42
38
 
43
- sig { params(other: T.untyped).returns(T::Boolean) }
39
+ #: (untyped other) -> bool
44
40
  def ==(other)
45
41
  !!(super(other) && @value == other.value && @name == other.name)
46
42
  end
@@ -55,22 +51,22 @@ module CLI
55
51
  end
56
52
 
57
53
  class Flag < Node
58
- sig { returns(String) }
54
+ #: String
59
55
  attr_reader :value
60
56
 
61
- sig { params(value: String).void }
57
+ #: (String value) -> void
62
58
  def initialize(value)
63
59
  @value = value
64
60
  super()
65
61
  end
66
62
  private_class_method(:new) # don't instantiate this class directly
67
63
 
68
- sig { returns(String) }
64
+ #: -> String
69
65
  def inspect
70
66
  "#<#{self.class.name} #{@value}>"
71
67
  end
72
68
 
73
- sig { params(other: T.untyped).returns(T::Boolean) }
69
+ #: (untyped other) -> bool
74
70
  def ==(other)
75
71
  !!(super(other) && @value == other.value)
76
72
  end
@@ -85,42 +81,42 @@ module CLI
85
81
  end
86
82
 
87
83
  class Argument < Node
88
- sig { returns(String) }
84
+ #: String
89
85
  attr_reader :value
90
86
 
91
- sig { params(value: String).void }
87
+ #: (String value) -> void
92
88
  def initialize(value)
93
89
  @value = value
94
90
  super()
95
91
  end
96
92
 
97
- sig { returns(String) }
93
+ #: -> String
98
94
  def inspect
99
95
  "#<#{self.class.name} #{@value}>"
100
96
  end
101
97
 
102
- sig { params(other: T.untyped).returns(T::Boolean) }
98
+ #: (untyped other) -> bool
103
99
  def ==(other)
104
100
  !!(super(other) && @value == other.value)
105
101
  end
106
102
  end
107
103
 
108
104
  class Unparsed < Node
109
- sig { returns(T::Array[String]) }
105
+ #: Array[String]
110
106
  attr_reader :value
111
107
 
112
- sig { params(value: T::Array[String]).void }
108
+ #: (Array[String] value) -> void
113
109
  def initialize(value)
114
110
  @value = value
115
111
  super()
116
112
  end
117
113
 
118
- sig { returns(String) }
114
+ #: -> String
119
115
  def inspect
120
116
  "#<#{self.class.name} #{@value.join(" ")}>"
121
117
  end
122
118
 
123
- sig { params(other: T.untyped).returns(T::Boolean) }
119
+ #: (untyped other) -> bool
124
120
  def ==(other)
125
121
  !!(super(other) && @value == other.value)
126
122
  end
@@ -6,32 +6,28 @@ module CLI
6
6
  module Kit
7
7
  module Args
8
8
  class Parser
9
- extend T::Sig
10
-
11
9
  autoload :Node, 'cli/kit/args/parser/node'
12
10
 
13
11
  Error = Class.new(Args::Error)
14
12
 
15
13
  class InvalidOptionError < Error
16
- extend T::Sig
17
- sig { params(option: String).void }
14
+ #: (String option) -> void
18
15
  def initialize(option)
19
16
  super("invalid option -- '#{option}'")
20
17
  end
21
18
  end
22
19
 
23
20
  class OptionRequiresAnArgumentError < Error
24
- extend T::Sig
25
- sig { params(option: String).void }
21
+ #: (String option) -> void
26
22
  def initialize(option)
27
23
  super("option requires an argument -- '#{option}'")
28
24
  end
29
25
  end
30
26
 
31
- sig { params(tokens: T::Array[Tokenizer::Token]).returns(T::Array[Node]) }
27
+ #: (Array[Tokenizer::Token] tokens) -> Array[Node]
32
28
  def parse(tokens)
33
- nodes = T.let([], T::Array[Node])
34
- args = T.let(tokens, T::Array[T.nilable(Tokenizer::Token)])
29
+ nodes = [] #: Array[Node]
30
+ args = tokens #: Array[Tokenizer::Token?]
35
31
  args << nil # to make each_cons pass (args.last, nil) on the final round.
36
32
  state = :init
37
33
  # TODO: test that "--height -- 3" is parsed correctly.
@@ -40,7 +36,10 @@ module CLI
40
36
  when :skip
41
37
  state = :init
42
38
  when :init
43
- state, val = parse_token(T.must(arg), next_arg)
39
+ state, val = parse_token(
40
+ arg, #: as !nil
41
+ next_arg,
42
+ )
44
43
  nodes << val
45
44
  when :unparsed
46
45
  unless arg.is_a?(Tokenizer::Token::UnparsedArgument)
@@ -60,17 +59,14 @@ module CLI
60
59
  nodes
61
60
  end
62
61
 
63
- sig { params(definition: Definition).void }
62
+ #: (Definition definition) -> void
64
63
  def initialize(definition)
65
64
  @defn = definition
66
65
  end
67
66
 
68
67
  private
69
68
 
70
- sig do
71
- params(token: Tokenizer::Token, next_token: T.nilable(Tokenizer::Token))
72
- .returns([Symbol, Parser::Node])
73
- end
69
+ #: (Tokenizer::Token token, Tokenizer::Token? next_token) -> [Symbol, Parser::Node]
74
70
  def parse_token(token, next_token)
75
71
  case token
76
72
  when Tokenizer::Token::LongOptionName
@@ -104,7 +100,7 @@ module CLI
104
100
  end
105
101
  end
106
102
 
107
- sig { params(arg: Tokenizer::Token::OptionName, next_arg: T.nilable(Tokenizer::Token)).returns(Node) }
103
+ #: (Tokenizer::Token::OptionName arg, Tokenizer::Token? next_arg) -> Node
108
104
  def parse_option(arg, next_arg)
109
105
  case next_arg
110
106
  when nil, Tokenizer::Token::LongOptionName,
@@ -6,43 +6,37 @@ module CLI
6
6
  module Kit
7
7
  module Args
8
8
  module Tokenizer
9
- extend T::Sig
10
-
11
9
  Error = Class.new(Args::Error)
12
10
 
13
11
  class InvalidShortOption < Error
14
- extend T::Sig
15
- sig { params(short_option: String).void }
12
+ #: (String short_option) -> void
16
13
  def initialize(short_option)
17
14
  super("invalid short option: '-#{short_option}'")
18
15
  end
19
16
  end
20
17
 
21
18
  class InvalidCharInShortOption < Error
22
- extend T::Sig
23
- sig { params(short_option: String, char: String).void }
19
+ #: (String short_option, String char) -> void
24
20
  def initialize(short_option, char)
25
21
  super("invalid character '#{char}' in short option: '-#{short_option}'")
26
22
  end
27
23
  end
28
24
 
29
25
  class Token
30
- extend T::Sig
31
-
32
- sig { returns(String) }
26
+ #: String
33
27
  attr_reader :value
34
28
 
35
- sig { params(value: String).void }
29
+ #: (String value) -> void
36
30
  def initialize(value)
37
31
  @value = value
38
32
  end
39
33
 
40
- sig { returns(String) }
34
+ #: -> String
41
35
  def inspect
42
36
  "#<#{self.class.name} #{@value}>"
43
37
  end
44
38
 
45
- sig { params(other: T.untyped).returns(T::Boolean) }
39
+ #: (untyped other) -> bool
46
40
  def ==(other)
47
41
  self.class == other.class && @value == other.value
48
42
  end
@@ -58,9 +52,7 @@ module CLI
58
52
  end
59
53
 
60
54
  class << self
61
- extend T::Sig
62
-
63
- sig { params(raw_args: T::Array[String]).returns(T::Array[Token]) }
55
+ #: (Array[String] raw_args) -> Array[Token]
64
56
  def tokenize(raw_args)
65
57
  args = []
66
58
 
@@ -76,12 +68,17 @@ module CLI
76
68
  mode = :unparsed
77
69
  when /\A--./
78
70
  name, value = arg.split('=', 2)
79
- args << Token::LongOptionName.new(T.must(T.must(name)[2..-1]))
71
+ name = name #: as !nil
72
+ args << Token::LongOptionName.new(
73
+ name[2..-1], #: as !nil
74
+ )
80
75
  if value
81
76
  args << Token::OptionValue.new(value)
82
77
  end
83
78
  when /\A-./
84
- args.concat(tokenize_short_option(T.must(arg[1..-1])))
79
+ args.concat(tokenize_short_option(
80
+ arg[1..-1], #: as !nil
81
+ ))
85
82
  else
86
83
  args << if args.last.is_a?(Token::OptionName)
87
84
  Token::OptionValueOrPositionalArgument.new(arg)
@@ -95,7 +92,7 @@ module CLI
95
92
  args
96
93
  end
97
94
 
98
- sig { params(arg: String).returns(T::Array[Token]) }
95
+ #: (String arg) -> Array[Token]
99
96
  def tokenize_short_option(arg)
100
97
  args = []
101
98
  mode = :init
@@ -4,28 +4,24 @@ require 'cli/kit'
4
4
 
5
5
  module CLI
6
6
  module Kit
7
+ # @abstract
7
8
  class BaseCommand
8
- extend T::Sig
9
- extend T::Helpers
10
9
  include CLI::Kit::CommandHelp
11
10
  extend CLI::Kit::CommandHelp::ClassMethods
12
- abstract!
13
11
 
14
12
  class << self
15
- extend T::Sig
16
-
17
- sig { returns(T::Boolean) }
13
+ #: -> bool
18
14
  def defined?
19
15
  true
20
16
  end
21
17
 
22
- sig { params(args: T::Array[String], command_name: String).void }
18
+ #: (Array[String] args, String command_name) -> void
23
19
  def call(args, command_name)
24
20
  new.call(args, command_name)
25
21
  end
26
22
  end
27
23
 
28
- sig { returns(T::Boolean) }
24
+ #: -> bool
29
25
  def has_subcommands?
30
26
  false
31
27
  end
@@ -5,10 +5,9 @@ require 'cli/kit'
5
5
  module CLI
6
6
  module Kit
7
7
  module CommandHelp
8
- extend T::Sig
9
8
  include Kernel # for sorbet
10
9
 
11
- sig { params(args: T::Array[String], name: String).void }
10
+ #: (Array[String] args, String name) -> void
12
11
  def call(args, name)
13
12
  begin
14
13
  opts = self.class.opts_class
@@ -36,26 +35,24 @@ module CLI
36
35
  end
37
36
 
38
37
  # use to implement error handling
39
- sig { params(op: T.untyped, name: String).void }
38
+ #: (untyped op, String name) -> void
40
39
  def invoke_wrapper(op, name)
41
40
  invoke(op, name)
42
41
  end
43
42
 
44
- sig { params(op: T.untyped, name: String).void }
43
+ #: (untyped op, String name) -> void
45
44
  def invoke(op, name)
46
45
  raise(NotImplementedError, '#invoke must be implemented, or #call overridden')
47
46
  end
48
47
 
49
48
  class << self
50
- extend T::Sig
51
-
52
- sig { params(tool_name: String).void }
49
+ #: String
53
50
  attr_writer :tool_name
54
51
 
55
- sig { params(max_desc_length: Integer).void }
52
+ #: Integer
56
53
  attr_writer :max_desc_length
57
54
 
58
- sig { returns(String) }
55
+ #: -> String
59
56
  def _tool_name
60
57
  unless @tool_name
61
58
  raise 'You must set CLI::Kit::CommandHelp.tool_name='
@@ -64,14 +61,13 @@ module CLI
64
61
  @tool_name
65
62
  end
66
63
 
67
- sig { returns(Integer) }
64
+ #: -> Integer
68
65
  def _max_desc_length
69
66
  @max_desc_length || 80
70
67
  end
71
68
  end
72
69
 
73
70
  module ClassMethods
74
- extend T::Sig
75
71
  include Kernel # for sorbet
76
72
 
77
73
  DEFAULT_HELP_SECTIONS = [
@@ -82,7 +78,7 @@ module CLI
82
78
  :options,
83
79
  ]
84
80
 
85
- sig { returns(String) }
81
+ #: -> String
86
82
  def build_help
87
83
  h = (@help_sections || DEFAULT_HELP_SECTIONS).map do |section|
88
84
  case section
@@ -103,7 +99,7 @@ module CLI
103
99
  CLI::UI.fmt(h)
104
100
  end
105
101
 
106
- sig { returns(String) }
102
+ #: -> String
107
103
  def _command_name
108
104
  return @command_name if @command_name
109
105
 
@@ -111,12 +107,12 @@ module CLI
111
107
  last_camel.gsub(/([a-z])([A-Z])/, '\1-\2').downcase
112
108
  end
113
109
 
114
- sig { returns(String) }
110
+ #: -> String
115
111
  def _desc
116
112
  @desc
117
113
  end
118
114
 
119
- sig { returns(String) }
115
+ #: -> String
120
116
  def build_desc
121
117
  out = +"{{command:#{CommandHelp._tool_name} #{_command_name}}}"
122
118
  if @desc
@@ -125,14 +121,15 @@ module CLI
125
121
  "{{bold:#{out}}}"
126
122
  end
127
123
 
128
- sig { returns(T.untyped) }
124
+ #: -> untyped
129
125
  def opts_class
130
- T.unsafe(self).const_get(:Opts) # rubocop:disable Sorbet/ConstantsFromStrings
126
+ uself = self #: as untyped
127
+ uself.const_get(:Opts) # rubocop:disable Sorbet/ConstantsFromStrings
131
128
  rescue NameError
132
129
  Class.new(CLI::Kit::Opts)
133
130
  end
134
131
 
135
- sig { returns(T.nilable(String)) }
132
+ #: -> String?
136
133
  def build_options
137
134
  opts = opts_class
138
135
  return unless opts
@@ -151,7 +148,7 @@ module CLI
151
148
 
152
149
  return if @defn.options.empty? && @defn.flags.empty?
153
150
 
154
- merged = T.let(@defn.options, T::Array[T.any(Args::Definition::Option, Args::Definition::Flag)])
151
+ merged = @defn.options #: Array[(Args::Definition::Option | Args::Definition::Flag)]
155
152
  merged += @defn.flags
156
153
  merged.sort_by!(&:name)
157
154
  "{{bold:Options:}}\n" + merged.map do |o|
@@ -179,12 +176,12 @@ module CLI
179
176
  end.join("\n")
180
177
  end
181
178
 
182
- sig { params(sections: T::Array[Symbol]).void }
179
+ #: (Array[Symbol] sections) -> void
183
180
  def help_sections(sections)
184
181
  @help_sections = sections
185
182
  end
186
183
 
187
- sig { params(command_name: String).void }
184
+ #: (String command_name) -> void
188
185
  def command_name(command_name)
189
186
  if @command_name
190
187
  raise(ArgumentError, "Command name already set to #{@command_name}")
@@ -193,7 +190,7 @@ module CLI
193
190
  @command_name = command_name
194
191
  end
195
192
 
196
- sig { params(desc: String).void }
193
+ #: (String desc) -> void
197
194
  def desc(desc)
198
195
  # A limit of 80 characters has been chosen to fit on standard terminal configurations. `long_desc` is
199
196
  # available when descriptions don't fit nicely in that space. If you're using CLI::Kit for an application
@@ -213,7 +210,7 @@ module CLI
213
210
  @desc = desc
214
211
  end
215
212
 
216
- sig { params(long_desc: String).void }
213
+ #: (String long_desc) -> void
217
214
  def long_desc(long_desc)
218
215
  if @long_desc
219
216
  raise(ArgumentError, 'long description already set')
@@ -222,7 +219,7 @@ module CLI
222
219
  @long_desc = long_desc
223
220
  end
224
221
 
225
- sig { returns(String) }
222
+ #: -> String
226
223
  def build_usage
227
224
  '{{bold:Usage:}}' + case (@usage || []).size
228
225
  when 0
@@ -236,7 +233,7 @@ module CLI
236
233
  end
237
234
  end
238
235
 
239
- sig { returns(T.nilable(String)) }
236
+ #: -> String?
240
237
  def build_examples
241
238
  return unless @examples
242
239
 
@@ -254,13 +251,13 @@ module CLI
254
251
  end.join("\n\n")
255
252
  end
256
253
 
257
- sig { params(usage: String).void }
254
+ #: (String usage) -> void
258
255
  def usage(usage)
259
256
  @usage ||= []
260
257
  @usage << usage
261
258
  end
262
259
 
263
- sig { params(command: String, explanation: T.nilable(String)).void }
260
+ #: (String command, String? explanation) -> void
264
261
  def example(command, explanation)
265
262
  @examples ||= []
266
263
  @examples << [command, explanation]
@@ -5,58 +5,60 @@ require 'cli/kit'
5
5
  module CLI
6
6
  module Kit
7
7
  class CommandRegistry
8
- extend T::Sig
8
+ #: type command_or_proc = singleton(CLI::Kit::BaseCommand) | ^() -> singleton(CLI::Kit::BaseCommand)
9
9
 
10
- CommandOrProc = T.type_alias do
11
- T.any(T.class_of(CLI::Kit::BaseCommand), T.proc.returns(T.class_of(CLI::Kit::BaseCommand)))
12
- end
13
-
14
- sig { returns(T::Hash[String, CommandOrProc]) }
10
+ #: Hash[String, command_or_proc]
15
11
  attr_reader :commands
16
12
 
17
- sig { returns(T::Hash[String, String]) }
13
+ #: Hash[String, String]
18
14
  attr_reader :aliases
19
15
 
16
+ # @interface
20
17
  module ContextualResolver
21
- extend T::Sig
22
- extend T::Helpers
23
- interface!
24
-
25
- sig { abstract.returns(T::Array[String]) }
26
- def command_names; end
18
+ # @abstract
19
+ #: -> Array[String]
20
+ def command_names
21
+ raise(NotImplementedError)
22
+ end
27
23
 
28
- sig { abstract.returns(T::Hash[String, String]) }
29
- def aliases; end
24
+ # @abstract
25
+ #: -> Hash[String, String]
26
+ def aliases
27
+ raise(NotImplementedError)
28
+ end
30
29
 
31
- sig { abstract.params(_name: String).returns(T.class_of(CLI::Kit::BaseCommand)) }
32
- def command_class(_name); end
30
+ # @abstract
31
+ #: (String) -> singleton(CLI::Kit::BaseCommand)
32
+ def command_class(_name)
33
+ raise(NotImplementedError)
34
+ end
33
35
  end
34
36
 
35
37
  module NullContextualResolver
36
- extend T::Sig
37
38
  extend ContextualResolver
38
39
 
39
40
  class << self
40
- extend T::Sig
41
-
42
- sig { override.returns(T::Array[String]) }
41
+ # @override
42
+ #: -> Array[String]
43
43
  def command_names
44
44
  []
45
45
  end
46
46
 
47
- sig { override.returns(T::Hash[String, String]) }
47
+ # @override
48
+ #: -> Hash[String, String]
48
49
  def aliases
49
50
  {}
50
51
  end
51
52
 
52
- sig { override.params(_name: String).returns(T.class_of(CLI::Kit::BaseCommand)) }
53
+ # @override
54
+ #: (String _name) -> singleton(CLI::Kit::BaseCommand)
53
55
  def command_class(_name)
54
56
  raise(CLI::Kit::Abort, 'Cannot be called on the NullContextualResolver since command_names is empty')
55
57
  end
56
58
  end
57
59
  end
58
60
 
59
- sig { params(default: String, contextual_resolver: ContextualResolver).void }
61
+ #: (default: String, ?contextual_resolver: ContextualResolver) -> void
60
62
  def initialize(default:, contextual_resolver: NullContextualResolver)
61
63
  @commands = {}
62
64
  @aliases = {}
@@ -64,47 +66,49 @@ module CLI
64
66
  @contextual_resolver = contextual_resolver
65
67
  end
66
68
 
67
- sig { returns(T::Hash[String, T.class_of(CLI::Kit::BaseCommand)]) }
69
+ #: -> Hash[String, singleton(CLI::Kit::BaseCommand)]
68
70
  def resolved_commands
69
71
  @commands.each_with_object({}) do |(k, v), a|
70
72
  a[k] = resolve_class(v)
71
73
  end
72
74
  end
73
75
 
74
- sig { params(const: CommandOrProc, name: String).void }
76
+ #: (command_or_proc const, String name) -> void
75
77
  def add(const, name)
76
78
  commands[name] = const
77
79
  end
78
80
 
79
- sig { params(name: T.nilable(String)).returns([T.nilable(T.class_of(CLI::Kit::BaseCommand)), String]) }
81
+ #: (String? name) -> [singleton(CLI::Kit::BaseCommand)?, String]
80
82
  def lookup_command(name)
81
83
  name = @default if name.to_s.empty?
82
- resolve_command(T.must(name))
84
+ resolve_command(
85
+ name, #: as !nil
86
+ )
83
87
  end
84
88
 
85
- sig { params(from: String, to: String).void }
89
+ #: (String from, String to) -> void
86
90
  def add_alias(from, to)
87
91
  aliases[from] = to unless aliases[from]
88
92
  end
89
93
 
90
- sig { returns(T::Array[String]) }
94
+ #: -> Array[String]
91
95
  def command_names
92
96
  @contextual_resolver.command_names + commands.keys
93
97
  end
94
98
 
95
- sig { params(name: String).returns(T::Boolean) }
99
+ #: (String name) -> bool
96
100
  def exist?(name)
97
101
  !resolve_command(name).first.nil?
98
102
  end
99
103
 
100
104
  private
101
105
 
102
- sig { params(name: String).returns(String) }
106
+ #: (String name) -> String
103
107
  def resolve_alias(name)
104
108
  aliases[name] || @contextual_resolver.aliases.fetch(name, name)
105
109
  end
106
110
 
107
- sig { params(name: String).returns([T.nilable(T.class_of(CLI::Kit::BaseCommand)), String]) }
111
+ #: (String name) -> [singleton(CLI::Kit::BaseCommand)?, String]
108
112
  def resolve_command(name)
109
113
  name = resolve_alias(name)
110
114
  resolve_global_command(name) ||
@@ -112,7 +116,7 @@ module CLI
112
116
  [nil, name]
113
117
  end
114
118
 
115
- sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
119
+ #: (String name) -> [singleton(CLI::Kit::BaseCommand), String]?
116
120
  def resolve_global_command(name)
117
121
  klass = resolve_class(commands.fetch(name, nil))
118
122
  return unless klass
@@ -122,7 +126,7 @@ module CLI
122
126
  nil
123
127
  end
124
128
 
125
- sig { params(name: String).returns(T.nilable([T.class_of(CLI::Kit::BaseCommand), String])) }
129
+ #: (String name) -> [singleton(CLI::Kit::BaseCommand), String]?
126
130
  def resolve_contextual_command(name)
127
131
  found = @contextual_resolver.command_names.include?(name)
128
132
  return unless found
@@ -130,7 +134,7 @@ module CLI
130
134
  [@contextual_resolver.command_class(name), name]
131
135
  end
132
136
 
133
- sig { params(class_or_proc: T.nilable(CommandOrProc)).returns(T.nilable(T.class_of(CLI::Kit::BaseCommand))) }
137
+ #: (command_or_proc? class_or_proc) -> singleton(CLI::Kit::BaseCommand)?
134
138
  def resolve_class(class_or_proc)
135
139
  case class_or_proc
136
140
  when nil