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.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +2 -2
- data/.rubocop.sorbet.yml +1 -0
- data/.rubocop.yml +1 -2
- data/.ruby-version +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +47 -46
- data/Rakefile +0 -1
- data/bin/testunit +0 -1
- data/cli-kit.gemspec +1 -1
- data/dev.yml +3 -1
- data/examples/minimal/example.rb +1 -1
- data/examples/single-file/example.rb +4 -3
- data/gen/lib/gen/commands/help.rb +1 -3
- data/gen/lib/gen/commands/new.rb +2 -6
- data/gen/lib/gen/commands.rb +1 -7
- data/gen/lib/gen/entry_point.rb +1 -5
- data/gen/lib/gen/generator.rb +15 -19
- data/gen/lib/gen/help.rb +3 -7
- data/lib/cli/kit/args/definition.rb +37 -95
- data/lib/cli/kit/args/evaluation.rb +41 -60
- data/lib/cli/kit/args/parser/node.rb +19 -23
- data/lib/cli/kit/args/parser.rb +12 -16
- data/lib/cli/kit/args/tokenizer.rb +15 -18
- data/lib/cli/kit/base_command.rb +4 -8
- data/lib/cli/kit/command_help.rb +25 -28
- data/lib/cli/kit/command_registry.rb +40 -36
- data/lib/cli/kit/config.rb +14 -15
- data/lib/cli/kit/core_ext.rb +4 -6
- data/lib/cli/kit/error_handler.rb +19 -35
- data/lib/cli/kit/executor.rb +7 -16
- data/lib/cli/kit/ini.rb +8 -12
- data/lib/cli/kit/levenshtein.rb +7 -5
- data/lib/cli/kit/logger.rb +8 -10
- data/lib/cli/kit/opts.rb +34 -87
- data/lib/cli/kit/parse_args.rb +6 -6
- data/lib/cli/kit/resolver.rb +4 -6
- data/lib/cli/kit/support/test_helper.rb +10 -5
- data/lib/cli/kit/system.rb +25 -114
- data/lib/cli/kit/util.rb +15 -31
- data/lib/cli/kit/version.rb +1 -1
- data/lib/cli/kit.rb +17 -35
- metadata +5 -9
- 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
|
-
|
8
|
+
#: type command_or_proc = singleton(CLI::Kit::BaseCommand) | ^() -> singleton(CLI::Kit::BaseCommand)
|
9
9
|
|
10
|
-
|
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
|
-
|
13
|
+
#: Hash[String, String]
|
18
14
|
attr_reader :aliases
|
19
15
|
|
16
|
+
# @interface
|
20
17
|
module ContextualResolver
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def command_names; end
|
18
|
+
# @abstract
|
19
|
+
#: -> Array[String]
|
20
|
+
def command_names
|
21
|
+
raise(NotImplementedError)
|
22
|
+
end
|
27
23
|
|
28
|
-
|
29
|
-
|
24
|
+
# @abstract
|
25
|
+
#: -> Hash[String, String]
|
26
|
+
def aliases
|
27
|
+
raise(NotImplementedError)
|
28
|
+
end
|
30
29
|
|
31
|
-
|
32
|
-
|
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
|
-
|
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
|
-
|
47
|
+
# @override
|
48
|
+
#: -> Hash[String, String]
|
48
49
|
def aliases
|
49
50
|
{}
|
50
51
|
end
|
51
52
|
|
52
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
84
|
+
resolve_command(
|
85
|
+
name, #: as !nil
|
86
|
+
)
|
83
87
|
end
|
84
88
|
|
85
|
-
|
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
|
-
|
94
|
+
#: -> Array[String]
|
91
95
|
def command_names
|
92
96
|
@contextual_resolver.command_names + commands.keys
|
93
97
|
end
|
94
98
|
|
95
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/cli/kit/config.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
65
|
+
section.delete(name)
|
67
66
|
else
|
68
|
-
|
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
|
-
|
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
|
-
|
94
|
+
#: (String section) -> Hash[String, String]
|
96
95
|
def get_section(section)
|
97
96
|
(all_configs["[#{section}]"] || {}).dup
|
98
97
|
end
|
99
98
|
|
100
|
-
|
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
|
-
|
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
|
-
|
117
|
+
#: -> Hash[String, Hash[String, String]]
|
119
118
|
def all_configs
|
120
119
|
ini.ini
|
121
120
|
end
|
122
121
|
|
123
|
-
|
122
|
+
#: -> CLI::Kit::Ini
|
124
123
|
def ini
|
125
124
|
@ini ||= CLI::Kit::Ini.new(file).tap(&:parse)
|
126
125
|
end
|
127
126
|
|
128
|
-
|
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?
|
data/lib/cli/kit/core_ext.rb
CHANGED
@@ -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
|
-
|
9
|
+
#: -> bool
|
12
10
|
def bug?
|
13
11
|
true
|
14
12
|
end
|
15
13
|
|
16
|
-
|
14
|
+
#: -> bool
|
17
15
|
def silent?
|
18
16
|
false
|
19
17
|
end
|
20
18
|
|
21
|
-
|
19
|
+
#: (?bool bug) -> void
|
22
20
|
def bug!(bug = true)
|
23
21
|
singleton_class.define_method(:bug?) { bug }
|
24
22
|
end
|
25
23
|
|
26
|
-
|
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
|
-
|
9
|
+
#: type exception_reporter_or_proc = singleton(ExceptionReporter) | ^() -> singleton(ExceptionReporter)
|
10
10
|
|
11
|
-
|
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
|
-
|
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
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
117
|
+
#: (Exception? error) -> Exception?
|
134
118
|
def exception_for_submission(error)
|
135
119
|
# happens on normal non-error termination
|
136
|
-
return
|
120
|
+
return if error.nil?
|
137
121
|
|
138
|
-
return
|
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
|
-
|
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
|
-
|
155
|
+
#: -> singleton(ExceptionReporter)
|
172
156
|
def exception_reporter
|
173
157
|
case @exception_reporter_or_proc
|
174
158
|
when Proc
|
data/lib/cli/kit/executor.rb
CHANGED
@@ -7,15 +7,13 @@ require 'fileutils'
|
|
7
7
|
module CLI
|
8
8
|
module Kit
|
9
9
|
class Executor
|
10
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
52
|
+
#: -> String
|
57
53
|
def git_format
|
58
54
|
to_ini(git_format: true)
|
59
55
|
end
|
60
56
|
|
61
|
-
|
57
|
+
#: -> String
|
62
58
|
def to_s
|
63
59
|
to_ini
|
64
60
|
end
|
65
61
|
|
66
62
|
private
|
67
63
|
|
68
|
-
|
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
|
-
|
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
|
-
|
85
|
+
#: (String k) -> bool
|
90
86
|
def section_designator?(k)
|
91
87
|
k.start_with?('[') && k.end_with?(']')
|
92
88
|
end
|
data/lib/cli/kit/levenshtein.rb
CHANGED
@@ -28,13 +28,13 @@ require 'cli/kit'
|
|
28
28
|
module CLI
|
29
29
|
module Kit
|
30
30
|
module Levenshtein
|
31
|
-
|
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
|
-
|
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
|
-
|
57
|
+
b + 1,
|
56
58
|
i + 1, # deletion
|
57
|
-
|
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
|
-
|
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
|
data/lib/cli/kit/logger.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
87
|
+
#: -> bool
|
90
88
|
def debug?
|
91
89
|
val = ENV[@env_debug_name]
|
92
90
|
!!val && val != '0' && val != ''
|