clive 0.8.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/LICENSE +1 -1
  2. data/README.md +328 -227
  3. data/lib/clive.rb +130 -50
  4. data/lib/clive/argument.rb +170 -0
  5. data/lib/clive/arguments.rb +139 -0
  6. data/lib/clive/arguments/parser.rb +210 -0
  7. data/lib/clive/base.rb +189 -0
  8. data/lib/clive/command.rb +342 -444
  9. data/lib/clive/error.rb +66 -0
  10. data/lib/clive/formatter.rb +57 -141
  11. data/lib/clive/formatter/colour.rb +37 -0
  12. data/lib/clive/formatter/plain.rb +172 -0
  13. data/lib/clive/option.rb +185 -75
  14. data/lib/clive/option/runner.rb +163 -0
  15. data/lib/clive/output.rb +141 -16
  16. data/lib/clive/parser.rb +180 -87
  17. data/lib/clive/struct_hash.rb +109 -0
  18. data/lib/clive/type.rb +117 -0
  19. data/lib/clive/type/definitions.rb +170 -0
  20. data/lib/clive/type/lookup.rb +23 -0
  21. data/lib/clive/version.rb +3 -3
  22. data/spec/clive/a_cli_spec.rb +245 -0
  23. data/spec/clive/argument_spec.rb +148 -0
  24. data/spec/clive/arguments/parser_spec.rb +35 -0
  25. data/spec/clive/arguments_spec.rb +191 -0
  26. data/spec/clive/command_spec.rb +276 -209
  27. data/spec/clive/formatter/colour_spec.rb +129 -0
  28. data/spec/clive/formatter/plain_spec.rb +129 -0
  29. data/spec/clive/option/runner_spec.rb +92 -0
  30. data/spec/clive/option_spec.rb +149 -23
  31. data/spec/clive/output_spec.rb +86 -2
  32. data/spec/clive/parser_spec.rb +201 -81
  33. data/spec/clive/struct_hash_spec.rb +82 -0
  34. data/spec/clive/type/definitions_spec.rb +312 -0
  35. data/spec/clive/type_spec.rb +107 -0
  36. data/spec/clive_spec.rb +60 -0
  37. data/spec/extras/expectations.rb +86 -0
  38. data/spec/extras/focus.rb +22 -0
  39. data/spec/helper.rb +35 -0
  40. metadata +56 -36
  41. data/lib/clive/bool.rb +0 -67
  42. data/lib/clive/exceptions.rb +0 -54
  43. data/lib/clive/flag.rb +0 -199
  44. data/lib/clive/switch.rb +0 -31
  45. data/lib/clive/tokens.rb +0 -141
  46. data/spec/clive/bool_spec.rb +0 -54
  47. data/spec/clive/flag_spec.rb +0 -117
  48. data/spec/clive/formatter_spec.rb +0 -108
  49. data/spec/clive/switch_spec.rb +0 -14
  50. data/spec/clive/tokens_spec.rb +0 -38
  51. data/spec/shared_specs.rb +0 -16
  52. data/spec/spec_helper.rb +0 -12
@@ -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
@@ -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
@@ -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
@@ -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