gli 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -39,7 +39,7 @@ Though likely works on various other versions.
39
39
 
40
40
  == Documentation
41
41
 
42
- Extensive documentation is {available at the wiki}[https://github.com/davetron5000/gli/wiki]
42
+ Extensive documentation is {available at the wiki}[https://github.com/davetron5000/gli/wiki]. For API Documentation, start with the GLI module.
43
43
 
44
44
  == Links
45
45
 
data/bin/gli CHANGED
@@ -3,7 +3,7 @@
3
3
  # have this method, so we add it so we get resolved symlinks
4
4
  # and compatibility
5
5
  unless File.respond_to? :realpath
6
- class File
6
+ class File #:nodoc:
7
7
  def self.realpath path
8
8
  return realpath(File.readlink(path)) if symlink?(path)
9
9
  path
data/gli.rdoc CHANGED
@@ -15,7 +15,6 @@ These options are available for any command and are specified before the name of
15
15
  This is the directory where the projects directory will be made, so if you specify a project name foo and the root dir of ., the directory ./foo will be created
16
16
 
17
17
  [<tt>-v</tt>] Be verbose
18
- [<tt>--version</tt>] Show version
19
18
  == Commands
20
19
  [<tt>help</tt>] Shows list of commands or help for one command
21
20
  [<tt>init</tt>] Create a new GLI-based project
data/lib/gli.rb CHANGED
@@ -23,9 +23,15 @@ module GLI
23
23
  @@config_file = nil
24
24
  @@use_openstruct = false
25
25
  @@version = nil
26
+ @@stderr = $stderr
26
27
 
27
- # Reset the GLI module internal data structures; mostly for testing
28
- def reset
28
+ # Override the device of stderr; exposed only for testing
29
+ def error_device=(e) #:nodoc:
30
+ @@stderr = e
31
+ end
32
+
33
+ # Reset the GLI module internal data structures; mostly useful for testing
34
+ def reset # :nodoc:
29
35
  switches.clear
30
36
  flags.clear
31
37
  commands.clear
@@ -35,21 +41,51 @@ module GLI
35
41
  clear_nexts
36
42
  end
37
43
 
38
- # describe the next switch, flag, or command. This should be a
44
+ # Describe the next switch, flag, or command. This should be a
39
45
  # short, one-line description
46
+ #
47
+ # +description+:: A String of the short descripiton of the switch, flag, or command following
40
48
  def desc(description); @@next_desc = description; end
41
49
 
42
50
  # Provide a longer, more detailed description. This
43
- # will be reformatted and wrapped to fit in 80 columns
51
+ # will be reformatted and wrapped to fit in the terminal's columns
52
+ #
53
+ # +long_desc+:: A String that is s longer description of the switch, flag, or command following.
44
54
  def long_desc(long_desc); @@next_long_desc = long_desc; end
45
55
 
46
- # describe the argument name of the next flag
56
+ # Describe the argument name of the next flag. It's important to keep
57
+ # this VERY short and, ideally, without any spaces (see Example).
58
+ #
59
+ # +name+:: A String that *briefly* describes the argument given to the following command or flag.
60
+ #
61
+ # Example:
62
+ # desc 'Set the filename'
63
+ # arg_name 'file_name'
64
+ # flag [:f,:filename]
65
+ #
66
+ # Produces:
67
+ # -f, --filename=file_name Set the filename
47
68
  def arg_name(name); @@next_arg_name = name; end
48
69
 
49
70
  # set the default value of the next flag
71
+ #
72
+ # +val+:: A String reprensenting the default value to be used for the following flag if the user doesn't specify one
73
+ # and, when using a config file, the config also doesn't specify one
50
74
  def default_value(val); @@next_default_value = val; end
51
75
 
52
76
  # Create a flag, which is a switch that takes an argument
77
+ #
78
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names
79
+ # and aliases for this flag.
80
+ #
81
+ # Example:
82
+ #
83
+ # desc 'Set the filename'
84
+ # flag [:f,:filename,'file-name']
85
+ #
86
+ # Produces:
87
+ #
88
+ # -f, --filename, --file-name=arg Set the filename
53
89
  def flag(*names)
54
90
  names = [names].flatten
55
91
  verify_unused(names,flags,switches,"in global options")
@@ -58,7 +94,10 @@ module GLI
58
94
  clear_nexts
59
95
  end
60
96
 
61
- # Create a switch
97
+ # Create a switch, which is a command line flag that takes no arguments (thus, it _switches_ something on)
98
+ #
99
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names
100
+ # and aliases for this switch.
62
101
  def switch(*names)
63
102
  names = [names].flatten
64
103
  verify_unused(names,flags,switches,"in global options")
@@ -67,8 +106,11 @@ module GLI
67
106
  clear_nexts
68
107
  end
69
108
 
70
- # Sets the config file. If not an absolute path
71
- # sets the path to the user's home directory
109
+ # Sets that this app uses a config file as well as the name of the config file.
110
+ #
111
+ # +filename+:: A String representing the path to the file to use for the config file. If it's an absolute
112
+ # path, this is treated as the path to the file. If it's *not*, it's treated as relative to the user's home
113
+ # directory as produced by <code>Etc.getpwuid.dir</code>.
72
114
  def config_file(filename)
73
115
  if filename =~ /^\//
74
116
  @@config_file = filename
@@ -79,7 +121,11 @@ module GLI
79
121
  @@config_file
80
122
  end
81
123
 
82
- # Define a command.
124
+ # Define a new command. This takes a block that will be given an instance of the Command that was created.
125
+ # You then may call methods on this object to define aspects of that Command.
126
+ #
127
+ # +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names and aliases for this command.
128
+ #
83
129
  def command(*names)
84
130
  command = Command.new([names].flatten,@@next_desc,@@next_arg_name,@@next_long_desc)
85
131
  commands[command.name] = command
@@ -97,8 +143,8 @@ module GLI
97
143
  @@pre_block = a_proc
98
144
  end
99
145
 
100
- # Define a block to run after command hase been executed, only
101
- # if there was not an error.
146
+ # Define a block to run after the command was executed, <b>only
147
+ # if there was not an error</b>.
102
148
  # The block will receive the global-options,command,options, and arguments
103
149
  def post(&a_proc)
104
150
  @@post_block = a_proc
@@ -106,65 +152,103 @@ module GLI
106
152
 
107
153
  # Define a block to run if an error occurs.
108
154
  # The block will receive any Exception that was caught.
109
- # It should return false to avoid the built-in error handling (which basically just
110
- # prints out a message)
155
+ # It should evaluate to false to avoid the built-in error handling (which basically just
156
+ # prints out a message). GLI uses a variety of exceptions that you can use to find out what
157
+ # errors might've occurred during command-line parsing:
158
+ # * GLI::CustomExit
159
+ # * GLI::UnknownCommandArgument
160
+ # * GLI::UnknownGlobalArgument
161
+ # * GLI::UnknownCommand
162
+ # * GLI::BadCommandLine
111
163
  def on_error(&a_proc)
112
164
  @@error_block = a_proc
113
165
  end
114
166
 
115
167
  # Indicate the version of your application
168
+ #
169
+ # +version+:: String containing the version of your application.
116
170
  def version(version)
117
171
  @@version = version
118
172
  end
119
173
 
120
- # Call this with "true" will cause the <tt>global_options</tt> and
121
- # <tt>options</tt> passed to your code to be wrapped in
122
- # GLI::Option, which is a subclass of OpenStruct that adds
174
+ # Call this with +true+ will cause the +global_options+ and
175
+ # +options+ passed to your code to be wrapped in
176
+ # Options, which is a subclass of +OpenStruct+ that adds
123
177
  # <tt>[]</tt> and <tt>[]=</tt> methods.
178
+ #
179
+ # +use_openstruct+:: a Boolean indicating if we should use OpenStruct instead of Hashes
124
180
  def use_openstruct(use_openstruct)
125
181
  @@use_openstruct = use_openstruct
126
182
  end
127
183
 
128
184
  # Runs whatever command is needed based on the arguments.
129
185
  #
130
- # args - the command line ARGV array
186
+ # +args+:: the command line ARGV array
131
187
  #
132
188
  # Returns a number that would be a reasonable exit code
133
- def run(args)
189
+ def run(args) #:nodoc:
134
190
  rdoc = RDocCommand.new
135
191
  commands[:rdoc] = rdoc if !commands[:rdoc]
136
192
  commands[:help] = DefaultHelpCommand.new(@@version,rdoc) if !commands[:help]
193
+ exit_code = 0
137
194
  begin
138
195
  config = parse_config
139
196
  global_options,command,options,arguments = parse_options(args,config)
140
197
  copy_options_to_aliased_versions(global_options,command,options)
141
- proceed = true
142
- global_options = convert_to_option?(global_options)
143
- options = convert_to_option?(options)
144
- proceed = @@pre_block.call(global_options,command,options,arguments) if @@pre_block
145
- if proceed
198
+ global_options = convert_to_openstruct?(global_options)
199
+ options = convert_to_openstruct?(options)
200
+ if proceed?(global_options,command,options,arguments)
146
201
  command = commands[:help] if !command
147
202
  command.execute(global_options,options,arguments)
148
203
  @@post_block.call(global_options,command,options,arguments) if @@post_block
149
204
  end
150
- 0
151
205
  rescue Exception => ex
152
- regular_error_handling = true
153
- regular_error_handling = @@error_block.call(ex) if @@error_block
154
206
 
155
- if regular_error_handling
156
- $stderr.puts "error: #{ex.message}"
157
- end
207
+ @@stderr.puts error_message(ex) if regular_error_handling?(ex)
158
208
 
159
209
  raise ex if ENV['GLI_DEBUG'] == 'true'
160
210
 
161
- case ex
162
- when BadCommandLine then -1
163
- when CustomExit then ex.exit_code
164
- else
211
+ exit_code = if ex.respond_to? :exit_code
212
+ ex.exit_code
213
+ else
165
214
  -2
166
215
  end
167
216
  end
217
+ exit_code
218
+ end
219
+
220
+ # True if we should proceed with executing the command; this calls
221
+ # the pre block if it's defined
222
+ def proceed?(global_options,command,options,arguments) #:nodoc:
223
+ if @@pre_block
224
+ @@pre_block.call(global_options,command,options,arguments)
225
+ else
226
+ true
227
+ end
228
+ end
229
+
230
+ # Returns true if we should proceed with GLI's basic error handling.
231
+ # This calls the error block if the user provided one
232
+ def regular_error_handling?(ex) #:nodoc:
233
+ if @@error_block
234
+ @@error_block.call(ex)
235
+ else
236
+ true
237
+ end
238
+ end
239
+
240
+ # Returns a String of the error message to show the user
241
+ # +ex+:: The exception we caught that launched the error handling routines
242
+ def error_message(ex) #:nodoc:
243
+ msg = "error: #{ex.message}"
244
+ case ex
245
+ when UnknownCommand
246
+ msg += ". Use '#{program_name} help' for a list of commands"
247
+ when UnknownCommandArgument
248
+ msg += ". Use '#{program_name} help #{ex.command.name}' for a list of command options"
249
+ when UnknownGlobalArgument
250
+ msg += ". Use '#{program_name} help' for a list of global options"
251
+ end
168
252
  end
169
253
 
170
254
  # Simpler means of exiting with a custom exit code. This will
@@ -174,17 +258,36 @@ module GLI
174
258
  raise CustomExit.new(message,exit_code)
175
259
  end
176
260
 
261
+ # Set or get the name of the program, if you don't want the default (which is
262
+ # the name of the command line program). This
263
+ # is only used currently in the help and rdoc commands.
264
+ #
265
+ # +override+:: A String that represents the name of the program to use, other than the default.
266
+ #
267
+ # Returns the current program name, as a String
268
+ def program_name(override=nil)
269
+ if override
270
+ @@program_name = override
271
+ end
272
+ @@program_name
273
+ end
274
+
275
+ alias :d :desc
276
+ alias :f :flag
277
+ alias :s :switch
278
+ alias :c :command
279
+
177
280
  # Possibly returns a copy of the passed-in Hash as an instance of GLI::Option.
178
- # By default, it will *not*, however by putting <tt>use_openstruct true</tt>
281
+ # By default, it will *not*. However by putting <tt>use_openstruct true</tt>
179
282
  # in your CLI definition, it will
180
- def convert_to_option?(options)
283
+ def convert_to_openstruct?(options) # :nodoc:
181
284
  @@use_openstruct ? Options.new(options) : options
182
285
  end
183
286
 
184
287
  # Copies all options in both global_options and options to keys for the aliases of those flags.
185
288
  # For example, if a flag works with either -f or --flag, this will copy the value from [:f] to [:flag]
186
289
  # to allow the user to access the options by any alias
187
- def copy_options_to_aliased_versions(global_options,command,options)
290
+ def copy_options_to_aliased_versions(global_options,command,options) # :nodoc:
188
291
  copy_options_to_aliases(global_options,self)
189
292
  copy_options_to_aliases(options,command)
190
293
  end
@@ -194,7 +297,7 @@ module GLI
194
297
  #
195
298
  # options - Hash of options parsed from command line; this is an I/O param
196
299
  # gli_like - Object resonding to flags and switches in the same way that GLI or a Command instance do
197
- def copy_options_to_aliases(options,gli_like)
300
+ def copy_options_to_aliases(options,gli_like) # :nodoc:
198
301
  new_options = {}
199
302
  options.each do |key,value|
200
303
  if gli_like.flags[key] && gli_like.flags[key].aliases
@@ -210,7 +313,7 @@ module GLI
210
313
  options.merge!(new_options)
211
314
  end
212
315
 
213
- def parse_config
316
+ def parse_config # :nodoc:
214
317
  return nil if @@config_file.nil?
215
318
  require 'yaml'
216
319
  if File.exist?(@@config_file)
@@ -220,19 +323,12 @@ module GLI
220
323
  end
221
324
  end
222
325
 
223
- def program_name(override=nil)
224
- if override
225
- @@program_name = override
226
- end
227
- @@program_name
228
- end
229
-
230
326
  # Returns an array of four values:
231
327
  # * global options (as a Hash)
232
328
  # * Command
233
329
  # * command options (as a Hash)
234
330
  # * arguments (as an Array)
235
- def parse_options(args,config=nil)
331
+ def parse_options(args,config=nil) # :nodoc:
236
332
  command_configs = {}
237
333
  if config.nil?
238
334
  config = {}
@@ -247,7 +343,7 @@ module GLI
247
343
 
248
344
  # Finds the index of the first non-flag
249
345
  # argument or -1 if there wasn't one.
250
- def find_non_flag_index(args)
346
+ def find_non_flag_index(args) # :nodoc:
251
347
  args.each_index do |i|
252
348
  return i if args[i] =~ /^[^\-]/;
253
349
  return i-1 if args[i] =~ /^\-\-$/;
@@ -255,12 +351,7 @@ module GLI
255
351
  -1;
256
352
  end
257
353
 
258
- alias :d :desc
259
- alias :f :flag
260
- alias :s :switch
261
- alias :c :command
262
-
263
- def clear_nexts
354
+ def clear_nexts # :nodoc:
264
355
  @@next_desc = nil
265
356
  @@next_arg_name = nil
266
357
  @@next_default_value = nil
@@ -269,17 +360,23 @@ module GLI
269
360
 
270
361
  clear_nexts
271
362
 
272
- def flags; @@flags ||= {}; end
273
- def switches; @@switches ||= {}; end
274
- def commands; @@commands ||= {}; end
363
+ def flags # :nodoc:
364
+ @@flags ||= {}
365
+ end
366
+ def switches # :nodoc:
367
+ @@switches ||= {}
368
+ end
369
+ def commands # :nodoc:
370
+ @@commands ||= {}
371
+ end
275
372
 
276
373
  # Recursive helper for parsing command line options
277
- # [args] the arguments that have yet to be processed
278
- # [global_options] the global options hash
279
- # [command] the Command that has been identified (or nil if not identified yet)
280
- # [command_options] options for Command
281
- # [arguments] the arguments for Command
282
- # [command_configs] the configuration file for all commands, used as defaults
374
+ # <code>args</code>:: the arguments that have yet to be processed
375
+ # <code>global_options</code>:: the global options hash
376
+ # <code>command</code>:: the Command that has been identified (or nil if not identified yet)
377
+ # <code>command_options</code>:: options for Command
378
+ # <code>arguments</code>:: the arguments for Command
379
+ # <code>command_configs</code>:: the configuration file for all commands, used as defaults
283
380
  #
284
381
  # This works by finding the first non-switch/flag argument, and taking that sublist and trying to pick out
285
382
  # flags and switches. After this is done, one of the following is true:
@@ -292,7 +389,7 @@ module GLI
292
389
  #
293
390
  # Once the command has been found, we start looking for command-specific flags and switches.
294
391
  # When those have been found, we know the rest of the argument list is arguments for the command
295
- def parse_options_helper(args,global_options,command,command_options,arguments,command_configs)
392
+ def parse_options_helper(args,global_options,command,command_options,arguments,command_configs) # :nodoc:
296
393
  non_flag_i = find_non_flag_index(args)
297
394
  all_flags = false
298
395
  if non_flag_i == 0
@@ -300,7 +397,7 @@ module GLI
300
397
  if !command
301
398
  command_name = args.shift
302
399
  command = find_command(command_name)
303
- raise BadCommandLine.new("Unknown command '#{command_name}'") if !command
400
+ raise UnknownCommand.new("Unknown command '#{command_name}'") if !command
304
401
  return parse_options_helper(args,
305
402
  global_options,
306
403
  command,
@@ -366,16 +463,16 @@ module GLI
366
463
  try_me.delete arg
367
464
  break
368
465
  end
369
- raise BadCommandLine.new("Unknown argument #{arg}") if arg =~ /^\-/
466
+ raise UnknownCommandArgument.new("Unknown option #{arg}",command) if arg =~ /^\-/
370
467
  end
371
468
  return [global_options,command,command_options,try_me + rest]
372
469
  else
373
470
  # Now we have our command name
374
471
  command_name = try_me.shift
375
- raise BadCommandLine.new("Unknown argument #{command_name}") if command_name =~ /^\-/
472
+ raise UnknownGlobalArgument.new("Unknown option #{command_name}") if command_name =~ /^\-/
376
473
 
377
474
  command = find_command(command_name)
378
- raise BadCommandLine.new("Unknown command '#{command_name}'") if !command
475
+ raise UnknownCommand.new("Unknown command '#{command_name}'") if !command
379
476
 
380
477
  return parse_options_helper(rest,
381
478
  global_options,
@@ -388,11 +485,11 @@ module GLI
388
485
 
389
486
  end
390
487
 
391
- def default_command_options(command,command_configs)
488
+ def default_command_options(command,command_configs) # :nodoc:
392
489
  options = (command_configs && command_configs[command.name.to_sym]) || {}
393
490
  end
394
491
 
395
- def find_command(name)
492
+ def find_command(name) # :nodoc:
396
493
  sym = name.to_sym
397
494
  return commands[name.to_sym] if commands[sym]
398
495
  commands.keys.each do |command_name|
@@ -403,7 +500,7 @@ module GLI
403
500
  end
404
501
 
405
502
  # Checks that the names passed in have not been used in another flag or option
406
- def verify_unused(names,flags,switches,context)
503
+ def verify_unused(names,flags,switches,context) # :nodoc:
407
504
  names.each do |name|
408
505
  verify_unused_in_option(name,flags,"flag",context)
409
506
  verify_unused_in_option(name,switches,"switch",context)
@@ -412,7 +509,7 @@ module GLI
412
509
 
413
510
  private
414
511
 
415
- def verify_unused_in_option(name,option_like,type,context)
512
+ def verify_unused_in_option(name,option_like,type,context) # :nodoc:
416
513
  raise ArgumentError.new("#{name} has already been specified as a #{type} #{context}") if option_like[name]
417
514
  option_like.each do |one_option_name,one_option|
418
515
  if one_option.aliases
@@ -1,47 +1,62 @@
1
1
  require 'gli/command_line_token.rb'
2
2
 
3
3
  module GLI
4
- # A command to be run, in context of global flags and switches
4
+ # A command to be run, in context of global flags and switches. You are given an instance of this class
5
+ # to the block you use for GLI#command. You then use the methods described here to describe the
6
+ # command-specific command-line arguments, much as you use the methods in GLI to describe the global
7
+ # command-line interface
5
8
  class Command < CommandLineToken
6
9
 
7
10
  # Create a new command
8
11
  #
9
- # [names] the name or names of this command (symbol or Array of symbols)
10
- # [description] description of this command
11
- # [arguments_name] description of the arguments, or nil if this command doesn't take arguments
12
- # [long_desc] a longer description of the command, possibly with multiple lines and text formatting
13
- #
14
- def initialize(names,description,arguments_name=nil,long_desc=nil)
12
+ # +names+:: A String, Symbol, or Array of String or Symbol that represents the name(s) of this command.
13
+ # +description+:: short description of this command as a Strign
14
+ # +arguments_name+:: description of the arguments as a String, or nil if this command doesn't take arguments
15
+ # +long_desc+:: a longer description of the command, possibly with multiple lines and text formatting
16
+ def initialize(names,description,arguments_name=nil,long_desc=nil) # :nodoc:
15
17
  super(names,description,long_desc)
16
18
  @arguments_description = arguments_name || ''
17
19
  clear_nexts
18
20
  end
19
21
 
20
- def arguments_description; @arguments_description; end
22
+ # Return the arguments description
23
+ def arguments_description #:nodoc:
24
+ @arguments_description
25
+ end
21
26
 
22
- def names
27
+ # Return the Array of the command's names
28
+ def names #:nodoc:
23
29
  all_forms
24
30
  end
25
31
 
26
- def usage
32
+ # Get the usage string
33
+ # CR: This should probably not be here
34
+ def usage #:nodoc:
27
35
  usage = name.to_s
28
- usage += ' [options]' if !flags.empty? || !switches.empty?
36
+ usage += ' [command options]' if !flags.empty? || !switches.empty?
29
37
  usage += ' ' + @arguments_description if @arguments_description
30
38
  usage
31
39
  end
32
40
 
33
- def flags; @flags ||= {}; end
34
- def switches; @switches ||= {}; end
41
+ # Return the flags as a Hash
42
+ def flags #:nodoc:
43
+ @flags ||= {}
44
+ end
45
+ # Return the switches as a Hash
46
+ def switches #:nodoc:
47
+ @switches ||= {}
48
+ end
35
49
 
36
- # describe the next switch or flag
50
+ # describe the next switch or flag just as GLI#desc does.
37
51
  def desc(description); @next_desc = description; end
38
- # long description of this flag/switch
52
+ # set the long description of this flag/switch, just as GLI#long_desc does.
39
53
  def long_desc(long_desc); @next_long_desc = long_desc; end
40
- # describe the argument name of the next flag
54
+ # describe the argument name of the next flag, just as GLI#arg_name does.
41
55
  def arg_name(name); @next_arg_name = name; end
42
- # set the default value of the next flag
56
+ # set the default value of the next flag, just as GLI#default_value does.
43
57
  def default_value(val); @next_default_value = val; end
44
58
 
59
+ # Create a command-specific flag, similar to GLI#flag
45
60
  def flag(*names)
46
61
  names = [names].flatten
47
62
  GLI.verify_unused(names,flags,switches,"in command #{name}")
@@ -50,7 +65,7 @@ module GLI
50
65
  clear_nexts
51
66
  end
52
67
 
53
- # Create a switch
68
+ # Create a command-specific switch, similar to GLI#switch
54
69
  def switch(*names)
55
70
  names = [names].flatten
56
71
  GLI.verify_unused(names,flags,switches,"in command #{name}")
@@ -59,22 +74,34 @@ module GLI
59
74
  clear_nexts
60
75
  end
61
76
 
77
+ # Define the action to take when the user executes this command
78
+ #
79
+ # +block+:: A block of code to execute. The block will be given 3 arguments:
80
+ # +global_options+:: A Hash (or Options, see GLI#use_openstruct) of the _global_ options specified
81
+ # by the user, with defaults set and config file values used (if using a config file, see
82
+ # GLI#config_file)
83
+ # +options+:: A Hash (or Options, see GLI#use_openstruct) of the command-specific options specified by the
84
+ # user, with defaults set and config file values used (if using a config file, see GLI#config_file)
85
+ # +arguments+:: An Array of Strings representing the unparsed command line arguments
86
+ # The block's result value is not used; raise an exception or use GLI#exit_now! if you need an early exit based
87
+ # on an error condition
62
88
  def action(&block)
63
89
  @action = block
64
90
  end
65
91
 
66
- def self.name_as_string(name)
92
+ def self.name_as_string(name) #:nodoc:
67
93
  name.to_s
68
94
  end
69
95
 
70
- def clear_nexts
96
+ def clear_nexts #:nodoc:
71
97
  @next_desc = nil
72
98
  @next_arg_name = nil
73
99
  @next_default_value = nil
74
100
  @next_long_desc = nil
75
101
  end
76
102
 
77
- def execute(global_options,options,arguments)
103
+ # Executes the command
104
+ def execute(global_options,options,arguments) #:nodoc:
78
105
  @action.call(global_options,options,arguments)
79
106
  end
80
107
  end
@@ -1,22 +1,23 @@
1
1
  module GLI
2
- # Logical element of a command line, mostly so that subclasses can have similar
2
+ # Abstract base class for a logical element of a command line, mostly so that subclasses can have similar
3
3
  # initialization and interface
4
4
  class CommandLineToken
5
- attr_reader :name
6
- attr_reader :aliases
7
- attr_reader :description
8
- attr_reader :long_description
5
+ attr_reader :name #:ndoc:
6
+ attr_reader :aliases #:ndoc:
7
+ attr_reader :description #:ndoc:
8
+ attr_reader :long_description #:ndoc:
9
9
 
10
- def initialize(names,description,long_description=nil)
10
+ def initialize(names,description,long_description=nil) #:ndoc:
11
11
  @description = description
12
12
  @long_description = long_description
13
13
  @name,@aliases,@names = parse_names(names)
14
14
  end
15
15
 
16
- def usage
16
+ def usage #:nodoc:
17
17
  all_forms
18
18
  end
19
19
 
20
+ # Sort based on name
20
21
  def <=>(other)
21
22
  self.name.to_s <=> other.name.to_s
22
23
  end
@@ -1,13 +1,30 @@
1
1
  module GLI
2
2
  # Indicates that the command line invocation was bad
3
3
  class BadCommandLine < Exception
4
- def initialize(message)
4
+ def exit_code; -1; end
5
+ end
6
+
7
+ # Indicates the bad command line was an unknown command
8
+ class UnknownCommand < BadCommandLine
9
+ end
10
+
11
+ # Indicates the bad command line was an unknown global argument
12
+ class UnknownGlobalArgument < BadCommandLine
13
+ end
14
+
15
+ # Indicates the bad command line was an unknown command argument
16
+ class UnknownCommandArgument < BadCommandLine
17
+ attr_reader :command
18
+ # +message+:: the error message to show the user
19
+ # +command+:: the command we were using to parse command-specific options
20
+ def initialize(message,command)
5
21
  super(message)
22
+ @command = command
6
23
  end
7
24
  end
8
25
 
9
26
  # Raise this if you want to use an exit status that isn't the default
10
- # provided by GLI.
27
+ # provided by GLI. Note that GLI#exit_now! might be a bit more to your liking.
11
28
  #
12
29
  # Example:
13
30
  #
@@ -15,11 +32,11 @@ module GLI
15
32
  # raise CustomExit.new("Bad SQL",-6) unless valid_sql?(args[0])
16
33
  #
17
34
  class CustomExit < Exception
18
- attr_reader :exit_code
35
+ attr_reader :exit_code #:nodoc:
19
36
  # Create a custom exit exception
20
37
  #
21
- # message - String containing error message to show the user
22
- # exit_code - the exit code to use, overridding GLI's default
38
+ # +message+:: String containing error message to show the user
39
+ # +exit_code+:: the exit code to use (as an Int), overridding GLI's default
23
40
  def initialize(message,exit_code)
24
41
  super(message)
25
42
  @exit_code = exit_code
@@ -2,7 +2,7 @@ require 'gli/command_line_token.rb'
2
2
 
3
3
  module GLI
4
4
  # Defines a flag, which is to say a switch that takes an argument
5
- class Flag < Switch
5
+ class Flag < Switch # :nodoc:
6
6
 
7
7
  attr_reader :default_value
8
8
 
@@ -1,12 +1,15 @@
1
1
  require 'ostruct'
2
2
 
3
3
  module GLI
4
+ # Subclass of OpenStruct that provides hash-like methods for #[] and #[]=. Note that is is *not* a Hash.
4
5
  class Options < OpenStruct
5
6
 
7
+ # Return the value of an attribute
6
8
  def[](k)
7
9
  @table[k.to_sym]
8
10
  end
9
11
 
12
+ # Set the value of an attribute
10
13
  def[]=(k, v)
11
14
  @table[k.to_sym] = v
12
15
  end
@@ -2,7 +2,7 @@ require 'gli/command_line_token.rb'
2
2
 
3
3
  module GLI
4
4
  # Defines a command line switch
5
- class Switch < CommandLineToken
5
+ class Switch < CommandLineToken #:nodoc:
6
6
 
7
7
  def initialize(names,description,long_desc=nil)
8
8
  super(names,description,long_desc)
@@ -28,8 +28,8 @@ module GLI
28
28
 
29
29
  # Finds the switch in the given arg, returning the arg to keep.
30
30
  # Returns an array of size 2:
31
- # [0] true or false if the arg was found
32
- # [1] the remaining arg to keep in the command line or nil to remove it
31
+ # index 0:: true or false if the arg was found
32
+ # index 1:: the remaining arg to keep in the command line or nil to remove it
33
33
  def find_me(arg)
34
34
  if @names[arg]
35
35
  return [true,nil]
@@ -1,5 +1,10 @@
1
1
  module GLI
2
- # Class to encapsulate stuff about the terminal. This is a singleton, mostly to facilitate testing.
2
+ # Class to encapsulate stuff about the terminal. This is useful to application developers
3
+ # as a canonical means to get information about the user's current terminal configuraiton.
4
+ # GLI uses this to determine the number of columns to use when printing to the screen.
5
+ #
6
+ # To access it, use Terminal#instance. This is a singleton mostly to facilitate testing, but
7
+ # it seems reasonable enough, since there's only one terminal in effect
3
8
  #
4
9
  # Example:
5
10
  #
@@ -20,29 +25,31 @@ module GLI
20
25
 
21
26
  # Set the default size of the terminal to use when we can't figure it out
22
27
  #
23
- # size - array of two int [cols,rows]
28
+ # +size+:: array of two int [cols,rows]
24
29
  def self.default_size=(size)
25
30
  @@default_size = size
26
31
  end
27
32
 
28
- # Provide access to the shared instance
33
+ # Provide access to the shared instance.
29
34
  def self.instance; @@instance ||= Terminal.new; end
30
35
 
31
36
  # Call this to cause methods to throw exceptions rather than return a sane default. You
32
37
  # probably don't want to call this unless you are writing tests
33
- def make_unsafe!;
38
+ def make_unsafe!
34
39
  @unsafe = true
35
40
  end
36
41
 
37
42
  # Returns true if the given command exists on this system
38
43
  #
39
- # command - The command to check for
44
+ # +command+:: The command, as a String, to check for, without any path information.
40
45
  def command_exists?(command)
41
46
  ENV['PATH'].split(File::PATH_SEPARATOR).any? {|d| File.exists? File.join(d, command) }
42
47
  end
43
48
 
44
- # Ripped from hirb https://github.com/cldwalker/hirb/blob/master/lib/hirb/util.rb
45
- # Returns an array of size two ints representing the terminal width and height
49
+ # Get the size of the current terminal.
50
+ # Ripped from hirb[https://github.com/cldwalker/hirb/blob/master/lib/hirb/util.rb]
51
+ #
52
+ # Returns an Array of size two Ints representing the terminal width and height
46
53
  def size
47
54
  if (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/)
48
55
  [ENV['COLUMNS'].to_i, ENV['LINES'].to_i]
@@ -1,3 +1,3 @@
1
1
  module GLI
2
- VERSION = '1.2.5'
2
+ VERSION = '1.2.6'
3
3
  end
@@ -3,9 +3,9 @@ require 'gli/command'
3
3
  require 'gli/terminal'
4
4
 
5
5
  module GLI
6
- class DefaultHelpCommand < Command
6
+ class DefaultHelpCommand < Command #:nodoc:
7
7
  @@output = $stdout
8
- # Exposed for testing :nodoc:
8
+ # Exposed for testing
9
9
  def self.output_device=(o); @@output = o; end
10
10
 
11
11
  def initialize(version,*omit_from_list)
@@ -47,18 +47,20 @@ module GLI
47
47
  private
48
48
 
49
49
  def list_global_flags
50
- usage = "usage: #{GLI.program_name} command"
50
+ usage = "usage: #{GLI.program_name} "
51
51
  all_options = GLI.switches.merge(GLI.flags)
52
52
  if !all_options.empty?
53
- usage += ' [options]'
53
+ usage += "[global options] "
54
54
  end
55
+ usage += "command"
56
+ usage += ' [command options]'
55
57
  @@output.puts usage
56
58
  @@output.puts
57
59
  if @version
58
60
  @@output.puts "Version: #{@version}"
59
61
  @@output.puts
60
62
  end
61
- @@output.puts 'Options:' if !all_options.empty?
63
+ @@output.puts 'Global Options:' if !all_options.empty?
62
64
  output_command_tokens_for_help(all_options)
63
65
  @@output.puts if !all_options.empty?
64
66
  end
@@ -85,7 +87,7 @@ module GLI
85
87
  all_options = command.switches.merge(command.flags)
86
88
  if !all_options.empty?
87
89
  @@output.puts
88
- @@output.puts "Options:"
90
+ @@output.puts "Command Options:"
89
91
  output_command_tokens_for_help(all_options)
90
92
  end
91
93
  else
@@ -3,7 +3,7 @@ require 'gli/command'
3
3
  require 'yaml'
4
4
 
5
5
  module GLI
6
- class InitConfig < Command
6
+ class InitConfig < Command # :nodoc:
7
7
  COMMANDS_KEY = 'commands'
8
8
 
9
9
  def initialize(config_file_name)
@@ -27,8 +27,7 @@ module GLI
27
27
  YAML.dump(config,file)
28
28
  end
29
29
  else
30
- puts "Not overwriting existing config file #{@filename}"
31
- puts 'Use --force to override'
30
+ raise "Not overwriting existing config file #{@filename}, use --force to override"
32
31
  end
33
32
  end
34
33
  end
@@ -2,13 +2,50 @@ require 'gli'
2
2
  require 'fileutils'
3
3
 
4
4
  module GLI
5
- class RDocCommand < Command
5
+ class RDocCommand < Command # :nodoc:
6
6
 
7
7
  def initialize
8
- super(:rdoc,'Generates RDoc for your command line interface')
8
+ super(:rdoc,'Generates RDoc (and other types of documentation) for your command line interface')
9
+ self.desc 'Create a very basic scaffold for a cheat-style cheatsheet, in addition to rdoc'
10
+ self.switch 'cheatsheet'
11
+ self.desc 'Include a manapage suitable for gem man, in addition to rdoc'
12
+ self.switch 'manpage'
13
+ self.desc 'Do not create rdoc'
14
+ self.switch 'no-rdoc'
9
15
  end
10
16
 
11
- def execute(g,o,a)
17
+ def execute(g,options,a)
18
+ create_rdoc unless options[:'no-rdoc']
19
+ create_manpage if options[:manpage]
20
+ create_cheatsheet if options[:cheatsheet]
21
+ end
22
+
23
+ def create_cheatsheet
24
+ File.open("#{GLI.program_name}.cheat",'w') do |file|
25
+ file << GLI.program_name
26
+ file << "\n"
27
+ file << GLI.program_name.length.times.inject("") { |a,x| a + "=" }
28
+ file << "\n"
29
+ file << "\n"
30
+ file << "Installation:\n"
31
+ file << "$ gem install #{GLI.program_name}\n\n"
32
+ GLI.commands.values.sort.each do |command|
33
+ next if command == self
34
+ file << command.description
35
+ file << "\n"
36
+ [command.name,command.aliases].flatten.each do |name|
37
+ next unless name
38
+ file << "$ #{GLI.program_name} #{name} #{command.arguments_description}\n"
39
+ end
40
+ file << "\n"
41
+ end
42
+ end
43
+ end
44
+
45
+ def create_manpage
46
+ end
47
+
48
+ def create_rdoc
12
49
  File.open("#{GLI.program_name}.rdoc",'w') do |file|
13
50
  file << "= <tt>#{GLI.program_name}</tt>\n\n"
14
51
  file << " "
@@ -2,7 +2,7 @@ require 'gli'
2
2
  require 'fileutils'
3
3
 
4
4
  module GLI
5
- class Scaffold
5
+ class Scaffold #:nodoc:
6
6
 
7
7
  def self.create_scaffold(root_dir,create_test_dir,create_ext_dir,project_name,commands,force=false,dry_run=false)
8
8
  dirs = [File.join(root_dir,project_name,'lib')]
@@ -58,6 +58,8 @@ bin/#{project_name}
58
58
  s.rdoc_options << '--title' << '#{project_name}' << '--main' << 'README.rdoc' << '-ri'
59
59
  s.bindir = 'bin'
60
60
  s.executables << '#{project_name}'
61
+ s.add_development_dependency('rake')
62
+ s.add_development_dependency('rdoc')
61
63
  end
62
64
  EOS
63
65
  end
@@ -137,8 +139,7 @@ EOS
137
139
  puts "Created #{root_dir}/#{project_name}/Rakefile"
138
140
  File.open("#{root_dir}/#{project_name}/Gemfile",'w') do |bundler_file|
139
141
  bundler_file.puts "source :rubygems"
140
- bundler_file.puts "gem: 'rake'"
141
- bundler_file.puts "gem: 'rdoc'"
142
+ bundler_file.puts "gemspec"
142
143
  end
143
144
  puts "Created #{root_dir}/#{project_name}/Gemfile"
144
145
  end
@@ -155,7 +156,7 @@ EOS
155
156
  # have this method, so we add it so we get resolved symlinks
156
157
  # and compatibility
157
158
  unless File.respond_to? :realpath
158
- class File
159
+ class File #:nodoc:
159
160
  def self.realpath path
160
161
  return realpath(File.readlink(path)) if symlink?(path)
161
162
  path
@@ -253,7 +254,7 @@ EOS
253
254
  if !force
254
255
  dirs.each do |dir|
255
256
  if File.exist? dir
256
- puts "#{dir} exists; use --force to override"
257
+ raise "#{dir} exists; use --force to override"
257
258
  exists = true
258
259
  end
259
260
  end
@@ -262,7 +263,7 @@ EOS
262
263
  dirs.each do |dir|
263
264
  puts "Creating dir #{dir}..."
264
265
  if dry_run
265
- $stderr.puts "dry-run; #{dir} not created"
266
+ puts "dry-run; #{dir} not created"
266
267
  else
267
268
  FileUtils.mkdir_p dir
268
269
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gli
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
5
4
  prerelease: false
6
5
  segments:
7
6
  - 1
8
7
  - 2
9
- - 5
10
- version: 1.2.5
8
+ - 6
9
+ version: 1.2.6
11
10
  platform: ruby
12
11
  authors:
13
12
  - David Copeland
@@ -15,10 +14,82 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-12-12 00:00:00 -05:00
17
+ date: 2011-03-06 00:00:00 -05:00
19
18
  default_executable:
20
- dependencies: []
21
-
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rake
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 8
31
+ - 7
32
+ version: 0.8.7
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rcov
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 0
45
+ - 9
46
+ - 8
47
+ version: 0.9.8
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: rdoc
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 2
60
+ - 4
61
+ - 3
62
+ version: 2.4.3
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: sdoc
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ - 2
76
+ - 20
77
+ version: 0.2.20
78
+ type: :development
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ name: grancher
82
+ prerelease: false
83
+ requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ type: :development
92
+ version_requirements: *id005
22
93
  description: An application and API for describing command line interfaces that can be used to quickly create a shell for executing command-line tasks. The command line user interface is similar to Gits, in that it takes global options, a command, command-specific options, and arguments
23
94
  email: davidcopeland@naildrivin5.com
24
95
  executables:
@@ -64,7 +135,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
64
135
  requirements:
65
136
  - - ">="
66
137
  - !ruby/object:Gem::Version
67
- hash: 3
68
138
  segments:
69
139
  - 0
70
140
  version: "0"
@@ -73,7 +143,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
143
  requirements:
74
144
  - - ">="
75
145
  - !ruby/object:Gem::Version
76
- hash: 3
77
146
  segments:
78
147
  - 0
79
148
  version: "0"