clive 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,7 +6,7 @@
6
6
  #
7
7
  #
8
8
 
9
- class Clive
9
+ module Clive
10
10
  module Output
11
11
 
12
12
  end
@@ -68,23 +68,19 @@ class String
68
68
  colour("\e[4#{code}m")
69
69
  end
70
70
 
71
- # Light white doesn't exist
72
- unless name == "white"
73
- # Change name to grey instead of l_black
74
- _name = "l_#{name}"
75
- if name == "black"
76
- _name = "grey"
77
- end
78
-
79
- define_method "#{_name}" do
80
- colour("\e[9#{code}m")
81
- end
82
-
83
- define_method "#{_name}_bg" do
84
- colour("\e[10#{code}m")
85
- end
71
+ # Change name to grey instead of l_black
72
+ l_name = "l_#{name}"
73
+ if name == "black"
74
+ l_name = "grey"
75
+ end
76
+
77
+ define_method "#{l_name}" do
78
+ colour("\e[9#{code}m")
79
+ end
80
+
81
+ define_method "#{l_name}_bg" do
82
+ colour("\e[10#{code}m")
86
83
  end
87
- end
88
84
 
85
+ end
89
86
  end
90
-
@@ -8,7 +8,11 @@ require 'clive/switch'
8
8
  require 'clive/flag'
9
9
  require 'clive/bool'
10
10
 
11
- class Clive
11
+ require 'clive/output'
12
+ require 'clive/formatter'
13
+
14
+
15
+ module Clive
12
16
 
13
17
  # A module wrapping the command line parsing of clive. In the future this
14
18
  # will be the only way of using clive.
@@ -19,11 +23,7 @@ class Clive
19
23
  #
20
24
  # class CLI
21
25
  # include Clive::Parser
22
- #
23
- # @@opts ||= {}
24
- # def self.opts
25
- # @@opts
26
- # end
26
+ # option_hash :opts
27
27
  #
28
28
  # switch :v, :verbose, "Run verbosely" do
29
29
  # opts[:verbose] = true
@@ -34,32 +34,95 @@ class Clive
34
34
  # p CLI.opts
35
35
  #
36
36
  module Parser
37
-
37
+
38
+ # When the module is included we need to keep track of the new class it
39
+ # is now in and we need to create a new base command. So here instance
40
+ # variables are set directly in the new class, and the class is made to
41
+ # extend the methods in Parser so they are available as class methods.
42
+ #
38
43
  def self.included(klass)
39
- @@klass = klass
40
- @@klass.extend(self)
41
- @@base = Clive::Command.new(true)
44
+ klass.instance_variable_set("@klass", klass)
45
+ klass.extend(self)
46
+ klass.instance_variable_set "@base", Clive::Command.new(true)
42
47
  end
43
-
48
+
49
+ # @return [Clive::Command]
50
+ # The base command to forward method calls to.
51
+ #
52
+ def base; @base; end
53
+
54
+ # @see Clive::Command#run
44
55
  def parse(argv)
45
- @@base.run(argv)
56
+ base.run(argv)
46
57
  end
47
58
 
59
+ # @see Clive::Command#flag
48
60
  def flag(*args, &block)
49
- @@base.flag(*args, &block)
61
+ base.flag(*args, &block)
50
62
  end
51
63
 
64
+ # @see Clive::Command#switch
52
65
  def switch(*args, &block)
53
- @@base.switch(*args, &block)
66
+ base.switch(*args, &block)
54
67
  end
55
68
 
69
+ # @see Clive::Command#command
56
70
  def command(*args, &block)
57
- @@base.command(*args, &block)
71
+ base.command(*args, &block)
58
72
  end
59
73
 
74
+ # @see Clive::Command#bool
60
75
  def bool(*args, &block)
61
- @@base.bool(*args, &block)
76
+ base.bool(*args, &block)
77
+ end
78
+
79
+ # @see Clive::Command#desc
80
+ def desc(*args)
81
+ base.desc(*args)
82
+ end
83
+
84
+ # @see Clive::Command#help_formatter
85
+ def help_formatter(*args, &block)
86
+ base.help_formatter(*args, &block)
87
+ end
88
+
89
+
90
+ # @see http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
91
+ # or because that doesn't exist anymore from this mirror
92
+ # http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html
93
+ #
94
+ def meta_def(name, &blk)
95
+ (class << self; self; end).instance_eval { define_method(name, &blk) }
96
+ end
97
+
98
+ def option_var(name, value=nil)
99
+ @klass.meta_def(name) do
100
+ instance_variable_get("@#{name}")
101
+ end
102
+ @klass.meta_def("#{name}=") do |val|
103
+ instance_variable_set("@#{name}", val)
104
+ end
105
+ instance_variable_set("@#{name}", value)
106
+ end
107
+
108
+ # Create a new hash which is accessible to the options in the new class
109
+ # but can also be accessed from outside the class. Defines getters and
110
+ # setters for the symbols given, and sets their initial value to +{}+.
111
+ #
112
+ # @param args [Symbol]
113
+ #
114
+ def option_hash(*args)
115
+ args.each do |arg|
116
+ option_var(arg, {})
117
+ end
118
+ end
119
+
120
+ def option_array(*args)
121
+ args.each do |arg|
122
+ option_var(arg, [])
123
+ end
62
124
  end
125
+ alias_method :option_list, :option_array
63
126
 
64
127
  end
65
128
  end
@@ -1,4 +1,4 @@
1
- class Clive
1
+ module Clive
2
2
 
3
3
  # A string that takes no argument, beginning with one or two dashes
4
4
  # eg. ruby --version
@@ -8,26 +8,17 @@ class Clive
8
8
 
9
9
  # Create a new Switch instance.
10
10
  #
11
- # +short+ _or_ +long+ may be omitted but not both.
11
+ # @param names [Array[Symbol]]
12
+ # An array of names the option can be invoked by.
12
13
  #
13
- # @overload switch(short, long, desc, &block)
14
- # Creates a new switch
15
- # @param [Symbol] short single character for short switch, eg. +:v+ => +-v+
16
- # @param [Symbol] long longer switch to be used, eg. +:verbose+ => +--verbose+
17
- # @param [String] desc the description for the switch
14
+ # @param desc [String]
15
+ # A description of what the option does.
18
16
  #
19
17
  # @yield A block to run if the switch is triggered
20
18
  #
21
- def initialize(*args, &block)
22
- @names = []
23
- args.each do |i|
24
- case i
25
- when Symbol
26
- @names << i.to_s
27
- when String
28
- @desc = i
29
- end
30
- end
19
+ def initialize(names, desc, &block)
20
+ @names = names.map(&:to_s)
21
+ @desc = desc
31
22
  @block = block
32
23
  end
33
24
 
@@ -1,4 +1,4 @@
1
- class Clive
1
+ module Clive
2
2
 
3
3
  # A subclass of Array to allow the creation of arrays that look
4
4
  # like:
@@ -1,3 +1,3 @@
1
- class Clive
2
- VERSION = '0.6.2'
1
+ module Clive
2
+ VERSION = '0.7.0'
3
3
  end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Clive::Bool do
4
+
5
+ subject { Clive::Bool.new([:n, :name], "A test", true) {|arg| puts arg } }
6
+ let(:falsey) { Clive::Bool.new([:n, :name], "A test", false) {|arg| 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
@@ -0,0 +1,260 @@
1
+ require 'spec_helper'
2
+
3
+ describe Clive::Command do
4
+
5
+ context "when creating a base command" do
6
+ subject { Clive::Command.new(true) {} }
7
+ end
8
+
9
+ subject {
10
+ Clive::Command.new(:co, :comm, "A command") do
11
+ bool(:boo) {}
12
+ switch(:swi) {}
13
+ flag(:fla) {}
14
+ command(:com) {}
15
+ end
16
+ }
17
+
18
+ it_behaves_like "an option"
19
+
20
+ describe "#initialize" do
21
+ subject {
22
+ Clive::Command.new(:com, "A command") do
23
+ flag(:test)
24
+ end
25
+ }
26
+
27
+ it "generates a help header" do
28
+ File.stub!(:basename).and_return("test")
29
+ subject.instance_variable_get("@header").should == "Usage: test com [options]"
30
+ end
31
+
32
+ it "generates an option missing proc" do
33
+ proc = subject.instance_variable_get("@option_missing")
34
+ expect {
35
+ proc.call("hey")
36
+ }.should raise_error Clive::NoOptionError
37
+ end
38
+
39
+ it "sets the help formatter to :default" do
40
+ formatter = subject.instance_variable_get("@help_formatter")
41
+ formatter.should == subject.help_formatter(:default)
42
+ end
43
+
44
+ it "doesn't run the block given" do
45
+ subject.flags.size.should == 0
46
+ end
47
+
48
+ it "generates a help switch" do
49
+ subject.switches.map {|i| i.names}.should include ["h", "help"]
50
+ end
51
+ end
52
+
53
+ describe "#bools" do
54
+ it "returns an array of bools" do
55
+ subject.find
56
+ subject.bools.each do |i|
57
+ i.should be_kind_of Clive::Bool
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "#switches" do
63
+ it "returns an array of switches" do
64
+ subject.find
65
+ subject.switches.each do |i|
66
+ i.should be_kind_of Clive::Switch
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "#flags" do
72
+ it "returns an array of flags" do
73
+ subject.find
74
+ subject.flags.each do |i|
75
+ i.should be_kind_of Clive::Flag
76
+ end
77
+ end
78
+ end
79
+
80
+ describe "#find" do
81
+ it "runs the block for the command" do
82
+ subject.flags.size.should == 0
83
+ subject.find
84
+ subject.flags.size.should == 1
85
+ end
86
+
87
+ it "sets the block to nil" do
88
+ subject.find
89
+ subject.block.should be_nil
90
+ end
91
+ end
92
+
93
+ describe "#run" do
94
+ it "returns an array of unused arguments" do
95
+ subject.find
96
+ subject.run(%w(--swi what)).should == ['what']
97
+ end
98
+ end
99
+
100
+ describe "#tokenize" do
101
+ it "returns an array of tokens" do
102
+ subject.find
103
+ res = [
104
+ [:switch, subject.bools.find {|i| i.names == ["boo"] }],
105
+ [:argument, "what"]
106
+ ]
107
+ subject.tokenize(%w(--boo what)).should == res
108
+ end
109
+ end
110
+
111
+ describe "#parse" do
112
+ it "returns an array of tokens"
113
+ end
114
+
115
+ describe "#to_h" do
116
+ it "returns a hash of data for help formatting" do
117
+ hsh = {'names' => subject.names, 'desc' => subject.desc}
118
+ subject.to_h.should == hsh
119
+ end
120
+ end
121
+
122
+ describe "#command" do
123
+ it "creates a new command" do
124
+ expect {
125
+ subject.command(:comm)
126
+ }.should change {subject.commands.size}.by(1)
127
+ end
128
+
129
+ it "resets the current description" do
130
+ subject.desc 'A command'
131
+ subject.command(:comm)
132
+ subject.current_desc.should == ""
133
+ end
134
+ end
135
+
136
+ describe "#switch" do
137
+ it "creates a new switch" do
138
+ expect {
139
+ subject.switch(:s, :switch)
140
+ }.should change {subject.switches.size}.by(1)
141
+ end
142
+
143
+ it "resets the current description" do
144
+ subject.desc 'A switch'
145
+ subject.switch(:s, :switch)
146
+ subject.current_desc.should == ""
147
+ end
148
+ end
149
+
150
+ describe "#flag" do
151
+ it "creates a new flag" do
152
+ expect {
153
+ subject.flag(:f, :flag)
154
+ }.should change {subject.flags.size}.by(1)
155
+ end
156
+
157
+ it "resets the current description" do
158
+ subject.desc 'A flag'
159
+ subject.flag(:f, :flag)
160
+ subject.current_desc.should == ""
161
+ end
162
+ end
163
+
164
+ describe "#bool" do
165
+ it "creates two bool switches" do
166
+ expect {
167
+ subject.bool(:b, :bool)
168
+ }.should change {subject.bools.size}.by(2)
169
+ end
170
+
171
+ it "resets the current description" do
172
+ subject.desc 'A bool'
173
+ subject.bool(:b, :bool)
174
+ subject.current_desc.should == ""
175
+ end
176
+ end
177
+
178
+ describe "#desc" do
179
+ context "when called with no arguments" do
180
+ it "returns the description for the command" do
181
+ subject.desc.should == "A command"
182
+ end
183
+ end
184
+
185
+ context "when called with an argument" do
186
+ it "sets the current description" do
187
+ subject.desc "A new desc"
188
+ subject.instance_variable_get("@current_desc").should == "A new desc"
189
+ end
190
+ end
191
+ end
192
+
193
+ describe "#option_missing" do
194
+ it "sets the option missing proc" do
195
+ proc = lambda {|n| puts "What? #{name} doesn't exist" }
196
+ subject.option_missing(&proc)
197
+ subject.instance_variable_get("@option_missing").should == proc
198
+ end
199
+ end
200
+
201
+ describe "#header" do
202
+ it "sets the header" do
203
+ subject.header "A header"
204
+ subject.instance_variable_get("@header").should == "A header"
205
+ end
206
+ end
207
+
208
+ describe "#footer" do
209
+ it "sets the footer" do
210
+ subject.footer "A footer"
211
+ subject.instance_variable_get("@footer").should == "A footer"
212
+ end
213
+ end
214
+
215
+ describe "#build_help" do
216
+ it "adds a switch for help" do
217
+ subject.options = Clive::Array.new
218
+ subject.options.should be_empty
219
+ subject.build_help
220
+ subject.options.map(&:names).should include ['h', 'help']
221
+ end
222
+ end
223
+
224
+ describe "#help" do
225
+ it "returns a string of help" do
226
+ help = <<EOS
227
+ Usage: rspec co, comm [options]
228
+
229
+ Options:
230
+ -h, --help \e[90mDisplay help\e[0m
231
+ EOS
232
+
233
+ subject.help.should == help
234
+ end
235
+ end
236
+
237
+ describe "#help_formatter" do
238
+ context "when called with a symbol" do
239
+ it "uses the named formatter" do
240
+ before = subject.instance_variable_get("@formatter")
241
+ subject.help_formatter(:white)
242
+ subject.instance_variable_get("@formatter").should_not == before
243
+ end
244
+ end
245
+
246
+ context "when called with argumentss and a block" do
247
+ it "creates a new help formatter" do
248
+ subject.help_formatter :width => 40, :prepend => 5 do |h|
249
+ h.switch "switch"
250
+ h.bool "bool"
251
+ h.flag "flag"
252
+ h.command "command"
253
+ end
254
+ formatter = subject.instance_variable_get("@formatter")
255
+ formatter.width.should == 40
256
+ end
257
+ end
258
+ end
259
+
260
+ end