coglius 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|