command_kit 0.1.0.pre2 → 0.2.1
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 +15 -0
- data/.rubocop.yml +141 -0
- data/ChangeLog.md +98 -2
- data/Gemfile +3 -0
- data/README.md +189 -117
- data/Rakefile +3 -2
- data/command_kit.gemspec +4 -4
- data/examples/command.rb +1 -1
- data/gemspec.yml +10 -2
- data/lib/command_kit/arguments/argument.rb +2 -0
- data/lib/command_kit/arguments/argument_value.rb +2 -0
- data/lib/command_kit/arguments.rb +23 -4
- data/lib/command_kit/colors.rb +253 -45
- data/lib/command_kit/command.rb +6 -1
- data/lib/command_kit/command_name.rb +9 -0
- data/lib/command_kit/commands/auto_load.rb +24 -1
- data/lib/command_kit/commands/auto_require.rb +16 -0
- data/lib/command_kit/commands/command.rb +3 -0
- data/lib/command_kit/commands/help.rb +5 -2
- data/lib/command_kit/commands/parent_command.rb +7 -0
- data/lib/command_kit/commands/subcommand.rb +13 -1
- data/lib/command_kit/commands.rb +54 -9
- data/lib/command_kit/description.rb +12 -1
- data/lib/command_kit/env/home.rb +9 -0
- data/lib/command_kit/env/path.rb +16 -1
- data/lib/command_kit/env.rb +4 -0
- data/lib/command_kit/examples.rb +12 -1
- data/lib/command_kit/exception_handler.rb +4 -0
- data/lib/command_kit/help/man.rb +26 -30
- data/lib/command_kit/help.rb +7 -1
- data/lib/command_kit/inflector.rb +49 -17
- data/lib/command_kit/interactive.rb +248 -0
- data/lib/command_kit/main.rb +18 -9
- data/lib/command_kit/man.rb +44 -0
- data/lib/command_kit/open_app.rb +69 -0
- data/lib/command_kit/options/option.rb +3 -6
- data/lib/command_kit/options/option_value.rb +5 -2
- data/lib/command_kit/options/parser.rb +46 -19
- data/lib/command_kit/options/quiet.rb +3 -0
- data/lib/command_kit/options/verbose.rb +5 -0
- data/lib/command_kit/options/version.rb +6 -0
- data/lib/command_kit/options.rb +32 -7
- data/lib/command_kit/os/linux.rb +157 -0
- data/lib/command_kit/os.rb +165 -11
- data/lib/command_kit/package_manager.rb +200 -0
- data/lib/command_kit/pager.rb +80 -11
- data/lib/command_kit/printing/indent.rb +27 -4
- data/lib/command_kit/printing.rb +35 -1
- data/lib/command_kit/program_name.rb +7 -0
- data/lib/command_kit/stdio.rb +24 -0
- data/lib/command_kit/sudo.rb +40 -0
- data/lib/command_kit/terminal.rb +159 -0
- data/lib/command_kit/usage.rb +14 -0
- data/lib/command_kit/version.rb +1 -1
- data/lib/command_kit/xdg.rb +13 -0
- data/lib/command_kit.rb +1 -0
- data/spec/arguments/argument_spec.rb +2 -2
- data/spec/arguments_spec.rb +53 -27
- data/spec/colors_spec.rb +277 -13
- data/spec/command_name_spec.rb +1 -1
- data/spec/command_spec.rb +79 -5
- data/spec/commands/auto_load/subcommand_spec.rb +1 -1
- data/spec/commands/auto_load_spec.rb +34 -3
- data/spec/commands/auto_require_spec.rb +2 -2
- data/spec/commands/help_spec.rb +1 -1
- data/spec/commands/parent_command_spec.rb +1 -1
- data/spec/commands/subcommand_spec.rb +1 -1
- data/spec/commands_spec.rb +103 -29
- data/spec/description_spec.rb +1 -25
- data/spec/env/home_spec.rb +1 -1
- data/spec/env/path_spec.rb +7 -1
- data/spec/examples_spec.rb +1 -25
- data/spec/exception_handler_spec.rb +1 -1
- data/spec/help/man_spec.rb +45 -58
- data/spec/help_spec.rb +0 -25
- data/spec/inflector_spec.rb +71 -9
- data/spec/interactive_spec.rb +415 -0
- data/spec/main_spec.rb +7 -7
- data/spec/man_spec.rb +46 -0
- data/spec/open_app_spec.rb +85 -0
- data/spec/options/option_spec.rb +5 -5
- data/spec/options/option_value_spec.rb +56 -1
- data/spec/options_spec.rb +283 -1
- data/spec/os/linux_spec.rb +164 -0
- data/spec/os_spec.rb +201 -14
- data/spec/package_manager_spec.rb +806 -0
- data/spec/pager_spec.rb +76 -11
- data/spec/printing/indent_spec.rb +8 -6
- data/spec/printing_spec.rb +33 -3
- data/spec/program_name_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -3
- data/spec/sudo_spec.rb +51 -0
- data/spec/{console_spec.rb → terminal_spec.rb} +65 -35
- data/spec/usage_spec.rb +2 -2
- data/spec/xdg_spec.rb +1 -1
- metadata +26 -8
- data/lib/command_kit/console.rb +0 -141
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'command_kit/stdio'
|
2
|
+
require 'command_kit/env'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'io/console'
|
6
|
+
rescue LoadError
|
7
|
+
end
|
8
|
+
|
9
|
+
module CommandKit
|
10
|
+
#
|
11
|
+
# Provides direct access to the terminal.
|
12
|
+
#
|
13
|
+
# ## Environment Variables
|
14
|
+
#
|
15
|
+
# * `LINES` - The explicit number of lines or rows the console should have.
|
16
|
+
# * `COLUMNS` - The explicit number of columns the console should have.
|
17
|
+
#
|
18
|
+
# @see https://rubydoc.info/gems/io-console/IO
|
19
|
+
#
|
20
|
+
module Terminal
|
21
|
+
include Stdio
|
22
|
+
include Env
|
23
|
+
|
24
|
+
# The default terminal height to fallback to.
|
25
|
+
DEFAULT_TERMINAL_HEIGHT = 25
|
26
|
+
|
27
|
+
# The default terminal width to fallback to.
|
28
|
+
DEFAULT_TERMINAL_WIDTH = 80
|
29
|
+
|
30
|
+
#
|
31
|
+
# Initializes any terminal settings.
|
32
|
+
#
|
33
|
+
# @param [Hash{Symbol => Object}] kwargs
|
34
|
+
# Additional keyword arguments.
|
35
|
+
#
|
36
|
+
# @note
|
37
|
+
# If the `$LINES` env variable is set, and is non-zero, it will be
|
38
|
+
# returned by {#terminal_height}.
|
39
|
+
#
|
40
|
+
# @note
|
41
|
+
# If the `$COLUMNS` env variable is set, and is non-zero, it will be
|
42
|
+
# returned by {#terminal_width}.
|
43
|
+
#
|
44
|
+
# @api public
|
45
|
+
#
|
46
|
+
def initialize(**kwargs)
|
47
|
+
super(**kwargs)
|
48
|
+
|
49
|
+
@terminal_height = if (lines = env['LINES'])
|
50
|
+
lines.to_i
|
51
|
+
else
|
52
|
+
DEFAULT_TERMINAL_HEIGHT
|
53
|
+
end
|
54
|
+
|
55
|
+
@terminal_width = if (columns = env['COLUMNS'])
|
56
|
+
columns.to_i
|
57
|
+
else
|
58
|
+
DEFAULT_TERMINAL_WIDTH
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Determines if program is running in a terminal.
|
64
|
+
#
|
65
|
+
# @return [Boolean]
|
66
|
+
# Specifies whether {Stdio#stdout stdout} is connected to a terminal.
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
#
|
70
|
+
def terminal?
|
71
|
+
IO.respond_to?(:console) && stdout.tty?
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# @since 0.2.0
|
76
|
+
#
|
77
|
+
alias tty? terminal?
|
78
|
+
|
79
|
+
#
|
80
|
+
# Returns the terminal object, if {Stdio#stdout stdout} is connected to a
|
81
|
+
# terminal.
|
82
|
+
#
|
83
|
+
# @return [IO, nil]
|
84
|
+
# The IO objects or `nil` if {Stdio#stdout stdout} is not connected to a
|
85
|
+
# terminal.
|
86
|
+
#
|
87
|
+
# @example
|
88
|
+
# terminal
|
89
|
+
# # => #<File:/dev/tty>
|
90
|
+
#
|
91
|
+
# @see https://rubydoc.info/gems/io-console/IO
|
92
|
+
#
|
93
|
+
# @api semipublic
|
94
|
+
#
|
95
|
+
def terminal
|
96
|
+
IO.console if terminal?
|
97
|
+
end
|
98
|
+
|
99
|
+
#
|
100
|
+
# Returns the terminal's height in number of lines.
|
101
|
+
#
|
102
|
+
# @return [Integer]
|
103
|
+
# The terminal's height in number of lines.
|
104
|
+
#
|
105
|
+
# @example
|
106
|
+
# terminal_height
|
107
|
+
# # => 22
|
108
|
+
#
|
109
|
+
# @api public
|
110
|
+
#
|
111
|
+
def terminal_height
|
112
|
+
if (terminal = self.terminal)
|
113
|
+
terminal.winsize[0]
|
114
|
+
else
|
115
|
+
@terminal_height
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# Returns the terminal's width in number of lines.
|
121
|
+
#
|
122
|
+
# @return [Integer]
|
123
|
+
# The terminal's width in number of columns.
|
124
|
+
#
|
125
|
+
# @example
|
126
|
+
# terminal_width
|
127
|
+
# # => 91
|
128
|
+
#
|
129
|
+
# @api public
|
130
|
+
#
|
131
|
+
def terminal_width
|
132
|
+
if (terminal = self.terminal)
|
133
|
+
terminal.winsize[1]
|
134
|
+
else
|
135
|
+
@terminal_width
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# The terminal height (lines) and width (columns).
|
141
|
+
#
|
142
|
+
# @return [(Integer, Integer)]
|
143
|
+
# Returns the height and width of the terminal.
|
144
|
+
#
|
145
|
+
# @example
|
146
|
+
# terminal_size
|
147
|
+
# # => [23, 91]
|
148
|
+
#
|
149
|
+
# @api public
|
150
|
+
#
|
151
|
+
def terminal_size
|
152
|
+
if (terminal = self.terminal)
|
153
|
+
terminal.winsize
|
154
|
+
else
|
155
|
+
[@terminal_height, @terminal_width]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/lib/command_kit/usage.rb
CHANGED
@@ -15,6 +15,9 @@ module CommandKit
|
|
15
15
|
include CommandName
|
16
16
|
include Help
|
17
17
|
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
18
21
|
module ModuleMethods
|
19
22
|
#
|
20
23
|
# Extends {ClassMethods} or {ModuleMethods}, depending on whether {Usage}
|
@@ -50,6 +53,11 @@ module CommandKit
|
|
50
53
|
# @return [String, Array<String>]
|
51
54
|
# The class'es or superclass'es usage string(s).
|
52
55
|
#
|
56
|
+
# @example
|
57
|
+
# usage "[options] ARG1 ARG2 [ARG3 ...]"
|
58
|
+
#
|
59
|
+
# @api public
|
60
|
+
#
|
53
61
|
def usage(new_usage=nil)
|
54
62
|
if new_usage
|
55
63
|
@usage = new_usage
|
@@ -65,6 +73,8 @@ module CommandKit
|
|
65
73
|
#
|
66
74
|
# @return [Array<String>, String, nil]
|
67
75
|
#
|
76
|
+
# @api public
|
77
|
+
#
|
68
78
|
def usage
|
69
79
|
case (usage = self.class.usage)
|
70
80
|
when Array
|
@@ -77,6 +87,8 @@ module CommandKit
|
|
77
87
|
#
|
78
88
|
# Prints the `usage: ...` output.
|
79
89
|
#
|
90
|
+
# @api semipublic
|
91
|
+
#
|
80
92
|
def help_usage
|
81
93
|
case (usage = self.usage)
|
82
94
|
when Array
|
@@ -95,6 +107,8 @@ module CommandKit
|
|
95
107
|
#
|
96
108
|
# @see #help_usage
|
97
109
|
#
|
110
|
+
# @api public
|
111
|
+
#
|
98
112
|
def help
|
99
113
|
help_usage
|
100
114
|
end
|
data/lib/command_kit/version.rb
CHANGED
data/lib/command_kit/xdg.rb
CHANGED
@@ -24,6 +24,9 @@ module CommandKit
|
|
24
24
|
include CommandName
|
25
25
|
include Env::Home
|
26
26
|
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
27
30
|
module ModuleMethods
|
28
31
|
#
|
29
32
|
# Extends {ClassMethods} or {ModuleMethods}, depending on whether {XDG} is
|
@@ -61,6 +64,8 @@ module CommandKit
|
|
61
64
|
# {CommandName::ClassMethods#command_name} if no {#xdg_namespace} has
|
62
65
|
# been defined.
|
63
66
|
#
|
67
|
+
# @api public
|
68
|
+
#
|
64
69
|
def xdg_namespace(new_namespace=nil)
|
65
70
|
if new_namespace
|
66
71
|
@xdg_namespace = new_namespace.to_s
|
@@ -77,16 +82,22 @@ module CommandKit
|
|
77
82
|
# The `~/.config/<xdg_namespace>` directory.
|
78
83
|
#
|
79
84
|
# @return [String]
|
85
|
+
#
|
86
|
+
# @api public
|
80
87
|
attr_reader :config_dir
|
81
88
|
|
82
89
|
# The `~/.local/share/<xdg_namespace>` directory.
|
83
90
|
#
|
84
91
|
# @return [String]
|
92
|
+
#
|
93
|
+
# @api public
|
85
94
|
attr_reader :local_share_dir
|
86
95
|
|
87
96
|
# The `~/.cache/<xdg_namespace>` directory.
|
88
97
|
#
|
89
98
|
# @return [String]
|
99
|
+
#
|
100
|
+
# @api public
|
90
101
|
attr_reader :cache_dir
|
91
102
|
|
92
103
|
#
|
@@ -138,6 +149,8 @@ module CommandKit
|
|
138
149
|
#
|
139
150
|
# @see ClassMethods#xdg_namespace
|
140
151
|
#
|
152
|
+
# @api semipublic
|
153
|
+
#
|
141
154
|
def xdg_namespace
|
142
155
|
self.class.xdg_namespace
|
143
156
|
end
|
data/lib/command_kit.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/arguments/argument'
|
3
3
|
|
4
|
-
describe Arguments::Argument do
|
4
|
+
describe CommandKit::Arguments::Argument do
|
5
5
|
let(:name) { :foo }
|
6
6
|
let(:usage) { 'FOO' }
|
7
7
|
let(:required) { true }
|
@@ -126,7 +126,7 @@ describe Arguments::Argument do
|
|
126
126
|
let(:repeats) { false }
|
127
127
|
|
128
128
|
it "must return the usage name unchanged" do
|
129
|
-
expect(subject.usage).to eq(
|
129
|
+
expect(subject.usage).to eq(usage)
|
130
130
|
end
|
131
131
|
end
|
132
132
|
end
|
data/spec/arguments_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'command_kit/arguments'
|
3
3
|
|
4
|
-
describe Arguments do
|
4
|
+
describe CommandKit::Arguments do
|
5
5
|
module TestArguments
|
6
6
|
class ImplicitCmd
|
7
7
|
include CommandKit::Arguments
|
@@ -13,8 +13,8 @@ describe Arguments do
|
|
13
13
|
describe ".included" do
|
14
14
|
subject { command_class }
|
15
15
|
|
16
|
-
it { expect(subject).to include(Main) }
|
17
|
-
it { expect(subject).to include(Help) }
|
16
|
+
it { expect(subject).to include(CommandKit::Main) }
|
17
|
+
it { expect(subject).to include(CommandKit::Help) }
|
18
18
|
end
|
19
19
|
|
20
20
|
describe ".arguments" do
|
@@ -137,6 +137,56 @@ describe Arguments do
|
|
137
137
|
|
138
138
|
subject { command_class.new }
|
139
139
|
|
140
|
+
describe "#main" do
|
141
|
+
module TestArguments
|
142
|
+
class TestCommand
|
143
|
+
|
144
|
+
include CommandKit::Arguments
|
145
|
+
|
146
|
+
argument :argument1, required: true,
|
147
|
+
usage: 'ARG1',
|
148
|
+
desc: "Argument 1"
|
149
|
+
|
150
|
+
argument :argument2, required: false,
|
151
|
+
usage: 'ARG2',
|
152
|
+
desc: "Argument 2"
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
let(:command_class) { TestArguments::TestCommand }
|
158
|
+
|
159
|
+
context "when given the correct number of arguments" do
|
160
|
+
let(:argv) { %w[arg1 arg2] }
|
161
|
+
|
162
|
+
it "must parse options before validating the number of arguments" do
|
163
|
+
expect {
|
164
|
+
expect(subject.main(argv)).to eq(0)
|
165
|
+
}.to_not output.to_stderr
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context "when given fewer than the required number of arguments" do
|
170
|
+
let(:argv) { %w[] }
|
171
|
+
|
172
|
+
it "must print an error message and return 1" do
|
173
|
+
expect {
|
174
|
+
expect(subject.main(argv)).to eq(1)
|
175
|
+
}.to output("#{subject.command_name}: insufficient number of arguments.#{$/}").to_stderr
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context "when given more than the total number of arguments" do
|
180
|
+
let(:argv) { %w[foo bar baz] }
|
181
|
+
|
182
|
+
it "must print an error message and return 1" do
|
183
|
+
expect {
|
184
|
+
expect(subject.main(argv)).to eq(1)
|
185
|
+
}.to output("#{subject.command_name}: too many arguments given.#{$/}").to_stderr
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
140
190
|
describe "#help_arguments" do
|
141
191
|
context "when #arguments returns {}" do
|
142
192
|
module TestArguments
|
@@ -192,29 +242,5 @@ describe Arguments do
|
|
192
242
|
|
193
243
|
subject.help
|
194
244
|
end
|
195
|
-
|
196
|
-
context "when the superclass defines it's own #help method" do
|
197
|
-
module TestDescription
|
198
|
-
class SuperclassHelpMethod
|
199
|
-
def help
|
200
|
-
puts 'superclass'
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
class InheritedHelpMethod < SuperclassHelpMethod
|
205
|
-
include CommandKit::Arguments
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
let(:super_command_class) { TestDescription::SuperclassHelpMethod }
|
210
|
-
let(:command_class) { TestDescription::InheritedHelpMethod }
|
211
|
-
|
212
|
-
it "must call the superclass'es #help method first" do
|
213
|
-
expect_any_instance_of(super_command_class).to receive(:help)
|
214
|
-
expect(subject).to receive(:help_arguments)
|
215
|
-
|
216
|
-
subject.help
|
217
|
-
end
|
218
|
-
end
|
219
245
|
end
|
220
246
|
end
|