clive 0.8.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.md +328 -227
- data/lib/clive.rb +130 -50
- data/lib/clive/argument.rb +170 -0
- data/lib/clive/arguments.rb +139 -0
- data/lib/clive/arguments/parser.rb +210 -0
- data/lib/clive/base.rb +189 -0
- data/lib/clive/command.rb +342 -444
- data/lib/clive/error.rb +66 -0
- data/lib/clive/formatter.rb +57 -141
- data/lib/clive/formatter/colour.rb +37 -0
- data/lib/clive/formatter/plain.rb +172 -0
- data/lib/clive/option.rb +185 -75
- data/lib/clive/option/runner.rb +163 -0
- data/lib/clive/output.rb +141 -16
- data/lib/clive/parser.rb +180 -87
- data/lib/clive/struct_hash.rb +109 -0
- data/lib/clive/type.rb +117 -0
- data/lib/clive/type/definitions.rb +170 -0
- data/lib/clive/type/lookup.rb +23 -0
- data/lib/clive/version.rb +3 -3
- data/spec/clive/a_cli_spec.rb +245 -0
- data/spec/clive/argument_spec.rb +148 -0
- data/spec/clive/arguments/parser_spec.rb +35 -0
- data/spec/clive/arguments_spec.rb +191 -0
- data/spec/clive/command_spec.rb +276 -209
- data/spec/clive/formatter/colour_spec.rb +129 -0
- data/spec/clive/formatter/plain_spec.rb +129 -0
- data/spec/clive/option/runner_spec.rb +92 -0
- data/spec/clive/option_spec.rb +149 -23
- data/spec/clive/output_spec.rb +86 -2
- data/spec/clive/parser_spec.rb +201 -81
- data/spec/clive/struct_hash_spec.rb +82 -0
- data/spec/clive/type/definitions_spec.rb +312 -0
- data/spec/clive/type_spec.rb +107 -0
- data/spec/clive_spec.rb +60 -0
- data/spec/extras/expectations.rb +86 -0
- data/spec/extras/focus.rb +22 -0
- data/spec/helper.rb +35 -0
- metadata +56 -36
- data/lib/clive/bool.rb +0 -67
- data/lib/clive/exceptions.rb +0 -54
- data/lib/clive/flag.rb +0 -199
- data/lib/clive/switch.rb +0 -31
- data/lib/clive/tokens.rb +0 -141
- data/spec/clive/bool_spec.rb +0 -54
- data/spec/clive/flag_spec.rb +0 -117
- data/spec/clive/formatter_spec.rb +0 -108
- data/spec/clive/switch_spec.rb +0 -14
- data/spec/clive/tokens_spec.rb +0 -38
- data/spec/shared_specs.rb +0 -16
- data/spec/spec_helper.rb +0 -12
data/lib/clive/switch.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
module Clive
|
2
|
-
|
3
|
-
# A string that takes no argument, beginning with one or two dashes
|
4
|
-
# eg. ruby --version
|
5
|
-
# ruby -v
|
6
|
-
#
|
7
|
-
class Switch < Option
|
8
|
-
|
9
|
-
# Create a new Switch instance.
|
10
|
-
#
|
11
|
-
# @param names [Array[Symbol]]
|
12
|
-
# An array of names the option can be invoked by.
|
13
|
-
#
|
14
|
-
# @param desc [String]
|
15
|
-
# A description of what the option does.
|
16
|
-
#
|
17
|
-
# @yield A block to run if the switch is triggered
|
18
|
-
#
|
19
|
-
def initialize(names, desc, &block)
|
20
|
-
@names = names.map(&:to_s)
|
21
|
-
@desc = desc
|
22
|
-
@block = block
|
23
|
-
end
|
24
|
-
|
25
|
-
# Runs the block that was given
|
26
|
-
def run
|
27
|
-
@block.call
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
data/lib/clive/tokens.rb
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
module Clive
|
2
|
-
|
3
|
-
# A subclass of Array to allow the creation of arrays that look
|
4
|
-
# like:
|
5
|
-
#
|
6
|
-
# [[:word, 'Value'], [:long, 'verbose'], [:short, 'r']]
|
7
|
-
#
|
8
|
-
# The tokens are not stored like that but as the string
|
9
|
-
# representations:
|
10
|
-
#
|
11
|
-
# ["Value", "--verbose", "-r"]
|
12
|
-
#
|
13
|
-
class Tokens < Array
|
14
|
-
|
15
|
-
TOKEN_KEYS = [:word, :short, :long]
|
16
|
-
|
17
|
-
# Create a new Tokens instance. Pass either an array of tokens
|
18
|
-
# or a plain array, they will be converted correctly.
|
19
|
-
#
|
20
|
-
# @param [Array] args
|
21
|
-
# pass either
|
22
|
-
# ["command", "--flag"]
|
23
|
-
# # or
|
24
|
-
# [[:word, "command"], [:long, "flag"]]
|
25
|
-
# @return [Tokens]
|
26
|
-
#
|
27
|
-
def initialize(args=[])
|
28
|
-
if token?(args[0])
|
29
|
-
r = []
|
30
|
-
args.each {|i| r << token_to_string(i)}
|
31
|
-
args = r
|
32
|
-
end
|
33
|
-
super(args)
|
34
|
-
end
|
35
|
-
|
36
|
-
# Turn +@tokens+ into an array, this ensures that shorts are split
|
37
|
-
# as is expected
|
38
|
-
#
|
39
|
-
# @return [Array] array representation of tokens held
|
40
|
-
def array
|
41
|
-
return [] unless self.tokens
|
42
|
-
arr = []
|
43
|
-
self.tokens.each do |i|
|
44
|
-
k, v = i[0], i[1]
|
45
|
-
case k
|
46
|
-
when :long
|
47
|
-
arr << "--#{v}"
|
48
|
-
when :short
|
49
|
-
arr << "-#{v}"
|
50
|
-
when :word
|
51
|
-
arr << v
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
arr
|
56
|
-
end
|
57
|
-
|
58
|
-
# Creates an array of tokens based on +self+.
|
59
|
-
# Strings beginning with a -, eg. -n become [:short, "n"].
|
60
|
-
# Strings beginning with --, eg. --verbose become [:long, "verbose"].
|
61
|
-
# Strings which begin with neither become [:word, "value"].
|
62
|
-
#
|
63
|
-
# @return [Array] the tokens that are held
|
64
|
-
def tokens
|
65
|
-
t = []
|
66
|
-
self.each do |i|
|
67
|
-
case i
|
68
|
-
when /\-\-.+/
|
69
|
-
if i.include?('=')
|
70
|
-
a, b = i[2..i.length].split('=')
|
71
|
-
t << [:long, a] << [:word, b]
|
72
|
-
else
|
73
|
-
t << [:long, i[2..i.length]]
|
74
|
-
end
|
75
|
-
when /\-.+/
|
76
|
-
i[1..i.length].split('').each do |j|
|
77
|
-
t << [:short, j]
|
78
|
-
end
|
79
|
-
else
|
80
|
-
t << [:word, i]
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
t
|
85
|
-
end
|
86
|
-
|
87
|
-
# @see #tokens
|
88
|
-
def self.to_tokens(arr)
|
89
|
-
Tokens.new(arr).tokens
|
90
|
-
end
|
91
|
-
|
92
|
-
# @see #array
|
93
|
-
def self.to_array(tokens)
|
94
|
-
Tokens.new(tokens).array
|
95
|
-
end
|
96
|
-
|
97
|
-
# Checks to see if it is a token being added and changes it back
|
98
|
-
def <<(val)
|
99
|
-
if token?(val)
|
100
|
-
super(token_to_string(val))
|
101
|
-
else
|
102
|
-
super
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# Test whether an array is a token
|
107
|
-
#
|
108
|
-
# @param [Array]
|
109
|
-
# @return [Boolean]
|
110
|
-
#
|
111
|
-
# @example
|
112
|
-
#
|
113
|
-
# t.token?([:word, "something"]) #=> true
|
114
|
-
# t.token?(["a", "normal", "array"]) #=> false
|
115
|
-
#
|
116
|
-
def token?(arr)
|
117
|
-
return false if arr.nil?
|
118
|
-
TOKEN_KEYS.include?(arr[0])
|
119
|
-
end
|
120
|
-
|
121
|
-
# Convert a tokens to its string representation
|
122
|
-
def token_to_string(token)
|
123
|
-
k, v = token[0], token[1]
|
124
|
-
case k
|
125
|
-
when :long
|
126
|
-
"--#{v}"
|
127
|
-
when :short
|
128
|
-
"-#{v}"
|
129
|
-
when :word
|
130
|
-
v
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
# This is here to force the use of #tokens and #array when
|
135
|
-
# accessing the contents
|
136
|
-
def inspect
|
137
|
-
"#<Clive::Tokens:0x#{'%x' % (self.object_id << 1)} #{self.tokens}>"
|
138
|
-
end
|
139
|
-
|
140
|
-
end
|
141
|
-
end
|
data/spec/clive/bool_spec.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Clive::Bool do
|
4
|
-
|
5
|
-
subject { Clive::Bool.new([:n, :name], "A test", true) {|arg| $stdout.puts arg } }
|
6
|
-
let(:falsey) { Clive::Bool.new([:n, :name], "A test", false) {|arg| $stdout.puts arg } }
|
7
|
-
|
8
|
-
describe "#truth" do
|
9
|
-
it "returns the truth" do
|
10
|
-
subject.truth.should == true
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
it_behaves_like "an option"
|
15
|
-
|
16
|
-
context "when no long name is given" do
|
17
|
-
it "raises an error" do
|
18
|
-
expect {
|
19
|
-
Clive::Bool.new([:n], "Short test", true) {}
|
20
|
-
}.should raise_error Clive::MissingLongName
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "#run" do
|
25
|
-
context "when truth is true" do
|
26
|
-
it "passes true to the block" do
|
27
|
-
$stdout.should_receive(:puts).with(true)
|
28
|
-
subject.run
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
context "when truth is false" do
|
33
|
-
it "passes false to the block" do
|
34
|
-
$stdout.should_receive(:puts).with(false)
|
35
|
-
falsey.run
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "#to_h" do
|
41
|
-
context "when truth is true" do
|
42
|
-
it "returns hash for help formatter" do
|
43
|
-
hsh = {'names' => subject.names_to_strings(true),
|
44
|
-
'desc' => subject.desc}
|
45
|
-
subject.to_h.should == hsh
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context "when truth is false" do
|
50
|
-
specify { falsey.to_h.should be_nil }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
data/spec/clive/flag_spec.rb
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Clive::Flag do
|
4
|
-
|
5
|
-
subject { Clive::Flag.new([:S, :say], "Say something", "WORD(S)") {|i| $stdout.puts i } }
|
6
|
-
|
7
|
-
it_behaves_like "an option"
|
8
|
-
|
9
|
-
describe "#run" do
|
10
|
-
it "calls the block with the argument" do
|
11
|
-
$stdout.should_receive(:puts).with("hey")
|
12
|
-
subject.run(["hey"])
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "#arg_size" do
|
17
|
-
context "when choice is available" do
|
18
|
-
it "returns 1" do
|
19
|
-
subject.args = 1..5
|
20
|
-
subject.arg_size.should == 1
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
context "when arguments are required" do
|
25
|
-
subject { Clive::Flag.new([:n], "Description", "REQ [OPT] REQ2 [OPT2] [OPT3]") }
|
26
|
-
|
27
|
-
it "returns the number of all arguments" do
|
28
|
-
subject.arg_size(:all).should == 5
|
29
|
-
end
|
30
|
-
|
31
|
-
it "returns the number of optional arguments" do
|
32
|
-
subject.arg_size(:optional).should == 3
|
33
|
-
end
|
34
|
-
|
35
|
-
it "returns the number of mandatory arguments" do
|
36
|
-
subject.arg_size(:mandatory).should == 2
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe "#args_to_string" do
|
42
|
-
|
43
|
-
context "when a list of options" do
|
44
|
-
it "returns the arguments as a string" do
|
45
|
-
subject.args = "first [second]"
|
46
|
-
subject.args_to_string.should == "<first> [second]"
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
context "when a splat as option" do
|
51
|
-
it "returns the argument and ellipsis" do
|
52
|
-
subject.args = "arg..."
|
53
|
-
subject.args_to_string.should == "<arg1> ..."
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context "when a choice of options" do
|
58
|
-
it "returns an empty string" do
|
59
|
-
subject.args = %w(a b c)
|
60
|
-
subject.args_to_string.should == ""
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
context "when a range of options" do
|
65
|
-
it "returns an empty string" do
|
66
|
-
subject.args = 1..5
|
67
|
-
subject.args_to_string.should == ""
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
describe "#options_to_string" do
|
74
|
-
|
75
|
-
context "when a list of options" do
|
76
|
-
it "returns an empty string" do
|
77
|
-
subject.args = "first [second]"
|
78
|
-
subject.options_to_string.should == ""
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context "when a splat as option" do
|
83
|
-
it "returns an empty string" do
|
84
|
-
subject.args = "arg..."
|
85
|
-
subject.options_to_string.should == ""
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context "when a choice of options" do
|
90
|
-
it "returns the choices joined" do
|
91
|
-
subject.args = %w(a b c)
|
92
|
-
subject.options_to_string.should == "(a, b, c)"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
context "when a range of options" do
|
97
|
-
it "returns a string representation of the range" do
|
98
|
-
subject.args = 1..5
|
99
|
-
subject.options_to_string.should == "(1..5)"
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
|
105
|
-
describe "#to_h" do
|
106
|
-
it "returns a hash" do
|
107
|
-
hsh = {
|
108
|
-
"names" => %w(-S --say),
|
109
|
-
"desc" => "Say something",
|
110
|
-
"args" => "<WORD(S)>",
|
111
|
-
"options" => ""
|
112
|
-
}
|
113
|
-
subject.to_h.should == hsh
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
end
|
@@ -1,108 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Clive::Formatter do
|
4
|
-
|
5
|
-
describe Clive::Formatter::Obj do
|
6
|
-
subject { Clive::Formatter::Obj.new({:test => 5}) }
|
7
|
-
|
8
|
-
describe "#initialize" do
|
9
|
-
it "defines methods given by hash" do
|
10
|
-
subject.test.should == 5
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "#evaluate" do
|
15
|
-
it "evaluates code within the object" do
|
16
|
-
$stdout.should_receive(:puts).with(5)
|
17
|
-
subject.evaluate("$stdout.puts test")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
|
23
|
-
subject { Clive::Formatter.new(30, 5) }
|
24
|
-
|
25
|
-
|
26
|
-
describe "#switch" do
|
27
|
-
it "sets format for switches" do
|
28
|
-
subject.switch("{desc}")
|
29
|
-
subject.instance_variable_get("@switch").should == "{desc}"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
describe "#bool" do
|
34
|
-
it "sets format for bools" do
|
35
|
-
subject.bool "{desc}"
|
36
|
-
subject.instance_variable_get("@bool").should == "{desc}"
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "#flag" do
|
41
|
-
it "sets format for flags" do
|
42
|
-
subject.flag "{desc}"
|
43
|
-
subject.instance_variable_get("@flag").should == "{desc}"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe "#command" do
|
48
|
-
it "sets format for commands" do
|
49
|
-
subject.command "{desc}"
|
50
|
-
subject.instance_variable_get("@command").should == "{desc}"
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
describe "#format" do
|
56
|
-
it "generates the help" do
|
57
|
-
formatter = Clive::Command.setup(Class.new).help_formatter(:white)
|
58
|
-
options = [
|
59
|
-
Clive::Switch.new([:t, :test], "A test switch"),
|
60
|
-
Clive::Bool.new([:boolean], "A bool", true),
|
61
|
-
Clive::Bool.new([:boolean], "A bool", false),
|
62
|
-
Clive::Flag.new([:args], "With args", "ARG [OPT]"),
|
63
|
-
Clive::Flag.new([:choose], "With options", ["a", "b", "c"])
|
64
|
-
]
|
65
|
-
command = Clive::Command.new([:command], "A command", Class.new)
|
66
|
-
result = <<EOS
|
67
|
-
head
|
68
|
-
|
69
|
-
Commands:
|
70
|
-
command A command
|
71
|
-
|
72
|
-
Options:
|
73
|
-
-t, --test A test switch
|
74
|
-
--[no-]boolean A bool
|
75
|
-
--args <ARG> [OPT] With args \e[1m\e[0m
|
76
|
-
--choose With options \e[1m(a, b, c)\e[0m
|
77
|
-
|
78
|
-
foot
|
79
|
-
EOS
|
80
|
-
|
81
|
-
formatter.format("head", "foot", [command], options).should == result
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
describe "#parse" do
|
87
|
-
it "parses before and after '{spaces}' separately" do
|
88
|
-
args = {"name" => "a", "desc" => "something"}
|
89
|
-
subject.should_receive(:parse_format).with("{name}", args).and_return("")
|
90
|
-
subject.should_receive(:parse_format).with("{desc}", args).and_return("")
|
91
|
-
subject.parse("{name}{spaces}{desc}", args)
|
92
|
-
end
|
93
|
-
|
94
|
-
it "calculates the correct number of spaces" do
|
95
|
-
args = {"name" => "a long name", "desc" => "|a short desc"}
|
96
|
-
subject.parse("{name}{spaces}{desc}", args).split('|')[0].size.should == 30
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe "#parse_format" do
|
101
|
-
it "inserts the arguments into the format" do
|
102
|
-
subject.parse_format(
|
103
|
-
"{desc}{name}", {'desc' => 'a', 'name' => 'b'}
|
104
|
-
).should == "ab"
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
end
|