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.
- 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
|