gli 1.6.0 → 2.0.0.rc3

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.
Files changed (78) hide show
  1. data/.gitignore +11 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +8 -0
  5. data/LICENSE.txt +201 -0
  6. data/ObjectModel.graffle +1191 -0
  7. data/README.rdoc +60 -10
  8. data/Rakefile +145 -0
  9. data/bin/gli +12 -30
  10. data/bin/report_on_rake_results +10 -0
  11. data/bin/test_all_rubies.sh +6 -0
  12. data/features/gli_executable.feature +84 -0
  13. data/features/gli_init.feature +219 -0
  14. data/features/step_definitions/gli_executable_steps.rb +12 -0
  15. data/features/step_definitions/gli_init_steps.rb +11 -0
  16. data/features/step_definitions/todo_steps.rb +69 -0
  17. data/features/support/env.rb +49 -0
  18. data/features/todo.feature +182 -0
  19. data/gli.cheat +95 -0
  20. data/gli.gemspec +34 -0
  21. data/lib/gli.rb +11 -571
  22. data/lib/gli/app.rb +184 -0
  23. data/lib/gli/app_support.rb +226 -0
  24. data/lib/gli/command.rb +107 -95
  25. data/lib/gli/command_line_option.rb +34 -0
  26. data/lib/gli/command_line_token.rb +13 -9
  27. data/lib/gli/command_support.rb +200 -0
  28. data/lib/gli/commands/compound_command.rb +42 -0
  29. data/lib/gli/commands/help.rb +63 -0
  30. data/lib/gli/commands/help_modules/command_help_format.rb +134 -0
  31. data/lib/gli/commands/help_modules/global_help_format.rb +61 -0
  32. data/lib/gli/commands/help_modules/list_formatter.rb +22 -0
  33. data/lib/gli/commands/help_modules/options_formatter.rb +50 -0
  34. data/lib/gli/commands/help_modules/text_wrapper.rb +53 -0
  35. data/lib/gli/commands/initconfig.rb +67 -0
  36. data/lib/{support → gli/commands}/scaffold.rb +150 -34
  37. data/lib/gli/dsl.rb +194 -0
  38. data/lib/gli/exceptions.rb +13 -4
  39. data/lib/gli/flag.rb +30 -41
  40. data/lib/gli/gli_option_parser.rb +98 -0
  41. data/lib/gli/option_parser_factory.rb +44 -0
  42. data/lib/gli/options.rb +2 -1
  43. data/lib/gli/switch.rb +19 -51
  44. data/lib/gli/terminal.rb +30 -20
  45. data/lib/gli/version.rb +5 -0
  46. data/test/apps/README.md +2 -0
  47. data/test/apps/todo/Gemfile +2 -0
  48. data/test/apps/todo/README.rdoc +6 -0
  49. data/test/apps/todo/Rakefile +23 -0
  50. data/test/apps/todo/bin/todo +52 -0
  51. data/test/apps/todo/lib/todo/commands/create.rb +22 -0
  52. data/test/apps/todo/lib/todo/commands/list.rb +53 -0
  53. data/test/apps/todo/lib/todo/commands/ls.rb +47 -0
  54. data/test/apps/todo/lib/todo/version.rb +3 -0
  55. data/test/apps/todo/test/tc_nothing.rb +14 -0
  56. data/test/apps/todo/todo.gemspec +23 -0
  57. data/test/apps/todo/todo.rdoc +5 -0
  58. data/test/config.yaml +10 -0
  59. data/test/fake_std_out.rb +30 -0
  60. data/test/gli.reek +122 -0
  61. data/test/init_simplecov.rb +8 -0
  62. data/test/option_test_helper.rb +13 -0
  63. data/test/roodi.yaml +18 -0
  64. data/test/tc_command.rb +260 -0
  65. data/test/tc_compount_command.rb +22 -0
  66. data/test/tc_flag.rb +56 -0
  67. data/test/tc_gli.rb +611 -0
  68. data/test/tc_help.rb +223 -0
  69. data/test/tc_options.rb +31 -0
  70. data/test/tc_subcommands.rb +162 -0
  71. data/test/tc_switch.rb +57 -0
  72. data/test/tc_terminal.rb +97 -0
  73. data/test/test_helper.rb +13 -0
  74. metadata +318 -49
  75. data/lib/gli_version.rb +0 -3
  76. data/lib/support/help.rb +0 -179
  77. data/lib/support/initconfig.rb +0 -34
  78. data/lib/support/rdoc.rb +0 -119
data/lib/gli/app.rb ADDED
@@ -0,0 +1,184 @@
1
+ require 'etc'
2
+ require 'optparse'
3
+ require 'gli/copy_options_to_aliases'
4
+ require 'gli/dsl'
5
+
6
+ module GLI
7
+ # A means to define and parse a command line interface that works as
8
+ # Git's does, in that you specify global options, a command name, command
9
+ # specific options, and then command arguments.
10
+ module App
11
+ include CopyOptionsToAliases
12
+ include DSL
13
+ include AppSupport
14
+
15
+ # Loads ruby files in the load path that start with
16
+ # +path+, which are presumed to be commands for your executable.
17
+ # This is a glorified +require+, but could also be used as a plugin mechanism.
18
+ # You could manipualte the load path at runtime and this call
19
+ # would find those files
20
+ #
21
+ # path:: a path relative to somewhere in the <code>LOAD_PATH</code>, from which all <code>.rb</code> files will be required.
22
+ def commands_from(path)
23
+ $LOAD_PATH.each do |load_path|
24
+ commands_path = File.join(load_path,path)
25
+ if File.exists? commands_path
26
+ Dir.entries(commands_path).each do |entry|
27
+ file = File.join(commands_path,entry)
28
+ if file =~ /\.rb$/
29
+ require file
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ # Describe the overall application/programm. This should be a one-sentence summary
37
+ # of what your program does that will appear in the help output.
38
+ #
39
+ # +description+:: A String of the short description of your program's purpose
40
+ def program_desc(description=nil)
41
+ if description
42
+ @program_desc = description
43
+ end
44
+ @program_desc
45
+ end
46
+
47
+ # Use this if the following command should not have the pre block executed.
48
+ # By default, the pre block is executed before each command and can result in
49
+ # aborting the call. Using this will avoid that behavior for the following command
50
+ def skips_pre
51
+ @skips_pre = true
52
+ end
53
+
54
+ # Use this if the following command should not have the post block executed.
55
+ # By default, the post block is executed after each command.
56
+ # Using this will avoid that behavior for the following command
57
+ def skips_post
58
+ @skips_post = true
59
+ end
60
+
61
+ # Sets that this app uses a config file as well as the name of the config file.
62
+ #
63
+ # +filename+:: A String representing the path to the file to use for the config file. If it's an absolute
64
+ # path, this is treated as the path to the file. If it's *not*, it's treated as relative to the user's home
65
+ # directory as produced by <code>File.expand_path('~')</code>.
66
+ def config_file(filename)
67
+ if filename =~ /^\//
68
+ @config_file = filename
69
+ else
70
+ @config_file = File.join(File.expand_path(ENV['HOME']),filename)
71
+ end
72
+ commands[:initconfig] = InitConfig.new(@config_file,commands,flags,switches)
73
+ @config_file
74
+ end
75
+
76
+ # Define a block to run after command line arguments are parsed
77
+ # but before any command is run. If this block raises an exception
78
+ # the command specified will not be executed.
79
+ # The block will receive the global-options,command,options, and arguments
80
+ # If this block evaluates to true, the program will proceed; otherwise
81
+ # the program will end immediately
82
+ def pre(&a_proc)
83
+ @pre_block = a_proc
84
+ end
85
+
86
+ # Define a block to run after the command was executed, <b>only
87
+ # if there was not an error</b>.
88
+ # The block will receive the global-options,command,options, and arguments
89
+ def post(&a_proc)
90
+ @post_block = a_proc
91
+ end
92
+
93
+ # Define a block to run if an error occurs.
94
+ # The block will receive any Exception that was caught.
95
+ # It should evaluate to false to avoid the built-in error handling (which basically just
96
+ # prints out a message). GLI uses a variety of exceptions that you can use to find out what
97
+ # errors might've occurred during command-line parsing:
98
+ # * GLI::CustomExit
99
+ # * GLI::UnknownCommandArgument
100
+ # * GLI::UnknownGlobalArgument
101
+ # * GLI::UnknownCommand
102
+ # * GLI::BadCommandLine
103
+ def on_error(&a_proc)
104
+ @error_block = a_proc
105
+ end
106
+
107
+ # Indicate the version of your application
108
+ #
109
+ # +version+:: String containing the version of your application.
110
+ def version(version)
111
+ @version = version
112
+ end
113
+
114
+ # Call this with +true+ will cause the +global_options+ and
115
+ # +options+ passed to your code to be wrapped in
116
+ # Options, which is a subclass of +OpenStruct+ that adds
117
+ # <tt>[]</tt> and <tt>[]=</tt> methods.
118
+ #
119
+ # +use_openstruct+:: a Boolean indicating if we should use OpenStruct instead of Hashes
120
+ def use_openstruct(use_openstruct)
121
+ @use_openstruct = use_openstruct
122
+ end
123
+
124
+ # Configure a type conversion not already provided by the underlying OptionParser.
125
+ # This works more or less like the OptionParser version.
126
+ #
127
+ # object:: the class (or whatever) that triggers the type conversion
128
+ # block:: the block that will be given the string argument and is expected
129
+ # to return the converted value
130
+ #
131
+ # Example
132
+ #
133
+ # accept(Hash) do |value|
134
+ # result = {}
135
+ # value.split(/,/) do |pair|
136
+ # k,v = pair.split(/:/)
137
+ # result[k] = v
138
+ # end
139
+ # result
140
+ # end
141
+ #
142
+ # flag :properties, :type => Hash
143
+ def accept(object,&block)
144
+ accepts[object] = block
145
+ end
146
+
147
+ # Simpler means of exiting with a custom exit code. This will
148
+ # raise a CustomExit with the given message and exit code, which will ultimatley
149
+ # cause your application to exit with the given exit_code as its exit status
150
+ # Use #help_now! if you want to show the help in addition to the error message
151
+ #
152
+ # message:: message to show the user
153
+ # exit_code:: exit code to exit as, defaults to 1
154
+ def exit_now!(message,exit_code=1)
155
+ raise CustomExit.new(message,exit_code)
156
+ end
157
+
158
+ # Exit now, showing the user help for the command they executed. Use #exit_now! to just show the error message
159
+ #
160
+ # message:: message to indicate how the user has messed up the CLI invocation
161
+ def help_now!(message)
162
+ exception = OptionParser::ParseError.new(message)
163
+ class << exception
164
+ def exit_code; 64; end
165
+ end
166
+ raise exception
167
+ end
168
+
169
+ def program_name(override=nil) #:nodoc:
170
+ warn "#program_name has been deprecated"
171
+ end
172
+
173
+ # Sets a default command to run when none is specified on the command line. Note that
174
+ # if you use this, you won't be able to pass arguments, flags, or switches
175
+ # to the command when run in default mode. All flags and switches are treated
176
+ # as global, and any argument will be interpretted as the command name and likely
177
+ # fail.
178
+ #
179
+ # +command+:: Command as a Symbol to run as default
180
+ def default_command(command)
181
+ @default_command = command.to_sym
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,226 @@
1
+ module GLI
2
+ # Internals for make App work
3
+ module AppSupport
4
+ # Override the device of stderr; exposed only for testing
5
+ def error_device=(e) #:nodoc:
6
+ @stderr = e
7
+ end
8
+
9
+ def context_description
10
+ "in global context"
11
+ end
12
+
13
+ # Reset the GLI module internal data structures; mostly useful for testing
14
+ def reset # :nodoc:
15
+ switches.clear
16
+ flags.clear
17
+ commands.clear
18
+ @version = nil
19
+ @config_file = nil
20
+ @use_openstruct = false
21
+ @prog_desc = nil
22
+ @error_block = false
23
+ @pre_block = false
24
+ @post_block = false
25
+ @default_command = :help
26
+ clear_nexts
27
+ end
28
+
29
+ # Get the version string
30
+ def version_string #:nodoc
31
+ @version
32
+ end
33
+
34
+ # Runs whatever command is needed based on the arguments.
35
+ #
36
+ # +args+:: the command line ARGV array
37
+ #
38
+ # Returns a number that would be a reasonable exit code
39
+ def run(args) #:nodoc:
40
+ command = nil
41
+ begin
42
+ override_defaults_based_on_config(parse_config)
43
+
44
+ add_help_switch_if_needed(switches)
45
+
46
+ global_options,command,options,arguments = GLIOptionParser.new(commands,flags,switches,accepts).parse_options(args)
47
+
48
+ copy_options_to_aliased_versions(global_options,command,options)
49
+
50
+ global_options = convert_to_openstruct_if_needed(global_options)
51
+ options = convert_to_openstruct_if_needed(options)
52
+
53
+ if proceed?(global_options,command,options,arguments)
54
+ command ||= commands[:help]
55
+ call_command(command,global_options,options,arguments)
56
+ end
57
+ 0
58
+ rescue Exception => ex
59
+ handle_exception(ex,command)
60
+ end
61
+ end
62
+
63
+
64
+ # Return the name of the config file; mostly useful for generating help docs
65
+ def config_file_name #:nodoc:
66
+ @config_file
67
+ end
68
+
69
+ def accepts #:nodoc:
70
+ @accepts ||= {}
71
+ end
72
+
73
+ # Copies all options in both global_options and options to keys for the aliases of those flags.
74
+ # For example, if a flag works with either -f or --flag, this will copy the value from [:f] to [:flag]
75
+ # to allow the user to access the options by any alias
76
+ def copy_options_to_aliased_versions(global_options,command,options) # :nodoc:
77
+ copy_options_to_aliases(global_options)
78
+ command.copy_options_to_aliases(options)
79
+ end
80
+
81
+ def parse_config # :nodoc:
82
+ config = {
83
+ 'commands' => {},
84
+ }
85
+ if @config_file && File.exist?(@config_file)
86
+ require 'yaml'
87
+ config.merge!(File.open(@config_file) { |file| YAML::load(file) })
88
+ end
89
+ config
90
+ end
91
+
92
+ def clear_nexts # :nodoc:
93
+ super
94
+ @skips_post = false
95
+ @skips_pre = false
96
+ end
97
+
98
+ def stderr
99
+ @stderr ||= STDERR
100
+ end
101
+
102
+ def self.included(klass)
103
+ @stderr = $stderr
104
+ end
105
+
106
+ def flags # :nodoc:
107
+ @flags ||= {}
108
+ end
109
+
110
+ def switches # :nodoc:
111
+ @switches ||= {}
112
+ end
113
+
114
+ def commands # :nodoc:
115
+ @commands ||= {:help => GLI::Commands::Help.new(self)}
116
+ end
117
+
118
+ def pre_block
119
+ @pre_block ||= Proc.new do
120
+ true
121
+ end
122
+ end
123
+
124
+ def post_block
125
+ @post_block ||= Proc.new do
126
+ end
127
+ end
128
+
129
+ # Sets the default values for flags based on the configuration
130
+ def override_defaults_based_on_config(config)
131
+ override_default(flags,config)
132
+ override_default(switches,config)
133
+
134
+ override_command_defaults(commands,config)
135
+ end
136
+
137
+ def override_command_defaults(command_list,config)
138
+ command_list.each do |command_name,command|
139
+ next if command_name == :initconfig || command.nil?
140
+ command_config = (config['commands'] || {})[command_name] || {}
141
+
142
+ override_default(command.topmost_ancestor.flags,command_config)
143
+ override_default(command.topmost_ancestor.switches,command_config)
144
+
145
+ override_command_defaults(command.commands,command_config)
146
+ end
147
+ end
148
+
149
+ def override_default(tokens,config)
150
+ tokens.each do |name,token|
151
+ token.default_value=config[name] if config[name]
152
+ end
153
+ end
154
+
155
+ private
156
+
157
+ def handle_exception(ex,command)
158
+ if regular_error_handling?(ex)
159
+ stderr.puts error_message(ex)
160
+ if ex.kind_of?(OptionParser::ParseError) || ex.kind_of?(BadCommandLine)
161
+ stderr.puts
162
+ commands[:help] and commands[:help].execute([],[],command.nil? ? [] : [command.name.to_s])
163
+ end
164
+ end
165
+
166
+ raise ex if ENV['GLI_DEBUG'] == 'true'
167
+
168
+ ex.extend(GLI::StandardException)
169
+ ex.exit_code
170
+ end
171
+
172
+ # Possibly returns a copy of the passed-in Hash as an instance of GLI::Option.
173
+ # By default, it will *not*. However by putting <tt>use_openstruct true</tt>
174
+ # in your CLI definition, it will
175
+ def convert_to_openstruct_if_needed(options) # :nodoc:
176
+ @use_openstruct ? Options.new(options) : options
177
+ end
178
+
179
+ def add_help_switch_if_needed(switches)
180
+ help_switch_exists = switches.values.find { |switch|
181
+ (Array(switch.aliases) + [switch.name]).find { |an_alias|
182
+ an_alias.to_s == 'help'
183
+ }
184
+ }
185
+ unless help_switch_exists
186
+ desc 'Show this message'
187
+ switch :help, :negatable => false
188
+ end
189
+ end
190
+
191
+ # True if we should proceed with executing the command; this calls
192
+ # the pre block if it's defined
193
+ def proceed?(global_options,command,options,arguments) #:nodoc:
194
+ if command && command.skips_pre
195
+ true
196
+ else
197
+ pre_block.call(global_options,command,options,arguments)
198
+ end
199
+ end
200
+
201
+ # Returns true if we should proceed with GLI's basic error handling.
202
+ # This calls the error block if the user provided one
203
+ def regular_error_handling?(ex) #:nodoc:
204
+ if @error_block
205
+ @error_block.call(ex)
206
+ else
207
+ true
208
+ end
209
+ end
210
+
211
+ # Returns a String of the error message to show the user
212
+ # +ex+:: The exception we caught that launched the error handling routines
213
+ def error_message(ex) #:nodoc:
214
+ "error: #{ex.message}"
215
+ end
216
+
217
+ def call_command(command,global_options,options,arguments)
218
+ arguments = arguments.map { |arg| arg.dup } # unfreeze
219
+ command.execute(global_options,options,arguments)
220
+ unless command.skips_post
221
+ post_block.call(global_options,command,options,arguments)
222
+ end
223
+ end
224
+
225
+ end
226
+ end
data/lib/gli/command.rb CHANGED
@@ -1,124 +1,136 @@
1
1
  require 'gli/command_line_token.rb'
2
2
  require 'gli/copy_options_to_aliases.rb'
3
+ require 'gli/dsl.rb'
3
4
 
4
5
  module GLI
5
6
  # A command to be run, in context of global flags and switches. You are given an instance of this class
6
- # to the block you use for GLI#command. You then use the methods described here to describe the
7
- # command-specific command-line arguments, much as you use the methods in GLI to describe the global
8
- # command-line interface
7
+ # to the block you use for GLI::DSL#command. This class mixes in GLI::DSL so all of those methods are available
8
+ # to describe the command, in addition to the methods documented here, most importantly
9
+ # #action.
10
+ #
11
+ # Example:
12
+ #
13
+ # command :list do |c| # <- c is an instance of GLI::Command
14
+ # c.desc 'use long form'
15
+ # c.switch :l
16
+ #
17
+ # c.action do |global,options,args|
18
+ # # list things here
19
+ # end
20
+ #
21
+ # c.command :tasks do |t| # <- t is an instance of GLI::Command
22
+ # # this is a "subcommand" of list
23
+ #
24
+ # t.action do |global,options,args|
25
+ # # do whatever list tasks should do
26
+ # end
27
+ # end
28
+ # end
29
+ #
9
30
  class Command < CommandLineToken
10
31
  include CopyOptionsToAliases
32
+ include DSL
33
+ include CommandSupport
11
34
 
12
- # Create a new command
35
+ # Create a new command.
13
36
  #
14
- # +names+:: A String, Symbol, or Array of String or Symbol that represents the name(s) of this command.
15
- # +description+:: short description of this command as a Strign
16
- # +arguments_name+:: description of the arguments as a String, or nil if this command doesn't take arguments
17
- # +long_desc+:: a longer description of the command, possibly with multiple lines and text formatting
18
- # +skips_pre+:: if true, this command advertises that it doesn't want the pre block called first
19
- # +skips_post+:: if true, this command advertises that it doesn't want the post block called after it
20
- def initialize(names,description,arguments_name=nil,long_desc=nil,skips_pre=false,skips_post=false) # :nodoc:
21
- super(names,description,long_desc)
22
- @arguments_description = arguments_name || ''
23
- @skips_pre = skips_pre
24
- @skips_post = skips_post
37
+ # options:: Keys should be:
38
+ # +names+:: A String, Symbol, or Array of String or Symbol that represents the name(s) of this command (required).
39
+ # +description+:: short description of this command as a String
40
+ # +arguments_name+:: description of the arguments as a String, or nil if this command doesn't take arguments
41
+ # +long_desc+:: a longer description of the command, possibly with multiple lines. A double line-break is treated
42
+ # as a paragraph break. No other formatting is respected, though inner whitespace is maintained.
43
+ # +skips_pre+:: if true, this command advertises that it doesn't want the pre block called first
44
+ # +skips_post+:: if true, this command advertises that it doesn't want the post block called after it
45
+ def initialize(options)
46
+ super(options[:names],options[:description],options[:long_desc])
47
+ @arguments_description = options[:arguments_name] || ''
48
+ @skips_pre = options[:skips_pre]
49
+ @skips_post = options[:skips_post]
25
50
  clear_nexts
26
51
  end
27
52
 
28
- # Return the arguments description
29
- def arguments_description #:nodoc:
30
- @arguments_description
31
- end
32
-
33
- # If true, this command doesn't want the pre block run before it executes
34
- def skips_pre #:nodoc:
35
- @skips_pre
36
- end
37
-
38
- # If true, this command doesn't want the post block run before it executes
39
- def skips_post #:nodoc:
40
- @skips_post
41
- end
42
-
43
- # Return the Array of the command's names
44
- def names #:nodoc:
45
- all_forms
46
- end
47
-
48
- # Get the usage string
49
- # CR: This should probably not be here
50
- def usage #:nodoc:
51
- usage = name.to_s
52
- usage += ' [command options]' if !flags.empty? || !switches.empty?
53
- usage += ' ' + @arguments_description if @arguments_description
54
- usage
55
- end
56
-
57
- # Return the flags as a Hash
58
- def flags #:nodoc:
59
- @flags ||= {}
60
- end
61
- # Return the switches as a Hash
62
- def switches #:nodoc:
63
- @switches ||= {}
64
- end
65
-
66
- # describe the next switch or flag just as GLI#desc does.
67
- def desc(description); @next_desc = description; end
68
- # set the long description of this flag/switch, just as GLI#long_desc does.
69
- def long_desc(long_desc); @next_long_desc = long_desc; end
70
- # describe the argument name of the next flag, just as GLI#arg_name does.
71
- def arg_name(name); @next_arg_name = name; end
72
- # set the default value of the next flag, just as GLI#default_value does.
73
- def default_value(val); @next_default_value = val; end
74
-
75
- # Create a command-specific flag, similar to GLI#flag
76
- def flag(*names)
77
- names = [names].flatten
78
- GLI.verify_unused(names,flags,switches,"in command #{name}")
79
- flag = Flag.new(names,@next_desc,@next_arg_name,@next_default_value,@next_long_desc)
80
- flags[flag.name] = flag
81
- clear_nexts
82
- end
83
-
84
- # Create a command-specific switch, similar to GLI#switch
85
- def switch(*names)
86
- names = [names].flatten
87
- GLI.verify_unused(names,flags,switches,"in command #{name}")
88
- switch = Switch.new(names,@next_desc,@next_long_desc)
89
- switches[switch.name] = switch
90
- clear_nexts
53
+ # Set the default command if this command has subcommands and the user doesn't
54
+ # provide a subcommand when invoking THIS command. When nil, this will show an error and the help
55
+ # for this command; when set, the command with this name will be executed.
56
+ #
57
+ # +command_name+:: The primary name of the subcommand of this command that should be run by default as a String or Symbol.
58
+ def default_command(command_name)
59
+ @default_command = command_name
91
60
  end
92
61
 
93
- # Define the action to take when the user executes this command
62
+ # Define the action to take when the user executes this command. Every command should either define this
63
+ # action block, or have subcommands (or both).
94
64
  #
95
65
  # +block+:: A block of code to execute. The block will be given 3 arguments:
96
- # +global_options+:: A Hash (or Options, see GLI#use_openstruct) of the _global_ options specified
66
+ # +global_options+:: A Hash of the _global_ options specified
97
67
  # by the user, with defaults set and config file values used (if using a config file, see
98
- # GLI#config_file)
99
- # +options+:: A Hash (or Options, see GLI#use_openstruct) of the command-specific options specified by the
100
- # user, with defaults set and config file values used (if using a config file, see GLI#config_file)
68
+ # GLI::App#config_file)
69
+ # +options+:: A Hash of the command-specific options specified by the
70
+ # user, with defaults set and config file values used (if using a config file, see
71
+ # GLI::App#config_file).
101
72
  # +arguments+:: An Array of Strings representing the unparsed command line arguments
102
73
  # The block's result value is not used; raise an exception or use GLI#exit_now! if you need an early exit based
103
74
  # on an error condition
75
+ #
104
76
  def action(&block)
105
77
  @action = block
106
78
  end
107
79
 
108
- def self.name_as_string(name) #:nodoc:
109
- name.to_s
110
- end
111
-
112
- def clear_nexts #:nodoc:
113
- @next_desc = nil
114
- @next_arg_name = nil
115
- @next_default_value = nil
116
- @next_long_desc = nil
80
+ # Describes this commands action block when it *also* has subcommands.
81
+ # In this case, the GLI::DSL#desc value is the general description of the commands
82
+ # that this command groups, and the value for *this* method documents what
83
+ # will happen if you omit a subcommand.
84
+ #
85
+ # Note that if you omit the action block and specify a subcommand, that subcommand's
86
+ # description will be used to describe what happens by default.
87
+ #
88
+ # desc:: the description of what this command's action block does.
89
+ #
90
+ # Example
91
+ #
92
+ # desc 'list things'
93
+ # command :list do |c|
94
+ #
95
+ # c.desc 'list tasks'
96
+ # c.command :tasks do |t|
97
+ # t.action do |global,options,args|
98
+ # end
99
+ # end
100
+ #
101
+ # c.desc 'list contexts'
102
+ # c.command :contexts do |t|
103
+ # t.action do |global,options,args|
104
+ # end
105
+ # end
106
+ #
107
+ # c.default_desc 'list both tasks and contexts'
108
+ # c.action do |global,options,args|
109
+ # # list everything
110
+ # end
111
+ # end
112
+ #
113
+ #
114
+ # > todo help list
115
+ # NAME
116
+ # list - List things
117
+ #
118
+ # SYNOPSIS
119
+ # todo [global options] list [command options]
120
+ # todo [global options] list [command options] tasks
121
+ # todo [global options] list [command options] contexts
122
+ #
123
+ # COMMANDS
124
+ # <default> - list both tasks and contexts
125
+ # tasks - list tasks
126
+ # contexts - list contexts
127
+ #
128
+ def default_desc(desc)
129
+ @default_desc = desc
117
130
  end
118
131
 
119
- # Executes the command
120
- def execute(global_options,options,arguments) #:nodoc:
121
- @action.call(global_options,options,arguments)
132
+ def self.name_as_string(name,negatable=false) #:nodoc:
133
+ name.to_s
122
134
  end
123
135
  end
124
136
  end