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.
data/lib/cli/kit/opts.rb CHANGED
@@ -5,16 +5,11 @@ require 'cli/kit'
5
5
  module CLI
6
6
  module Kit
7
7
  class Opts
8
- extend T::Sig
9
-
10
8
  module Mixin
11
- extend T::Sig
12
9
  include Kernel
13
10
 
14
11
  module MixinClassMethods
15
- extend T::Sig
16
-
17
- sig { params(included_module: Module).void }
12
+ #: (Module included_module) -> void
18
13
  def include(included_module)
19
14
  super
20
15
  return unless included_module.is_a?(MixinClassMethods)
@@ -28,36 +23,26 @@ module CLI
28
23
  track_method(method_name)
29
24
  end
30
25
 
31
- sig { params(method_name: Symbol).void }
26
+ #: (Symbol method_name) -> void
32
27
  def track_method(method_name)
33
28
  @tracked_methods ||= []
34
29
  @tracked_methods << method_name unless @tracked_methods.include?(method_name)
35
30
  end
36
31
 
37
- sig { returns(T::Array[Symbol]) }
32
+ #: -> Array[Symbol]
38
33
  def tracked_methods
39
34
  @tracked_methods || []
40
35
  end
41
36
  end
42
37
 
43
38
  class << self
44
- extend T::Sig
45
-
46
- sig { params(klass: Module).void }
39
+ #: (Module klass) -> void
47
40
  def included(klass)
48
41
  klass.extend(MixinClassMethods)
49
42
  end
50
43
  end
51
44
 
52
- sig do
53
- params(
54
- name: Symbol,
55
- short: T.nilable(String),
56
- long: T.nilable(String),
57
- desc: T.nilable(String),
58
- default: T.any(NilClass, String, T.proc.returns(String)),
59
- ).returns(T.nilable(String))
60
- end
45
+ #: (?name: Symbol, ?short: String?, ?long: String?, ?desc: String?, ?default: (String | ^-> String)?) -> String?
61
46
  def option(name: infer_name, short: nil, long: nil, desc: nil, default: nil)
62
47
  unless default.nil?
63
48
  raise(ArgumentError, 'declare options with non-nil defaults using `option!` instead of `option`')
@@ -74,15 +59,7 @@ module CLI
74
59
  end
75
60
  end
76
61
 
77
- sig do
78
- params(
79
- name: Symbol,
80
- short: T.nilable(String),
81
- long: T.nilable(String),
82
- desc: T.nilable(String),
83
- default: T.any(NilClass, String, T.proc.returns(String)),
84
- ).returns(String)
85
- end
62
+ #: (?name: Symbol, ?short: String?, ?long: String?, ?desc: String?, ?default: (String | ^-> String)?) -> String
86
63
  def option!(name: infer_name, short: nil, long: nil, desc: nil, default: nil)
87
64
  case @obj
88
65
  when Args::Definition
@@ -95,15 +72,7 @@ module CLI
95
72
  end
96
73
  end
97
74
 
98
- sig do
99
- params(
100
- name: Symbol,
101
- short: T.nilable(String),
102
- long: T.nilable(String),
103
- desc: T.nilable(String),
104
- default: T.any(T::Array[String], T.proc.returns(T::Array[String])),
105
- ).returns(T::Array[String])
106
- end
75
+ #: (?name: Symbol, ?short: String?, ?long: String?, ?desc: String?, ?default: (Array[String] | ^-> Array[String])) -> Array[String]
107
76
  def multi_option(name: infer_name, short: nil, long: nil, desc: nil, default: [])
108
77
  case @obj
109
78
  when Args::Definition
@@ -116,14 +85,7 @@ module CLI
116
85
  end
117
86
  end
118
87
 
119
- sig do
120
- params(
121
- name: Symbol,
122
- short: T.nilable(String),
123
- long: T.nilable(String),
124
- desc: T.nilable(String),
125
- ).returns(T::Boolean)
126
- end
88
+ #: (?name: Symbol, ?short: String?, ?long: String?, ?desc: String?) -> bool
127
89
  def flag(name: infer_name, short: nil, long: nil, desc: nil)
128
90
  case @obj
129
91
  when Args::Definition
@@ -134,7 +96,7 @@ module CLI
134
96
  end
135
97
  end
136
98
 
137
- sig { params(name: Symbol, desc: T.nilable(String)).returns(String) }
99
+ #: (?name: Symbol, ?desc: String?) -> String
138
100
  def position!(name: infer_name, desc: nil)
139
101
  case @obj
140
102
  when Args::Definition
@@ -145,18 +107,7 @@ module CLI
145
107
  end
146
108
  end
147
109
 
148
- sig do
149
- params(
150
- name: Symbol,
151
- desc: T.nilable(String),
152
- default: T.any(NilClass, String, T.proc.returns(String)),
153
- skip: T.any(
154
- NilClass,
155
- T.proc.returns(T::Boolean),
156
- T.proc.params(arg0: String).returns(T::Boolean),
157
- ),
158
- ).returns(T.nilable(String))
159
- end
110
+ #: (?name: Symbol, ?desc: String?, ?default: (String | ^-> String)?, ?skip: (^-> bool | ^(String arg0) -> bool)?) -> String?
160
111
  def position(name: infer_name, desc: nil, default: nil, skip: nil)
161
112
  case @obj
162
113
  when Args::Definition
@@ -167,7 +118,7 @@ module CLI
167
118
  end
168
119
  end
169
120
 
170
- sig { params(name: Symbol, desc: T.nilable(String)).returns(T::Array[String]) }
121
+ #: (?name: Symbol, ?desc: String?) -> Array[String]
171
122
  def rest(name: infer_name, desc: nil)
172
123
  case @obj
173
124
  when Args::Definition
@@ -180,14 +131,14 @@ module CLI
180
131
 
181
132
  private
182
133
 
183
- sig { params(label: T.nilable(String)).returns(T.nilable(Symbol)) }
134
+ #: (String? label) -> Symbol?
184
135
  def symbolize(label)
185
136
  return if label.nil?
186
137
 
187
138
  label.split('#').last&.to_sym
188
139
  end
189
140
 
190
- sig { returns(Symbol) }
141
+ #: -> Symbol
191
142
  def infer_name
192
143
  to_skip = 1
193
144
  Kernel.caller_locations.each do |loc|
@@ -197,7 +148,7 @@ module CLI
197
148
  to_skip -= 1
198
149
  next
199
150
  end
200
- return T.must(symbolize(loc.label))
151
+ return symbolize(loc.label) #: as !nil
201
152
  end
202
153
  raise(ArgumentError, 'could not infer name')
203
154
  end
@@ -206,24 +157,18 @@ module CLI
206
157
 
207
158
  DEFAULT_OPTIONS = [:helpflag]
208
159
 
209
- sig { returns(T::Boolean) }
160
+ #: -> bool
210
161
  def helpflag
211
162
  flag(name: :help, short: '-h', long: '--help', desc: 'Show this help message')
212
163
  end
213
164
 
214
- sig { returns(T::Array[String]) }
165
+ #: -> Array[String]
215
166
  def unparsed
216
167
  obj = assert_result!
217
168
  obj.unparsed
218
169
  end
219
170
 
220
- sig do
221
- params(
222
- block: T.nilable(
223
- T.proc.params(arg0: Symbol, arg1: T.nilable(String)).void,
224
- ),
225
- ).returns(T.untyped)
226
- end
171
+ #: ?{ (Symbol arg0, String? arg1) -> void } -> untyped
227
172
  def each_option(&block)
228
173
  return enum_for(:each_option) unless block_given?
229
174
 
@@ -235,13 +180,7 @@ module CLI
235
180
  end
236
181
  end
237
182
 
238
- sig do
239
- params(
240
- block: T.nilable(
241
- T.proc.params(arg0: Symbol, arg1: T::Boolean).void,
242
- ),
243
- ).returns(T.untyped)
244
- end
183
+ #: ?{ (Symbol arg0, bool arg1) -> void } -> untyped
245
184
  def each_flag(&block)
246
185
  return enum_for(:each_flag) unless block_given?
247
186
 
@@ -253,7 +192,7 @@ module CLI
253
192
  end
254
193
  end
255
194
 
256
- sig { params(name: String).returns(T.nilable(T.any(String, T::Boolean))) }
195
+ #: (String name) -> (String | bool)?
257
196
  def [](name)
258
197
  obj = assert_result!
259
198
  if obj.opt.respond_to?(name)
@@ -263,7 +202,7 @@ module CLI
263
202
  end
264
203
  end
265
204
 
266
- sig { params(name: String).returns(T.nilable(String)) }
205
+ #: (String name) -> String?
267
206
  def lookup_option(name)
268
207
  obj = assert_result!
269
208
  obj.opt.send(name)
@@ -272,7 +211,7 @@ module CLI
272
211
  nil
273
212
  end
274
213
 
275
- sig { params(name: String).returns(T::Boolean) }
214
+ #: (String name) -> bool
276
215
  def lookup_flag(name)
277
216
  obj = assert_result!
278
217
  obj.flag.send(name)
@@ -280,17 +219,18 @@ module CLI
280
219
  false
281
220
  end
282
221
 
283
- sig { returns(Args::Evaluation) }
222
+ #: -> Args::Evaluation
284
223
  def assert_result!
285
224
  raise(NotImplementedError, 'not implemented') if @obj.is_a?(Args::Definition)
286
225
 
287
226
  @obj
288
227
  end
289
228
 
290
- sig { params(defn: Args::Definition).void }
229
+ #: (Args::Definition defn) -> void
291
230
  def define!(defn)
292
231
  @obj = defn
293
- T.cast(self.class, Mixin::MixinClassMethods).tracked_methods.each do |m|
232
+ klass = self.class #: as Mixin::MixinClassMethods
233
+ klass.tracked_methods.each do |m|
294
234
  send(m)
295
235
  end
296
236
  DEFAULT_OPTIONS.each do |m|
@@ -298,7 +238,7 @@ module CLI
298
238
  end
299
239
  end
300
240
 
301
- sig { params(ev: Args::Evaluation).void }
241
+ #: (Args::Evaluation ev) -> void
302
242
  def evaluate!(ev)
303
243
  @obj = ev
304
244
  ev.resolve_positions!
@@ -6,18 +6,12 @@ module CLI
6
6
  # because sorbet type-checking takes the pedantic route that module doesn't include Kernel, therefore
7
7
  # this is necessary (even tho it's ~probably fine~)
8
8
  include Kernel
9
- extend T::Sig
10
9
 
11
- # T.untyped is used in two places. The interpretation of dynamic values from the provided `opts`
10
+ # untyped is used in two places. The interpretation of dynamic values from the provided `opts`
12
11
  # and the resulting args[:opts] is pretty broad. There seems to be minimal value in expressing a
13
- # tighter subset of T.untyped.
12
+ # tighter subset of untyped.
14
13
 
15
- sig do
16
- params(
17
- args: T.any(Array, String),
18
- opts_defn: T::Hash[Symbol, T::Array[T.untyped]],
19
- ).returns(T::Hash[Symbol, T.untyped])
20
- end
14
+ #: ((Array | String) args, Hash[Symbol, Array[untyped]] opts_defn) -> Hash[Symbol, untyped]
21
15
  def parse_args(args, opts_defn)
22
16
  start_opts, parser_config = opts_defn.reduce([{}, []]) do |(ini, pcfg), (n, cfg)|
23
17
  (vals, desc, short, klass) = cfg
@@ -38,7 +32,8 @@ module CLI
38
32
  long = "--#{n.to_s.tr("_", "-")}" + (mark.nil? ? '' : " #{mark}")
39
33
  opt_args = klass.nil? ? [short, long, desc] : [short, long, klass, desc]
40
34
 
41
- T.unsafe(opt_p).on(*opt_args) do |v|
35
+ unsafe_opt_p = opt_p #: as untyped
36
+ unsafe_opt_p.on(*opt_args) do |v|
42
37
  acc_opts[n] = if acc_opts.key?(n)
43
38
  Array(acc_opts[n]) + Array(v || def_val)
44
39
  else
@@ -5,15 +5,13 @@ require 'cli/kit'
5
5
  module CLI
6
6
  module Kit
7
7
  class Resolver
8
- extend T::Sig
9
-
10
- sig { params(tool_name: String, command_registry: CLI::Kit::CommandRegistry).void }
8
+ #: (tool_name: String, command_registry: CLI::Kit::CommandRegistry) -> void
11
9
  def initialize(tool_name:, command_registry:)
12
10
  @tool_name = tool_name
13
11
  @command_registry = command_registry
14
12
  end
15
13
 
16
- sig { params(args: T::Array[String]).returns([T.class_of(CLI::Kit::BaseCommand), String, T::Array[String]]) }
14
+ #: (Array[String] args) -> [singleton(CLI::Kit::BaseCommand), String, Array[String]]
17
15
  def call(args)
18
16
  args = args.dup
19
17
  command_name = args.shift
@@ -30,7 +28,7 @@ module CLI
30
28
 
31
29
  private
32
30
 
33
- sig { params(name: T.nilable(String)).void }
31
+ #: (String? name) -> void
34
32
  def command_not_found(name)
35
33
  CLI::UI::Frame.open('Command not found', color: :red, timing: false) do
36
34
  $stderr.puts(CLI::UI.fmt("{{command:#{@tool_name} #{name}}} was not found"))
@@ -59,7 +57,7 @@ module CLI
59
57
  end
60
58
  end
61
59
 
62
- sig { returns(T::Array[String]) }
60
+ #: -> Array[String]
63
61
  def commands_and_aliases
64
62
  @command_registry.command_names + @command_registry.aliases.keys
65
63
  end
@@ -14,7 +14,8 @@ module CLI
14
14
  CLI::Kit::System.reset!
15
15
  # this is in minitest, but sorbet doesn't know that. probably we
16
16
  # could structure this better.
17
- T.unsafe(self).assert(false, errors) if should_raise && !errors.nil?
17
+ uself = self #: as untyped
18
+ uself.assert(false, errors) if should_raise && !errors.nil?
18
19
  errors
19
20
  end
20
21
 
@@ -67,7 +68,8 @@ module CLI
67
68
 
68
69
  # Otherwise handle the command
69
70
  if expected_command[:allow]
70
- T.unsafe(self).original_system(*a, sudo: sudo, env: env, **kwargs)
71
+ uself = self #: as untyped
72
+ uself.original_system(*a, sudo: sudo, env: env, **kwargs)
71
73
  else
72
74
  FakeSuccess.new(expected_command[:success])
73
75
  end
@@ -83,7 +85,8 @@ module CLI
83
85
 
84
86
  # Otherwise handle the command
85
87
  if expected_command[:allow]
86
- T.unsafe(self).original_capture2(*a, sudo: sudo, env: env, **kwargs)
88
+ uself = self #: as untyped
89
+ uself.original_capture2(*a, sudo: sudo, env: env, **kwargs)
87
90
  else
88
91
  [
89
92
  expected_command[:stdout],
@@ -102,7 +105,8 @@ module CLI
102
105
 
103
106
  # Otherwise handle the command
104
107
  if expected_command[:allow]
105
- T.unsafe(self).original_capture2e(*a, sudo: sudo, env: env, **kwargs)
108
+ uself = self #: as untyped
109
+ uself.original_capture2e(*a, sudo: sudo, env: env, **kwargs)
106
110
  else
107
111
  [
108
112
  expected_command[:stdout],
@@ -121,7 +125,8 @@ module CLI
121
125
 
122
126
  # Otherwise handle the command
123
127
  if expected_command[:allow]
124
- T.unsafe(self).original_capture3(*a, sudo: sudo, env: env, **kwargs)
128
+ uself = self #: as untyped
129
+ uself.original_capture3(*a, sudo: sudo, env: env, **kwargs)
125
130
  else
126
131
  [
127
132
  expected_command[:stdout],
@@ -9,8 +9,6 @@ module CLI
9
9
  module System
10
10
  SUDO_PROMPT = CLI::UI.fmt('{{info:(sudo)}} Password: ')
11
11
  class << self
12
- extend T::Sig
13
-
14
12
  # Ask for sudo access with a message explaning the need for it
15
13
  # Will make subsequent commands capable of running with sudo for a period of time
16
14
  #
@@ -20,7 +18,7 @@ module CLI
20
18
  # #### Usage
21
19
  # `ctx.sudo_reason("We need to do a thing")`
22
20
  #
23
- sig { params(msg: String).void }
21
+ #: (String msg) -> void
24
22
  def sudo_reason(msg)
25
23
  # See if sudo has a cached password
26
24
  %x(env SUDO_ASKPASS=/usr/bin/false sudo -A true > /dev/null 2>&1)
@@ -48,16 +46,7 @@ module CLI
48
46
  # #### Usage
49
47
  # `out, stat = CLI::Kit::System.capture2('ls', 'a_folder')`
50
48
  #
51
- sig do
52
- params(
53
- cmd: String,
54
- args: String,
55
- sudo: T.any(T::Boolean, String),
56
- env: T::Hash[String, T.nilable(String)],
57
- kwargs: T.untyped,
58
- )
59
- .returns([String, Process::Status])
60
- end
49
+ #: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, Process::Status]
61
50
  def capture2(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
62
51
  delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture2)
63
52
  end
@@ -79,16 +68,7 @@ module CLI
79
68
  # #### Usage
80
69
  # `out_and_err, stat = CLI::Kit::System.capture2e('ls', 'a_folder')`
81
70
  #
82
- sig do
83
- params(
84
- cmd: String,
85
- args: String,
86
- sudo: T.any(T::Boolean, String),
87
- env: T::Hash[String, T.nilable(String)],
88
- kwargs: T.untyped,
89
- )
90
- .returns([String, Process::Status])
91
- end
71
+ #: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, Process::Status]
92
72
  def capture2e(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
93
73
  delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture2e)
94
74
  end
@@ -111,70 +91,22 @@ module CLI
111
91
  # #### Usage
112
92
  # `out, err, stat = CLI::Kit::System.capture3('ls', 'a_folder')`
113
93
  #
114
- sig do
115
- params(
116
- cmd: String,
117
- args: String,
118
- sudo: T.any(T::Boolean, String),
119
- env: T::Hash[String, T.nilable(String)],
120
- kwargs: T.untyped,
121
- )
122
- .returns([String, String, Process::Status])
123
- end
94
+ #: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) -> [String, String, Process::Status]
124
95
  def capture3(cmd, *args, sudo: false, env: ENV.to_h, **kwargs)
125
96
  delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :capture3)
126
97
  end
127
98
 
128
- sig do
129
- params(
130
- cmd: String,
131
- args: String,
132
- sudo: T.any(T::Boolean, String),
133
- env: T::Hash[String, T.nilable(String)],
134
- kwargs: T.untyped,
135
- block: T.nilable(
136
- T.proc.params(stdin: IO, stdout: IO, wait_thr: Process::Waiter)
137
- .returns([IO, IO, Process::Waiter]),
138
- ),
139
- )
140
- .returns([IO, IO, Process::Waiter])
141
- end
99
+ #: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, Process::Waiter wait_thr) -> [IO, IO, Process::Waiter] } -> [IO, IO, Process::Waiter]
142
100
  def popen2(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
143
101
  delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen2, &block)
144
102
  end
145
103
 
146
- sig do
147
- params(
148
- cmd: String,
149
- args: String,
150
- sudo: T.any(T::Boolean, String),
151
- env: T::Hash[String, T.nilable(String)],
152
- kwargs: T.untyped,
153
- block: T.nilable(
154
- T.proc.params(stdin: IO, stdout: IO, wait_thr: Process::Waiter)
155
- .returns([IO, IO, Process::Waiter]),
156
- ),
157
- )
158
- .returns([IO, IO, Process::Waiter])
159
- end
104
+ #: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, Process::Waiter wait_thr) -> [IO, IO, Process::Waiter] } -> [IO, IO, Process::Waiter]
160
105
  def popen2e(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
161
106
  delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen2e, &block)
162
107
  end
163
108
 
164
- sig do
165
- params(
166
- cmd: String,
167
- args: String,
168
- sudo: T.any(T::Boolean, String),
169
- env: T::Hash[String, T.nilable(String)],
170
- kwargs: T.untyped,
171
- block: T.nilable(
172
- T.proc.params(stdin: IO, stdout: IO, stderr: IO, wait_thr: Process::Waiter)
173
- .returns([IO, IO, IO, Process::Waiter]),
174
- ),
175
- )
176
- .returns([IO, IO, IO, Process::Waiter])
177
- end
109
+ #: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], **untyped kwargs) ?{ (IO stdin, IO stdout, IO stderr, Process::Waiter wait_thr) -> [IO, IO, IO, Process::Waiter] } -> [IO, IO, IO, Process::Waiter]
178
110
  def popen3(cmd, *args, sudo: false, env: ENV.to_h, **kwargs, &block)
179
111
  delegate_open3(cmd, args, kwargs, sudo: sudo, env: env, method: :popen3, &block)
180
112
  end
@@ -194,18 +126,7 @@ module CLI
194
126
  # #### Usage
195
127
  # `stat = CLI::Kit::System.system('ls', 'a_folder')`
196
128
  #
197
- sig do
198
- params(
199
- cmd: String,
200
- args: String,
201
- sudo: T.any(T::Boolean, String),
202
- env: T::Hash[String, T.nilable(String)],
203
- stdin: T.nilable(T.any(IO, String, Integer, Symbol)),
204
- kwargs: T.untyped,
205
- block: T.nilable(T.proc.params(out: String, err: String).void),
206
- )
207
- .returns(Process::Status)
208
- end
129
+ #: (String cmd, *String args, ?sudo: (String | bool), ?env: Hash[String, String?], ?stdin: (IO | String | Integer | Symbol)?, **untyped kwargs) ?{ (String out, String err) -> void } -> Process::Status
209
130
  def system(cmd, *args, sudo: false, env: ENV.to_h, stdin: nil, **kwargs, &block)
210
131
  cmd, args = apply_sudo(cmd, args, sudo)
211
132
 
@@ -219,7 +140,8 @@ module CLI
219
140
  STDIN
220
141
  end
221
142
  cmd, args = resolve_path(cmd, args, env)
222
- pid = T.unsafe(Process).spawn(env, cmd, *args, 0 => in_stream, :out => out_w, :err => err_w, **kwargs)
143
+ process = Process #: as untyped
144
+ pid = process.spawn(env, cmd, *args, 0 => in_stream, :out => out_w, :err => err_w, **kwargs)
223
145
  out_w.close
224
146
  err_w.close
225
147
 
@@ -260,15 +182,16 @@ module CLI
260
182
  # Split off trailing partial UTF-8 Characters. UTF-8 Multibyte characters start with a 11xxxxxx byte that tells
261
183
  # how many following bytes are part of this character, followed by some number of 10xxxxxx bytes. This simple
262
184
  # algorithm will split off a whole trailing multi-byte character.
263
- sig { params(data: String).returns([String, String]) }
185
+ #: (String data) -> [String, String]
264
186
  def split_partial_characters(data)
265
- last_byte = T.must(data.getbyte(-1))
187
+ last_byte = data.getbyte(-1) #: as !nil
266
188
  return [data, ''] if (last_byte & 0b1000_0000).zero?
267
189
 
268
190
  # UTF-8 is up to 4 characters per rune, so we could never want to trim more than that, and we want to avoid
269
191
  # allocating an array for the whole of data with bytes
270
192
  min_bound = -[4, data.bytesize].min
271
- final_bytes = T.must(data.byteslice(min_bound..-1)).bytes
193
+ fb = data.byteslice(min_bound..-1) #: as !nil
194
+ final_bytes = fb.bytes
272
195
  partial_character_sub_index = final_bytes.rindex { |byte| byte & 0b1100_0000 == 0b1100_0000 }
273
196
 
274
197
  # Bail out for non UTF-8
@@ -293,10 +216,13 @@ module CLI
293
216
 
294
217
  partial_character_index = min_bound + partial_character_sub_index
295
218
 
296
- [T.must(data.byteslice(0...partial_character_index)), T.must(data.byteslice(partial_character_index..-1))]
219
+ [
220
+ data.byteslice(0...partial_character_index), #: as !nil
221
+ data.byteslice(partial_character_index..-1), #: as !nil
222
+ ]
297
223
  end
298
224
 
299
- sig { returns(Symbol) }
225
+ #: -> Symbol
300
226
  def os
301
227
  return :mac if /darwin/.match(RUBY_PLATFORM)
302
228
  return :linux if /linux/.match(RUBY_PLATFORM)
@@ -305,7 +231,7 @@ module CLI
305
231
  raise "Could not determine OS from platform #{RUBY_PLATFORM}"
306
232
  end
307
233
 
308
- sig { params(cmd: String, env: T::Hash[String, T.nilable(String)]).returns(T.nilable(String)) }
234
+ #: (String cmd, Hash[String, String?] env) -> String?
309
235
  def which(cmd, env)
310
236
  exts = os == :windows ? (env['PATHEXT'] || 'exe').split(';') : ['']
311
237
  (env['PATH'] || '').split(File::PATH_SEPARATOR).each do |path|
@@ -320,10 +246,7 @@ module CLI
320
246
 
321
247
  private
322
248
 
323
- sig do
324
- params(cmd: String, args: T::Array[String], sudo: T.any(T::Boolean, String))
325
- .returns([String, T::Array[String]])
326
- end
249
+ #: (String cmd, Array[String] args, (String | bool) sudo) -> [String, Array[String]]
327
250
  def apply_sudo(cmd, args, sudo)
328
251
  return [cmd, args] if !sudo || Process.uid.zero?
329
252
 
@@ -331,21 +254,12 @@ module CLI
331
254
  ['sudo', args.unshift('-E', '-S', '-p', SUDO_PROMPT, '--', cmd)]
332
255
  end
333
256
 
334
- sig do
335
- params(
336
- cmd: String,
337
- args: T::Array[String],
338
- kwargs: T::Hash[Symbol, T.untyped],
339
- sudo: T.any(T::Boolean, String),
340
- env: T::Hash[String, T.nilable(String)],
341
- method: Symbol,
342
- block: T.untyped,
343
- ).returns(T.untyped)
344
- end
257
+ #: (String cmd, Array[String] args, Hash[Symbol, untyped] kwargs, ?sudo: (String | bool), ?env: Hash[String, String?], ?method: Symbol) ?{ (?) -> untyped } -> untyped
345
258
  def delegate_open3(cmd, args, kwargs, sudo: raise, env: raise, method: raise, &block)
346
259
  cmd, args = apply_sudo(cmd, args, sudo)
347
260
  cmd, args = resolve_path(cmd, args, env)
348
- T.unsafe(Open3).send(method, env, cmd, *args, **kwargs, &block)
261
+ open3 = Open3 #: as untyped
262
+ open3.send(method, env, cmd, *args, **kwargs, &block)
349
263
  rescue Errno::EINTR
350
264
  raise(Errno::EINTR, "command interrupted: #{cmd} #{args.join(" ")}")
351
265
  end
@@ -359,10 +273,7 @@ module CLI
359
273
  # project.
360
274
  #
361
275
  # See https://github.com/Shopify/dev/pull/625 for more details.
362
- sig do
363
- params(cmd: String, args: T::Array[String], env: T::Hash[String, T.nilable(String)])
364
- .returns([String, T::Array[String]])
365
- end
276
+ #: (String cmd, Array[String] args, Hash[String, String?] env) -> [String, Array[String]]
366
277
  def resolve_path(cmd, args, env)
367
278
  # If only one argument was provided, make sure it's interpreted by a shell.
368
279
  if args.empty?