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
@@ -0,0 +1,129 @@
1
+ $: << File.dirname(__FILE__) + '/../..'
2
+ require 'helper'
3
+
4
+ describe Clive::Formatter::Colour do
5
+
6
+ let :clive do
7
+ Clive.new {
8
+
9
+ header 'Usage: clive_test.rb [command] [options]'
10
+ footer 'Further help is available online'
11
+
12
+ opt :version, :tail => true
13
+
14
+ opt :S, :super_size, :head => true
15
+ bool :a, :auto
16
+ opt :s, :size, 'Size of thing', :arg => '<size>'
17
+
18
+
19
+ desc 'A super long description for a super stupid option, this should test the _extreme_ wrapping abilities as it should all be aligned. Maybe I should go for another couple of lines just for good measure. That\'s all'
20
+ opt :complex, :arg => '[<one>] <two> [<three>]'
21
+
22
+ command :new, 'Creates new things', :arg => '<dir>' do
23
+ opt :type, :in => %w(post page blog), :default => :page
24
+ opt :force, 'Force overwrite'
25
+ end
26
+ }
27
+ end
28
+
29
+ subject { Clive::Formatter::Colour }
30
+
31
+ describe '#to_s' do
32
+
33
+ it 'builds the help string' do
34
+ this {
35
+ clive.run s('help'), :formatter => subject.new(:width => 80)
36
+ }.must_output <<EOS
37
+ Usage: clive_test.rb [command] [options]
38
+
39
+ Commands:
40
+ new <dir> \e[90m# \e[0m\e[90mCreates new things\e[0m
41
+ help [<command>] \e[90m# \e[0m\e[90mDisplay help\e[0m
42
+
43
+ Options:
44
+ -S, --super-size
45
+ -a, --[no-]auto
46
+ --complex [<one>] <two> [<three>] \e[90m# \e[0m\e[90mA super long description for a
47
+ super stupid option, this should
48
+ test the _extreme_ wrapping
49
+ abilities as it should all be
50
+ aligned. Maybe I should go for
51
+ another couple of lines just for
52
+ good measure. That's all\e[0m
53
+ -s, --size <size> \e[90m# \e[0m\e[90mSize of thing\e[0m
54
+ -h, --help \e[90m# \e[0m\e[90mDisplay this help message\e[0m
55
+ --version
56
+
57
+ Further help is available online
58
+ EOS
59
+ end
60
+
61
+ it 'obeys minimum ratio' do
62
+ this {
63
+ clive.run s('help'), :formatter => subject.new(:width => 80, :min_ratio => 0.7)
64
+ }.must_output r = <<EOS
65
+ Usage: clive_test.rb [command] [options]
66
+
67
+ Commands:
68
+ new <dir> \e[90m# \e[0m\e[90mCreates new things\e[0m
69
+ help [<command>] \e[90m# \e[0m\e[90mDisplay help\e[0m
70
+
71
+ Options:
72
+ -S, --super-size
73
+ -a, --[no-]auto
74
+ --complex [<one>] <two> [<three>] \e[90m# \e[0m\e[90mA super long
75
+ description for a
76
+ super stupid option,
77
+ this should test the
78
+ _extreme_ wrapping
79
+ abilities as it
80
+ should all be
81
+ aligned. Maybe I
82
+ should go for
83
+ another couple of
84
+ lines just for good
85
+ measure. That's all\e[0m
86
+ -s, --size <size> \e[90m# \e[0m\e[90mSize of thing\e[0m
87
+ -h, --help \e[90m# \e[0m\e[90mDisplay this help
88
+ message\e[0m
89
+ --version
90
+
91
+ Further help is available online
92
+ EOS
93
+ #------------------------------------------------------------------------------| 80
94
+ # |======================| 24
95
+
96
+
97
+ end
98
+
99
+ it 'obeys the maximum ratio' do
100
+ this {
101
+ clive.run s('help'), :formatter => subject.new(:width => 80, :min_ratio => 0, :max_ratio => 0.3)
102
+ }.must_output <<EOS
103
+ Usage: clive_test.rb [command] [options]
104
+
105
+ Commands:
106
+ new <dir> \e[90m# \e[0m\e[90mCreates new things\e[0m
107
+ help [<command>] \e[90m# \e[0m\e[90mDisplay help\e[0m
108
+
109
+ Options:
110
+ -S, --super-size
111
+ -a, --[no-]auto
112
+ --complex [<one>] <two> [<three>]
113
+ \e[90m# \e[0m\e[90mA super long description for a super stupid option,
114
+ this should test the _extreme_ wrapping abilities as
115
+ it should all be aligned. Maybe I should go for
116
+ another couple of lines just for good measure.
117
+ That's all\e[0m
118
+ -s, --size <size> \e[90m# \e[0m\e[90mSize of thing\e[0m
119
+ -h, --help \e[90m# \e[0m\e[90mDisplay this help message\e[0m
120
+ --version
121
+
122
+ Further help is available online
123
+ EOS
124
+ #======================| #
125
+ #------------------------------------------------------------------------------|
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,129 @@
1
+ $: << File.dirname(__FILE__) + '/../..'
2
+ require 'helper'
3
+
4
+ describe Clive::Formatter::Plain do
5
+
6
+ let :clive do
7
+ Clive.new {
8
+
9
+ header 'Usage: clive_test.rb [command] [options]'
10
+ footer 'Further help is available online'
11
+
12
+ opt :version, :tail => true
13
+
14
+ opt :S, :super_size, :head => true
15
+ bool :a, :auto
16
+ opt :s, :size, 'Size of thing', :arg => '<size>'
17
+
18
+
19
+ desc 'A super long description for a super stupid option, this should test the _extreme_ wrapping abilities as it should all be aligned. Maybe I should go for another couple of lines just for good measure. That\'s all'
20
+ opt :complex, :arg => '[<one>] <two> [<three>]'
21
+
22
+ command :new, 'Creates new things', :arg => '<dir>' do
23
+ opt :type, :in => %w(post page blog), :default => :page
24
+ opt :force, 'Force overwrite'
25
+ end
26
+ }
27
+ end
28
+
29
+ subject { Clive::Formatter::Plain }
30
+
31
+ describe '#to_s' do
32
+
33
+ it 'builds the help string' do
34
+ this {
35
+ clive.run s('help'), :formatter => subject.new(:width => 80)
36
+ }.must_output <<EOS
37
+ Usage: clive_test.rb [command] [options]
38
+
39
+ Commands:
40
+ new <dir> # Creates new things
41
+ help [<command>] # Display help
42
+
43
+ Options:
44
+ -S, --super-size
45
+ -a, --[no-]auto
46
+ --complex [<one>] <two> [<three>] # A super long description for a
47
+ super stupid option, this should
48
+ test the _extreme_ wrapping
49
+ abilities as it should all be
50
+ aligned. Maybe I should go for
51
+ another couple of lines just for
52
+ good measure. That's all
53
+ -s, --size <size> # Size of thing
54
+ -h, --help # Display this help message
55
+ --version
56
+
57
+ Further help is available online
58
+ EOS
59
+ end
60
+
61
+ it 'obeys minimum ratio' do
62
+ this {
63
+ clive.run s('help'), :formatter => subject.new(:width => 80, :min_ratio => 0.7)
64
+ }.must_output r = <<EOS
65
+ Usage: clive_test.rb [command] [options]
66
+
67
+ Commands:
68
+ new <dir> # Creates new things
69
+ help [<command>] # Display help
70
+
71
+ Options:
72
+ -S, --super-size
73
+ -a, --[no-]auto
74
+ --complex [<one>] <two> [<three>] # A super long
75
+ description for a
76
+ super stupid option,
77
+ this should test the
78
+ _extreme_ wrapping
79
+ abilities as it
80
+ should all be
81
+ aligned. Maybe I
82
+ should go for
83
+ another couple of
84
+ lines just for good
85
+ measure. That's all
86
+ -s, --size <size> # Size of thing
87
+ -h, --help # Display this help
88
+ message
89
+ --version
90
+
91
+ Further help is available online
92
+ EOS
93
+ #------------------------------------------------------------------------------| 80
94
+ # |======================| 24
95
+
96
+
97
+ end
98
+
99
+ it 'obeys the maximum ratio' do
100
+ this {
101
+ clive.run s('help'), :formatter => subject.new(:width => 80, :min_ratio => 0, :max_ratio => 0.3)
102
+ }.must_output <<EOS
103
+ Usage: clive_test.rb [command] [options]
104
+
105
+ Commands:
106
+ new <dir> # Creates new things
107
+ help [<command>] # Display help
108
+
109
+ Options:
110
+ -S, --super-size
111
+ -a, --[no-]auto
112
+ --complex [<one>] <two> [<three>]
113
+ # A super long description for a super stupid option,
114
+ this should test the _extreme_ wrapping abilities as
115
+ it should all be aligned. Maybe I should go for
116
+ another couple of lines just for good measure.
117
+ That's all
118
+ -s, --size <size> # Size of thing
119
+ -h, --help # Display this help message
120
+ --version
121
+
122
+ Further help is available online
123
+ EOS
124
+ #======================| #
125
+ #------------------------------------------------------------------------------|
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,92 @@
1
+ $: << File.dirname(__FILE__) + '/../..'
2
+ require 'helper'
3
+
4
+ describe Clive::Option::Runner do
5
+ subject { Clive::Option::Runner }
6
+
7
+ describe '#_run' do
8
+ it 'executes the function passed within it' do
9
+ this {
10
+ subject._run({}, {}, proc { puts self.name })
11
+ }.must_output "Clive::Option::Runner\n"
12
+ end
13
+ end
14
+
15
+ describe '#get' do
16
+ it 'gets a value from state' do
17
+ this {
18
+ subject._run({}, {:a => 1}, proc { puts get(:a) })
19
+ }.must_output "1\n"
20
+ end
21
+ end
22
+
23
+ describe '#set' do
24
+ it 'sets a value to state' do
25
+ state = {}
26
+ subject._run({}, state, proc { set(:a, 1) })
27
+ state[:a].must_equal 1
28
+ end
29
+ end
30
+
31
+ describe '#update' do
32
+ it 'updates a state value using a method' do
33
+ state = {:name => 'John Doe'}
34
+ subject._run({}, state, proc {
35
+ update :name, :upcase
36
+ })
37
+ state[:name].must_equal "JOHN DOE"
38
+ end
39
+
40
+ it 'updates a state value using a method with arguments' do
41
+ state = {:line => "A man a plan a canal"}
42
+ subject._run({}, state, proc {
43
+ update :line, :gsub, /[Aa]/, 'i'
44
+ })
45
+ state[:line].must_equal "i min i plin i cinil"
46
+ end
47
+
48
+ it 'updates a state value using a block' do
49
+ state = {:list => []}
50
+ subject._run({}, state, proc {
51
+ update(:list) {|l| l << 1 }
52
+ })
53
+ state[:list].must_equal [1]
54
+ end
55
+
56
+ it 'raises an exception if arguments are missing' do
57
+ this {
58
+ subject._run({}, {}, proc { update(:a) })
59
+ }.must_raise ArgumentError
60
+ end
61
+ end
62
+
63
+ describe '#has?' do
64
+ it 'is true if the state contains the key' do
65
+ this {
66
+ subject._run({}, {:key => nil}, proc { puts has?(:key) })
67
+ }.must_output "true\n"
68
+ end
69
+
70
+ it 'is false if the state does not have the key' do
71
+ this {
72
+ subject._run({}, {}, proc { puts has?(:key) })
73
+ }.must_output "false\n"
74
+ end
75
+
76
+ end
77
+
78
+ describe '#method_missing' do
79
+ it 'makes the arguments available by name' do
80
+ this {
81
+ subject._run({:a => 1}, {}, proc { puts a })
82
+ }.must_output "1\n"
83
+ end
84
+
85
+ it 'passes unknown calls to super' do
86
+ this {
87
+ subject.run({}, {}, proc { puts z })
88
+ }.must_raise NoMethodError
89
+ end
90
+ end
91
+
92
+ end
@@ -1,34 +1,160 @@
1
- require 'spec_helper'
1
+ $: << File.dirname(__FILE__) + '/..'
2
+ require 'helper'
2
3
 
3
4
  describe Clive::Option do
4
- subject { Clive::Option.new([:n, :names], "A test option") { $stdout.puts "hi" } }
5
+ subject { Clive::Option }
5
6
 
6
- it_behaves_like "an option"
7
-
8
- describe "#run" do
9
- it "calls the block" do
10
- $stdout.should_receive(:puts).with("hi")
11
- subject.run
7
+ def option_with(config, &block)
8
+ Clive::Option.new [:o, :opt], "", config, &block
9
+ end
10
+
11
+ describe '#initialize' do
12
+ it 'sorts names by size' do
13
+ subject.new([:zz, :a]).names.must_equal [:a, :zz]
14
+ subject.new([:aa, :z]).names.must_equal [:z, :aa]
15
+ end
16
+
17
+ let(:opt) { option_with :head => true, :args => '<a> <b>', :as => [String, Integer] }
18
+
19
+ it 'finds all options' do
20
+ opt.config.must_include :head
21
+ opt.config.wont_include :args
22
+ end
23
+
24
+ it 'uses default options when not set' do
25
+ opt.config.must_include :runner
26
+ end
27
+
28
+ describe 'setting :head' do
29
+ it 'is true if head is set to true' do
30
+ option_with(:head => true).config.must_contain :head => true
31
+ end
32
+
33
+ it 'is false otherwise' do
34
+ option_with({}).config.must_contain :head => false
35
+ end
36
+ end
37
+
38
+ describe 'setting :tail' do
39
+ it 'is true if tail is set to true' do
40
+ option_with(:tail => true).config.must_contain :tail => true
41
+ end
42
+
43
+ it 'is false otherwise' do
44
+ option_with({}).config.must_contain :tail => false
45
+ end
46
+ end
47
+
48
+ describe 'setting :boolean' do
49
+ it 'is true if boolean is set to true' do
50
+ option_with(:boolean => true).config.must_contain :boolean => true
51
+ end
52
+
53
+ it 'is false otherwise' do
54
+ option_with({}).config.must_contain :boolean => false
55
+ end
56
+ end
57
+
58
+ it 'creates the args list' do
59
+ opt.args.first.must_be_argument :name => :a, :type => Clive::Type::String
60
+ opt.args.last.must_be_argument :name => :b, :type => Clive::Type::Integer
12
61
  end
13
62
  end
14
-
15
- describe "#sort_name" do
16
- it "returns the name to sort by" do
17
- subject.sort_name.should == 'n'
63
+
64
+ describe '#name' do
65
+ it 'returns the long name' do
66
+ opt = subject.new [:opt, :o]
67
+ opt.name.must_equal :opt
68
+ end
69
+
70
+ it 'returns the short name if no long name exists' do
71
+ opt = subject.new [:o]
72
+ opt.name.must_equal :o
73
+ end
74
+ end
75
+
76
+ describe '#to_s' do
77
+ it 'returns a string representation of the option' do
78
+ opt = subject.new [:o, :opt]
79
+ opt.to_s.must_equal "-o, --opt"
80
+ end
81
+
82
+ it 'adds a --[no-] prefix to boolean options' do
83
+ opt = subject.new [:o, :opt], "", :boolean => true
84
+ opt.to_s.must_equal "-o, --[no-]opt"
85
+ end
86
+
87
+ it 'uses dashes instead of underscores' do
88
+ opt = subject.new [:S, :super_long_option_name]
89
+ opt.to_s.must_equal "-S, --super-long-option-name"
18
90
  end
19
91
  end
20
-
21
- describe "#<=>" do
22
- it "sorts by #sort_name" do
23
- other = Clive::Option.new([:z, :apple], "Another") {}
24
- (subject <=> other).should == -1
92
+
93
+ describe '#run' do
94
+ let(:block) { proc {} }
95
+
96
+ it 'calls Runner#_run with true if #boolean?' do
97
+ t = mock
98
+ t.expects(:_run).with([[:truth, true]], {}, block)
99
+ ot = option_with :boolean => true, :runner => t, &block
100
+ ot.run({}, [true])
101
+ end
102
+
103
+ it 'calls Runner#_run with false if #boolean?' do
104
+ f = mock
105
+ f.expects(:_run).with([[:truth, false]], {}, block)
106
+ of = option_with :boolean => true, :runner => f, &block
107
+ of.run({}, [false])
108
+ end
109
+
110
+ it 'calls Runner#_run with mapped args' do
111
+ r = mock
112
+ r.expects(:_run).with([[:a, 'a'], [:b, 'b']], {}, block)
113
+ o = option_with :args => '<a> <b>', :runner => r, &block
114
+ o.run({}, ['a', 'b'])
115
+ end
116
+
117
+ it 'sets state if no block exists' do
118
+ o = option_with :args => '<a> <b>'
119
+ state = Clive::StructHash.new
120
+ o.run state, ['a', 'b']
121
+ state[:opt].must_equal ['a', 'b']
25
122
  end
26
123
  end
27
-
28
- describe "#to_h" do
29
- it "returns a hash for help" do
30
- hsh = {"names" => subject.names_to_strings, "desc" => subject.desc}
31
- subject.to_h.should == hsh
124
+
125
+ describe '#<=>' do
126
+ let(:heada) { subject.new [:a], "", :head => true }
127
+ let(:headz) { subject.new [:z], "", :head => true }
128
+ let(:taila) { subject.new [:a], "", :tail => true }
129
+ let(:tailz) { subject.new [:z], "", :tail => true }
130
+ let(:aaa) { subject.new [:aaa] }
131
+ let(:zzz) { subject.new [:zzz] }
132
+
133
+ it 'puts head?s first' do
134
+ heada.must_be :<, aaa
135
+ heada.must_be :<, zzz
136
+ end
137
+
138
+ it 'compares 2 head?s alphabetically' do
139
+ heada.must_be :<, headz
140
+ end
141
+
142
+ it 'puts tail?s last' do
143
+ taila.must_be :>, aaa
144
+ taila.must_be :>, zzz
145
+ end
146
+
147
+ it 'compares 2 tail?s alphabetically' do
148
+ taila.must_be :<, tailz
149
+ end
150
+
151
+ it 'compares options based on #name' do
152
+ aaa.must_be :<, zzz
153
+ end
154
+
155
+ it 'sorts options properly' do
156
+ [taila, headz, tailz, zzz, heada, aaa].sort.
157
+ must_equal [heada, headz, aaa, zzz, taila, tailz]
32
158
  end
33
159
  end
34
- end
160
+ end