cri 2.7.1 → 2.8.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/Gemfile.lock +21 -34
- data/NEWS.md +8 -0
- data/README.adoc +12 -0
- data/Rakefile +4 -7
- data/lib/cri/command.rb +37 -10
- data/lib/cri/command_dsl.rb +11 -0
- data/lib/cri/commands/basic_root.rb +1 -1
- data/lib/cri/option_parser.rb +2 -2
- data/lib/cri/version.rb +1 -1
- data/test/test_argument_array.rb +2 -0
- data/test/test_base.rb +2 -0
- data/test/test_basic_help.rb +2 -0
- data/test/test_basic_root.rb +14 -1
- data/test/test_command.rb +78 -5
- data/test/test_command_dsl.rb +2 -0
- data/test/test_command_runner.rb +2 -0
- data/test/test_option_parser.rb +2 -0
- data/test/test_string_formatter.rb +2 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef8c0cab47165e8e00e78ffa23c72a9569656a64
|
4
|
+
data.tar.gz: 59473eac71bfa27211fe462321d5fd64e997c694
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8e7c91fbb4550ec9744f18cf21ff9e2ee02dd324f3a85bc3e660442545ce766bda90d8fc003985f19ec845a26c7c7040c9cef9e69dbe5af461992f42540cbcb
|
7
|
+
data.tar.gz: 4008d8b904781cd7f1b8da699fa26b1f66842387517e43676db912d9d7551e232bb2fa3337600fe028c4f6a764cdacd3ef2f4cd5736e9212601f6b1d1e434b66
|
data/Gemfile.lock
CHANGED
@@ -7,54 +7,41 @@ PATH
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
asciidoctor (1.5.
|
10
|
+
asciidoctor (1.5.5)
|
11
11
|
ast (2.3.0)
|
12
12
|
colored (1.2)
|
13
|
-
coveralls (0.8.
|
14
|
-
json (
|
15
|
-
|
16
|
-
simplecov (~> 0.10.0)
|
13
|
+
coveralls (0.8.20)
|
14
|
+
json (>= 1.8, < 3)
|
15
|
+
simplecov (~> 0.14.1)
|
17
16
|
term-ansicolor (~> 1.3)
|
18
|
-
thor (~> 0.19.
|
17
|
+
thor (~> 0.19.4)
|
18
|
+
tins (~> 1.6)
|
19
19
|
docile (1.1.5)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
domain_name (~> 0.5)
|
24
|
-
json (1.8.2)
|
25
|
-
mime-types (2.5)
|
26
|
-
minitest (5.6.1)
|
27
|
-
netrc (0.10.3)
|
28
|
-
parser (2.3.3.1)
|
20
|
+
json (2.0.3)
|
21
|
+
minitest (5.10.1)
|
22
|
+
parser (2.4.0.0)
|
29
23
|
ast (~> 2.2)
|
30
24
|
powerpack (0.1.1)
|
31
|
-
rainbow (2.1
|
32
|
-
rake (
|
33
|
-
|
34
|
-
|
35
|
-
mime-types (>= 1.16, < 3.0)
|
36
|
-
netrc (~> 0.7)
|
37
|
-
rubocop (0.46.0)
|
38
|
-
parser (>= 2.3.1.1, < 3.0)
|
25
|
+
rainbow (2.2.1)
|
26
|
+
rake (12.0.0)
|
27
|
+
rubocop (0.48.0)
|
28
|
+
parser (>= 2.3.3.1, < 3.0)
|
39
29
|
powerpack (~> 0.1)
|
40
30
|
rainbow (>= 1.99.1, < 3.0)
|
41
31
|
ruby-progressbar (~> 1.7)
|
42
32
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
43
33
|
ruby-progressbar (1.8.1)
|
44
|
-
simplecov (0.
|
34
|
+
simplecov (0.14.1)
|
45
35
|
docile (~> 1.1.0)
|
46
|
-
json (
|
36
|
+
json (>= 1.8, < 3)
|
47
37
|
simplecov-html (~> 0.10.0)
|
48
38
|
simplecov-html (0.10.0)
|
49
|
-
term-ansicolor (1.
|
39
|
+
term-ansicolor (1.5.0)
|
50
40
|
tins (~> 1.0)
|
51
|
-
thor (0.19.
|
52
|
-
tins (1.
|
53
|
-
|
54
|
-
|
55
|
-
unf_ext (0.0.7.1)
|
56
|
-
unicode-display_width (1.1.1)
|
57
|
-
yard (0.8.7.6)
|
41
|
+
thor (0.19.4)
|
42
|
+
tins (1.13.2)
|
43
|
+
unicode-display_width (1.1.3)
|
44
|
+
yard (0.9.8)
|
58
45
|
|
59
46
|
PLATFORMS
|
60
47
|
ruby
|
@@ -70,4 +57,4 @@ DEPENDENCIES
|
|
70
57
|
yard
|
71
58
|
|
72
59
|
BUNDLED WITH
|
73
|
-
1.
|
60
|
+
1.14.6
|
data/NEWS.md
CHANGED
data/README.adoc
CHANGED
@@ -9,6 +9,10 @@ link:http://inch-ci.org/github/ddfreyne/cri/[image:http://inch-ci.org/github/ddf
|
|
9
9
|
Cri is a library for building easy-to-use command-line tools with support for
|
10
10
|
nested commands.
|
11
11
|
|
12
|
+
== Requirements ==
|
13
|
+
|
14
|
+
Cri requires Ruby 2.1 or newer.
|
15
|
+
|
12
16
|
== Usage ==
|
13
17
|
|
14
18
|
The central concept in Cri is the _command_, which has option definitions as
|
@@ -189,6 +193,14 @@ root_cmd.add_command(cmd_commit)
|
|
189
193
|
root.cmd.add_command(cmd_init)
|
190
194
|
--------------------------------------------------------------------------------
|
191
195
|
|
196
|
+
You can specify a default subcommand. This subcommand will be executed when the
|
197
|
+
command has subcommands, and no subcommands are otherwise explicitly specified:
|
198
|
+
|
199
|
+
[source,ruby]
|
200
|
+
--------------------------------------------------------------------------------
|
201
|
+
default_subcommand 'compile'
|
202
|
+
--------------------------------------------------------------------------------
|
203
|
+
|
192
204
|
== Contributors ==
|
193
205
|
|
194
206
|
* Toon Willems
|
data/Rakefile
CHANGED
@@ -14,18 +14,15 @@ YARD::Rake::YardocTask.new(:doc) do |yard|
|
|
14
14
|
]
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
FileList['./test/**/test_*.rb', './test/**/*_spec.rb'].each do |fn|
|
21
|
-
require fn
|
22
|
-
end
|
17
|
+
Rake::TestTask.new(:test_unit) do |t|
|
18
|
+
t.test_files = Dir['test/**/*_spec.rb'] + Dir['test/**/test_*.rb']
|
19
|
+
t.libs << 'test'
|
23
20
|
end
|
24
21
|
|
25
22
|
RuboCop::RakeTask.new(:test_style) do |task|
|
26
23
|
task.options = %w(--display-cop-names --format simple)
|
27
24
|
end
|
28
25
|
|
29
|
-
task test:
|
26
|
+
task test: %i(test_unit test_style)
|
30
27
|
|
31
28
|
task default: :test
|
data/lib/cri/command.rb
CHANGED
@@ -38,6 +38,20 @@ module Cri
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
# Signals that Cri should abort execution. Unless otherwise specified using the `hard_exit`
|
42
|
+
# param, this exception will cause Cri to exit the running process.
|
43
|
+
#
|
44
|
+
# @api private
|
45
|
+
class CriExitException < StandardError
|
46
|
+
def initialize(is_error:)
|
47
|
+
@is_error = is_error
|
48
|
+
end
|
49
|
+
|
50
|
+
def error?
|
51
|
+
@is_error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
41
55
|
# @return [Cri::Command, nil] This command’s supercommand, or nil if the
|
42
56
|
# command has no supercommand
|
43
57
|
attr_accessor :supercommand
|
@@ -46,6 +60,9 @@ module Cri
|
|
46
60
|
attr_accessor :commands
|
47
61
|
alias subcommands commands
|
48
62
|
|
63
|
+
# @return [Symbol] The name of the default subcommand
|
64
|
+
attr_accessor :default_subcommand_name
|
65
|
+
|
49
66
|
# @return [String] The name
|
50
67
|
attr_accessor :name
|
51
68
|
|
@@ -123,6 +140,7 @@ module Cri
|
|
123
140
|
@aliases = Set.new
|
124
141
|
@commands = Set.new
|
125
142
|
@option_definitions = Set.new
|
143
|
+
@default_subcommand_name = nil
|
126
144
|
end
|
127
145
|
|
128
146
|
# Modifies the command using the DSL.
|
@@ -211,19 +229,21 @@ module Cri
|
|
211
229
|
# @param [String] name The full, partial or aliases name of the command
|
212
230
|
#
|
213
231
|
# @return [Cri::Command] The command with the given name
|
214
|
-
def command_named(name)
|
232
|
+
def command_named(name, hard_exit: true)
|
215
233
|
commands = commands_named(name)
|
216
234
|
|
217
235
|
if commands.empty?
|
218
236
|
$stderr.puts "#{self.name}: unknown command '#{name}'\n"
|
219
|
-
|
237
|
+
raise CriExitException.new(is_error: true)
|
220
238
|
elsif commands.size > 1
|
221
239
|
$stderr.puts "#{self.name}: '#{name}' is ambiguous:"
|
222
240
|
$stderr.puts " #{commands.map(&:name).sort.join(' ')}"
|
223
|
-
|
241
|
+
raise CriExitException.new(is_error: true)
|
224
242
|
else
|
225
243
|
commands[0]
|
226
244
|
end
|
245
|
+
rescue CriExitException => e
|
246
|
+
exit(e.error? ? 1 : 0) if hard_exit
|
227
247
|
end
|
228
248
|
|
229
249
|
# Runs the command with the given command-line arguments, possibly invoking
|
@@ -235,7 +255,7 @@ module Cri
|
|
235
255
|
# supercommand
|
236
256
|
#
|
237
257
|
# @return [void]
|
238
|
-
def run(opts_and_args, parent_opts = {})
|
258
|
+
def run(opts_and_args, parent_opts = {}, hard_exit: true)
|
239
259
|
# Parse up to command name
|
240
260
|
stuff = partition(opts_and_args)
|
241
261
|
opts_before_subcmd, subcmd_name, opts_and_args_after_subcmd = *stuff
|
@@ -248,14 +268,21 @@ module Cri
|
|
248
268
|
|
249
269
|
# Get command
|
250
270
|
if subcmd_name.nil?
|
251
|
-
|
252
|
-
|
271
|
+
if default_subcommand_name
|
272
|
+
subcmd_name = default_subcommand_name
|
273
|
+
else
|
274
|
+
$stderr.puts "#{name}: no command given"
|
275
|
+
raise CriExitException.new(is_error: true)
|
276
|
+
end
|
253
277
|
end
|
254
|
-
subcommand = command_named(subcmd_name)
|
278
|
+
subcommand = command_named(subcmd_name, hard_exit: hard_exit)
|
279
|
+
return if subcommand.nil?
|
255
280
|
|
256
281
|
# Run
|
257
|
-
subcommand.run(opts_and_args_after_subcmd, opts_before_subcmd)
|
282
|
+
subcommand.run(opts_and_args_after_subcmd, opts_before_subcmd, hard_exit: hard_exit)
|
258
283
|
end
|
284
|
+
rescue CriExitException => e
|
285
|
+
exit(e.error? ? 1 : 0) if hard_exit
|
259
286
|
end
|
260
287
|
|
261
288
|
# Runs the actual command with the given command-line arguments, not
|
@@ -343,10 +370,10 @@ module Cri
|
|
343
370
|
yield
|
344
371
|
rescue Cri::OptionParser::IllegalOptionError => e
|
345
372
|
$stderr.puts "#{name}: illegal option -- #{e}"
|
346
|
-
|
373
|
+
raise CriExitException.new(is_error: true)
|
347
374
|
rescue Cri::OptionParser::OptionRequiresAnArgumentError => e
|
348
375
|
$stderr.puts "#{name}: option requires an argument -- #{e}"
|
349
|
-
|
376
|
+
raise CriExitException.new(is_error: true)
|
350
377
|
end
|
351
378
|
end
|
352
379
|
end
|
data/lib/cri/command_dsl.rb
CHANGED
@@ -31,6 +31,17 @@ module Cri
|
|
31
31
|
@command.add_command(command)
|
32
32
|
end
|
33
33
|
|
34
|
+
# Sets the name of the default subcommand, i.e. the subcommand that will
|
35
|
+
# be executed if no subcommand is explicitly specified. This is `nil` by
|
36
|
+
# default, and will typically only be set for the root command.
|
37
|
+
#
|
38
|
+
# @param [String, nil] name The name of the default subcommand
|
39
|
+
#
|
40
|
+
# @return [void]
|
41
|
+
def default_subcommand(name)
|
42
|
+
@command.default_subcommand_name = name
|
43
|
+
end
|
44
|
+
|
34
45
|
# Sets the command name.
|
35
46
|
#
|
36
47
|
# @param [String] arg The new command name
|
data/lib/cri/option_parser.rb
CHANGED
@@ -199,7 +199,7 @@ module Cri
|
|
199
199
|
definition = @definitions.find { |d| d[:long] == option_key }
|
200
200
|
raise IllegalOptionError.new(option_key) if definition.nil?
|
201
201
|
|
202
|
-
if
|
202
|
+
if %i(required optional).include?(definition[:argument])
|
203
203
|
# Get option value if necessary
|
204
204
|
if option_value.nil?
|
205
205
|
option_value = find_option_value(definition, option_key)
|
@@ -226,7 +226,7 @@ module Cri
|
|
226
226
|
if option_keys.length > 1 && definition[:argument] == :required
|
227
227
|
# This is a combined option and it requires an argument, so complain
|
228
228
|
raise OptionRequiresAnArgumentError.new(option_key)
|
229
|
-
elsif
|
229
|
+
elsif %i(required optional).include?(definition[:argument])
|
230
230
|
# Get option value
|
231
231
|
option_value = find_option_value(definition, option_key)
|
232
232
|
|
data/lib/cri/version.rb
CHANGED
data/test/test_argument_array.rb
CHANGED
data/test/test_base.rb
CHANGED
data/test/test_basic_help.rb
CHANGED
data/test/test_basic_root.rb
CHANGED
@@ -1,12 +1,25 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
1
3
|
module Cri
|
2
4
|
class BasicRootTestCase < Cri::TestCase
|
3
5
|
def test_run_with_help
|
4
6
|
cmd = Cri::Command.new_basic_root
|
5
7
|
|
6
8
|
stdout, _stderr = capture_io_while do
|
7
|
-
assert_raises SystemExit do
|
9
|
+
err = assert_raises SystemExit do
|
8
10
|
cmd.run(%w(-h))
|
9
11
|
end
|
12
|
+
assert_equal 0, err.status
|
13
|
+
end
|
14
|
+
|
15
|
+
assert stdout =~ /COMMANDS.*\n.*help.*show help/
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_run_with_help_no_exit
|
19
|
+
cmd = Cri::Command.new_basic_root
|
20
|
+
|
21
|
+
stdout, _stderr = capture_io_while do
|
22
|
+
cmd.run(%w(-h), {}, hard_exit: false)
|
10
23
|
end
|
11
24
|
|
12
25
|
assert stdout =~ /COMMANDS.*\n.*help.*show help/
|
data/test/test_command.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
1
3
|
module Cri
|
2
4
|
class CommandTestCase < Cri::TestCase
|
3
5
|
def simple_cmd
|
@@ -145,9 +147,19 @@ module Cri
|
|
145
147
|
|
146
148
|
def test_invoke_simple_with_missing_opt_arg
|
147
149
|
out, err = capture_io_while do
|
148
|
-
assert_raises SystemExit do
|
150
|
+
err = assert_raises SystemExit do
|
149
151
|
simple_cmd.run(%w(-b))
|
150
152
|
end
|
153
|
+
assert_equal 1, err.status
|
154
|
+
end
|
155
|
+
|
156
|
+
assert_equal [], lines(out)
|
157
|
+
assert_equal ['moo: option requires an argument -- b'], lines(err)
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_invoke_simple_with_missing_opt_arg_no_exit
|
161
|
+
out, err = capture_io_while do
|
162
|
+
simple_cmd.run(%w(-b), {}, hard_exit: false)
|
151
163
|
end
|
152
164
|
|
153
165
|
assert_equal [], lines(out)
|
@@ -156,9 +168,19 @@ module Cri
|
|
156
168
|
|
157
169
|
def test_invoke_simple_with_illegal_opt
|
158
170
|
out, err = capture_io_while do
|
159
|
-
assert_raises SystemExit do
|
171
|
+
err = assert_raises SystemExit do
|
160
172
|
simple_cmd.run(%w(-z))
|
161
173
|
end
|
174
|
+
assert_equal 1, err.status
|
175
|
+
end
|
176
|
+
|
177
|
+
assert_equal [], lines(out)
|
178
|
+
assert_equal ['moo: illegal option -- z'], lines(err)
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_invoke_simple_with_illegal_opt_no_exit
|
182
|
+
out, err = capture_io_while do
|
183
|
+
simple_cmd.run(%w(-z), {}, hard_exit: false)
|
162
184
|
end
|
163
185
|
|
164
186
|
assert_equal [], lines(out)
|
@@ -176,9 +198,19 @@ module Cri
|
|
176
198
|
|
177
199
|
def test_invoke_nested_without_opts_or_args
|
178
200
|
out, err = capture_io_while do
|
179
|
-
assert_raises SystemExit do
|
201
|
+
err = assert_raises SystemExit do
|
180
202
|
nested_cmd.run(%w())
|
181
203
|
end
|
204
|
+
assert_equal 1, err.status
|
205
|
+
end
|
206
|
+
|
207
|
+
assert_equal [], lines(out)
|
208
|
+
assert_equal ['super: no command given'], lines(err)
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_invoke_nested_without_opts_or_args_no_exit
|
212
|
+
out, err = capture_io_while do
|
213
|
+
nested_cmd.run(%w(), {}, hard_exit: false)
|
182
214
|
end
|
183
215
|
|
184
216
|
assert_equal [], lines(out)
|
@@ -196,9 +228,19 @@ module Cri
|
|
196
228
|
|
197
229
|
def test_invoke_nested_with_incorrect_command_name
|
198
230
|
out, err = capture_io_while do
|
199
|
-
assert_raises SystemExit do
|
231
|
+
err = assert_raises SystemExit do
|
200
232
|
nested_cmd.run(%w(oogabooga))
|
201
233
|
end
|
234
|
+
assert_equal 1, err.status
|
235
|
+
end
|
236
|
+
|
237
|
+
assert_equal [], lines(out)
|
238
|
+
assert_equal ["super: unknown command 'oogabooga'"], lines(err)
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_invoke_nested_with_incorrect_command_name_no_exit
|
242
|
+
out, err = capture_io_while do
|
243
|
+
nested_cmd.run(%w(oogabooga), {}, hard_exit: false)
|
202
244
|
end
|
203
245
|
|
204
246
|
assert_equal [], lines(out)
|
@@ -207,9 +249,19 @@ module Cri
|
|
207
249
|
|
208
250
|
def test_invoke_nested_with_ambiguous_command_name
|
209
251
|
out, err = capture_io_while do
|
210
|
-
assert_raises SystemExit do
|
252
|
+
err = assert_raises SystemExit do
|
211
253
|
nested_cmd.run(%w(s))
|
212
254
|
end
|
255
|
+
assert_equal 1, err.status
|
256
|
+
end
|
257
|
+
|
258
|
+
assert_equal [], lines(out)
|
259
|
+
assert_equal ["super: 's' is ambiguous:", ' sink sub'], lines(err)
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_invoke_nested_with_ambiguous_command_name_no_exit
|
263
|
+
out, err = capture_io_while do
|
264
|
+
nested_cmd.run(%w(s), {}, hard_exit: false)
|
213
265
|
end
|
214
266
|
|
215
267
|
assert_equal [], lines(out)
|
@@ -559,5 +611,26 @@ module Cri
|
|
559
611
|
|
560
612
|
assert_equal [bar, foo, qux], [foo, bar, qux].sort
|
561
613
|
end
|
614
|
+
|
615
|
+
def test_default_subcommand
|
616
|
+
subcommand = Cri::Command.define do
|
617
|
+
name 'sub'
|
618
|
+
|
619
|
+
run do |_opts, _args, _c|
|
620
|
+
$stdout.puts 'I am the subcommand!'
|
621
|
+
end
|
622
|
+
end
|
623
|
+
|
624
|
+
cmd = Cri::Command.define do
|
625
|
+
name 'super'
|
626
|
+
default_subcommand 'sub'
|
627
|
+
subcommand subcommand
|
628
|
+
end
|
629
|
+
|
630
|
+
out, _err = capture_io_while do
|
631
|
+
cmd.run([])
|
632
|
+
end
|
633
|
+
assert_equal "I am the subcommand!\n", out
|
634
|
+
end
|
562
635
|
end
|
563
636
|
end
|
data/test/test_command_dsl.rb
CHANGED
data/test/test_command_runner.rb
CHANGED
data/test/test_option_parser.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cri
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Defreyne
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colored
|
@@ -101,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
101
|
version: '0'
|
102
102
|
requirements: []
|
103
103
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.6.
|
104
|
+
rubygems_version: 2.6.11
|
105
105
|
signing_key:
|
106
106
|
specification_version: 4
|
107
107
|
summary: a library for building easy-to-use command-line tools
|