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 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