rubikon 0.2.1 → 0.3.0
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/LICENSE +0 -0
- data/README.md +39 -16
- data/Rakefile +29 -16
- data/lib/core_ext/string.rb +16 -0
- data/lib/rubikon/application/base.rb +10 -10
- data/lib/rubikon/application/class_methods.rb +19 -31
- data/lib/rubikon/application/dsl_methods.rb +427 -0
- data/lib/rubikon/application/instance_methods.rb +160 -261
- data/lib/rubikon/command.rb +135 -0
- data/lib/rubikon/exceptions.rb +62 -9
- data/lib/rubikon/flag.rb +56 -0
- data/lib/rubikon/option.rb +30 -0
- data/lib/rubikon/parameter.rb +101 -0
- data/lib/rubikon/progress_bar.rb +23 -12
- data/lib/rubikon/throbber.rb +10 -5
- data/lib/rubikon.rb +14 -3
- data/test/application_tests.rb +60 -73
- data/test/command_tests.rb +102 -0
- data/test/commands/external_command.rb +1 -0
- data/test/flag_tests.rb +40 -0
- data/test/option_tests.rb +75 -0
- data/test/progress_bar_tests.rb +13 -3
- data/test/test_helper.rb +3 -3
- data/test/testapps.rb +64 -0
- data/test/throbber_tests.rb +25 -3
- metadata +64 -19
- data/VERSION.yml +0 -4
- data/lib/rubikon/action.rb +0 -74
- data/test/action_tests.rb +0 -36
- data/test/testapp.rb +0 -64
@@ -1,8 +1,12 @@
|
|
1
|
-
# This code is free software; you can redistribute it and/or modify it under
|
2
|
-
# terms of the new BSD License.
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
3
|
#
|
4
|
-
# Copyright (c) 2009, Sebastian Staudt
|
4
|
+
# Copyright (c) 2009-2010, Sebastian Staudt
|
5
5
|
|
6
|
+
require 'rubikon/command'
|
7
|
+
require 'rubikon/exceptions'
|
8
|
+
require 'rubikon/flag'
|
9
|
+
require 'rubikon/option'
|
6
10
|
require 'rubikon/progress_bar'
|
7
11
|
require 'rubikon/throbber'
|
8
12
|
|
@@ -10,183 +14,70 @@ module Rubikon
|
|
10
14
|
|
11
15
|
module Application
|
12
16
|
|
17
|
+
# This module contains internal instance methods of +Application::Base+ and
|
18
|
+
# its subclasses.
|
19
|
+
#
|
20
|
+
# @author Sebastian Staudt
|
21
|
+
# @see Application::Base
|
22
|
+
# @since 0.2.0
|
13
23
|
module InstanceMethods
|
14
24
|
|
15
|
-
#
|
16
|
-
|
17
|
-
# If you really need to override this in your application class, be sure to
|
18
|
-
# call +super+
|
19
|
-
def initialize
|
20
|
-
@actions = {}
|
21
|
-
@aliases = {}
|
22
|
-
@default = nil
|
23
|
-
@initialized = false
|
24
|
-
@settings = {
|
25
|
-
:autorun => true,
|
26
|
-
:auto_shortopts => true,
|
27
|
-
:dashed_options => true,
|
28
|
-
:help_banner => "Usage: #{$0}",
|
29
|
-
:istream => $stdin,
|
30
|
-
:name => self.class.to_s,
|
31
|
-
:ostream => $stdout,
|
32
|
-
:raise_errors => false
|
33
|
-
}
|
34
|
-
end
|
35
|
-
|
36
|
-
# Define an Application Action
|
37
|
-
#
|
38
|
-
# +name+:: The name of the action. Used as an option parameter.
|
39
|
-
# +options+:: A Hash of options to be used on the created Action
|
40
|
-
# (default: <tt>{}</tt>)
|
41
|
-
# +block+:: A block containing the code that should be executed when this
|
42
|
-
# Action is called, i.e. when the Application is called with
|
43
|
-
# the associated option parameter
|
44
|
-
def action(name, options = {}, &block)
|
45
|
-
raise "No block given" unless block_given?
|
46
|
-
|
47
|
-
action = Action.new(options, &block)
|
48
|
-
|
49
|
-
key = name.to_s
|
50
|
-
if @settings[:dashed_options]
|
51
|
-
if @settings[:auto_shortopts]
|
52
|
-
short_key = "-#{key[0..0]}"
|
53
|
-
@actions[short_key.to_sym] = action unless @actions.key? short_key
|
54
|
-
end
|
55
|
-
key = "--#{key}"
|
56
|
-
end
|
57
|
-
|
58
|
-
@actions[key.to_sym] = action
|
59
|
-
end
|
60
|
-
|
61
|
-
# Define an alias to an Action
|
62
|
-
#
|
63
|
-
# +name+:: The name of the alias
|
64
|
-
# +action+:: The name of the Action that should be aliased
|
65
|
-
#
|
66
|
-
# Example:
|
67
|
-
#
|
68
|
-
# action_alias :doit, :dosomething
|
69
|
-
def action_alias(name, action)
|
70
|
-
@aliases[name.to_sym] = action.to_sym
|
71
|
-
end
|
72
|
-
|
73
|
-
# Define the default Action of the Application
|
74
|
-
#
|
75
|
-
# +options+:: A Hash of options to be used on the created Action
|
76
|
-
# (default: <tt>{}</tt>)
|
77
|
-
# +block+:: A block containing the code that should be executed when this
|
78
|
-
# Action is called, i.e. when no option is given to the
|
79
|
-
# Application
|
80
|
-
def default(options = {}, &block)
|
81
|
-
@default = Action.new(options, &block)
|
82
|
-
end
|
83
|
-
|
84
|
-
# Prompts the user for input
|
85
|
-
#
|
86
|
-
# If +prompt+ is not empty this will display a prompt using
|
87
|
-
# <tt>prompt.to_s</tt>.
|
88
|
-
#
|
89
|
-
# +prompt+:: A String or other Object responding to +to_s+ used for
|
90
|
-
# displaying a prompt to the user (default: <tt>''</tt>)
|
91
|
-
#
|
92
|
-
# Example:
|
93
|
-
#
|
94
|
-
# action 'interactive' do
|
95
|
-
# # Display a prompt "Please type something: "
|
96
|
-
# user_provided_value = input 'Please type something'
|
97
|
-
#
|
98
|
-
# # Do something with the data
|
99
|
-
# ...
|
100
|
-
# end
|
101
|
-
def input(prompt = '')
|
102
|
-
unless prompt.to_s.empty?
|
103
|
-
ostream << "#{prompt}: "
|
104
|
-
end
|
105
|
-
@settings[:istream].gets[0..-2]
|
106
|
-
end
|
107
|
-
|
108
|
-
# Convenience method for accessing the user-defined output stream
|
109
|
-
#
|
110
|
-
# Use this if you want to work directly with the output stream
|
111
|
-
#
|
112
|
-
# Example:
|
113
|
-
#
|
114
|
-
# ostream.flush
|
115
|
-
def ostream
|
116
|
-
@settings[:ostream]
|
117
|
-
end
|
118
|
-
|
119
|
-
# Displays a progress bar while the given block is executed
|
120
|
-
#
|
121
|
-
# Inside the block you have access to a instance of ProgressBar. So you
|
122
|
-
# can update the progress using <tt>ProgressBar#+</tt>.
|
123
|
-
#
|
124
|
-
# +options+:: A Hash of options that should be passed to the ProgressBar
|
125
|
-
# object. For available options see ProgressBar
|
126
|
-
# +block+:: The block to execute
|
127
|
-
#
|
128
|
-
# Example:
|
129
|
-
#
|
130
|
-
# progress_bar(:maximum => 5) do |progress|
|
131
|
-
# 5.times do |file|
|
132
|
-
# File.read("any#{file}.txt")
|
133
|
-
# progress.+
|
134
|
-
# end
|
135
|
-
# end
|
136
|
-
def progress_bar(*options, &block)
|
137
|
-
hidden_output do |ostream|
|
138
|
-
options = options[0]
|
139
|
-
options[:ostream] = ostream
|
140
|
-
|
141
|
-
progress = ProgressBar.new(options)
|
142
|
-
|
143
|
-
block.call(progress)
|
144
|
-
end
|
145
|
-
end
|
25
|
+
# @return [String] The absolute path of the application
|
26
|
+
attr_reader :path
|
146
27
|
|
147
|
-
#
|
28
|
+
# Initialize with default settings
|
148
29
|
#
|
149
|
-
#
|
150
|
-
|
151
|
-
@settings[:ostream] << text
|
152
|
-
@settings[:ostream].flush
|
153
|
-
end
|
154
|
-
|
155
|
-
# Output a character using +IO#putc+ of the output stream
|
30
|
+
# If you really need to override this in your application class, be sure
|
31
|
+
# to call +super+
|
156
32
|
#
|
157
|
-
#
|
158
|
-
def
|
159
|
-
@
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
@settings
|
33
|
+
# @see #set
|
34
|
+
def initialize
|
35
|
+
@commands = {}
|
36
|
+
@current_command = nil
|
37
|
+
@current_global_option = nil
|
38
|
+
@global_parameters = {}
|
39
|
+
@initialized = false
|
40
|
+
@parameters = []
|
41
|
+
@path = File.dirname($0)
|
42
|
+
@settings = {
|
43
|
+
:autorun => true,
|
44
|
+
:help_as_default => true,
|
45
|
+
:help_banner => "Usage: #{$0}",
|
46
|
+
:istream => $stdin,
|
47
|
+
:name => self.class.to_s,
|
48
|
+
:ostream => $stdout,
|
49
|
+
:raise_errors => false
|
50
|
+
}
|
167
51
|
end
|
168
52
|
|
169
53
|
# Run this application
|
170
54
|
#
|
171
|
-
#
|
172
|
-
#
|
55
|
+
# Calling this method explicitly is not required when you want to create
|
56
|
+
# a simple application (having one main class inheriting from
|
57
|
+
# Rubikon::Application). But it's useful for testing or if you want to
|
58
|
+
# have some sort of sub-applications.
|
173
59
|
#
|
174
|
-
#
|
175
|
-
#
|
176
|
-
# Rubikon::Application). But it's useful for testing or if you want to have
|
177
|
-
# some sort of sub-applications.
|
60
|
+
# @param [Array<String>] args The command line arguments that should be
|
61
|
+
# given to the application as options
|
178
62
|
def run(args = ARGV)
|
179
|
-
init unless @initialized
|
180
|
-
action_results = []
|
181
|
-
|
182
63
|
begin
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
64
|
+
init unless @initialized
|
65
|
+
|
66
|
+
command, parameters, args = parse_arguments(args)
|
67
|
+
|
68
|
+
parameters.each do |parameter|
|
69
|
+
if parameter.is_a? Option
|
70
|
+
parameter.check_args
|
71
|
+
@current_global_option = parameter
|
188
72
|
end
|
73
|
+
parameter.active!
|
74
|
+
@current_global_option = nil
|
189
75
|
end
|
76
|
+
|
77
|
+
@current_command = command
|
78
|
+
result = command.run(*args)
|
79
|
+
@current_command = nil
|
80
|
+
result
|
190
81
|
rescue
|
191
82
|
raise $! if @settings[:raise_errors]
|
192
83
|
|
@@ -194,96 +85,62 @@ module Rubikon
|
|
194
85
|
puts " #{$!.backtrace.join("\n ")}" if $DEBUG
|
195
86
|
exit 1
|
196
87
|
end
|
197
|
-
|
198
|
-
action_results
|
199
|
-
end
|
200
|
-
|
201
|
-
# Sets an application setting
|
202
|
-
#
|
203
|
-
# +setting+:: The name of the setting to change, will be symbolized first.
|
204
|
-
# +value+:: The value the setting should be changed to
|
205
|
-
#
|
206
|
-
# Available settings
|
207
|
-
# +autorun+:: If true, let the application run as soon as its class
|
208
|
-
# is defined
|
209
|
-
# +dashed_options+:: If true, each option is prepended with a double-dash
|
210
|
-
# (<tt>-</tt><tt>-</tt>)
|
211
|
-
# +help_banner+:: Defines a banner for the help message (<em>unused</em>)
|
212
|
-
# +istream+:: Defines an input stream to use
|
213
|
-
# +name+:: Defines the name of the application
|
214
|
-
# +ostream+:: Defines an output stream to use
|
215
|
-
# +raise_errors+:: If true, raise errors, otherwise fail gracefully
|
216
|
-
#
|
217
|
-
# Example:
|
218
|
-
#
|
219
|
-
# set :name, 'My App'
|
220
|
-
# set :autorun, false
|
221
|
-
def set(setting, value)
|
222
|
-
@settings[setting.to_sym] = value
|
223
|
-
end
|
224
|
-
|
225
|
-
# Displays a throbber while the given block is executed
|
226
|
-
#
|
227
|
-
# Example:
|
228
|
-
#
|
229
|
-
# action 'slow' do
|
230
|
-
# throbber do
|
231
|
-
# # Add some long running code here
|
232
|
-
# ...
|
233
|
-
# end
|
234
|
-
# end
|
235
|
-
def throbber(&block)
|
236
|
-
hidden_output do |ostream|
|
237
|
-
code_thread = Thread.new { block.call }
|
238
|
-
throbber_thread = Throbber.new(ostream, code_thread)
|
239
|
-
|
240
|
-
code_thread.join
|
241
|
-
throbber_thread.join
|
242
|
-
end
|
243
88
|
end
|
244
89
|
|
245
90
|
private
|
246
91
|
|
247
|
-
#
|
92
|
+
# Defines a global Flag for enabling debug output
|
248
93
|
#
|
249
|
-
#
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
unless @actions.key? key
|
258
|
-
@actions[key] = @actions[action]
|
259
|
-
else
|
260
|
-
warn "There's already an action called \"#{key}\"."
|
261
|
-
end
|
94
|
+
# This will define a Flag <tt>--debug</tt> (with alias <tt>-d</tt>) to
|
95
|
+
# enable debug output.
|
96
|
+
# Using it sets Ruby's global variable <tt>$DEBUG</tt> to +true+.
|
97
|
+
#
|
98
|
+
# @return [Flag]
|
99
|
+
def debug_flag
|
100
|
+
global_flag :debug do
|
101
|
+
$DEBUG = true
|
262
102
|
end
|
103
|
+
global_flag :d => :debug
|
263
104
|
end
|
264
105
|
|
265
|
-
# Defines
|
106
|
+
# Defines a command for displaying a help screen
|
266
107
|
#
|
267
|
-
# This takes any defined
|
108
|
+
# This takes any defined commands and it's corresponding options and
|
268
109
|
# descriptions and displays them in a user-friendly manner.
|
269
|
-
def
|
270
|
-
|
110
|
+
def help_command
|
111
|
+
command :help, 'Display this help screen' do
|
112
|
+
put @settings[:help_banner]
|
113
|
+
|
271
114
|
help = {}
|
272
|
-
@
|
273
|
-
help[
|
274
|
-
help[action] << option.to_s
|
115
|
+
@commands.each_value do |command|
|
116
|
+
help[command.name.to_s] = command.description
|
275
117
|
end
|
276
118
|
|
277
|
-
|
278
|
-
|
279
|
-
|
119
|
+
global_params = ''
|
120
|
+
@global_parameters.values.uniq.sort {|a,b| a.name.to_s <=> b.name.to_s }.each do |param|
|
121
|
+
global_params << ' ['
|
122
|
+
([param.name] + param.aliases).each_with_index do |name, index|
|
123
|
+
name = name.to_s
|
124
|
+
global_params << '|' if index > 0
|
125
|
+
global_params << '-' if name.size > 1
|
126
|
+
global_params << "-#{name}"
|
127
|
+
end
|
128
|
+
global_params << ' ...' if param.is_a?(Option)
|
129
|
+
global_params << ']'
|
130
|
+
end
|
280
131
|
|
281
|
-
help.
|
282
|
-
|
132
|
+
default_description = help.delete('__default')
|
133
|
+
if default_description.nil?
|
134
|
+
puts "#{global_params} command [args]\n\n"
|
135
|
+
else
|
136
|
+
puts "#{global_params} [command] [args]\n\n"
|
137
|
+
puts "Without command: #{default_description}\n\n"
|
283
138
|
end
|
284
|
-
|
285
|
-
|
286
|
-
|
139
|
+
|
140
|
+
puts "Commands:"
|
141
|
+
max_command_length = help.keys.max { |a, b| a.size <=> b.size }.size
|
142
|
+
help.sort_by { |name, description| name }.each do |name, description|
|
143
|
+
puts " #{name.ljust(max_command_length)} #{description}"
|
287
144
|
end
|
288
145
|
end
|
289
146
|
end
|
@@ -291,7 +148,8 @@ module Rubikon
|
|
291
148
|
# Hide output inside the given block and print it after the block has
|
292
149
|
# finished
|
293
150
|
#
|
294
|
-
#
|
151
|
+
# @param [Proc] block The block that should not print output while it's
|
152
|
+
# running
|
295
153
|
#
|
296
154
|
# If the block needs to print to the real IO stream, it can access it
|
297
155
|
# using its first parameter.
|
@@ -310,32 +168,73 @@ module Rubikon
|
|
310
168
|
# run, but <em>after</em> the application is setup, i.e. after the user
|
311
169
|
# has defined the application class.
|
312
170
|
def init
|
313
|
-
|
314
|
-
|
171
|
+
debug_flag
|
172
|
+
help_command
|
173
|
+
verbose_flag
|
174
|
+
|
175
|
+
if @settings[:help_as_default] && !@commands.keys.include?(:__default)
|
176
|
+
default :help
|
177
|
+
end
|
178
|
+
|
315
179
|
@initialized = true
|
316
180
|
end
|
317
181
|
|
318
|
-
# Parses the
|
319
|
-
#
|
320
|
-
#
|
321
|
-
#
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
182
|
+
# Parses the command-line arguments given to the application by the
|
183
|
+
# user. This distinguishes between commands, global flags and command
|
184
|
+
# flags
|
185
|
+
#
|
186
|
+
# @param [Array] args The command-line arguments
|
187
|
+
# @return [Command, Array<Symbol>, Array] The command to execute, the
|
188
|
+
# parameters of this command that have been supplied and any
|
189
|
+
# additional command-line arguments supplied
|
190
|
+
def parse_arguments(args)
|
191
|
+
command_arg = args.shift
|
192
|
+
if command_arg.nil? || command_arg.start_with?('-')
|
193
|
+
command = @commands[:__default]
|
194
|
+
args.unshift(command_arg) unless command_arg.nil?
|
195
|
+
raise NoDefaultCommandError if command.nil?
|
196
|
+
else
|
197
|
+
command = @commands[command_arg.to_sym]
|
198
|
+
raise UnknownCommandError.new(command_arg) if command.nil?
|
199
|
+
end
|
200
|
+
|
201
|
+
parameter = nil
|
202
|
+
parameters = []
|
203
|
+
args.dup.each do |arg|
|
204
|
+
if arg.start_with?('--')
|
205
|
+
parameter = @global_parameters[arg[2..-1].to_sym]
|
206
|
+
elsif arg.start_with?('-')
|
207
|
+
parameter = @global_parameters[arg[1..-1].to_sym]
|
333
208
|
else
|
334
|
-
|
209
|
+
if !parameter.nil? && parameter.more_args?
|
210
|
+
parameter.args << args.delete(arg)
|
211
|
+
else
|
212
|
+
parameter = nil
|
213
|
+
end
|
214
|
+
next
|
215
|
+
end
|
216
|
+
|
217
|
+
unless parameter.nil?
|
218
|
+
parameters << parameter
|
219
|
+
args.delete(arg)
|
335
220
|
end
|
336
221
|
end
|
337
222
|
|
338
|
-
|
223
|
+
return command, parameters, args
|
224
|
+
end
|
225
|
+
|
226
|
+
# Defines a global Flag for enabling verbose output
|
227
|
+
#
|
228
|
+
# This will define a Flag <tt>--verbose</tt> and <tt>-v</tt> to enable
|
229
|
+
# verbose output.
|
230
|
+
# Using it sets Ruby's global variable <tt>$VERBOSE</tt> to +true+.
|
231
|
+
#
|
232
|
+
# @return [Flag] The debug Flag object
|
233
|
+
def verbose_flag
|
234
|
+
global_flag :verbose do
|
235
|
+
$VERBOSE = true
|
236
|
+
end
|
237
|
+
global_flag :v => :verbose
|
339
238
|
end
|
340
239
|
|
341
240
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'rubikon/application/base'
|
7
|
+
require 'rubikon/exceptions'
|
8
|
+
require 'rubikon/parameter'
|
9
|
+
|
10
|
+
module Rubikon
|
11
|
+
|
12
|
+
# Instances of the Command class are used to define the real code that should
|
13
|
+
# be executed when running the Application.
|
14
|
+
#
|
15
|
+
# @author Sebastian Staudt
|
16
|
+
# @since 0.3.0
|
17
|
+
class Command
|
18
|
+
|
19
|
+
include Parameter
|
20
|
+
|
21
|
+
attr_accessor :description
|
22
|
+
attr_reader :args, :params
|
23
|
+
alias_method :arguments, :args
|
24
|
+
alias_method :parameters, :params
|
25
|
+
|
26
|
+
# Create a new application command with the given name with a reference to
|
27
|
+
# the app it belongs to
|
28
|
+
#
|
29
|
+
# @param [Application::Base] app A reference to the application
|
30
|
+
# instance this command belongs to
|
31
|
+
# @param [#to_sym] name The name of this command, used in application
|
32
|
+
# arguments
|
33
|
+
# @param [Proc] block The code block which should be executed by this
|
34
|
+
# command
|
35
|
+
# @raise [ArgumentError] if the given application object isn't a Rubikon
|
36
|
+
# application
|
37
|
+
# @raise [BlockMissingError] if no command code block is given and a
|
38
|
+
# command file does not exist
|
39
|
+
def initialize(app, name, &block)
|
40
|
+
raise ArgumentError unless app.is_a? Application::Base
|
41
|
+
super(name, nil)
|
42
|
+
|
43
|
+
@app = app
|
44
|
+
@params = {}
|
45
|
+
|
46
|
+
if block_given?
|
47
|
+
@block = block
|
48
|
+
else
|
49
|
+
@file_name = "#{@app.path}/commands/#{name}.rb"
|
50
|
+
raise BlockMissingError unless File.exists?(@file_name)
|
51
|
+
code = open(@file_name).read
|
52
|
+
@block = Proc.new { instance_eval(code) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Add a new Parameter for this command
|
57
|
+
#
|
58
|
+
# @param [Parameter, Hash] parameter The parameter to add to this
|
59
|
+
# command. This might also be a Hash where every key will be an
|
60
|
+
# alias to the corresponding value, e.g. <tt>{ :alias => :parameter
|
61
|
+
# }</tt>.
|
62
|
+
# @see Parameter
|
63
|
+
def <<(parameter)
|
64
|
+
if parameter.is_a? Hash
|
65
|
+
parameter.each do |alias_name, name|
|
66
|
+
alias_name = alias_name.to_sym
|
67
|
+
name = name.to_sym
|
68
|
+
parameter = @params[name]
|
69
|
+
if parameter.nil?
|
70
|
+
@params[alias_name] = name
|
71
|
+
else
|
72
|
+
parameter.aliases << alias_name
|
73
|
+
@params[alias_name] = parameter
|
74
|
+
end
|
75
|
+
end
|
76
|
+
else
|
77
|
+
raise ArgumentError unless parameter.is_a? Parameter
|
78
|
+
@params.each do |name, param|
|
79
|
+
if param == parameter.name
|
80
|
+
parameter.aliases << name
|
81
|
+
end
|
82
|
+
end
|
83
|
+
@params[parameter.name] = parameter
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Parses the arguments of this command and sets each Parameter as active
|
88
|
+
# if it has been supplied by the user on the command-line. Additional
|
89
|
+
# arguments are passed to the individual parameters.
|
90
|
+
#
|
91
|
+
# @param [Array<String>] args The arguments that have been passed to this
|
92
|
+
# command
|
93
|
+
# @raise [UnknownParameterError] if an undefined parameter is passed to the
|
94
|
+
# command
|
95
|
+
# @see Flag
|
96
|
+
# @see Option
|
97
|
+
def parse_arguments(args)
|
98
|
+
@args = []
|
99
|
+
parameter = nil
|
100
|
+
args.each do |arg|
|
101
|
+
if arg.start_with?('-')
|
102
|
+
parameter_name = arg.start_with?('--') ? arg[2..-1] : arg[1..-1]
|
103
|
+
parameter = @params[parameter_name.to_sym]
|
104
|
+
raise UnknownParameterError.new(arg) if parameter.nil?
|
105
|
+
end
|
106
|
+
|
107
|
+
unless parameter.nil? || parameter.active?
|
108
|
+
parameter.active!
|
109
|
+
next
|
110
|
+
end
|
111
|
+
|
112
|
+
if parameter.nil? || !parameter.more_args?
|
113
|
+
@args << arg
|
114
|
+
else
|
115
|
+
parameter << arg
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
@params.values.each do |param|
|
120
|
+
param.check_args if param.is_a?(Option) && param.active?
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Run this command's code block
|
125
|
+
#
|
126
|
+
# @param [Array<String>] args The arguments that have been passed to this
|
127
|
+
# command
|
128
|
+
def run(*args)
|
129
|
+
parse_arguments(args)
|
130
|
+
@app.instance_eval(&@block)
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|