optix 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in optix.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,25 @@
1
+ Copyright (C) 2012, moe@busyloop.net
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a
4
+ copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, pulverize, distribute,
7
+ synergize, compost, defenestrate, sublicense, and/or sell copies of the
8
+ Software, and to permit persons to whom the Software is furnished to do
9
+ so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included
12
+ in all copies or substantial portions of the Software.
13
+
14
+ If the Author of the Software (the "Author") needs a place to crash and
15
+ you have a sofa available, you should maybe give the Author a break and
16
+ let him sleep on your couch.
17
+
18
+ If you are caught in a dire situation wherein you only have enough time
19
+ to save one person out of a group, and the Author is a member of that
20
+ group, you must save the Author.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO BLAH BLAH BLAH ISN'T IT FUNNY
24
+ HOW UPPER-CASE MAKES IT SOUND LIKE THE LICENSE IS ANGRY AND SHOUTING AT YOU.
25
+
data/README.md ADDED
@@ -0,0 +1,431 @@
1
+ # Optix
2
+
3
+ Optix is an unobtrusive, composable command line parser based on Trollop.
4
+
5
+
6
+ ## Features
7
+
8
+ * Lightweight, unobtrusive syntax.
9
+ No subclassing or introduction of dependencies.
10
+
11
+ * Supports subcommands such as `git remote show origin` with arbitrary nesting.
12
+
13
+ * Subcommands inherit from their parent. Common options (such as '--debug' or '--loglevel')
14
+ need to be declared only once to make them available to an entire branch.
15
+
16
+ * Stands on the shoulders of [Trollop](http://trollop.rubyforge.org) (by William Morgan), one of the most complete and robust
17
+ option-parser implementations ever created.
18
+
19
+ * Automatic validation and help-screens.
20
+
21
+ * Strong test-suite.
22
+
23
+ ## Installation
24
+
25
+ $ gem install optix
26
+
27
+ ## Example
28
+
29
+ ```ruby
30
+ #!/usr/bin/env ruby
31
+ require 'optix'
32
+
33
+ module Example
34
+ module Printer
35
+ # Declare the "root"-command
36
+ Optix::command do
37
+ text "I am printer. I print strings to the screen."
38
+ text "Please invoke one of my not so many sub-commands."
39
+
40
+ # Declare a global option (all subcommands inherit this)
41
+ opt :debug, "Enable debugging", :default => false
42
+ end
43
+
44
+ # Declare sub-command
45
+ Optix::command 'print' do
46
+ desc "Print a string"
47
+ text "Print a string to the screen"
48
+ params "<string>"
49
+
50
+ opt :count, "Print how many times?", :default => 1
51
+
52
+ # This block is invoked when validations pass.
53
+ exec do |cmd, opts, argv|
54
+ if argv.length < 1
55
+ raise Optix::HelpNeeded
56
+ end
57
+
58
+ puts "DEBUGGING IS ENABLED!" if opts[:debug]
59
+ (1..opts[:count]).each do
60
+ puts argv.join(' ')
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ if __FILE__ == $0
68
+ # Perform the actual parsing and execution.
69
+ Optix.invoke!(ARGV)
70
+ end
71
+ ```
72
+
73
+ The above code in action:
74
+
75
+ ```
76
+ $ ./printer.rb --help
77
+
78
+ Usage: ./printer.rb <subcommand>
79
+
80
+ I am printer. I print strings to the screen.
81
+ Please invoke one of my not so many sub-commands.
82
+
83
+ Options:
84
+ --debug, -d: Enable debugging
85
+ --help, -h: Show this message
86
+
87
+ Commands:
88
+ print Print a string
89
+
90
+ ```
91
+
92
+ See the `examples/`-folder for more elaborate examples.
93
+
94
+ ## Documentation
95
+
96
+ ### Commands and Sub-Commands
97
+
98
+ Commands may be declared anywhere, at any time, in any order.
99
+ Declaring the "root"-command looks like this:
100
+
101
+ ```ruby
102
+ require 'optix'
103
+
104
+ Optix::command do
105
+ # opts, triggers, etc
106
+ end
107
+ ```
108
+
109
+ Now, let's add a sub-command:
110
+
111
+ ```ruby
112
+ Optix::command 'sub' do
113
+ # opts, triggers, etc
114
+ end
115
+ ```
116
+
117
+ And finally, a sub-sub command:
118
+
119
+ ```ruby
120
+ Optix::command 'sub sub' do
121
+ # opts, triggers, etc
122
+ end
123
+ ```
124
+
125
+ Remember: Optix doesn't care about the order of declarations.
126
+ The `sub sub` command may be declared prior to the `sub` command.
127
+
128
+ A common pattern is to insert your `Optix::command` blocks directly
129
+ at the module level so they get invoked during class-loading.
130
+ This way your CLI assembles itself automatically and the
131
+ command-hierarchy mirrors the modules/classes that
132
+ are actually loaded.
133
+
134
+
135
+ ### Optix::command DSL
136
+
137
+ Within `Optix::command` the following directives are available:
138
+
139
+ ### desc
140
+
141
+ Short description, displayed in the subcommand-list on the help-screen of the *parent* command.
142
+
143
+ ```ruby
144
+ Optix::command "frobnitz" do
145
+ desc "Frobnicates the gizmo"
146
+ end
147
+ ```
148
+
149
+ ### text
150
+
151
+ Long description, displayed on the help-screen for this command.
152
+
153
+ ```ruby
154
+ Optix::command "frobnitz" do
155
+ text "Frobnicate the gizmo by subtle twiddling."
156
+ text "Please only apply this to 2-state devices or you might bork it."
157
+ end
158
+ ```
159
+
160
+ * May be called multiple times for a multi-line description.
161
+
162
+
163
+ ### opt
164
+
165
+ Declares an option.
166
+
167
+ ```ruby
168
+ Optix::command do
169
+ opt :some_name, "some description", :default => 'some_default'
170
+ end
171
+ ```
172
+
173
+ Takes the following optional arguments:
174
+
175
+ * `:long` Specify the long form of the argument, i.e. the form with two dashes.
176
+ If unspecified, will be automatically derived based on the argument name by turning the name
177
+ option into a string, and replacing any _'s by -'s.
178
+
179
+ * `:short` Specify the short form of the argument, i.e. the form with one dash.
180
+ If unspecified, will be automatically derived from argument name.
181
+
182
+ * `:type` Require that the argument take a parameter or parameters of a given type. For a *single parameter*,
183
+ the value can be one of **:int**, **:integer**, **:string**, **:double**, **:float**, **:io**, **:date**,
184
+ or a corresponding Ruby class (e.g. **Integer** for **:int**).
185
+ For *multiple-argument parameters*, the value can be one of **:ints**, **:integers**, **:strings**, **:doubles**,
186
+ **:floats**, **:ios** or **:dates**. If unset, the default argument type is **:flag**, meaning that the argument
187
+ does not take a parameter. The specification of `:type` is not necessary if a `:default` is given.
188
+
189
+ * `:default` Set the default value for an argument. Without a default value, the opts-hash passed to `exec{}`
190
+ and `filter{}` will have a *nil* value for this key unless the argument is given on the commandline.
191
+ The argument type is derived automatically from the class of the default value given, so specifying a `:type`
192
+ is not necessary if a `:default` is given. (But see below for an important caveat when `:multi` is specified too.)
193
+ If the argument is a flag, and the default is set to **true**, then if it is specified on the the commandline
194
+ the value will be **false**.
195
+
196
+ * `:required` If set to **true**, the argument must be provided on the commandline.
197
+
198
+ * `:multi` If set to **true**, allows multiple occurrences of the option on the commandline.
199
+ Otherwise, only a single instance of the option is allowed.
200
+
201
+ Note that there are two types of argument multiplicity: an argument
202
+ can take multiple values, e.g. "--arg 1 2 3". An argument can also
203
+ be allowed to occur multiple times, e.g. "--arg 1 --arg 2".
204
+
205
+ Arguments that take multiple values should have a `:type` parameter
206
+ or a `:default` value of an array of the correct type (e.g. [String]).
207
+
208
+ The value of this argument will be an array of the parameters on the
209
+ commandline.
210
+
211
+ Arguments that can occur multiple times should be marked with
212
+ `:multi => true`. The value of this argument will also be an array.
213
+ In contrast with regular non-multi options, if not specified on
214
+ the commandline, the default value will be [], not nil.
215
+
216
+ These two attributes can be combined (e.g. **:type => :strings**,
217
+ **:multi => true**), in which case the value of the argument will be
218
+ an array of arrays.
219
+
220
+ There's one ambiguous case to be aware of: when `:multi` is **true** and a
221
+ `:default` is set to an array (of something), it's ambiguous whether this
222
+ is a multi-value argument as well as a multi-occurrence argument.
223
+ In thise case, we assume that it's not a multi-value argument.
224
+ If you want a multi-value, multi-occurrence argument with a default
225
+ value, you must specify `:type` as well.
226
+
227
+ ### params
228
+
229
+ Describes positional parameters that this command accepts.
230
+
231
+ ```ruby
232
+ Optix::command do
233
+ params "<foo> [bar]"
234
+ end
235
+ ```
236
+
237
+ * Note: Optix does **not** validate or inspect positional parameters at all (this is your job, inside exec{}).
238
+ The value of this command is only used to display a proper synopsis in the help-screen.
239
+
240
+ ### depends
241
+
242
+ Marks two (or more!) options as requiring each other. Only handles
243
+ undirected (i.e., mutual) dependencies.
244
+
245
+ ```ruby
246
+ Optix::command do
247
+ opt :we, ""
248
+ opt :are, ""
249
+ opt :family, ""
250
+ depends :we, :are, :family
251
+ end
252
+ ```
253
+
254
+ ### conflicts
255
+
256
+ Marks two (or more!) options as conflicting.
257
+
258
+ ```ruby
259
+ Optix::command do
260
+ opt :force, "Force this operation"
261
+ opt :no_op, "Dry run, don't actually do anything"
262
+ conflict :force, :no_op
263
+ end
264
+ ```
265
+
266
+ ### trigger
267
+
268
+ Triggers allow to short-circuit argument parsing for "action-options"
269
+ (options that directly trigger an action) such as `--version`.
270
+
271
+ ```ruby
272
+ Optix::command do
273
+ opt :version, "Print version and exit"
274
+ trigger :version do
275
+ puts "Version 1.0"
276
+ end
277
+ end
278
+ ```
279
+
280
+ * Triggers fire *before* validation.
281
+
282
+ * Parsing stops after a trigger has fired.
283
+
284
+ * A trigger can only be bound to an existing `opt`. I.e. you must first
285
+ declare `opt :version` before you can bind a trigger with `trigger
286
+ :version`.
287
+
288
+ * A trigger may be bound to multiple options like so: `trigger [:version,
289
+ :other, :etc] do ...`
290
+
291
+ * You may raise `Optix::HelpNeeded` inside your trigger to abort
292
+ parsing and display the help-screen.
293
+
294
+
295
+ ### filter
296
+
297
+ Filters allow to group functionality that is common to a branch of subcommands.
298
+
299
+ ```ruby
300
+ Optix::command do
301
+ opt :debug, "Enable debugging"
302
+ filter do |cmd, opts, argv|
303
+ if opts[:debug]
304
+ # .. enable debugging ..
305
+ end
306
+ end
307
+ end
308
+ ```
309
+
310
+ * Filters fire *after* validation, for each command in the chain.
311
+
312
+ * Parsing continues normally after a filter has fired.
313
+
314
+ * Your block receives three arguments:
315
+ * `cmd` (Array) The full command that was executed, e.g.: ['foo', 'bar', 'baz']
316
+ * `opts` (Hash) The options-hash, e.g.: { :debug => true }
317
+ * `argv` (Array) Positional parameters that your command may have received, e.g.: ['a','b','c']
318
+
319
+ * You may raise `Optix::HelpNeeded` inside your filter to abort
320
+ parsing and display the help-screen.
321
+
322
+
323
+ ### exec
324
+
325
+ The exec-block is called when your command is invoked, after validation
326
+ passed. It should contain (or invoke) your actual business logic.
327
+
328
+ ```ruby
329
+ Optix::command do
330
+ exec do |cmd, opts, argv|
331
+ if opts[:debug]
332
+ # .. enable debugging ..
333
+ end
334
+ end
335
+ end
336
+ ```
337
+
338
+ * Your block receives three arguments:
339
+ * `cmd` (Array) The full command that was executed, e.g.: ['foo', 'bar', 'baz']
340
+ * `opts` (Hash) The options-hash, e.g.: { :debug => true }
341
+ * `argv` (Array) Positional parameters that your command may have received, e.g.: ['a','b','c']
342
+
343
+ * You may raise `Optix::HelpNeeded` inside your exec-block to abort
344
+ parsing and display the help-screen.
345
+
346
+
347
+ ## Chain of execution
348
+
349
+ This is the chain of execution when you pass ['foo', 'bar', 'batz'] to `Optix.invoke!`:
350
+
351
+ 1. Triggers for `foo` (if any, execution stops if a trigger fires)
352
+ 1. Triggers for `bar` (if any, execution stops if a trigger fires)
353
+ 1. Triggers for `batz` (if any, execution stops if a trigger fires)
354
+ 1. Validation
355
+ 1. Filters for `foo` (if any)
356
+ 1. Filters for `bar` (if any)
357
+ 1. Filters for `batz` (if any)
358
+ 1. Exec{}-block for `batz`
359
+
360
+
361
+
362
+ ## Scopes
363
+
364
+ In rare cases you may want to have multiple independent Optix command-trees in a single app.
365
+ This can be achieved by passing a scope-name to your command-declarations, like so:
366
+
367
+ ```ruby
368
+ # Declare root-command in the :default scope
369
+ Optix::command '', :default do
370
+ # opts, triggers, etc
371
+ end
372
+
373
+ # Declare root-command in another, independent scope
374
+ Optix::command '', :other_scope do
375
+ end
376
+
377
+ # Declare a sub-command in the other scope
378
+ Optix::command 'sub', :other_scope do
379
+ end
380
+
381
+ # Then either invoke the :default scope
382
+ Optix.invoke!(ARGV)
383
+ # ...or...
384
+ Optix.invoke!(ARGV, :other_scope)
385
+ ```
386
+
387
+ ## Re-initialization
388
+
389
+ In even rarer cases you may need to reset Optix at runtime.
390
+ To make Optix forget all scopes, configuration and commands, invoke:
391
+
392
+ `Optix.reset!`
393
+
394
+
395
+ ## Contributing
396
+
397
+ Patches are welcome, especially bugfixes.
398
+
399
+ 1. Fork it
400
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
401
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
402
+ 4. Push to the branch (`git push origin my-new-feature`)
403
+ 5. Create new Pull Request
404
+
405
+ ## License
406
+
407
+ Copyright (C) 2012, moe@busyloop.net
408
+
409
+ Permission is hereby granted, free of charge, to any person obtaining a
410
+ copy of this software and associated documentation files (the "Software"),
411
+ to deal in the Software without restriction, including without limitation
412
+ the rights to use, copy, modify, merge, publish, pulverize, distribute,
413
+ synergize, compost, defenestrate, sublicense, and/or sell copies of the
414
+ Software, and to permit persons to whom the Software is furnished to do
415
+ so, subject to the following conditions:
416
+
417
+ The above copyright notice and this permission notice shall be included
418
+ in all copies or substantial portions of the Software.
419
+
420
+ If the Author of the Software (the "Author") needs a place to crash and
421
+ you have a sofa available, you should maybe give the Author a break and
422
+ let him sleep on your couch.
423
+
424
+ If you are caught in a dire situation wherein you only have enough time
425
+ to save one person out of a group, and the Author is a member of that
426
+ group, you must save the Author.
427
+
428
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
429
+ INCLUDING BUT NOT LIMITED TO BLAH BLAH BLAH ISN'T IT FUNNY HOW UPPER-CASE MAKES IT
430
+ SOUND LIKE THE LICENSE IS ANGRY AND SHOUTING AT YOU.
431
+
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ task :default => :test
7
+
8
+ RSpec::Core::RakeTask.new("test:spec") do |t|
9
+ t.pattern = 'spec/*_spec.rb'
10
+ t.rcov = false
11
+ #t.rspec_opts = '-b -c -f progress --tag ~benchmark'
12
+ t.rspec_opts = '-b -c -f documentation --tag ~benchmark'
13
+ end
14
+
15
+ RSpec::Core::RakeTask.new("test:benchmark") do |t|
16
+ t.pattern = 'spec/*.rb'
17
+ t.rcov = false
18
+ t.rspec_opts = '-b -c -f documentation --tag benchmark'
19
+ end
20
+
21
+
22
+ namespace :test do
23
+ task :coverage do
24
+ #require 'cover_me'
25
+ #CoverMe.complete!
26
+ end
27
+ end
28
+
29
+ desc 'Run full test suite'
30
+ task :test => [ 'test:spec', 'test:coverage' ]
@@ -0,0 +1,188 @@
1
+ require 'optix'
2
+
3
+ #
4
+ # Example application to demonstrate Optix.
5
+ #
6
+ # The easiest way to get started is to download this file
7
+ # and actually run it. Play around, try invoking '--help',
8
+ # '-v', '--version' and the subcommands.
9
+ #
10
+ # Then come back here to learn how it's done. :)
11
+ #
12
+ module Example
13
+ class FileTool
14
+ # Declare the "root" command
15
+ # Also declaring the first-level sub-commands right here.
16
+ # Just like the root-command these commands can not be invoked
17
+ # directly (because they have sub-commands). Their declaration
18
+ # is not mandatory, but by declaring them explicitly we can add
19
+ # some useful help-texts to aid the user.
20
+ Optix::command do
21
+ # Let's have a nice description
22
+ text "This is FileTool, a little example application to demonstrate Optix."
23
+ text "It's safe to play around with. All operations are no-ops."
24
+ text "Your filesystem is never actually modified!"
25
+ text ""
26
+ text "Invoke me with one of the sub-commands to perform a dummy-operation."
27
+
28
+ # Note: Options are recursively inherited by sub-commands.
29
+ # Thus, any option we declare here will also be available
30
+ # in all sub-commands.
31
+ opt :debug, "Enable debugging", :default => false
32
+ opt :version, "Print version and exit"
33
+
34
+ # Triggers fire immediately, before validation.
35
+ #
36
+ # This one short-circuits the '--version' and '-v' opts.
37
+ # We want to print/exit immediately when we encounter
38
+ # them, regardless of other opts or subcommands.
39
+ #
40
+ # NOTE: Triggers can only bind to existing opts.
41
+ # Make sure to always declare the 'opt' before
42
+ # creating a 'trigger' (just like in this example).
43
+ trigger [:version] do
44
+ puts "Version 1.0"
45
+ # parsing stops after a trigger has fired.
46
+ end
47
+
48
+ # Filters are "pass-through", they fire for
49
+ # every intermediate sub-command. We use it here
50
+ # to set up a common debug-mechanism before the
51
+ # subcommand is invoked.
52
+ filter do |cmd, opts, argv|
53
+ if opts[:debug]
54
+ FileTool.enable_debug!
55
+ end
56
+ end
57
+
58
+ # Note this command has no exec{}-block.
59
+ # It would never fire because this command has sub-commands.
60
+ # When a command has sub-commands then it can no longer be
61
+ # invoked directly (that would only lead to confusion and
62
+ # bad accidents).
63
+ end
64
+
65
+ Optix::command 'file' do
66
+ desc "Operations on files"
67
+ text "Please invoke one of the sub-commands to perform a file-operation."
68
+ end
69
+
70
+ Optix::command 'dir' do
71
+ desc "Operations on directories"
72
+ text "Please invoke one of the sub-commands to perform a directory-operation."
73
+ end
74
+
75
+ def self.enable_debug!
76
+ # enable debugging...
77
+ end
78
+ end
79
+ end
80
+
81
+ module Example
82
+ class FileTool
83
+ class Move
84
+ # Here we declare the subcommand 'file move'
85
+ Optix::command 'file move' do
86
+ # Short one-liner for the sub-command list in parent help-screen
87
+ desc "Move a file"
88
+
89
+ # Verbose description for the help-screen
90
+ text "Move a file from <source> to <dest>"
91
+ text "The destination will not be overwritten unless --force is applied."
92
+
93
+ opt :force, "Force overwrite", :default => false
94
+
95
+ # This text is only used in the help-screen. Positional arguments are
96
+ # *not* checked by Optix, you have to do that yourself in the exec{}-block.
97
+ params "<source> <dest>"
98
+
99
+ exec do |cmd, opts, argv|
100
+ # bail if we didn't receive enough parameters
101
+ if argv.length < 2
102
+ puts "Error: #{cmd.join(' ')} must be invoked with 2 parameters."
103
+ exit 1
104
+ end
105
+
106
+ puts "#{cmd.join(' ')} called with #{opts}, #{argv}"
107
+ end
108
+ end
109
+
110
+ # Here we declare the subcommand 'dir move'
111
+ Optix::command 'dir move' do
112
+ desc "Move directory from A to B"
113
+
114
+ text "Move a directory from <source> to <dest>"
115
+ text "The destination will not be overwritten unless --force is applied."
116
+ opt :force, "Force overwrite", :default => false
117
+ params "<source> <dest>"
118
+
119
+ exec do |cmd, opts, argv|
120
+ if argv.length < 2
121
+ puts "Error: #{cmd.join(' ')} must be invoked with 2 parameters."
122
+ exit 1
123
+ end
124
+ puts "#{cmd.join(' ')} called with #{opts}, #{argv}"
125
+ end
126
+ end
127
+ end
128
+
129
+ class Copy
130
+ # Here we declare the subcommand 'file copy'
131
+ Optix::command 'file copy' do
132
+ # Short one-liner for the sub-command list in parent help-screen
133
+ desc "Copy a file"
134
+
135
+ # Verbose description for the help-screen
136
+ text "Copy a file from <source> to <dest>"
137
+ text "The destination will not be overwritten unless --force is applied."
138
+
139
+ opt :force, "Force overwrite", :default => false
140
+
141
+ # This text is only used in the help-screen. Positional arguments are
142
+ # *not* checked by Optix, you have to do that yourself in the exec{}-block.
143
+ params "<source> <dest>"
144
+
145
+ exec do |cmd, opts, argv|
146
+ # bail if we didn't receive enough parameters
147
+ if argv.length < 2
148
+ puts "Error: #{cmd.join(' ')} must be invoked with 2 parameters."
149
+ exit 1
150
+ end
151
+
152
+ puts "#{cmd.join(' ')} called with #{opts}, #{argv}"
153
+ end
154
+ end
155
+
156
+ # Here we declare the subcommand 'dir copy'
157
+ Optix::command 'dir copy' do
158
+ desc "Copy directory from A to B"
159
+
160
+ text "Copy a directory from <source> to <dest>"
161
+ text "The destination will not be overwritten unless --force is applied."
162
+ opt :force, "Force overwrite", :default => false
163
+ params "<source> <dest>"
164
+
165
+ exec do |cmd, opts, argv|
166
+ if argv.length < 2
167
+ puts "Error: #{cmd.join(' ')} must be invoked with 2 parameters."
168
+ exit 1
169
+ end
170
+ puts "#{cmd.join(' ')} called with #{opts}, #{argv}"
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ if __FILE__ == $0
178
+ # Perform some configuration (optional!)
179
+ Optix.configure do
180
+ # override a help-text template
181
+ # see the source-code for full list of available config keys
182
+ text_header_usage 'Syntax: %0 %command %params'
183
+ end
184
+
185
+ # Perform the actual parsing and execution.
186
+ Optix.invoke!(ARGV)
187
+ end
188
+