gli 1.6.0 → 2.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +11 -0
- data/.rvmrc +1 -0
- data/.travis.yml +10 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +201 -0
- data/ObjectModel.graffle +1191 -0
- data/README.rdoc +60 -10
- data/Rakefile +145 -0
- data/bin/gli +12 -30
- data/bin/report_on_rake_results +10 -0
- data/bin/test_all_rubies.sh +6 -0
- data/features/gli_executable.feature +84 -0
- data/features/gli_init.feature +219 -0
- data/features/step_definitions/gli_executable_steps.rb +12 -0
- data/features/step_definitions/gli_init_steps.rb +11 -0
- data/features/step_definitions/todo_steps.rb +69 -0
- data/features/support/env.rb +49 -0
- data/features/todo.feature +182 -0
- data/gli.cheat +95 -0
- data/gli.gemspec +34 -0
- data/lib/gli.rb +11 -571
- data/lib/gli/app.rb +184 -0
- data/lib/gli/app_support.rb +226 -0
- data/lib/gli/command.rb +107 -95
- data/lib/gli/command_line_option.rb +34 -0
- data/lib/gli/command_line_token.rb +13 -9
- data/lib/gli/command_support.rb +200 -0
- data/lib/gli/commands/compound_command.rb +42 -0
- data/lib/gli/commands/help.rb +63 -0
- data/lib/gli/commands/help_modules/command_help_format.rb +134 -0
- data/lib/gli/commands/help_modules/global_help_format.rb +61 -0
- data/lib/gli/commands/help_modules/list_formatter.rb +22 -0
- data/lib/gli/commands/help_modules/options_formatter.rb +50 -0
- data/lib/gli/commands/help_modules/text_wrapper.rb +53 -0
- data/lib/gli/commands/initconfig.rb +67 -0
- data/lib/{support → gli/commands}/scaffold.rb +150 -34
- data/lib/gli/dsl.rb +194 -0
- data/lib/gli/exceptions.rb +13 -4
- data/lib/gli/flag.rb +30 -41
- data/lib/gli/gli_option_parser.rb +98 -0
- data/lib/gli/option_parser_factory.rb +44 -0
- data/lib/gli/options.rb +2 -1
- data/lib/gli/switch.rb +19 -51
- data/lib/gli/terminal.rb +30 -20
- data/lib/gli/version.rb +5 -0
- data/test/apps/README.md +2 -0
- data/test/apps/todo/Gemfile +2 -0
- data/test/apps/todo/README.rdoc +6 -0
- data/test/apps/todo/Rakefile +23 -0
- data/test/apps/todo/bin/todo +52 -0
- data/test/apps/todo/lib/todo/commands/create.rb +22 -0
- data/test/apps/todo/lib/todo/commands/list.rb +53 -0
- data/test/apps/todo/lib/todo/commands/ls.rb +47 -0
- data/test/apps/todo/lib/todo/version.rb +3 -0
- data/test/apps/todo/test/tc_nothing.rb +14 -0
- data/test/apps/todo/todo.gemspec +23 -0
- data/test/apps/todo/todo.rdoc +5 -0
- data/test/config.yaml +10 -0
- data/test/fake_std_out.rb +30 -0
- data/test/gli.reek +122 -0
- data/test/init_simplecov.rb +8 -0
- data/test/option_test_helper.rb +13 -0
- data/test/roodi.yaml +18 -0
- data/test/tc_command.rb +260 -0
- data/test/tc_compount_command.rb +22 -0
- data/test/tc_flag.rb +56 -0
- data/test/tc_gli.rb +611 -0
- data/test/tc_help.rb +223 -0
- data/test/tc_options.rb +31 -0
- data/test/tc_subcommands.rb +162 -0
- data/test/tc_switch.rb +57 -0
- data/test/tc_terminal.rb +97 -0
- data/test/test_helper.rb +13 -0
- metadata +318 -49
- data/lib/gli_version.rb +0 -3
- data/lib/support/help.rb +0 -179
- data/lib/support/initconfig.rb +0 -34
- 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.
|
7
|
-
#
|
8
|
-
#
|
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
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@
|
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
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
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
|
100
|
-
# user, with defaults set and config file values used (if using a config file, see
|
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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
120
|
-
|
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
|