clive 0.6.2 → 0.7.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.
@@ -1,7 +1,8 @@
1
- class Clive
2
-
1
+ module Clive
2
+
3
3
  # A switch which can be triggered with either --no-[name] and --[name].
4
- # The 'truthness' of this is then passed to the block.
4
+ # The 'truth' of this is then passed to the block.
5
+ #
5
6
  class Bool < Option
6
7
  attr_accessor :truth
7
8
 
@@ -13,27 +14,27 @@ class Clive
13
14
  # +short+ and/or +desc+ can be omitted when creating a Boolean, all
14
15
  # other arguments must be present.
15
16
  #
16
- # @overload initialize(short, long, desc, truth, &block)
17
- # Creates a new boolean switch
18
- # @param [Symbol] short single character to use
19
- # @param [Symbol] long word/longer name for boolean switch
20
- # @param [String] desc description of use/purpose
17
+ # @param names [Array[Symbol]]
18
+ # Names that the boolean switch can be called with, must include
19
+ # a long name (eg. 2 or more characters) so that the --no- can
20
+ # be prefixed.
21
+ #
22
+ # @param desc [String]
23
+ # A description of the bool.
24
+ #
25
+ # @param truth [true, false]
26
+ # Truth of the switch to create.
21
27
  #
22
- # @yield [Boolean] A block to be run when the switch is triggered
23
- # @raise [MissingLongName] raises when a long name is not given
28
+ # @yield [true, false] A block to be run when the switch is triggered
29
+ # @raise [MissingLongName] Raised when a long name is not given
24
30
  #
25
- def initialize(*args, truth, &block)
31
+ def initialize(names, desc, truth, &block)
26
32
  @names = []
27
- args.each do |i|
28
- case i
29
- when Symbol
30
- if truth
31
- @names << i.to_s
32
- else
33
- @names << "no-#{i.to_s}" if i.length > 1
34
- end
35
- when String
36
- @desc = i
33
+ names.each do |i|
34
+ if truth
35
+ @names << i.to_s
36
+ else
37
+ @names << "no-#{i.to_s}" if i.length > 1
37
38
  end
38
39
  end
39
40
 
@@ -42,27 +43,24 @@ class Clive
42
43
  raise MissingLongName, @names[0]
43
44
  end
44
45
 
46
+ @desc = desc
45
47
  @truth = truth
46
48
  @block = block
47
49
  end
48
50
 
49
- # Run the block with +@truth+
51
+ # Run the block with the switches truth.
50
52
  def run
51
53
  @block.call(@truth)
52
54
  end
53
55
 
54
- # @param [Integer] width the total ideal width of help
55
- # @param [Integer] prepend the number of spaces to add before each line
56
- # @return [String] summary for help or nil if +@truth = false+
57
- def summary(width=30, prepend=5)
58
- return nil unless @truth
59
-
60
- n = names_to_strings(true).join(', ')
61
- spaces = width-n.length
62
- spaces = 1 if spaces < 1
63
- s = spaces(spaces)
64
- p = spaces(prepend)
65
- "#{p}#{n}#{s}#{@desc}"
56
+ # Should only return a hash when this is the 'true' switch.
57
+ # @see Clive::Option#to_h
58
+ def to_h
59
+ if @truth
60
+ {'names' => names_to_strings(true), 'desc' => @desc}
61
+ else
62
+ nil
63
+ end
66
64
  end
67
65
 
68
66
  end
@@ -1,4 +1,4 @@
1
- class Clive
1
+ module Clive
2
2
 
3
3
  # A string which describes the command to execute
4
4
  # eg. git add
@@ -8,18 +8,18 @@ class Clive
8
8
 
9
9
  attr_accessor :options, :commands
10
10
  attr_accessor :argv, :base
11
- attr_accessor :header, :footer
11
+ attr_reader :names, :current_desc
12
12
 
13
13
  # Create a new Command instance
14
14
  #
15
15
  # @overload initialize(base, &block)
16
16
  # Creates a new base Command to house everything else
17
- # @param [Boolean] base whether the command is the base
17
+ # @param base [Boolean] whether the command is the base
18
18
  #
19
- # @overload initialize(name, desc, &block)
19
+ # @overload initialize(names, desc, &block)
20
20
  # Creates a new Command as part of the base Command
21
- # @param [Symbol] name the name of the command
22
- # @param [String] desc the description of the command
21
+ # @param names [Symbol] the name of the command
22
+ # @param desc [String] the description of the command
23
23
  #
24
24
  # @yield A block to run, containing switches, flags and commands
25
25
  #
@@ -47,10 +47,15 @@ class Clive
47
47
  @block = block
48
48
  end
49
49
 
50
- @header = "Usage: #{File.basename($0, '.*')} "
51
- @header << (@base ? "[commands]" : @names.join(', '))
52
- @header << " [options]"
50
+ # Create basic header "Usage: filename [command] [options]
51
+ # or "Usage: filename commandname(s) [options]
52
+ @header = "Usage: #{File.basename($0, '.*')} " <<
53
+ (@base ? "[command]" : @names.join(', ')) <<
54
+ " [options]"
55
+
53
56
  @footer = nil
57
+ @current_desc = ""
58
+ help_formatter :default
54
59
 
55
60
  self.build_help
56
61
  end
@@ -146,7 +151,7 @@ class Clive
146
151
  pre_command << i
147
152
  end
148
153
  end
149
-
154
+
150
155
  post_command = Tokens.new(tokens.array - pre_command - [command])
151
156
  pre_command_tokens = parse(pre_command)
152
157
  r = pre_command_tokens
@@ -179,7 +184,7 @@ class Clive
179
184
  else
180
185
  if k == :word
181
186
  # add to last flag?
182
- if r.last && r.last[0] == :flag && r.last.size - 2 < r.last[1].args.size
187
+ if r.last && r.last[0] == :flag && r.last.size - 2 < r.last[1].arg_size
183
188
  r.last.push(v)
184
189
  else
185
190
  r << [:argument, v]
@@ -192,13 +197,16 @@ class Clive
192
197
  r
193
198
  end
194
199
 
195
- # @group Missing Helpers
200
+ def to_h
201
+ {
202
+ 'names' => @names,
203
+ 'desc' => @desc
204
+ }
205
+ end
196
206
 
197
- def option_missing(&block)
198
- @option_missing = block
199
- end
207
+
200
208
 
201
- # @group Creators
209
+ # @group DSL
202
210
 
203
211
  # Add a new command to +@commands+
204
212
  #
@@ -211,19 +219,35 @@ class Clive
211
219
  # and flags
212
220
  #
213
221
  def command(*args, &block)
214
- @commands << Command.new(*args, &block)
222
+ @commands << Command.new(*args, @current_desc, &block)
223
+ @current_desc = ""
215
224
  end
216
225
 
217
226
  # Add a new switch to +@switches+
218
227
  # @see Switch#initialize
219
228
  def switch(*args, &block)
220
- @options << Switch.new(*args, &block)
229
+ @options << Switch.new(args, @current_desc, &block)
230
+ @current_desc = ""
221
231
  end
222
232
 
223
233
  # Adds a new flag to +@flags+
224
234
  # @see Flag#initialize
225
235
  def flag(*args, &block)
226
- @options << Flag.new(*args, &block)
236
+ names = []
237
+ arg = []
238
+ args.each do |i|
239
+ if i.is_a? Symbol
240
+ names << i
241
+ else
242
+ if i[:arg]
243
+ arg << i[:arg]
244
+ else
245
+ arg << i[:args]
246
+ end
247
+ end
248
+ end
249
+ @options << Flag.new(names, @current_desc, arg, &block)
250
+ @current_desc = ""
227
251
  end
228
252
 
229
253
  # Creates a boolean switch. This is done by adding two switches of
@@ -232,21 +256,48 @@ class Clive
232
256
  #
233
257
  # @see Bool#initialize
234
258
  def bool(*args, &block)
235
- @options << Bool.new(*args, true, &block)
236
- @options << Bool.new(*args, false, &block)
259
+ @options << Bool.new(args, @current_desc, true, &block)
260
+ @options << Bool.new(args, @current_desc, false, &block)
261
+ @current_desc= ""
237
262
  end
238
263
 
239
- # @group Help
240
-
241
- # This actually creates a switch with "-h" and "--help" that controls
242
- # the help on this command.
243
- def build_help
244
- @options << Switch.new(:h, :help, "Display help") do
245
- puts self.help
246
- exit 0
264
+ # Add a description for the next option in the class. Or acts as an
265
+ # accessor for @desc.
266
+ #
267
+ # @example
268
+ #
269
+ # class CLI
270
+ # include Clive::Parser
271
+ #
272
+ # desc 'Force build docs'
273
+ # switch :force do
274
+ # # code
275
+ # end
276
+ # end
277
+ #
278
+ def desc(str=nil)
279
+ if str
280
+ @current_desc = str
281
+ else
282
+ @desc
247
283
  end
248
284
  end
249
285
 
286
+ # Define a block to execute when the option to execute cannot be found.
287
+ #
288
+ # @example
289
+ #
290
+ # class CLI
291
+ # include Clive::Parser
292
+ #
293
+ # option_missing do |name|
294
+ # puts "#{name} couldn't be found"
295
+ # end
296
+ #
297
+ def option_missing(&block)
298
+ @option_missing = block
299
+ end
300
+
250
301
  # Set the header
251
302
  def header(val)
252
303
  @header = val
@@ -257,40 +308,106 @@ class Clive
257
308
  @footer = val
258
309
  end
259
310
 
260
- def summary(width=30, prepend=5)
261
- a = @names.sort.join(', ')
262
- b = @desc
263
- s = spaces(width-a.length)
264
- p = spaces(prepend)
265
- "#{p}#{a}#{s}#{b}"
266
- end
311
+ # @group Help
267
312
 
313
+ # This actually creates a switch with "-h" and "--help" that controls
314
+ # the help on this command.
315
+ def build_help
316
+ @options << Switch.new([:h, :help], "Display help") do
317
+ puts self.help
318
+ exit 0
319
+ end
320
+ end
321
+
268
322
  # Generate the summary for help, show all flags and switches, but do not
269
323
  # show the flags and switches within each command. Should also prepend the
270
324
  # header and append the footer if set.
271
- def help(width=30, prepend=5)
272
- summary = "#{@header}\n"
325
+ def help
326
+ @formatter.format(@header, @footer, @commands, @options)
327
+ end
328
+
329
+ # This allows you to define how the output from #help looks.
330
+ #
331
+ # For this you have access to several tokens which are evaluated in an object
332
+ # with the correct values, this means you are able to use #join on arrays or
333
+ # prepend, etc. The variables (tokens) are:
334
+ #
335
+ # * prepend - a string of spaces as specified when #help_formatter is called
336
+ # * names - an array of names for the option
337
+ # * spaces - a string of spaces to align the descriptions properly
338
+ # * desc - a string of the description for the option
339
+ #
340
+ # And for flags you have access to:
341
+ #
342
+ # * args - an array of arguments for the flag
343
+ # * options - an array of options to choose from
344
+ #
345
+ #
346
+ # @overload help_formatter(args, &block)
347
+ # Create a new help formatter to use.
348
+ # @param args [Hash]
349
+ # @option args [Integer] :width Width before flexible spaces
350
+ # @option args [Integer] :prepend Width of spaces to prepend with
351
+ #
352
+ # @overload help_formatter(name)
353
+ # Use an existing help formatter.
354
+ # @param name [Symbol] name of the formatter (either +:default+ or +:white+)
355
+ #
356
+ #
357
+ # @example
358
+ #
359
+ # CLI.help_formatter do |h|
360
+ #
361
+ # h.switch "{prepend}{names.join(', ')} {spaces}{desc.grey}"
362
+ # h.bool "{prepend}{names.join(', ')} {spaces}{desc.grey}"
363
+ # h.flag "{prepend}{names.join(', ')} {args.join(' ')} {spaces}{desc.grey}"
364
+ # h.command "{prepend}{names.join(', ')} {spaces}{desc.grey}"
365
+ #
366
+ # end
367
+ #
368
+ #
369
+ def help_formatter(*args, &block)
370
+ if block_given?
371
+ width = 30
372
+ prepend = 5
273
373
 
274
- if @options.length > 0
275
- summary << "\n Options:\n"
276
- @options.sort.each do |i|
277
- next if i.names.include?("help")
278
- summary << i.summary(width, prepend) << "\n" if i.summary
374
+ unless args.empty?
375
+ args[0].each do |k,v|
376
+ case k
377
+ when :width
378
+ width = v
379
+ when :prepend
380
+ prepend = v
381
+ end
382
+ end
279
383
  end
280
- end
281
-
282
- if @commands.length > 0
283
- summary << "\n Commands:\n"
284
- @commands.sort.each do |i|
285
- summary << i.summary(width, prepend) << "\n"
384
+
385
+ @formatter = Formatter.new(width, prepend)
386
+ block.call(@formatter)
387
+ @formatter
388
+ else
389
+ case args[0]
390
+ when :default
391
+ help_formatter do |h|
392
+ h.switch "{prepend}{names.join(', ')} {spaces}{desc.grey}"
393
+ h.bool "{prepend}{names.join(', ')} {spaces}{desc.grey}"
394
+ h.flag "{prepend}{names.join(', ')} {args.join(' ')} {spaces}" <<
395
+ "{desc.grey} {options.join('(', ', ', ')').blue.bold}"
396
+ h.command "{prepend}{names.join(', ')} {spaces}{desc.grey}"
397
+ end
398
+
399
+ when :white
400
+ help_formatter do |h|
401
+ h.switch "{prepend}{names.join(', ')} {spaces}{desc}"
402
+ h.bool "{prepend}{names.join(', ')} {spaces}{desc}"
403
+ h.flag "{prepend}{names.join(', ')} {args.join(' ')} {spaces}" <<
404
+ "{desc} {options.join('(', ', ', ')').bold}"
405
+ h.command "{prepend}{names.join(', ')} {spaces}{desc}"
406
+ end
407
+
286
408
  end
287
409
  end
288
-
289
- summary << "\n#{@footer}\n" if @footer
290
-
291
- summary
292
410
  end
293
411
 
294
-
295
412
  end
296
413
  end
@@ -1,4 +1,4 @@
1
- class Clive
1
+ module Clive
2
2
 
3
3
  # General problem
4
4
  class CliveError < StandardError
@@ -23,7 +23,7 @@ class Clive
23
23
  self.reason + ': ' + args.join(' ')
24
24
  end
25
25
  alias_method :to_s, :message
26
-
26
+
27
27
  end
28
28
 
29
29
  # General problem with input
@@ -1,5 +1,4 @@
1
- class Clive
2
-
1
+ module Clive
3
2
  class Array < ::Array
4
3
 
5
4
  # If passed a Symbol or String will get the option or command with that name.
@@ -49,5 +48,24 @@ class Clive
49
48
  result
50
49
  end
51
50
 
51
+ alias_method :_join, :join
52
+
53
+ def join(*args)
54
+ case args.size
55
+ when 1
56
+ self._join(args[0])
57
+
58
+ when 2 # use second for last eg. 1, 2 and 3
59
+ self[0..-2]._join(args[0]) << args[1] << self[-1]
60
+
61
+ when 3 # prepend and append 1st and 3rd eg. (1, 2, 3)
62
+ if self[0] != ""
63
+ args[0] << self._join(args[1]) << args[2]
64
+ else
65
+ ""
66
+ end
67
+ end
68
+ end
69
+
52
70
  end
53
- end
71
+ end