coglius 0.0.1
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/Cogfile +15 -0
- data/LICENSE +201 -0
- data/lib/coglius.rb +29 -0
- data/lib/coglius/app.rb +250 -0
- data/lib/coglius/app_support.rb +284 -0
- data/lib/coglius/command.rb +149 -0
- data/lib/coglius/command_line_option.rb +34 -0
- data/lib/coglius/command_line_token.rb +62 -0
- data/lib/coglius/command_support.rb +214 -0
- data/lib/coglius/commands/compound_command.rb +42 -0
- data/lib/coglius/commands/doc.rb +215 -0
- data/lib/coglius/commands/help.rb +73 -0
- data/lib/coglius/commands/help_modules/arg_name_formatter.rb +20 -0
- data/lib/coglius/commands/help_modules/command_finder.rb +60 -0
- data/lib/coglius/commands/help_modules/command_help_format.rb +138 -0
- data/lib/coglius/commands/help_modules/global_help_format.rb +70 -0
- data/lib/coglius/commands/help_modules/help_completion_format.rb +31 -0
- data/lib/coglius/commands/help_modules/list_formatter.rb +23 -0
- data/lib/coglius/commands/help_modules/one_line_wrapper.rb +18 -0
- data/lib/coglius/commands/help_modules/options_formatter.rb +49 -0
- data/lib/coglius/commands/help_modules/text_wrapper.rb +53 -0
- data/lib/coglius/commands/help_modules/tty_only_wrapper.rb +23 -0
- data/lib/coglius/commands/help_modules/verbatim_wrapper.rb +16 -0
- data/lib/coglius/commands/initconfig.rb +69 -0
- data/lib/coglius/commands/rdoc_document_listener.rb +116 -0
- data/lib/coglius/commands/scaffold.rb +401 -0
- data/lib/coglius/copy_options_to_aliases.rb +33 -0
- data/lib/coglius/dsl.rb +221 -0
- data/lib/coglius/exceptions.rb +54 -0
- data/lib/coglius/flag.rb +68 -0
- data/lib/coglius/gli_option_parser.rb +124 -0
- data/lib/coglius/option_parser_factory.rb +45 -0
- data/lib/coglius/options.rb +23 -0
- data/lib/coglius/switch.rb +35 -0
- data/lib/coglius/terminal.rb +94 -0
- data/lib/coglius/version.rb +5 -0
- data/templates/coglius/generator.rb.erb +26 -0
- metadata +208 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
module Coglius
|
2
|
+
|
3
|
+
# Mixin that both Coglius and Command can use to copy command-line options to the aliased versions
|
4
|
+
# of flags and switches
|
5
|
+
#
|
6
|
+
# includers must provide the methods +flags+ and +switches+ that return an Array of Flag or Switch,
|
7
|
+
# respectively
|
8
|
+
module CopyOptionsToAliases # :nodoc:
|
9
|
+
# For each option in options, copies its value to keys for the aliases of the flags or
|
10
|
+
# switches in gli_like
|
11
|
+
#
|
12
|
+
# options - Hash of options parsed from command line; this is an I/O param
|
13
|
+
def copy_options_to_aliases(options) # :nodoc:
|
14
|
+
new_options = {}
|
15
|
+
options.each do |key,value|
|
16
|
+
if flags[key] && flags[key].aliases
|
17
|
+
copy_aliases(flags[key].aliases,new_options,value)
|
18
|
+
elsif switches[key] && switches[key].aliases
|
19
|
+
copy_aliases(switches[key].aliases,new_options,value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
options.merge!(new_options)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def copy_aliases(aliases,new_options,value)
|
28
|
+
aliases.each do |alias_name|
|
29
|
+
new_options[alias_name] = value
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/coglius/dsl.rb
ADDED
@@ -0,0 +1,221 @@
|
|
1
|
+
module Coglius
|
2
|
+
# The primary DSL for Coglius. This represents the methods shared between your top-level app and
|
3
|
+
# the commands. See Coglius::Command for additional methods that apply only to command objects.
|
4
|
+
module DSL
|
5
|
+
# Describe the next switch, flag, or command. This should be a
|
6
|
+
# short, one-line description
|
7
|
+
#
|
8
|
+
# +description+:: A String of the short descripiton of the switch, flag, or command following
|
9
|
+
def desc(description); @next_desc = description; end
|
10
|
+
alias :d :desc
|
11
|
+
|
12
|
+
# Provide a longer, more detailed description. This
|
13
|
+
# will be reformatted and wrapped to fit in the terminal's columns
|
14
|
+
#
|
15
|
+
# +long_desc+:: A String that is s longer description of the switch, flag, or command following.
|
16
|
+
def long_desc(long_desc); @next_long_desc = long_desc; end
|
17
|
+
|
18
|
+
# Describe the argument name of the next flag. It's important to keep
|
19
|
+
# this VERY short and, ideally, without any spaces (see Example).
|
20
|
+
#
|
21
|
+
# +name+:: A String that *briefly* describes the argument given to the following command or flag.
|
22
|
+
# +options+:: Symbol or array of symbols to annotate this argument. This doesn't affect parsing, just
|
23
|
+
# the help output. Values recognized are:
|
24
|
+
# +:optional+:: indicates this argument is optional; will format it with square brackets
|
25
|
+
# +:multiple+:: indicates multiple values are accepted; will format appropriately
|
26
|
+
#
|
27
|
+
# Example:
|
28
|
+
# desc 'Set the filename'
|
29
|
+
# arg_name 'file_name'
|
30
|
+
# flag [:f,:filename]
|
31
|
+
#
|
32
|
+
# Produces:
|
33
|
+
# -f, --filename=file_name Set the filename
|
34
|
+
def arg_name(name,options=[])
|
35
|
+
@next_arg_name = name
|
36
|
+
@next_arg_options = options
|
37
|
+
end
|
38
|
+
|
39
|
+
# set the default value of the next flag or switch
|
40
|
+
#
|
41
|
+
# +val+:: The default value to be used for the following flag if the user doesn't specify one
|
42
|
+
# and, when using a config file, the config also doesn't specify one. For a switch, this is
|
43
|
+
# the value to be used if the switch isn't specified on the command-line. Note that if you
|
44
|
+
# set a switch to have a default of true, using the switch on the command-line has no effect.
|
45
|
+
# To disable a switch where the default is true, use the <tt>--no-</tt> form.
|
46
|
+
def default_value(val); @next_default_value = val; end
|
47
|
+
|
48
|
+
# Create a flag, which is a switch that takes an argument
|
49
|
+
#
|
50
|
+
# +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names
|
51
|
+
# and aliases for this flag. The last element can be a hash of options:
|
52
|
+
# +:desc+:: the description, instead of using #desc
|
53
|
+
# +:long_desc+:: the long_description, instead of using #long_desc
|
54
|
+
# +:default_value+:: the default value, instead of using #default_value
|
55
|
+
# +:arg_name+:: the arg name, instead of using #arg_name
|
56
|
+
# +:must_match+:: A regexp that the flag's value must match
|
57
|
+
# +:type+:: A Class (or object you passed to Coglius::App#accept) to trigger type coversion
|
58
|
+
#
|
59
|
+
# Example:
|
60
|
+
#
|
61
|
+
# desc 'Set the filename'
|
62
|
+
# flag [:f,:filename,'file-name']
|
63
|
+
#
|
64
|
+
# flag :ipaddress, :desc => "IP Address", :must_match => /\d+\.\d+\.\d+\.\d+/
|
65
|
+
#
|
66
|
+
# flag :names, :desc => "list of names", :type => Array
|
67
|
+
#
|
68
|
+
# Produces:
|
69
|
+
#
|
70
|
+
# -f, --filename, --file-name=arg Set the filename
|
71
|
+
def flag(*names)
|
72
|
+
options = extract_options(names)
|
73
|
+
names = [names].flatten
|
74
|
+
|
75
|
+
verify_unused(names)
|
76
|
+
flag = Flag.new(names,options)
|
77
|
+
flags[flag.name] = flag
|
78
|
+
|
79
|
+
clear_nexts
|
80
|
+
flags_declaration_order << flag
|
81
|
+
flag
|
82
|
+
end
|
83
|
+
alias :f :flag
|
84
|
+
|
85
|
+
# Create a switch, which is a command line flag that takes no arguments (thus, it _switches_ something on)
|
86
|
+
#
|
87
|
+
# +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names
|
88
|
+
# and aliases for this switch. The last element can be a hash of options:
|
89
|
+
# +:desc+:: the description, instead of using #desc
|
90
|
+
# +:long_desc+:: the long_description, instead of using #long_desc
|
91
|
+
# +:default_value+:: if the switch is omitted, use this as the default value. By default, switches default to off, or +false+
|
92
|
+
# +:negatable+:: if true, this switch will get a negatable form (e.g. <tt>--[no-]switch</tt>, false it will not. Default is true
|
93
|
+
def switch(*names)
|
94
|
+
options = extract_options(names)
|
95
|
+
names = [names].flatten
|
96
|
+
|
97
|
+
verify_unused(names)
|
98
|
+
switch = Switch.new(names,options)
|
99
|
+
switches[switch.name] = switch
|
100
|
+
|
101
|
+
clear_nexts
|
102
|
+
switches_declaration_order << switch
|
103
|
+
switch
|
104
|
+
end
|
105
|
+
alias :s :switch
|
106
|
+
|
107
|
+
def clear_nexts # :nodoc:
|
108
|
+
@next_desc = nil
|
109
|
+
@next_arg_name = nil
|
110
|
+
@next_arg_options = nil
|
111
|
+
@next_default_value = nil
|
112
|
+
@next_long_desc = nil
|
113
|
+
end
|
114
|
+
|
115
|
+
# Define a new command. This can be done in a few ways, but the most common method is
|
116
|
+
# to pass a symbol (or Array of symbols) representing the command name (or names) and a block.
|
117
|
+
# The block will be given an instance of the Command that was created.
|
118
|
+
# You then may call methods on this object to define aspects of that Command.
|
119
|
+
#
|
120
|
+
# Alternatively, you can call this with a one element Hash, where the key is the symbol representing the name
|
121
|
+
# of the command, and the value being an Array of symbols representing the commands to call in order, as a
|
122
|
+
# chained or compound command. Note that these commands must exist already, and that only those command-specific
|
123
|
+
# options defined in *this* command will be parsed and passed to the chained commands. This might not be what you expect
|
124
|
+
#
|
125
|
+
# +names+:: a String or Symbol, or an Array of String or Symbol that represent all the different names and aliases
|
126
|
+
# for this command *or* a Hash, as described above.
|
127
|
+
#
|
128
|
+
# ==Examples
|
129
|
+
#
|
130
|
+
# # Make a command named list
|
131
|
+
# command :list do |c|
|
132
|
+
# c.action do |global_options,options,args|
|
133
|
+
# # your command code
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# # Make a command named list, callable by ls as well
|
138
|
+
# command [:list,:ls] do |c|
|
139
|
+
# c.action do |global_options,options,args|
|
140
|
+
# # your command code
|
141
|
+
# end
|
142
|
+
# end
|
143
|
+
#
|
144
|
+
# # Make a command named all, that calls list and list_contexts
|
145
|
+
# command :all => [ :list, :list_contexts ]
|
146
|
+
#
|
147
|
+
# # Make a command named all, aliased as :a:, that calls list and list_contexts
|
148
|
+
# command [:all,:a] => [ :list, :list_contexts ]
|
149
|
+
#
|
150
|
+
def command(*names)
|
151
|
+
command_options = {
|
152
|
+
:description => @next_desc,
|
153
|
+
:arguments_name => @next_arg_name,
|
154
|
+
:arguments_options => @next_arg_options,
|
155
|
+
:long_desc => @next_long_desc,
|
156
|
+
:skips_pre => @skips_pre,
|
157
|
+
:skips_post => @skips_post,
|
158
|
+
:skips_around => @skips_around,
|
159
|
+
}
|
160
|
+
if names.first.kind_of? Hash
|
161
|
+
command = Coglius::Commands::CompoundCommand.new(self,
|
162
|
+
names.first,
|
163
|
+
command_options)
|
164
|
+
command.parent = self
|
165
|
+
commands[command.name] = command
|
166
|
+
else
|
167
|
+
command = Command.new(command_options.merge(:names => [names].flatten))
|
168
|
+
command.parent = self
|
169
|
+
commands[command.name] = command
|
170
|
+
yield command
|
171
|
+
end
|
172
|
+
@commands_declaration_order ||= []
|
173
|
+
@commands_declaration_order << command
|
174
|
+
clear_nexts
|
175
|
+
end
|
176
|
+
alias :c :command
|
177
|
+
|
178
|
+
def flags_declaration_order # :nodoc:
|
179
|
+
@flags_declaration_order ||= []
|
180
|
+
end
|
181
|
+
|
182
|
+
def switches_declaration_order # :nodoc:
|
183
|
+
@switches_declaration_order ||= []
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
private
|
188
|
+
# Checks that the names passed in have not been used in another flag or option
|
189
|
+
def verify_unused(names) # :nodoc:
|
190
|
+
names.each do |name|
|
191
|
+
verify_unused_in_option(name,flags,"flag")
|
192
|
+
verify_unused_in_option(name,switches,"switch")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def verify_unused_in_option(name,option_like,type) # :nodoc:
|
197
|
+
return if name.to_s == 'help'
|
198
|
+
raise ArgumentError.new("#{name} has already been specified as a #{type} #{context_description}") if option_like[name]
|
199
|
+
option_like.each do |one_option_name,one_option|
|
200
|
+
if one_option.aliases
|
201
|
+
if one_option.aliases.include? name
|
202
|
+
raise ArgumentError.new("#{name} has already been specified as an alias of #{type} #{one_option_name} #{context_description}")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Extract the options hash out of the argument to flag/switch and
|
209
|
+
# set the values if using classic style
|
210
|
+
def extract_options(names)
|
211
|
+
options = {}
|
212
|
+
options = names.pop if names.last.kind_of? Hash
|
213
|
+
options = { :desc => @next_desc,
|
214
|
+
:long_desc => @next_long_desc,
|
215
|
+
:default_value => @next_default_value,
|
216
|
+
:arg_name => @next_arg_name}.merge(options)
|
217
|
+
end
|
218
|
+
|
219
|
+
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Coglius
|
2
|
+
# Mixed into all exceptions that Coglius handles; you can use this to catch
|
3
|
+
# anything that came from Coglius intentionally. You can also mix this into non-Coglius
|
4
|
+
# exceptions to get Coglius's exit behavior.
|
5
|
+
module StandardException
|
6
|
+
def exit_code; 1; end
|
7
|
+
end
|
8
|
+
# Indicates that the command line invocation was bad
|
9
|
+
class BadCommandLine < StandardError
|
10
|
+
include StandardException
|
11
|
+
def exit_code; 64; end
|
12
|
+
end
|
13
|
+
|
14
|
+
# Indicates the bad command line was an unknown command
|
15
|
+
class UnknownCommand < BadCommandLine
|
16
|
+
end
|
17
|
+
|
18
|
+
# Indicates the bad command line was an unknown global argument
|
19
|
+
class UnknownGlobalArgument < BadCommandLine
|
20
|
+
end
|
21
|
+
|
22
|
+
# Indicates the bad command line was an unknown command argument
|
23
|
+
class UnknownCommandArgument < BadCommandLine
|
24
|
+
# The command for which the argument was unknown
|
25
|
+
attr_reader :command
|
26
|
+
# +message+:: the error message to show the user
|
27
|
+
# +command+:: the command we were using to parse command-specific options
|
28
|
+
def initialize(message,command)
|
29
|
+
super(message)
|
30
|
+
@command = command
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Raise this if you want to use an exit status that isn't the default
|
35
|
+
# provided by Coglius. Note that Coglius::App#exit_now! might be a bit more to your liking.
|
36
|
+
#
|
37
|
+
# Example:
|
38
|
+
#
|
39
|
+
# raise CustomExit.new("Not connected to DB",-5) unless connected?
|
40
|
+
# raise CustomExit.new("Bad SQL",-6) unless valid_sql?(args[0])
|
41
|
+
#
|
42
|
+
class CustomExit < StandardError
|
43
|
+
include StandardException
|
44
|
+
attr_reader :exit_code #:nodoc:
|
45
|
+
# Create a custom exit exception
|
46
|
+
#
|
47
|
+
# +message+:: String containing error message to show the user
|
48
|
+
# +exit_code+:: the exit code to use (as an Int), overridding Coglius's default
|
49
|
+
def initialize(message,exit_code)
|
50
|
+
super(message)
|
51
|
+
@exit_code = exit_code
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/coglius/flag.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'coglius/command_line_option.rb'
|
2
|
+
|
3
|
+
module Coglius
|
4
|
+
# Defines a flag, which is to say a switch that takes an argument
|
5
|
+
class Flag < CommandLineOption # :nodoc:
|
6
|
+
|
7
|
+
# Regexp that is used to see if the flag's argument matches
|
8
|
+
attr_reader :must_match
|
9
|
+
|
10
|
+
# Type to which we want to cast the values
|
11
|
+
attr_reader :type
|
12
|
+
|
13
|
+
# Name of the argument that user configured
|
14
|
+
attr_reader :argument_name
|
15
|
+
|
16
|
+
# Creates a new option
|
17
|
+
#
|
18
|
+
# names:: Array of symbols or strings representing the names of this switch
|
19
|
+
# options:: hash of options:
|
20
|
+
# :desc:: the short description
|
21
|
+
# :long_desc:: the long description
|
22
|
+
# :default_value:: the default value of this option
|
23
|
+
# :arg_name:: the name of the flag's argument, default is "arg"
|
24
|
+
# :must_match:: a regexp that the flag's value must match
|
25
|
+
# :type:: a class to convert the value to
|
26
|
+
# :mask:: if true, the default value of this flag will not be output in the help.
|
27
|
+
# This is useful for password flags where you might not want to show it
|
28
|
+
# on the command-line.
|
29
|
+
def initialize(names,options)
|
30
|
+
super(names,options)
|
31
|
+
@argument_name = options[:arg_name] || "arg"
|
32
|
+
@default_value = options[:default_value]
|
33
|
+
@must_match = options[:must_match]
|
34
|
+
@type = options[:type]
|
35
|
+
@mask = options[:mask]
|
36
|
+
end
|
37
|
+
|
38
|
+
def safe_default_value
|
39
|
+
if @mask
|
40
|
+
"********"
|
41
|
+
else
|
42
|
+
default_value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def arguments_for_option_parser
|
47
|
+
args = all_forms_a.map { |name| "#{name} VAL" }
|
48
|
+
args << @must_match if @must_match
|
49
|
+
args << @type if @type
|
50
|
+
args
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns a string of all possible forms
|
54
|
+
# of this flag. Mostly intended for printing
|
55
|
+
# to the user.
|
56
|
+
def all_forms(joiner=', ')
|
57
|
+
forms = all_forms_a
|
58
|
+
string = forms.join(joiner)
|
59
|
+
if forms[-1] =~ /^\-\-/
|
60
|
+
string += '='
|
61
|
+
else
|
62
|
+
string += ' '
|
63
|
+
end
|
64
|
+
string += @argument_name
|
65
|
+
return string
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
module Coglius
|
2
|
+
# Parses the command-line options using an actual +OptionParser+
|
3
|
+
class CogliusOptionParser
|
4
|
+
def initialize(commands,flags,switches,accepts,default_command = nil)
|
5
|
+
@commands = commands
|
6
|
+
@flags = flags
|
7
|
+
@switches = switches
|
8
|
+
@accepts = accepts
|
9
|
+
@default_command = default_command
|
10
|
+
end
|
11
|
+
|
12
|
+
# Given the command-line argument array, returns and array of size 4:
|
13
|
+
#
|
14
|
+
# 0:: global options
|
15
|
+
# 1:: command, as a Command
|
16
|
+
# 2:: command-specific options
|
17
|
+
# 3:: unparsed arguments
|
18
|
+
def parse_options(args) # :nodoc:
|
19
|
+
args_clone = args.clone
|
20
|
+
global_options = {}
|
21
|
+
command = nil
|
22
|
+
command_options = {}
|
23
|
+
remaining_args = nil
|
24
|
+
|
25
|
+
global_options,command_name,args = parse_global_options(OptionParserFactory.new(@flags,@switches,@accepts), args)
|
26
|
+
@flags.each do |name,flag|
|
27
|
+
global_options[name] = flag.default_value unless global_options[name]
|
28
|
+
end
|
29
|
+
@switches.each do |name,switch|
|
30
|
+
global_options[name] = switch.default_value if global_options[name].nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
command_name ||= @default_command || :help
|
34
|
+
command = find_command(command_name)
|
35
|
+
if Array(command).empty?
|
36
|
+
raise UnknownCommand.new("Unknown command '#{command_name}'")
|
37
|
+
elsif command.kind_of? Array
|
38
|
+
raise UnknownCommand.new("Ambiguous command '#{command_name}'. It matches #{command.sort.join(',')}")
|
39
|
+
end
|
40
|
+
|
41
|
+
command_options,args = parse_command_options(OptionParserFactory.new(command.flags,command.switches,@accepts),
|
42
|
+
command,
|
43
|
+
args)
|
44
|
+
|
45
|
+
command.flags.each do |name,flag|
|
46
|
+
command_options[name] = flag.default_value unless command_options[name]
|
47
|
+
end
|
48
|
+
command.switches.each do |name,switch|
|
49
|
+
command_options[name] = switch.default_value if command_options[name].nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
[global_options,command,command_options,args]
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def parse_command_options(option_parser_factory,command,args)
|
58
|
+
option_parser,command_options = option_parser_factory.option_parser
|
59
|
+
help_args = %w(-h --help).reject { |_| command.has_option?(_) }
|
60
|
+
|
61
|
+
unless help_args.empty?
|
62
|
+
option_parser.on(*help_args) do
|
63
|
+
# We need to raise the help exception later in the process, after
|
64
|
+
# the command-line has been parsed, so we know what command
|
65
|
+
# to show help for. Unfortunately, we can't just call #action
|
66
|
+
# on the command to override what to do, so...metaprogramming.
|
67
|
+
class << command
|
68
|
+
def execute(*help_args)
|
69
|
+
exception = BadCommandLine.new(nil)
|
70
|
+
class << exception
|
71
|
+
def exit_code; 0; end
|
72
|
+
end
|
73
|
+
raise exception
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
option_parser.parse!(args)
|
79
|
+
[command_options,args]
|
80
|
+
rescue OptionParser::InvalidOption => ex
|
81
|
+
raise UnknownCommandArgument.new("Unknown option #{ex.args.join(' ')}",command)
|
82
|
+
rescue OptionParser::InvalidArgument => ex
|
83
|
+
raise UnknownCommandArgument.new("#{ex.reason}: #{ex.args.join(' ')}",command)
|
84
|
+
end
|
85
|
+
|
86
|
+
def parse_global_options(option_parser_factory,args,&error_handler)
|
87
|
+
if error_handler.nil?
|
88
|
+
error_handler = lambda { |message|
|
89
|
+
raise UnknownGlobalArgument.new(message)
|
90
|
+
}
|
91
|
+
end
|
92
|
+
option_parser,global_options = option_parser_factory.option_parser
|
93
|
+
command = nil
|
94
|
+
option_parser.order!(args) do |non_option|
|
95
|
+
command = non_option
|
96
|
+
break
|
97
|
+
end
|
98
|
+
[global_options,command,args]
|
99
|
+
rescue OptionParser::InvalidOption => ex
|
100
|
+
error_handler.call("Unknown option #{ex.args.join(' ')}")
|
101
|
+
rescue OptionParser::InvalidArgument => ex
|
102
|
+
error_handler.call("#{ex.reason}: #{ex.args.join(' ')}")
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_command(name) # :nodoc:
|
106
|
+
names_to_commands = {}
|
107
|
+
@commands.each do |command_name,command|
|
108
|
+
names_to_commands[command_name.to_s] = command
|
109
|
+
Array(command.aliases).each do |command_alias|
|
110
|
+
names_to_commands[command_alias.to_s] = command
|
111
|
+
end
|
112
|
+
end
|
113
|
+
names_to_commands.fetch(name.to_s) do |command_to_match|
|
114
|
+
find_command_by_partial_name(names_to_commands, command_to_match)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def find_command_by_partial_name(names_to_commands, command_to_match)
|
119
|
+
partial_matches = names_to_commands.keys.select { |command_name| command_name =~ /^#{command_to_match}/ }
|
120
|
+
return names_to_commands[partial_matches[0]] if partial_matches.size == 1
|
121
|
+
partial_matches
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|