cri 2.7.1 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 125652850f61d27f4d91ec9e3bbfa46f25c03d11
4
- data.tar.gz: dd5156012cb91ad551377bd807cd9b544300a618
3
+ metadata.gz: ef8c0cab47165e8e00e78ffa23c72a9569656a64
4
+ data.tar.gz: 59473eac71bfa27211fe462321d5fd64e997c694
5
5
  SHA512:
6
- metadata.gz: cd917c4f792476b45868a6c95c3a1a75ee88c3b49bdb05dd18e30bc637e69fe476d6a0f5d57cbdd86ddbc3e5d07ee24e63f8dd1a23bf207dbfc913e763237b81
7
- data.tar.gz: b697f2c2897405954a4c66437515648b4e3e18631bf3cb9059ef0e221a8bf5412d0bd1b744099ece0e894fc278406765c0754766347011507374ae69fa0642cc
6
+ metadata.gz: f8e7c91fbb4550ec9744f18cf21ff9e2ee02dd324f3a85bc3e660442545ce766bda90d8fc003985f19ec845a26c7c7040c9cef9e69dbe5af461992f42540cbcb
7
+ data.tar.gz: 4008d8b904781cd7f1b8da699fa26b1f66842387517e43676db912d9d7551e232bb2fa3337600fe028c4f6a764cdacd3ef2f4cd5736e9212601f6b1d1e434b66
@@ -7,54 +7,41 @@ PATH
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- asciidoctor (1.5.2)
10
+ asciidoctor (1.5.5)
11
11
  ast (2.3.0)
12
12
  colored (1.2)
13
- coveralls (0.8.1)
14
- json (~> 1.8)
15
- rest-client (>= 1.6.8, < 2)
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.1)
17
+ thor (~> 0.19.4)
18
+ tins (~> 1.6)
19
19
  docile (1.1.5)
20
- domain_name (0.5.24)
21
- unf (>= 0.0.5, < 1.0.0)
22
- http-cookie (1.0.2)
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.0)
32
- rake (10.4.2)
33
- rest-client (1.8.0)
34
- http-cookie (>= 1.0.2, < 2.0)
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.10.0)
34
+ simplecov (0.14.1)
45
35
  docile (~> 1.1.0)
46
- json (~> 1.8)
36
+ json (>= 1.8, < 3)
47
37
  simplecov-html (~> 0.10.0)
48
38
  simplecov-html (0.10.0)
49
- term-ansicolor (1.3.0)
39
+ term-ansicolor (1.5.0)
50
40
  tins (~> 1.0)
51
- thor (0.19.1)
52
- tins (1.5.1)
53
- unf (0.1.4)
54
- unf_ext
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.13.6
60
+ 1.14.6
data/NEWS.md CHANGED
@@ -1,6 +1,14 @@
1
1
  Cri News
2
2
  ========
3
3
 
4
+ 2.8.0
5
+ -----
6
+
7
+ Features:
8
+
9
+ * Allow passing `hard_exit: false` to `Command#run` to prevent `SystemExit` (#51)
10
+ * Allow specifying the default subcommand (#54)
11
+
4
12
  2.7.1
5
13
  -----
6
14
 
@@ -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
- task :test_unit do
18
- require './test/helper.rb'
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: [:test_unit, :test_style]
26
+ task test: %i(test_unit test_style)
30
27
 
31
28
  task default: :test
@@ -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
- exit 1
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
- exit 1
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
- $stderr.puts "#{name}: no command given"
252
- exit 1
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
- exit 1
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
- exit 1
376
+ raise CriExitException.new(is_error: true)
350
377
  end
351
378
  end
352
379
  end
@@ -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
@@ -1,6 +1,6 @@
1
1
  flag :h, :help, 'show help for this command' do |_value, cmd|
2
2
  puts cmd.help
3
- exit 0
3
+ raise CriExitException.new(is_error: false)
4
4
  end
5
5
 
6
6
  subcommand Cri::Command.new_basic_help
@@ -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 [:required, :optional].include?(definition[:argument])
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 [:required, :optional].include?(definition[:argument])
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
 
@@ -1,4 +1,4 @@
1
1
  module Cri
2
2
  # The current Cri version.
3
- VERSION = '2.7.1'.freeze
3
+ VERSION = '2.8.0'.freeze
4
4
  end
@@ -1,3 +1,5 @@
1
+ require 'helper'
2
+
1
3
  module Cri
2
4
  class ArgumentArrayTestCase < Cri::TestCase
3
5
  def test_initialize
@@ -1,3 +1,5 @@
1
+ require 'helper'
2
+
1
3
  module Cri
2
4
  class BaseTestCase < Cri::TestCase
3
5
  def test_stub; end
@@ -1,3 +1,5 @@
1
+ require 'helper'
2
+
1
3
  module Cri
2
4
  class BasicHelpTestCase < Cri::TestCase
3
5
  def test_run_without_supercommand
@@ -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/
@@ -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
@@ -1,3 +1,5 @@
1
+ require 'helper'
2
+
1
3
  module Cri
2
4
  class CommandDSLTestCase < Cri::TestCase
3
5
  def test_create_command
@@ -1,3 +1,5 @@
1
+ require 'helper'
2
+
1
3
  module Cri
2
4
  class CommandRunnerTestCase < Cri::TestCase
3
5
  def setup
@@ -1,3 +1,5 @@
1
+ require 'helper'
2
+
1
3
  module Cri
2
4
  class OptionParserTestCase < Cri::TestCase
3
5
  def test_parse_without_options
@@ -1,3 +1,5 @@
1
+ require 'helper'
2
+
1
3
  module Cri
2
4
  class CoreExtTestCase < Cri::TestCase
3
5
  def formatter
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.7.1
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: 2016-12-03 00:00:00.000000000 Z
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.8
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