optix 1.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/.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
+