cri 2.6.1 → 2.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +46 -21
- data/LICENSE +1 -1
- data/NEWS.md +12 -0
- data/README.adoc +1 -1
- data/Rakefile +7 -2
- data/cri.gemspec +5 -7
- data/lib/cri.rb +0 -2
- data/lib/cri/argument_array.rb +0 -4
- data/lib/cri/command.rb +31 -40
- data/lib/cri/command_dsl.rb +28 -18
- data/lib/cri/command_runner.rb +2 -6
- data/lib/cri/commands/basic_help.rb +2 -2
- data/lib/cri/commands/basic_root.rb +1 -1
- data/lib/cri/core_ext.rb +3 -1
- data/lib/cri/core_ext/string.rb +28 -30
- data/lib/cri/help_renderer.rb +105 -23
- data/lib/cri/option_parser.rb +13 -17
- data/lib/cri/platform.rb +1 -5
- data/lib/cri/string_formatter.rb +14 -9
- data/lib/cri/version.rb +1 -3
- data/test/helper.rb +38 -38
- data/test/test_argument_array.rb +7 -7
- data/test/test_base.rb +4 -4
- data/test/test_basic_help.rb +47 -47
- data/test/test_basic_root.rb +10 -10
- data/test/test_command.rb +424 -347
- data/test/test_command_dsl.rb +174 -150
- data/test/test_command_runner.rb +22 -23
- data/test/test_option_parser.rb +212 -224
- data/test/test_string_formatter.rb +97 -82
- metadata +3 -3
data/lib/cri/option_parser.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Cri
|
4
|
-
|
5
4
|
# Cri::OptionParser is used for parsing commandline options.
|
6
5
|
#
|
7
6
|
# Option definitions are hashes with the keys `:short`, `:long` and
|
@@ -56,7 +55,6 @@ module Cri
|
|
56
55
|
# }
|
57
56
|
# }
|
58
57
|
class OptionParser
|
59
|
-
|
60
58
|
# Error that will be raised when an unknown option is encountered.
|
61
59
|
class IllegalOptionError < Cri::Error
|
62
60
|
end
|
@@ -104,7 +102,7 @@ module Cri
|
|
104
102
|
#
|
105
103
|
# @return [Cri::OptionParser] The option parser self
|
106
104
|
def self.parse(arguments_and_options, definitions)
|
107
|
-
|
105
|
+
new(arguments_and_options, definitions).run
|
108
106
|
end
|
109
107
|
|
110
108
|
# Creates a new parser with the given options/arguments and definitions.
|
@@ -169,9 +167,9 @@ module Cri
|
|
169
167
|
|
170
168
|
if e == '--'
|
171
169
|
handle_dashdash(e)
|
172
|
-
elsif e =~ /^--./
|
170
|
+
elsif e =~ /^--./ && !@no_more_options
|
173
171
|
handle_dashdash_option(e)
|
174
|
-
elsif e =~ /^-./
|
172
|
+
elsif e =~ /^-./ && !@no_more_options
|
175
173
|
handle_dash_option(e)
|
176
174
|
else
|
177
175
|
add_argument(e)
|
@@ -182,7 +180,7 @@ module Cri
|
|
182
180
|
@running = false
|
183
181
|
end
|
184
182
|
|
185
|
-
|
183
|
+
private
|
186
184
|
|
187
185
|
def handle_dashdash(e)
|
188
186
|
add_argument(e)
|
@@ -192,8 +190,8 @@ module Cri
|
|
192
190
|
def handle_dashdash_option(e)
|
193
191
|
# Get option key, and option value if included
|
194
192
|
if e =~ /^--([^=]+)=(.+)$/
|
195
|
-
option_key =
|
196
|
-
option_value =
|
193
|
+
option_key = Regexp.last_match[1]
|
194
|
+
option_value = Regexp.last_match[2]
|
197
195
|
else
|
198
196
|
option_key = e[2..-1]
|
199
197
|
option_value = nil
|
@@ -201,9 +199,9 @@ module Cri
|
|
201
199
|
|
202
200
|
# Find definition
|
203
201
|
definition = @definitions.find { |d| d[:long] == option_key }
|
204
|
-
|
202
|
+
fail IllegalOptionError.new(option_key) if definition.nil?
|
205
203
|
|
206
|
-
if [
|
204
|
+
if [:required, :optional].include?(definition[:argument])
|
207
205
|
# Get option value if necessary
|
208
206
|
if option_value.nil?
|
209
207
|
option_value = find_option_value(definition, option_key)
|
@@ -225,12 +223,12 @@ module Cri
|
|
225
223
|
option_keys.each do |option_key|
|
226
224
|
# Find definition
|
227
225
|
definition = @definitions.find { |d| d[:short] == option_key }
|
228
|
-
|
226
|
+
fail IllegalOptionError.new(option_key) if definition.nil?
|
229
227
|
|
230
|
-
if option_keys.length > 1
|
228
|
+
if option_keys.length > 1 && definition[:argument] == :required
|
231
229
|
# This is a combined option and it requires an argument, so complain
|
232
|
-
|
233
|
-
elsif [
|
230
|
+
fail OptionRequiresAnArgumentError.new(option_key)
|
231
|
+
elsif [:required, :optional].include?(definition[:argument])
|
234
232
|
# Get option value
|
235
233
|
option_value = find_option_value(definition, option_key)
|
236
234
|
|
@@ -247,7 +245,7 @@ module Cri
|
|
247
245
|
option_value = @unprocessed_arguments_and_options.shift
|
248
246
|
if option_value.nil? || option_value =~ /^-/
|
249
247
|
if definition[:argument] == :required
|
250
|
-
|
248
|
+
fail OptionRequiresAnArgumentError.new(option_key)
|
251
249
|
else
|
252
250
|
@unprocessed_arguments_and_options.unshift(option_value)
|
253
251
|
option_value = true
|
@@ -275,7 +273,5 @@ module Cri
|
|
275
273
|
delegate.argument_added(value, self) unless delegate.nil?
|
276
274
|
end
|
277
275
|
end
|
278
|
-
|
279
276
|
end
|
280
|
-
|
281
277
|
end
|
data/lib/cri/platform.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Cri
|
4
|
-
|
5
4
|
module Platform
|
6
|
-
|
7
5
|
# @return [Boolean] true if the current platform is Windows, false
|
8
6
|
# otherwise.
|
9
7
|
def self.windows?
|
10
|
-
|
8
|
+
RUBY_PLATFORM =~ /windows|bccwin|cygwin|djgpp|mingw|mswin|wince/i
|
11
9
|
end
|
12
10
|
|
13
11
|
# Checks whether colors can be enabled. For colors to be enabled, the given
|
@@ -24,7 +22,5 @@ module Cri
|
|
24
22
|
true
|
25
23
|
end
|
26
24
|
end
|
27
|
-
|
28
25
|
end
|
29
|
-
|
30
26
|
end
|
data/lib/cri/string_formatter.rb
CHANGED
@@ -3,18 +3,16 @@
|
|
3
3
|
require 'colored'
|
4
4
|
|
5
5
|
module Cri
|
6
|
-
|
7
6
|
class StringFormatter
|
8
|
-
|
9
7
|
# Extracts individual paragraphs (separated by two newlines).
|
10
8
|
#
|
11
9
|
# @param [String] s The string to format
|
12
10
|
#
|
13
11
|
# @return [Array<String>] A list of paragraphs in the string
|
14
12
|
def to_paragraphs(s)
|
15
|
-
lines = s.scan(/([^\n]+\n|[^\n]*$)/).map { |
|
13
|
+
lines = s.scan(/([^\n]+\n|[^\n]*$)/).map { |l| l[0].strip }
|
16
14
|
|
17
|
-
paragraphs = [
|
15
|
+
paragraphs = [[]]
|
18
16
|
lines.each do |line|
|
19
17
|
if line.empty?
|
20
18
|
paragraphs << []
|
@@ -36,15 +34,18 @@ module Cri
|
|
36
34
|
#
|
37
35
|
# @param [Number] indentation The number of spaces to indent each line.
|
38
36
|
#
|
37
|
+
# @param [Boolean] first_line_already_indented Whether or not the first
|
38
|
+
# line is already indented
|
39
|
+
#
|
39
40
|
# @return [String] The word-wrapped and indented string
|
40
|
-
def wrap_and_indent(s, width, indentation)
|
41
|
+
def wrap_and_indent(s, width, indentation, first_line_already_indented = false)
|
41
42
|
indented_width = width - indentation
|
42
43
|
indent = ' ' * indentation
|
43
44
|
# Split into paragraphs
|
44
45
|
paragraphs = to_paragraphs(s)
|
45
46
|
|
46
47
|
# Wrap and indent each paragraph
|
47
|
-
paragraphs.map do |paragraph|
|
48
|
+
text = paragraphs.map do |paragraph|
|
48
49
|
# Initialize
|
49
50
|
lines = []
|
50
51
|
line = ''
|
@@ -58,13 +59,19 @@ module Cri
|
|
58
59
|
end
|
59
60
|
|
60
61
|
# Add word to line
|
61
|
-
line += (line == '' ? '' : ' '
|
62
|
+
line += (line == '' ? '' : ' ') + word
|
62
63
|
end
|
63
64
|
lines << line
|
64
65
|
|
65
66
|
# Join lines
|
66
67
|
lines.map { |l| indent + l }.join("\n")
|
67
68
|
end.join("\n\n")
|
69
|
+
|
70
|
+
if first_line_already_indented
|
71
|
+
text[indentation..-1]
|
72
|
+
else
|
73
|
+
text
|
74
|
+
end
|
68
75
|
end
|
69
76
|
|
70
77
|
# @param [String] s The string to format
|
@@ -102,7 +109,5 @@ module Cri
|
|
102
109
|
s
|
103
110
|
end
|
104
111
|
end
|
105
|
-
|
106
112
|
end
|
107
|
-
|
108
113
|
end
|
data/lib/cri/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -10,45 +10,45 @@ require 'cri'
|
|
10
10
|
|
11
11
|
require 'stringio'
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
13
|
+
module Cri
|
14
|
+
class TestCase < Minitest::Test
|
15
|
+
def setup
|
16
|
+
@orig_io = capture_io
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
uncapture_io(*@orig_io)
|
21
|
+
end
|
22
|
+
|
23
|
+
def capture_io_while(&block)
|
24
|
+
orig_io = capture_io
|
25
|
+
block.call
|
26
|
+
[$stdout.string, $stderr.string]
|
27
|
+
ensure
|
28
|
+
uncapture_io(*orig_io)
|
29
|
+
end
|
30
|
+
|
31
|
+
def lines(string)
|
32
|
+
string.scan(/^.*\n/).map { |s| s.chomp }
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def capture_io
|
38
|
+
orig_stdout = $stdout
|
39
|
+
orig_stderr = $stderr
|
40
|
+
|
41
|
+
$stdout = StringIO.new
|
42
|
+
$stderr = StringIO.new
|
43
|
+
|
44
|
+
[orig_stdout, orig_stderr]
|
45
|
+
end
|
46
|
+
|
47
|
+
def uncapture_io(orig_stdout, orig_stderr)
|
48
|
+
$stdout = orig_stdout
|
49
|
+
$stderr = orig_stderr
|
50
|
+
end
|
33
51
|
end
|
34
|
-
|
35
|
-
private
|
36
|
-
|
37
|
-
def capture_io
|
38
|
-
orig_stdout = $stdout
|
39
|
-
orig_stderr = $stderr
|
40
|
-
|
41
|
-
$stdout = StringIO.new
|
42
|
-
$stderr = StringIO.new
|
43
|
-
|
44
|
-
[ orig_stdout, orig_stderr ]
|
45
|
-
end
|
46
|
-
|
47
|
-
def uncapture_io(orig_stdout, orig_stderr)
|
48
|
-
$stdout = orig_stdout
|
49
|
-
$stderr = orig_stderr
|
50
|
-
end
|
51
|
-
|
52
52
|
end
|
53
53
|
|
54
54
|
# Unexpected system exit is unexpected
|
data/test/test_argument_array.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
3
|
+
module Cri
|
4
|
+
class ArgumentArrayTestCase < Cri::TestCase
|
5
|
+
def test_initialize
|
6
|
+
arr = Cri::ArgumentArray.new(['foo', 'bar', '--', 'baz'])
|
7
|
+
assert_equal %w(foo bar baz), arr
|
8
|
+
assert_equal ['foo', 'bar', '--', 'baz'], arr.raw
|
9
|
+
end
|
9
10
|
end
|
10
|
-
|
11
11
|
end
|
data/test/test_base.rb
CHANGED
data/test/test_basic_help.rb
CHANGED
@@ -1,67 +1,67 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
3
|
+
module Cri
|
4
|
+
class BasicHelpTestCase < Cri::TestCase
|
5
|
+
def test_run_without_supercommand
|
6
|
+
cmd = Cri::Command.new_basic_help
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
assert_raises Cri::NoHelpAvailableError do
|
9
|
-
cmd.run([])
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def test_run_with_supercommand
|
14
|
-
cmd = Cri::Command.define do
|
15
|
-
name 'meh'
|
8
|
+
assert_raises Cri::NoHelpAvailableError do
|
9
|
+
cmd.run([])
|
10
|
+
end
|
16
11
|
end
|
17
12
|
|
18
|
-
|
19
|
-
|
13
|
+
def test_run_with_supercommand
|
14
|
+
cmd = Cri::Command.define do
|
15
|
+
name 'meh'
|
16
|
+
end
|
20
17
|
|
21
|
-
|
22
|
-
|
18
|
+
help_cmd = Cri::Command.new_basic_help
|
19
|
+
cmd.add_command(help_cmd)
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
name 'root'
|
27
|
-
summary 'I am root!'
|
21
|
+
help_cmd.run([])
|
22
|
+
end
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
def test_run_with_chain_of_commands
|
25
|
+
cmd = Cri::Command.define do
|
26
|
+
name 'root'
|
27
|
+
summary 'I am root!'
|
32
28
|
|
33
29
|
subcommand do
|
34
|
-
name '
|
35
|
-
summary 'I am
|
30
|
+
name 'foo'
|
31
|
+
summary 'I am foo!'
|
32
|
+
|
33
|
+
subcommand do
|
34
|
+
name 'subsubby'
|
35
|
+
summary 'I am subsubby!'
|
36
|
+
end
|
36
37
|
end
|
37
38
|
end
|
38
|
-
end
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
help_cmd = Cri::Command.new_basic_help
|
41
|
+
cmd.add_command(help_cmd)
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
# Simple call
|
44
|
+
stdout, stderr = capture_io_while do
|
45
|
+
help_cmd.run(['foo'])
|
46
|
+
end
|
47
|
+
assert_match(/I am foo!/m, stdout)
|
48
|
+
assert_equal('', stderr)
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
50
|
+
# Subcommand
|
51
|
+
stdout, stderr = capture_io_while do
|
52
|
+
help_cmd.run(%w(foo subsubby))
|
53
|
+
end
|
54
|
+
assert_match(/I am subsubby!/m, stdout)
|
55
|
+
assert_equal('', stderr)
|
56
56
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
# Non-existing subcommand
|
58
|
+
stdout, stderr = capture_io_while do
|
59
|
+
assert_raises SystemExit do
|
60
|
+
help_cmd.run(%w(foo mysterycmd))
|
61
|
+
end
|
61
62
|
end
|
63
|
+
assert_equal '', stdout
|
64
|
+
assert_match(/foo: unknown command 'mysterycmd'/, stderr)
|
62
65
|
end
|
63
|
-
assert_equal '', stdout
|
64
|
-
assert_match(/foo: unknown command 'mysterycmd'/, stderr)
|
65
66
|
end
|
66
|
-
|
67
67
|
end
|
data/test/test_basic_root.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
|
3
|
+
module Cri
|
4
|
+
class BasicRootTestCase < Cri::TestCase
|
5
|
+
def test_run_with_help
|
6
|
+
cmd = Cri::Command.new_basic_root
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
assert_raises SystemExit do
|
10
|
-
cmd.run(%w( -h ))
|
8
|
+
stdout, _stderr = capture_io_while do
|
9
|
+
assert_raises SystemExit do
|
10
|
+
cmd.run(%w( -h ))
|
11
|
+
end
|
11
12
|
end
|
12
|
-
end
|
13
13
|
|
14
|
-
|
14
|
+
assert stdout =~ /COMMANDS.*\n.*help.*show help/
|
15
|
+
end
|
15
16
|
end
|
16
|
-
|
17
17
|
end
|