clive 0.8.1 → 1.0.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.
- 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
|