cli-kit 5.0.1 → 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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +2 -2
  3. data/.rubocop.sorbet.yml +1 -0
  4. data/.rubocop.yml +1 -2
  5. data/.ruby-version +1 -1
  6. data/Gemfile +1 -1
  7. data/Gemfile.lock +47 -46
  8. data/Rakefile +0 -1
  9. data/bin/testunit +0 -1
  10. data/cli-kit.gemspec +1 -1
  11. data/dev.yml +3 -1
  12. data/examples/minimal/example.rb +1 -1
  13. data/examples/single-file/example.rb +4 -3
  14. data/gen/lib/gen/commands/help.rb +1 -3
  15. data/gen/lib/gen/commands/new.rb +2 -6
  16. data/gen/lib/gen/commands.rb +1 -7
  17. data/gen/lib/gen/entry_point.rb +1 -5
  18. data/gen/lib/gen/generator.rb +15 -19
  19. data/gen/lib/gen/help.rb +3 -7
  20. data/lib/cli/kit/args/definition.rb +37 -95
  21. data/lib/cli/kit/args/evaluation.rb +41 -60
  22. data/lib/cli/kit/args/parser/node.rb +19 -23
  23. data/lib/cli/kit/args/parser.rb +12 -16
  24. data/lib/cli/kit/args/tokenizer.rb +15 -18
  25. data/lib/cli/kit/base_command.rb +4 -8
  26. data/lib/cli/kit/command_help.rb +25 -28
  27. data/lib/cli/kit/command_registry.rb +40 -36
  28. data/lib/cli/kit/config.rb +14 -15
  29. data/lib/cli/kit/core_ext.rb +4 -6
  30. data/lib/cli/kit/error_handler.rb +19 -35
  31. data/lib/cli/kit/executor.rb +7 -16
  32. data/lib/cli/kit/ini.rb +8 -12
  33. data/lib/cli/kit/levenshtein.rb +7 -5
  34. data/lib/cli/kit/logger.rb +8 -10
  35. data/lib/cli/kit/opts.rb +34 -87
  36. data/lib/cli/kit/parse_args.rb +6 -6
  37. data/lib/cli/kit/resolver.rb +4 -6
  38. data/lib/cli/kit/support/test_helper.rb +10 -5
  39. data/lib/cli/kit/system.rb +25 -114
  40. data/lib/cli/kit/util.rb +15 -31
  41. data/lib/cli/kit/version.rb +1 -1
  42. data/lib/cli/kit.rb +17 -35
  43. metadata +5 -9
  44. data/lib/cli/kit/sorbet_runtime_stub.rb +0 -154
@@ -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
@@ -6,11 +6,9 @@ require 'fileutils'
6
6
  module CLI
7
7
  module Kit
8
8
  class Config
9
- extend T::Sig
10
-
11
9
  XDG_CONFIG_HOME = 'XDG_CONFIG_HOME'
12
10
 
13
- sig { params(tool_name: String).void }
11
+ #: (tool_name: String) -> void
14
12
  def initialize(tool_name:)
15
13
  @tool_name = tool_name
16
14
  end
@@ -28,13 +26,13 @@ module CLI
28
26
  # #### Example Usage
29
27
  # `config.get('name.of.config')`
30
28
  #
31
- sig { params(section: String, name: String, default: T.nilable(String)).returns(T.nilable(String)) }
29
+ #: (String section, String name, ?default: String?) -> String?
32
30
  def get(section, name, default: nil)
33
31
  all_configs.dig("[#{section}]", name) || default
34
32
  end
35
33
 
36
34
  # Coalesce and enforce the value of a config to a boolean
37
- sig { params(section: String, name: String, default: T.nilable(T::Boolean)).returns(T.nilable(T::Boolean)) }
35
+ #: (String section, String name, ?default: bool?) -> bool?
38
36
  def get_bool(section, name, default: false)
39
37
  case get(section, name)
40
38
  when 'true'
@@ -58,14 +56,15 @@ module CLI
58
56
  # #### Example Usage
59
57
  # `config.set('section', 'name.of.config', 'value')`
60
58
  #
61
- sig { params(section: String, name: String, value: T.nilable(T.any(String, T::Boolean))).void }
59
+ #: (String section, String name, (String | bool)? value) -> void
62
60
  def set(section, name, value)
63
61
  all_configs["[#{section}]"] ||= {}
62
+ section = all_configs["[#{section}]"] #: as !nil
64
63
  case value
65
64
  when nil
66
- T.must(all_configs["[#{section}]"]).delete(name)
65
+ section.delete(name)
67
66
  else
68
- T.must(all_configs["[#{section}]"])[name] = value.to_s
67
+ section[name] = value.to_s
69
68
  end
70
69
  write_config
71
70
  end
@@ -79,7 +78,7 @@ module CLI
79
78
  # #### Example Usage
80
79
  # `config.unset('section', 'name.of.config')`
81
80
  #
82
- sig { params(section: String, name: String).void }
81
+ #: (String section, String name) -> void
83
82
  def unset(section, name)
84
83
  set(section, name, nil)
85
84
  end
@@ -92,12 +91,12 @@ module CLI
92
91
  # #### Example Usage
93
92
  # `config.get_section('section')`
94
93
  #
95
- sig { params(section: String).returns(T::Hash[String, String]) }
94
+ #: (String section) -> Hash[String, String]
96
95
  def get_section(section)
97
96
  (all_configs["[#{section}]"] || {}).dup
98
97
  end
99
98
 
100
- sig { returns(String) }
99
+ #: -> String
101
100
  def to_s
102
101
  ini.to_s
103
102
  end
@@ -107,7 +106,7 @@ module CLI
107
106
  # if ENV['XDG_CONFIG_HOME'] is not set, we default to ~/.config, e.g.:
108
107
  # ~/.config/tool/config
109
108
  #
110
- sig { returns(String) }
109
+ #: -> String
111
110
  def file
112
111
  config_home = ENV.fetch(XDG_CONFIG_HOME, '~/.config')
113
112
  File.expand_path(File.join(@tool_name, 'config'), config_home)
@@ -115,17 +114,17 @@ module CLI
115
114
 
116
115
  private
117
116
 
118
- sig { returns(T::Hash[String, T::Hash[String, String]]) }
117
+ #: -> Hash[String, Hash[String, String]]
119
118
  def all_configs
120
119
  ini.ini
121
120
  end
122
121
 
123
- sig { returns(CLI::Kit::Ini) }
122
+ #: -> CLI::Kit::Ini
124
123
  def ini
125
124
  @ini ||= CLI::Kit::Ini.new(file).tap(&:parse)
126
125
  end
127
126
 
128
- sig { void }
127
+ #: -> void
129
128
  def write_config
130
129
  all_configs.each do |section, sub_config|
131
130
  all_configs.delete(section) if sub_config.empty?
@@ -2,28 +2,26 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  class Exception
5
- extend(T::Sig)
6
-
7
5
  # You'd think instance variables @bug and @silent would work here. They
8
6
  # don't. I'm not sure why. If you, the reader, want to take some time to
9
7
  # figure it out, go ahead and refactor to that.
10
8
 
11
- sig { returns(T::Boolean) }
9
+ #: -> bool
12
10
  def bug?
13
11
  true
14
12
  end
15
13
 
16
- sig { returns(T::Boolean) }
14
+ #: -> bool
17
15
  def silent?
18
16
  false
19
17
  end
20
18
 
21
- sig { params(bug: T::Boolean).void }
19
+ #: (?bool bug) -> void
22
20
  def bug!(bug = true)
23
21
  singleton_class.define_method(:bug?) { bug }
24
22
  end
25
23
 
26
- sig { params(silent: T::Boolean).void }
24
+ #: (?bool silent) -> void
27
25
  def silent!(silent = true)
28
26
  singleton_class.define_method(:silent?) { silent }
29
27
  end
@@ -6,23 +6,12 @@ require 'English'
6
6
  module CLI
7
7
  module Kit
8
8
  class ErrorHandler
9
- extend T::Sig
9
+ #: type exception_reporter_or_proc = singleton(ExceptionReporter) | ^() -> singleton(ExceptionReporter)
10
10
 
11
- ExceptionReporterOrProc = T.type_alias do
12
- T.any(T.class_of(ExceptionReporter), T.proc.returns(T.class_of(ExceptionReporter)))
13
- end
14
-
15
- sig { params(override_exception_handler: T.proc.params(arg0: Exception).returns(Integer)).void }
11
+ #: ^(Exception arg0) -> Integer
16
12
  attr_writer :override_exception_handler
17
13
 
18
- sig do
19
- params(
20
- log_file: T.nilable(String),
21
- exception_reporter: ExceptionReporterOrProc,
22
- tool_name: T.nilable(String),
23
- dev_mode: T::Boolean,
24
- ).void
25
- end
14
+ #: (?log_file: String?, ?exception_reporter: exception_reporter_or_proc, ?tool_name: String?, ?dev_mode: bool) -> void
26
15
  def initialize(log_file: nil, exception_reporter: NullExceptionReporter, tool_name: nil, dev_mode: false)
27
16
  @log_file = log_file
28
17
  @exception_reporter_or_proc = exception_reporter
@@ -30,33 +19,28 @@ module CLI
30
19
  @dev_mode = dev_mode
31
20
  end
32
21
 
22
+ # @abstract
33
23
  class ExceptionReporter
34
- extend T::Sig
35
- extend T::Helpers
36
- abstract!
37
-
38
24
  class << self
39
- extend T::Sig
40
-
41
- sig { abstract.params(exception: T.nilable(Exception), logs: T.nilable(String)).void }
42
- def report(exception, logs = nil); end
25
+ # @abstract
26
+ #: (Exception?, ?String?) -> void
27
+ def report(exception, logs = nil)
28
+ raise(NotImplementedError)
29
+ end
43
30
  end
44
31
  end
45
32
 
46
33
  class NullExceptionReporter < ExceptionReporter
47
- extend T::Sig
48
-
49
34
  class << self
50
- extend T::Sig
51
-
52
- sig { override.params(_exception: T.nilable(Exception), _logs: T.nilable(String)).void }
35
+ # @override
36
+ #: (Exception? _exception, ?String? _logs) -> void
53
37
  def report(_exception, _logs = nil)
54
38
  nil
55
39
  end
56
40
  end
57
41
  end
58
42
 
59
- sig { params(block: T.proc.void).returns(Integer) }
43
+ #: { -> void } -> Integer
60
44
  def call(&block)
61
45
  # @at_exit_exception is set if handle_abort decides to submit an error.
62
46
  # $ERROR_INFO is set if we terminate because of a signal.
@@ -64,7 +48,7 @@ module CLI
64
48
  triage_all_exceptions(&block)
65
49
  end
66
50
 
67
- sig { params(error: T.nilable(Exception)).void }
51
+ #: (Exception? error) -> void
68
52
  def report_exception(error)
69
53
  if (notify_with = exception_for_submission(error))
70
54
  logs = nil
@@ -92,7 +76,7 @@ module CLI
92
76
  # they're #bug?
93
77
  #
94
78
  # Returns an exit status for the program.
95
- sig { params(block: T.proc.void).returns(Integer) }
79
+ #: { -> void } -> Integer
96
80
  def triage_all_exceptions(&block)
97
81
  begin
98
82
  block.call
@@ -130,12 +114,12 @@ module CLI
130
114
  e.bug? ? CLI::Kit::EXIT_BUG : CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG
131
115
  end
132
116
 
133
- sig { params(error: T.nilable(Exception)).returns(T.nilable(Exception)) }
117
+ #: (Exception? error) -> Exception?
134
118
  def exception_for_submission(error)
135
119
  # happens on normal non-error termination
136
- return(nil) if error.nil?
120
+ return if error.nil?
137
121
 
138
- return(nil) unless error.bug?
122
+ return unless error.bug?
139
123
 
140
124
  case error
141
125
  when SignalException
@@ -161,14 +145,14 @@ module CLI
161
145
  end
162
146
  end
163
147
 
164
- sig { params(message: String).void }
148
+ #: (String message) -> void
165
149
  def stderr_puts(message)
166
150
  $stderr.puts(CLI::UI.fmt("{{red:#{message}}}"))
167
151
  rescue Errno::EPIPE, Errno::EIO
168
152
  nil
169
153
  end
170
154
 
171
- sig { returns(T.class_of(ExceptionReporter)) }
155
+ #: -> singleton(ExceptionReporter)
172
156
  def exception_reporter
173
157
  case @exception_reporter_or_proc
174
158
  when Proc
@@ -7,15 +7,13 @@ require 'fileutils'
7
7
  module CLI
8
8
  module Kit
9
9
  class Executor
10
- extend T::Sig
11
-
12
- sig { params(log_file: String).void }
10
+ #: (log_file: String) -> void
13
11
  def initialize(log_file:)
14
12
  FileUtils.mkpath(File.dirname(log_file))
15
13
  @log_file = log_file
16
14
  end
17
15
 
18
- sig { params(command: T.class_of(CLI::Kit::BaseCommand), command_name: String, args: T::Array[String]).void }
16
+ #: (singleton(CLI::Kit::BaseCommand) command, String command_name, Array[String] args) -> void
19
17
  def call(command, command_name, args)
20
18
  with_traps do
21
19
  with_logging do |id|
@@ -36,10 +34,7 @@ module CLI
36
34
 
37
35
  private
38
36
 
39
- sig do
40
- type_parameters(:T).params(block: T.proc.params(id: String).returns(T.type_parameter(:T)))
41
- .returns(T.type_parameter(:T))
42
- end
37
+ #: [T] { (String id) -> T } -> T
43
38
  def with_logging(&block)
44
39
  CLI::UI.log_output_to(@log_file) do
45
40
  CLI::UI::StdoutRouter.with_id(on_streams: [CLI::UI::StdoutRouter.duplicate_output_to].compact) do |id|
@@ -48,18 +43,14 @@ module CLI
48
43
  end
49
44
  end
50
45
 
51
- sig { type_parameters(:T).params(block: T.proc.returns(T.type_parameter(:T))).returns(T.type_parameter(:T)) }
46
+ #: [T] { -> T } -> T
52
47
  def with_traps(&block)
53
48
  twrap('QUIT', method(:quit_handler)) do
54
49
  twrap('INFO', method(:info_handler), &block)
55
50
  end
56
51
  end
57
52
 
58
- sig do
59
- type_parameters(:T)
60
- .params(signal: String, handler: Method, block: T.proc.returns(T.type_parameter(:T)))
61
- .returns(T.type_parameter(:T))
62
- end
53
+ #: [T] (String signal, Method handler) { -> T } -> T
63
54
  def twrap(signal, handler, &block)
64
55
  return yield unless Signal.list.key?(signal)
65
56
 
@@ -78,7 +69,7 @@ module CLI
78
69
  end
79
70
  end
80
71
 
81
- sig { params(_sig: T.untyped).void }
72
+ #: (untyped _sig) -> void
82
73
  def quit_handler(_sig)
83
74
  z = caller
84
75
  CLI::UI.raw do
@@ -88,7 +79,7 @@ module CLI
88
79
  exit(CLI::Kit::EXIT_FAILURE_BUT_NOT_BUG)
89
80
  end
90
81
 
91
- sig { params(_sig: T.untyped).void }
82
+ #: (untyped _sig) -> void
92
83
  def info_handler(_sig)
93
84
  z = caller
94
85
  CLI::UI.raw do
data/lib/cli/kit/ini.rb CHANGED
@@ -17,14 +17,10 @@ module CLI
17
17
  # See the ini_test.rb file for more examples
18
18
  #
19
19
  class Ini
20
- extend T::Sig
21
-
22
- sig { returns(T::Hash[String, T::Hash[String, String]]) }
20
+ #: Hash[String, Hash[String, String]]
23
21
  attr_accessor :ini
24
22
 
25
- sig do
26
- params(path: T.nilable(String), config: T.nilable(String), default_section: String).void
27
- end
23
+ #: (?String? path, ?config: String?, ?default_section: String) -> void
28
24
  def initialize(path = nil, config: nil, default_section: '[global]')
29
25
  @config = if path && File.exist?(path)
30
26
  File.readlines(path)
@@ -35,7 +31,7 @@ module CLI
35
31
  @current_key = default_section
36
32
  end
37
33
 
38
- sig { returns(T::Hash[String, T::Hash[String, String]]) }
34
+ #: -> Hash[String, Hash[String, String]]
39
35
  def parse
40
36
  return @ini if @config.nil?
41
37
 
@@ -53,19 +49,19 @@ module CLI
53
49
  @ini
54
50
  end
55
51
 
56
- sig { returns(String) }
52
+ #: -> String
57
53
  def git_format
58
54
  to_ini(git_format: true)
59
55
  end
60
56
 
61
- sig { returns(String) }
57
+ #: -> String
62
58
  def to_s
63
59
  to_ini
64
60
  end
65
61
 
66
62
  private
67
63
 
68
- sig { params(git_format: T::Boolean).returns(String) }
64
+ #: (?git_format: bool) -> String
69
65
  def to_ini(git_format: false)
70
66
  optional_tab = git_format ? "\t" : ''
71
67
  str = []
@@ -79,14 +75,14 @@ module CLI
79
75
  str.join("\n")
80
76
  end
81
77
 
82
- sig { params(key: String, val: String).void }
78
+ #: (String key, String val) -> void
83
79
  def set_val(key, val)
84
80
  current_key = @current_key
85
81
  @ini[current_key] ||= {}
86
82
  @ini[current_key][key] = val
87
83
  end
88
84
 
89
- sig { params(k: String).returns(T::Boolean) }
85
+ #: (String k) -> bool
90
86
  def section_designator?(k)
91
87
  k.start_with?('[') && k.end_with?(']')
92
88
  end
@@ -28,13 +28,13 @@ require 'cli/kit'
28
28
  module CLI
29
29
  module Kit
30
30
  module Levenshtein
31
- extend T::Sig
31
+
32
32
 
33
33
  # This code is based directly on the Text gem implementation
34
34
  # Copyright (c) 2006-2013 Paul Battley, Michael Neumann, Tim Fletcher.
35
35
  #
36
36
  # Returns a value representing the "cost" of transforming str1 into str2
37
- sig { params(str1: String, str2: String).returns(Integer) }
37
+ #: (String str1, String str2) -> Integer
38
38
  def distance(str1, str2)
39
39
  n = str1.length
40
40
  m = str2.length
@@ -51,10 +51,12 @@ module CLI
51
51
  j = 0
52
52
  while j < m
53
53
  cost = char1 == str2_codepoints[j] ? 0 : 1
54
+ a = d[j] #: as !nil
55
+ b = d[j + 1] #: as !nil
54
56
  x = min3(
55
- T.must(d[j + 1]) + 1, # insertion
57
+ b + 1,
56
58
  i + 1, # deletion
57
- T.must(d[j]) + cost, # substitution
59
+ a + cost, # substitution
58
60
  )
59
61
  d[j] = i
60
62
  i = x
@@ -74,7 +76,7 @@ module CLI
74
76
  # faster than `[a, b, c].min` and puts less GC pressure.
75
77
  # See https://github.com/yuki24/did_you_mean/pull/1 for a performance
76
78
  # benchmark.
77
- sig { params(a: Integer, b: Integer, c: Integer).returns(Integer) }
79
+ #: (Integer a, Integer b, Integer c) -> Integer
78
80
  def min3(a, b, c)
79
81
  if a < b && a < c
80
82
  a
@@ -7,15 +7,13 @@ require 'fileutils'
7
7
  module CLI
8
8
  module Kit
9
9
  class Logger
10
- extend T::Sig
11
-
12
10
  MAX_LOG_SIZE = 5 * 1024 * 1000 # 5MB
13
11
  MAX_NUM_LOGS = 10
14
12
 
15
13
  # Constructor for CLI::Kit::Logger
16
14
  #
17
15
  # @param debug_log_file [String] path to the file where debug logs should be stored
18
- sig { params(debug_log_file: String, env_debug_name: String).void }
16
+ #: (debug_log_file: String, ?env_debug_name: String) -> void
19
17
  def initialize(debug_log_file:, env_debug_name: 'DEBUG')
20
18
  FileUtils.mkpath(File.dirname(debug_log_file))
21
19
  @debug_logger = ::Logger.new(debug_log_file, MAX_NUM_LOGS, MAX_LOG_SIZE)
@@ -27,7 +25,7 @@ module CLI
27
25
  #
28
26
  # @param msg [String] the message to log
29
27
  # @param debug [Boolean] determines if the debug logger will receive the log (default true)
30
- sig { params(msg: String, debug: T::Boolean).void }
28
+ #: (String msg, ?debug: bool) -> void
31
29
  def info(msg, debug: true)
32
30
  $stdout.puts CLI::UI.fmt(msg)
33
31
  @debug_logger.info(format_debug(msg)) if debug
@@ -38,7 +36,7 @@ module CLI
38
36
  #
39
37
  # @param msg [String] the message to log
40
38
  # @param debug [Boolean] determines if the debug logger will receive the log (default true)
41
- sig { params(msg: String, debug: T::Boolean).void }
39
+ #: (String msg, ?debug: bool) -> void
42
40
  def warn(msg, debug: true)
43
41
  $stdout.puts CLI::UI.fmt("{{yellow:#{msg}}}")
44
42
  @debug_logger.warn(format_debug(msg)) if debug
@@ -49,7 +47,7 @@ module CLI
49
47
  #
50
48
  # @param msg [String] the message to log
51
49
  # @param debug [Boolean] determines if the debug logger will receive the log (default true)
52
- sig { params(msg: String, debug: T::Boolean).void }
50
+ #: (String msg, ?debug: bool) -> void
53
51
  def error(msg, debug: true)
54
52
  $stderr.puts CLI::UI.fmt("{{red:#{msg}}}")
55
53
  @debug_logger.error(format_debug(msg)) if debug
@@ -60,7 +58,7 @@ module CLI
60
58
  #
61
59
  # @param msg [String] the message to log
62
60
  # @param debug [Boolean] determines if the debug logger will receive the log (default true)
63
- sig { params(msg: String, debug: T::Boolean).void }
61
+ #: (String msg, ?debug: bool) -> void
64
62
  def fatal(msg, debug: true)
65
63
  $stderr.puts CLI::UI.fmt("{{red:{{bold:Fatal:}} #{msg}}}")
66
64
  @debug_logger.fatal(format_debug(msg)) if debug
@@ -70,7 +68,7 @@ module CLI
70
68
  # Logs to the debug file, taking into account CLI::UI::StdoutRouter.current_id
71
69
  #
72
70
  # @param msg [String] the message to log
73
- sig { params(msg: String).void }
71
+ #: (String msg) -> void
74
72
  def debug(msg)
75
73
  $stdout.puts CLI::UI.fmt(msg) if debug?
76
74
  @debug_logger.debug(format_debug(msg))
@@ -78,7 +76,7 @@ module CLI
78
76
 
79
77
  private
80
78
 
81
- sig { params(msg: String).returns(String) }
79
+ #: (String msg) -> String
82
80
  def format_debug(msg)
83
81
  msg = CLI::UI.fmt(msg)
84
82
  return msg unless CLI::UI::StdoutRouter.current_id
@@ -86,7 +84,7 @@ module CLI
86
84
  "[#{CLI::UI::StdoutRouter.current_id&.fetch(:id, nil)}] #{msg}"
87
85
  end
88
86
 
89
- sig { returns(T::Boolean) }
87
+ #: -> bool
90
88
  def debug?
91
89
  val = ENV[@env_debug_name]
92
90
  !!val && val != '0' && val != ''