commandline 0.7.9
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/CHANGELOG +40 -0
- data/LICENSE +31 -0
- data/README +325 -0
- data/docs/index.html +1005 -0
- data/docs/posted-docs.index.html +1410 -0
- data/docs/tmp/app1.rb +11 -0
- data/docs/tmp/app1b.rb +15 -0
- data/docs/tmp/app2.rb +17 -0
- data/docs/tmp/app_exit.rb +16 -0
- data/docs/tmp/app_file.rb +24 -0
- data/docs/tmp/app_flag.rb +12 -0
- data/docs/tmp/app_replay.rb +19 -0
- data/lib/commandline.rb +16 -0
- data/lib/commandline/application.rb +437 -0
- data/lib/commandline/kernel.rb +17 -0
- data/lib/commandline/optionparser.rb +16 -0
- data/lib/commandline/optionparser/option.rb +185 -0
- data/lib/commandline/optionparser/optiondata.rb +75 -0
- data/lib/commandline/optionparser/optionparser.rb +518 -0
- data/lib/commandline/utils.rb +12 -0
- data/lib/open4.rb +79 -0
- data/lib/test/unit/systemtest.rb +77 -0
- metadata +77 -0
|
@@ -0,0 +1,1410 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
4
|
+
<head>
|
|
5
|
+
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
|
|
6
|
+
<title>CommandLine (with OptionParser)</title>
|
|
7
|
+
|
|
8
|
+
<style type="text/css">
|
|
9
|
+
body,td {
|
|
10
|
+
font-size: small;
|
|
11
|
+
line-height: 130%;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
a {
|
|
15
|
+
text-decoration: none;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
a:link, a:visited {
|
|
19
|
+
color: #2050f0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
h1, h2, h3, h4, h5, h6 {
|
|
23
|
+
color: #900;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
pre {
|
|
27
|
+
/*border-left: 7px solid #e8d8d8;*/
|
|
28
|
+
/*background-color: #ffeeff;*/
|
|
29
|
+
background-color: #eee;
|
|
30
|
+
/*
|
|
31
|
+
border-top: 2px solid #aaaaaa;
|
|
32
|
+
border-left: 2px solid #aaaaaa;
|
|
33
|
+
*/
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.sidebar {
|
|
37
|
+
font-size: smaller;
|
|
38
|
+
color: #70b0b0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.sidebar a:link {
|
|
42
|
+
color: #104020;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.sidebar a:visited {
|
|
46
|
+
color: #104020;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.sidebar a:hover {
|
|
50
|
+
color: #401020;
|
|
51
|
+
font-weight: bold;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.Sidebarwarning {
|
|
55
|
+
color: #902020;
|
|
56
|
+
padding-left: 1em;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.sidebarholder {
|
|
60
|
+
border-top: 2px solid #aaaaaa;
|
|
61
|
+
border-left: 2px solid #aaaaaa;
|
|
62
|
+
padding: 0px;
|
|
63
|
+
margin-bottom: 16px;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.sidebartitle {
|
|
67
|
+
background-color: #c0e0e0;
|
|
68
|
+
padding-left: 8px;
|
|
69
|
+
color: #0000cc;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.sidebarbody {
|
|
73
|
+
background-color: #f8ffff;
|
|
74
|
+
color: #a08080;
|
|
75
|
+
padding-left: 8px;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.sidebartext {
|
|
79
|
+
color: #80a0a0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.sidebar table table, .sidebar table table td {
|
|
83
|
+
color: #a08080;
|
|
84
|
+
padding-right: 0.5em;
|
|
85
|
+
padding-left: 0em;
|
|
86
|
+
padding-top: 0em;
|
|
87
|
+
padding-bottom: 0em;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.sidebarsubhead {
|
|
91
|
+
color: #503030;
|
|
92
|
+
background-color: #f8d0d0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.indent {
|
|
96
|
+
margin-left: 1.5em;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.catcount {
|
|
100
|
+
color: #807070;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.entry {
|
|
104
|
+
/*
|
|
105
|
+
border-top: 2px solid #aaaaaa;
|
|
106
|
+
border-left: 2px solid #aaaaaa;
|
|
107
|
+
*/
|
|
108
|
+
padding: 0px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.entrytitlebar {
|
|
112
|
+
/*background-color: #e0c0e0;*/
|
|
113
|
+
background-color: #aaaaff;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.entrytitle {
|
|
117
|
+
font-family: Arial,Helvetica;
|
|
118
|
+
color: #111166;
|
|
119
|
+
padding-left: 12pt;
|
|
120
|
+
font-size: large;
|
|
121
|
+
font-variant: small-caps;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.entrytitledetail {
|
|
125
|
+
text-align: right;
|
|
126
|
+
font-size: x-small;
|
|
127
|
+
padding-right: 12pt;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
.entrybody {
|
|
131
|
+
font-family: Arial;
|
|
132
|
+
background-color: #fff;
|
|
133
|
+
padding-left: 36pt;
|
|
134
|
+
padding-right: 12pt;
|
|
135
|
+
padding-bottom: 12pt;
|
|
136
|
+
line-height: 130%;
|
|
137
|
+
/*background-color: #f8f0f0;*/
|
|
138
|
+
background-color: #fff;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.entrybody h1,h2,h3,h4 {
|
|
142
|
+
background-color: #fff;
|
|
143
|
+
line-height: 100%;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.pagetitle {
|
|
147
|
+
font-size: xx-large;
|
|
148
|
+
font-family: Arial,Helvetica;
|
|
149
|
+
/*text-shadow: .18em .15em .2em #223366;*/
|
|
150
|
+
text-shadow: .18em .15em .2em #9999cc;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.titlemenu {
|
|
154
|
+
font-size: x-small;
|
|
155
|
+
font-family: Arial,Helvetica;
|
|
156
|
+
text-align: right;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.schedhead {
|
|
160
|
+
font-size: small;
|
|
161
|
+
font-family: Arial,Helvetica;
|
|
162
|
+
text-align: right;
|
|
163
|
+
font-weight: bold;
|
|
164
|
+
background-color: #403030;
|
|
165
|
+
color: #c0c0c0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.schedentry {
|
|
169
|
+
font-size: small;
|
|
170
|
+
font-family: Arial,Helvetica;
|
|
171
|
+
text-align: center;
|
|
172
|
+
background-color: #d0c0c0;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
.schedempty {
|
|
176
|
+
font-size: small;
|
|
177
|
+
background-color: #f0e0e0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.sidebartable {
|
|
181
|
+
color: #a08080;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.c {
|
|
185
|
+
text-align: right;
|
|
186
|
+
padding-right: 0.5em;
|
|
187
|
+
padding-left: 0em;
|
|
188
|
+
padding-top: 0em;
|
|
189
|
+
padding-bottom: 0em;
|
|
190
|
+
}
|
|
191
|
+
.ctitle {
|
|
192
|
+
text-align: right;
|
|
193
|
+
padding-right: 0.5em;
|
|
194
|
+
padding-left: 0em;
|
|
195
|
+
padding-top: 0em;
|
|
196
|
+
padding-bottom: 0em;
|
|
197
|
+
border-bottom: 1px solid #d0d0d0;
|
|
198
|
+
}
|
|
199
|
+
.ctotal {
|
|
200
|
+
text-align: right;
|
|
201
|
+
padding-right: 0.5em;
|
|
202
|
+
padding-left: 0em;
|
|
203
|
+
padding-top: 0em;
|
|
204
|
+
padding-bottom: 0em;
|
|
205
|
+
border-top: 1px solid #d0d0d0;
|
|
206
|
+
border-bottom: 1px solid #d0d0d0;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.caltoday {
|
|
210
|
+
text-align: right;
|
|
211
|
+
background-color: #f8d0d0;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
</style>
|
|
215
|
+
|
|
216
|
+
</head>
|
|
217
|
+
<body>
|
|
218
|
+
<table border="0" cellpadding="0" cellspacing="0" width="100%">
|
|
219
|
+
<tr valign="bottom">
|
|
220
|
+
<td class="pagetitle">CommandLine</a></td>
|
|
221
|
+
</tr>
|
|
222
|
+
</table>
|
|
223
|
+
<hr />
|
|
224
|
+
<table>
|
|
225
|
+
<tr valign="top"><td>
|
|
226
|
+
|
|
227
|
+
<table class="entry" border="0" cellspacing="0" width="100%">
|
|
228
|
+
<tr class="entrybody"><td colspan="3" class="entrybody">
|
|
229
|
+
<h1>Welcome to CommandLine</h1>
|
|
230
|
+
<ul>
|
|
231
|
+
<li>Copyright © 2005 Jim Freeze
|
|
232
|
+
|
|
233
|
+
</li>
|
|
234
|
+
<li>Author: Jim Freeze
|
|
235
|
+
|
|
236
|
+
</li>
|
|
237
|
+
<li><a href="http://www.freeze.org/ruby/optionparser/license.txt">License</a>
|
|
238
|
+
|
|
239
|
+
</li>
|
|
240
|
+
</ul>
|
|
241
|
+
<tt>CommandLine</tt> is a library that greatly simplifies the repetitive
|
|
242
|
+
process of building a command line user interface for your applications.
|
|
243
|
+
It's 'ruby-like' usage style streamlines application development so that
|
|
244
|
+
even applications with numerous configuration options can be quickly put
|
|
245
|
+
together. CommandLine automatically builds friendly usage and help
|
|
246
|
+
screens that are nicely formatted for the user. No longer is starting
|
|
247
|
+
an application a pain where you have to copy boiler plate code (or a
|
|
248
|
+
previous application) and retype repetitive code to get an application started.
|
|
249
|
+
|
|
250
|
+
<p>
|
|
251
|
+
<tt>CommandLine</tt> smartly handles the arguments passed on the commandline.
|
|
252
|
+
For example, if your application accepts arguments, and none are given, it prints a usage
|
|
253
|
+
statement. But, if your application accepts no arguments, <tt>CommandLine</tt> will happily
|
|
254
|
+
run your application. <tt>CommandLine</tt> also handles a complex set of
|
|
255
|
+
options through the <tt>OptionParser</tt> library, which is described below.
|
|
256
|
+
In addition to these features, <tt>CommandLine</tt> also ships with the
|
|
257
|
+
<b>ability to run system tests</b> on your applications. (Note: It was
|
|
258
|
+
recently noticed that the system test infrastructure needs some work
|
|
259
|
+
to make it more robust. Anyone willing to help out with this, please
|
|
260
|
+
contact me.)
|
|
261
|
+
|
|
262
|
+
<p>
|
|
263
|
+
<tt>OptionParser</tt> is
|
|
264
|
+
designed to be a flexible command line parser with a Ruby look and feel to
|
|
265
|
+
it. <tt>OptionParser</tt> got
|
|
266
|
+
its birth from the need for a parser that is standards compliant, yet
|
|
267
|
+
flexible. <tt>OptionParser</tt>
|
|
268
|
+
supports the standard command line styles of <tt>Unix</tt>, <tt>Gnu</tt>
|
|
269
|
+
and <tt>X Toolkit</tt>, but also lets you break those rules.
|
|
270
|
+
|
|
271
|
+
<p>
|
|
272
|
+
<tt>OptionParser</tt> is
|
|
273
|
+
not a port of a traditional command line parser, but it is written to meet
|
|
274
|
+
the feature requirements of traditional command line parsers. When using it
|
|
275
|
+
as a library, you should notice that it is expressive, supports
|
|
276
|
+
Ruby’s blocks and lambda’s, and is sprinkled with a little bit
|
|
277
|
+
of magic.
|
|
278
|
+
</p>
|
|
279
|
+
<p>
|
|
280
|
+
While the library can be used by itself, it is also designed to work with
|
|
281
|
+
the <tt>CommandLine::Application</tt> class. These tools work together to
|
|
282
|
+
facilitate the generation of a sophisticated (batch oriented) application
|
|
283
|
+
user interface in a matter of minutes.
|
|
284
|
+
</p>
|
|
285
|
+
<p>
|
|
286
|
+
If you need a refresher on the traditional option parsing schemes, see
|
|
287
|
+
<a href="#traditional">"Traditional Option Parsing Schemes"</a> below.
|
|
288
|
+
</p>
|
|
289
|
+
<h1>CommandLine Usage</h1>
|
|
290
|
+
<p>
|
|
291
|
+
<h2>Getting Started</h2>
|
|
292
|
+
<h3>Installing</h3>
|
|
293
|
+
<p>
|
|
294
|
+
CommandLine is a gem and can be installed using the <tt>gem</tt> install command:
|
|
295
|
+
<pre>
|
|
296
|
+
gem install -r commandline
|
|
297
|
+
</pre>
|
|
298
|
+
<h3>Loading the library</h3>
|
|
299
|
+
When using the library, it is loaded as usual with:
|
|
300
|
+
<pre>
|
|
301
|
+
require 'rubygems'
|
|
302
|
+
require 'commandline'
|
|
303
|
+
</pre>
|
|
304
|
+
|
|
305
|
+
<h2>CommandLine::Application</h2>
|
|
306
|
+
The <tt>CommandLine::Application</tt> class is only the class the most
|
|
307
|
+
users will need to interact with. This class has many wrappers and convenience
|
|
308
|
+
methods that utilize the <tt>Option</tt> and <tt>OptionParser</tt>
|
|
309
|
+
classes.
|
|
310
|
+
|
|
311
|
+
<h3>Example 1: A very simple application</h3>
|
|
312
|
+
When you want to test a new library, you usually aren't interested
|
|
313
|
+
in handling a vast array of options. You usually want just enough
|
|
314
|
+
of a user interface to make some specific calls into your library
|
|
315
|
+
too see how it responds. So, the simplist application is one that does
|
|
316
|
+
not go out of its way to identify itself and does not take any command
|
|
317
|
+
line arguments.
|
|
318
|
+
<pre>
|
|
319
|
+
#!/usr/bin/env ruby
|
|
320
|
+
|
|
321
|
+
require 'rubygems'
|
|
322
|
+
require 'commandline'
|
|
323
|
+
|
|
324
|
+
class App < CommandLine::Application
|
|
325
|
+
def main
|
|
326
|
+
puts "call your library here"
|
|
327
|
+
end
|
|
328
|
+
end#class App
|
|
329
|
+
</pre>
|
|
330
|
+
To run this app, we just change the mode and launch it:
|
|
331
|
+
<pre>
|
|
332
|
+
% chmod 755 myapp
|
|
333
|
+
% ./myapp
|
|
334
|
+
"call your library here"
|
|
335
|
+
</pre>
|
|
336
|
+
Notice that <tt>CommandLine</tt> does not complain about missing arguments.
|
|
337
|
+
It assumes that the number of expected arguments is zero, unless told otherwise.
|
|
338
|
+
|
|
339
|
+
<h3>Standard Options</h3>
|
|
340
|
+
But an application like this will be useless in about 2 hours when
|
|
341
|
+
you have forgotten what it does or how to use it. Let's dress it up
|
|
342
|
+
a little by adding a <tt>help</tt> option. And, since we are probably
|
|
343
|
+
going to need to debug this app, let's provide the ability to get
|
|
344
|
+
a backtrace when we need it.
|
|
345
|
+
|
|
346
|
+
<pre>
|
|
347
|
+
#!/usr/bin/env ruby
|
|
348
|
+
|
|
349
|
+
require 'rubygems'
|
|
350
|
+
require 'commandline'
|
|
351
|
+
|
|
352
|
+
class App < CommandLine::Application
|
|
353
|
+
def initialize
|
|
354
|
+
options :help, :debug
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def main
|
|
358
|
+
puts "call your library here"
|
|
359
|
+
end
|
|
360
|
+
end#class App
|
|
361
|
+
</pre>
|
|
362
|
+
|
|
363
|
+
Now, lets run the app with the help option.
|
|
364
|
+
<pre>
|
|
365
|
+
% ./myapp -h
|
|
366
|
+
NAME
|
|
367
|
+
|
|
368
|
+
myapp.rb
|
|
369
|
+
|
|
370
|
+
OPTIONS
|
|
371
|
+
|
|
372
|
+
--help,-h
|
|
373
|
+
Displays help page.
|
|
374
|
+
|
|
375
|
+
--debug,-d
|
|
376
|
+
Sets debug to true.
|
|
377
|
+
|
|
378
|
+
</pre>
|
|
379
|
+
|
|
380
|
+
<h3>Adding Expected Arguments</h3>
|
|
381
|
+
|
|
382
|
+
<p>
|
|
383
|
+
Ok, that's a little better. Now, let's tell our application that it needs
|
|
384
|
+
to accept a filename as an argument. We don't have to name the arguments,
|
|
385
|
+
but since there is only one, it is convenient to go ahead and give
|
|
386
|
+
it a name. We will call it <tt>@file</tt>.
|
|
387
|
+
We'll also add a synopsis so that we know how to call and use the application.
|
|
388
|
+
|
|
389
|
+
<pre>
|
|
390
|
+
#!/usr/bin/env ruby
|
|
391
|
+
require 'rubygems'
|
|
392
|
+
require 'commandline'
|
|
393
|
+
|
|
394
|
+
class App < CommandLine::Application
|
|
395
|
+
|
|
396
|
+
def initialize
|
|
397
|
+
synopsis "[-dh] file"
|
|
398
|
+
expected_args :file # will set instance variable @file to command line argument.
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
def main
|
|
402
|
+
puts "#{name} called with #{args.size} arguments: #{args.inspect}"
|
|
403
|
+
puts "@file = #{@file}"
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
end#class App
|
|
407
|
+
</pre>
|
|
408
|
+
|
|
409
|
+
And run it:
|
|
410
|
+
<pre>
|
|
411
|
+
% ruby myapp.rb
|
|
412
|
+
Usage: myapp.rb [-dh] file
|
|
413
|
+
% ruby myapp.rb fred_file
|
|
414
|
+
myapp.rb called with 1 arguments: ["fred_file"]
|
|
415
|
+
@file = fred_file
|
|
416
|
+
</pre>
|
|
417
|
+
|
|
418
|
+
You may notice that this application has a new method -- :initialize.
|
|
419
|
+
In this method, Since we've added some setup code to our application object, we created an
|
|
420
|
+
<tt>initialize</tt> method and put our code inside it.
|
|
421
|
+
<b>(BTW, don't mispell initialize. It can cause real confusion.)</b>
|
|
422
|
+
This is where all the
|
|
423
|
+
setup takes place for an application. Of course you are free to add other
|
|
424
|
+
methods to delegate complex tasks, but it is best if those methods
|
|
425
|
+
begin with an underscore '_', as we will see later.
|
|
426
|
+
<pre>
|
|
427
|
+
</pre>
|
|
428
|
+
|
|
429
|
+
<h3>Automatic Running</h3>
|
|
430
|
+
By the way, if you haven't picked up on it already, notice that
|
|
431
|
+
there <tt>myapp.rb</tt> does not contain any code that explicitly
|
|
432
|
+
launches <tt>App</tt>. This is handled automatically with an
|
|
433
|
+
<tt>at_exit {...}</tt> statement.
|
|
434
|
+
|
|
435
|
+
If you need to add <tt>at_exit</tt> handlers in your app, they will
|
|
436
|
+
be added during the execution of the built-in <tt>at_exit</tt> handler.
|
|
437
|
+
|
|
438
|
+
If this doesn't work for you, then you can always create an application
|
|
439
|
+
without the <em>auto run</em> feature.
|
|
440
|
+
|
|
441
|
+
<pre>
|
|
442
|
+
class App < CommandLine::Application_wo_AutoRun
|
|
443
|
+
...
|
|
444
|
+
end
|
|
445
|
+
</pre>
|
|
446
|
+
|
|
447
|
+
(If you have an idea for a better name, please share it with me.)
|
|
448
|
+
|
|
449
|
+
<h3>Adding Options</h3>
|
|
450
|
+
Most applications take options. These options usually come in two forms:
|
|
451
|
+
<b>Flags</b> or <b>Argument Identifiers</b>.
|
|
452
|
+
|
|
453
|
+
<h4>Flags</h4>
|
|
454
|
+
Option flags simply have a <tt>true</tt> or <tt>false</tt> value, depending if they
|
|
455
|
+
are present on the command line. You can define your own flags
|
|
456
|
+
explicitly:
|
|
457
|
+
<pre>
|
|
458
|
+
option :names => %w(--my-flag -m),
|
|
459
|
+
opt_description => "Sets my-flag to true"
|
|
460
|
+
opt_found => true,
|
|
461
|
+
opt_not_found => false
|
|
462
|
+
</pre>
|
|
463
|
+
|
|
464
|
+
Or, using the <tt>:flag</tt> shorthand provided by <tt>Application</tt>
|
|
465
|
+
<pre>
|
|
466
|
+
option :flag, :names => %w(--my-flag -m)
|
|
467
|
+
</pre>
|
|
468
|
+
|
|
469
|
+
Both methods produce the same results.
|
|
470
|
+
|
|
471
|
+
<pre>
|
|
472
|
+
OPTIONS
|
|
473
|
+
|
|
474
|
+
--my-flag,-m
|
|
475
|
+
Sets --my-flag to true.
|
|
476
|
+
</pre>
|
|
477
|
+
|
|
478
|
+
<h4>Argument Identifiers</h4>
|
|
479
|
+
More complex options take arguments, and <tt>CommandLine</tt> does not
|
|
480
|
+
place limitations on the argument list like most other option parsers do.
|
|
481
|
+
|
|
482
|
+
Consider the situtation where you need to indicate a file as a parameter
|
|
483
|
+
on the command line. This common case can be done simply with the notation:
|
|
484
|
+
|
|
485
|
+
<pre>
|
|
486
|
+
option :names => "--file",
|
|
487
|
+
opt_found => get_args
|
|
488
|
+
</pre>
|
|
489
|
+
|
|
490
|
+
And we retrieve the value with:
|
|
491
|
+
|
|
492
|
+
<pre>
|
|
493
|
+
opt :file # or opt "--file"
|
|
494
|
+
</pre>
|
|
495
|
+
|
|
496
|
+
or, more fully
|
|
497
|
+
<pre>
|
|
498
|
+
@option_data["--file"]
|
|
499
|
+
</pre>
|
|
500
|
+
|
|
501
|
+
Let's fill this app out a little more completely and look at it in more detail.
|
|
502
|
+
<pre>
|
|
503
|
+
#!/usr/bin/env ruby
|
|
504
|
+
|
|
505
|
+
require 'rubygems'
|
|
506
|
+
require 'commandline'
|
|
507
|
+
|
|
508
|
+
class App < CommandLine::Application
|
|
509
|
+
def initialize
|
|
510
|
+
author "Author Name"
|
|
511
|
+
copyright "Author Name, 2005"
|
|
512
|
+
synopsis "[-dh] [--in-file <in_file>] file"
|
|
513
|
+
short_description "Example application with one arg"
|
|
514
|
+
long_description "put your long description here!"
|
|
515
|
+
options :help, :debug
|
|
516
|
+
option :names => "--in-file", opt_found => get_args,
|
|
517
|
+
:opt_description => "Input file for sample app.",
|
|
518
|
+
:arg_description => "input_file"
|
|
519
|
+
expected_args :file
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def main
|
|
523
|
+
puts "args: #{args}
|
|
524
|
+
puts "--in-file: #{opt "--in-file"}"
|
|
525
|
+
end
|
|
526
|
+
end#class App
|
|
527
|
+
</pre>
|
|
528
|
+
|
|
529
|
+
Running this application without any arguments, we get the <em>usage</em>
|
|
530
|
+
since it is expecting an argument.
|
|
531
|
+
|
|
532
|
+
<pre>
|
|
533
|
+
% ./myapp.rb
|
|
534
|
+
Usage: myapp.rb [-dh] [--in-file <in_file>] file
|
|
535
|
+
</pre>
|
|
536
|
+
|
|
537
|
+
But, this may not be clear enough, so let's ask for the help page.
|
|
538
|
+
<pre>
|
|
539
|
+
</pre>
|
|
540
|
+
|
|
541
|
+
<pre>
|
|
542
|
+
% ./myapp.rb --help
|
|
543
|
+
NAME
|
|
544
|
+
|
|
545
|
+
app_file.rb - Example application with one arg
|
|
546
|
+
|
|
547
|
+
SYNOPSIS
|
|
548
|
+
|
|
549
|
+
app_file.rb [-dh] [--in-file <in_file>] file
|
|
550
|
+
|
|
551
|
+
DESCRIPTION
|
|
552
|
+
|
|
553
|
+
put your long description here!
|
|
554
|
+
|
|
555
|
+
OPTIONS
|
|
556
|
+
|
|
557
|
+
--help,-h
|
|
558
|
+
Displays help page.
|
|
559
|
+
|
|
560
|
+
--debug,-d
|
|
561
|
+
Sets debug to true.
|
|
562
|
+
|
|
563
|
+
--in-file input_file
|
|
564
|
+
Input file for sample app.
|
|
565
|
+
|
|
566
|
+
AUTHOR: Author Name
|
|
567
|
+
COPYRIGHT (c) Author Name, 2005
|
|
568
|
+
</pre>
|
|
569
|
+
|
|
570
|
+
Pretty nice for just a small amount of source code.
|
|
571
|
+
Now that we know how to use the application, let's call
|
|
572
|
+
it with some arguments and options.
|
|
573
|
+
|
|
574
|
+
<pre>
|
|
575
|
+
% ./myapp.rb file --in-file fred
|
|
576
|
+
args: file
|
|
577
|
+
--in-file: fred
|
|
578
|
+
</pre>
|
|
579
|
+
|
|
580
|
+
That's all there is to it.
|
|
581
|
+
|
|
582
|
+
<h2>Replay</h2>
|
|
583
|
+
<p>
|
|
584
|
+
If ever there was a nifty little feature for applications that
|
|
585
|
+
have large command lines, it is replay.
|
|
586
|
+
</p>
|
|
587
|
+
|
|
588
|
+
<p>
|
|
589
|
+
Replay is not my original idea, but I got it from a company
|
|
590
|
+
that I worked for. We had applications that would create
|
|
591
|
+
working directories and launch sub applications in those
|
|
592
|
+
working directories.
|
|
593
|
+
</p>
|
|
594
|
+
|
|
595
|
+
<p>
|
|
596
|
+
Some of these applications had hundreds
|
|
597
|
+
of options. The replay file was useful for those times that these
|
|
598
|
+
sub applications had to be launched manually. The <tt>.replay</tt>
|
|
599
|
+
file could be modified if needed, and the app re-launched with
|
|
600
|
+
a simple '<tt>app -r</tt>' from the commandline.
|
|
601
|
+
</p>
|
|
602
|
+
|
|
603
|
+
<h3>Activating Replay</h3>
|
|
604
|
+
<p>
|
|
605
|
+
Replay is activated by by calling <tt>use_replay</tt> in your
|
|
606
|
+
<em>initialization</em> method.
|
|
607
|
+
</p>
|
|
608
|
+
|
|
609
|
+
<p>
|
|
610
|
+
Replay stores the command line in a <tt>.replay</tt> file
|
|
611
|
+
in the working directory from which the app was launched.
|
|
612
|
+
Relaunching the app with -r uses the arguments from the
|
|
613
|
+
.replay file, saving typing and mistakes.
|
|
614
|
+
Without the -r flag, any existing replay file is overwritten
|
|
615
|
+
with the arguments sent to the application. If no arguments
|
|
616
|
+
are sent, the .replay file is left untouched.
|
|
617
|
+
If the -r flag is provided with other arguments, they are
|
|
618
|
+
ignored if <tt>@replay</tt> is set to true.
|
|
619
|
+
</p>
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
<pre>
|
|
623
|
+
#!/usr/bin/env ruby
|
|
624
|
+
require 'rubygems'
|
|
625
|
+
require 'commandline'
|
|
626
|
+
|
|
627
|
+
class App < CommandLine::Application
|
|
628
|
+
# If use_replay is given, and '-r' is supplied,
|
|
629
|
+
# it checks for the existance of a .replay file. If such a file
|
|
630
|
+
# exists, the app will use those arguments when run.
|
|
631
|
+
# Also, every time the app is run with arguments, the replay file
|
|
632
|
+
# is updated.
|
|
633
|
+
|
|
634
|
+
def initialize
|
|
635
|
+
use_replay
|
|
636
|
+
expected_args :input, :output
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
def main
|
|
640
|
+
p @arg_names
|
|
641
|
+
puts "#{name} called with #{@args.size} arguments: #{@args.inspect}"
|
|
642
|
+
puts "input: #{@input}"
|
|
643
|
+
puts "output: #{@output}"
|
|
644
|
+
end
|
|
645
|
+
end#class App
|
|
646
|
+
</pre>
|
|
647
|
+
|
|
648
|
+
Now we run the app:
|
|
649
|
+
<pre>
|
|
650
|
+
% ls
|
|
651
|
+
myapp.rb
|
|
652
|
+
% ./myapp.rb aa bb
|
|
653
|
+
[:input, :output]
|
|
654
|
+
myapp.rb called with 2 arguments: ["aa", "bb"]
|
|
655
|
+
input: aa
|
|
656
|
+
output: bb
|
|
657
|
+
|
|
658
|
+
% ls -A
|
|
659
|
+
.replay myapp.rb
|
|
660
|
+
|
|
661
|
+
% cat .replay
|
|
662
|
+
aa bb
|
|
663
|
+
</pre>
|
|
664
|
+
|
|
665
|
+
And, run it using replay:
|
|
666
|
+
|
|
667
|
+
<pre>
|
|
668
|
+
% ./myapp.rb -r
|
|
669
|
+
[:input, :output]
|
|
670
|
+
app_replay.rb called with 2 arguments: ["aa", "bb"]
|
|
671
|
+
input: aa
|
|
672
|
+
output: bb
|
|
673
|
+
</pre>
|
|
674
|
+
|
|
675
|
+
To customize your application and options, you can read the next section
|
|
676
|
+
for more low level details.
|
|
677
|
+
|
|
678
|
+
<h1>OptionParser Usage</h1>
|
|
679
|
+
<p>
|
|
680
|
+
The OptionParser
|
|
681
|
+
library consists of three classes, <tt>Option</tt>, <tt>OptionParser</tt> and
|
|
682
|
+
<tt>OptionData</tt>. For each option an <tt>Option</tt> object is created.
|
|
683
|
+
When you are ready to prepare for command line parsing, these options are
|
|
684
|
+
collected into an array and fed to <tt>OptionParser</tt>.
|
|
685
|
+
This <tt>OptionParser</tt>
|
|
686
|
+
object controls the type of option scheme that is implemented. When it
|
|
687
|
+
comes time to parse a command line, call the method <tt>Option#parse</tt>.
|
|
688
|
+
This will parse any array, but parses ARGV by default. The result is an
|
|
689
|
+
<tt>OptionData</tt> object. This object can be used from which to extract
|
|
690
|
+
values or it can be passed to another class as a fully encapsulated data
|
|
691
|
+
object.
|
|
692
|
+
</p>
|
|
693
|
+
<h3>Using Option Parser</h3>
|
|
694
|
+
<p>
|
|
695
|
+
An option is created with the following syntax:
|
|
696
|
+
</p>
|
|
697
|
+
<pre>
|
|
698
|
+
opt = Option.new([options], <properties>)
|
|
699
|
+
</pre>
|
|
700
|
+
<p>
|
|
701
|
+
The options can be <tt>:flag</tt> or <tt>:posix</tt>. <tt>:flag</tt> means
|
|
702
|
+
that the option is a mode flag and does not take any arguments.
|
|
703
|
+
<tt>:posix</tt> means that <tt>Option</tt> will validate the properties to
|
|
704
|
+
ensure they are posix compliant.
|
|
705
|
+
</p>
|
|
706
|
+
<p>
|
|
707
|
+
An option object has six properties. Four of these properties define
|
|
708
|
+
attributes of the object. The last two define <em>actions</em> that are
|
|
709
|
+
taken when a command line is parsed.
|
|
710
|
+
</p>
|
|
711
|
+
<ol>
|
|
712
|
+
<li>:names
|
|
713
|
+
|
|
714
|
+
</li>
|
|
715
|
+
<li>:arity
|
|
716
|
+
|
|
717
|
+
</li>
|
|
718
|
+
<li>:opt_description
|
|
719
|
+
|
|
720
|
+
</li>
|
|
721
|
+
<li>:arg_description
|
|
722
|
+
|
|
723
|
+
</li>
|
|
724
|
+
<li>:opt_found
|
|
725
|
+
|
|
726
|
+
</li>
|
|
727
|
+
<li>:opt_not_found
|
|
728
|
+
|
|
729
|
+
</li>
|
|
730
|
+
</ol>
|
|
731
|
+
<p>
|
|
732
|
+
It is not necessary to set values for all of these properties. Some are set
|
|
733
|
+
automatically, as we’ll see below.
|
|
734
|
+
</p>
|
|
735
|
+
<h3>Posix</h3>
|
|
736
|
+
<p>
|
|
737
|
+
The default <tt>Option</tt> object is non-posix.
|
|
738
|
+
</p>
|
|
739
|
+
<pre>
|
|
740
|
+
op1 = OptionParser.new(:posix, opts)
|
|
741
|
+
op2 = OptionParser.new(opts)
|
|
742
|
+
op1.posix #=> true
|
|
743
|
+
op2.posix #=> false
|
|
744
|
+
</pre>
|
|
745
|
+
<h3>Mode-Flag</h3>
|
|
746
|
+
<p>
|
|
747
|
+
To create a mode flag, that is, an option that is either true or false
|
|
748
|
+
depending if it is seen on the command line or not, we could write:
|
|
749
|
+
</p>
|
|
750
|
+
<pre>
|
|
751
|
+
opt_debug = Option.new(
|
|
752
|
+
:names => %w(--debug -d), # the flag has two names
|
|
753
|
+
:arity => [0,0], # this says take no arugments
|
|
754
|
+
:opt_description => "Sets debug to true",
|
|
755
|
+
:arg_description => "",
|
|
756
|
+
:opt_found => true, # true if seen on command line
|
|
757
|
+
:opt_not_found => false # false if not seen on command line
|
|
758
|
+
)
|
|
759
|
+
</pre>
|
|
760
|
+
<p>
|
|
761
|
+
Now, this is a lot of work just for a common mode-flag. However, there is a
|
|
762
|
+
shorter way:
|
|
763
|
+
</p>
|
|
764
|
+
<pre>
|
|
765
|
+
opt = Option.new(:flag, :names => %w(--debug -d))
|
|
766
|
+
</pre>
|
|
767
|
+
<p>
|
|
768
|
+
When <tt>Option</tt> sees the :flag option, it makes some assignments
|
|
769
|
+
behind the scenes and what you are left with is:
|
|
770
|
+
</p>
|
|
771
|
+
<pre>
|
|
772
|
+
:names => ["--debug", "-d"]
|
|
773
|
+
:arity => [0, 0]
|
|
774
|
+
:opt_description => "Sets debug to true." # debug is taken from the first name
|
|
775
|
+
:arg_description => ""
|
|
776
|
+
:opt_found => true
|
|
777
|
+
:opt_not_found => false
|
|
778
|
+
</pre>
|
|
779
|
+
<p>
|
|
780
|
+
For a common option like a mode-flag, <tt>Option</tt> will use the first
|
|
781
|
+
option ‘word’ it finds in the :names list and use that in the
|
|
782
|
+
automatic option text. Of course, if you don’t want any text, just
|
|
783
|
+
set the option description to an empty string:
|
|
784
|
+
</p>
|
|
785
|
+
<pre>
|
|
786
|
+
:opt_description => "".
|
|
787
|
+
</pre>
|
|
788
|
+
<h3>Option Arguments</h3>
|
|
789
|
+
<p>
|
|
790
|
+
If an option is not a mode flag, then it takes arguments. Most option
|
|
791
|
+
parsers only permit a single argument per option flag. If your application
|
|
792
|
+
needs multiple arguments, the standard method is just to repeat the option
|
|
793
|
+
multiple times, once for each required argument. For example, if I need to
|
|
794
|
+
pass two files to an application I would need something like:
|
|
795
|
+
</p>
|
|
796
|
+
<pre>
|
|
797
|
+
myapp -f file1 -f file2
|
|
798
|
+
</pre>
|
|
799
|
+
<p>
|
|
800
|
+
But, it would be cleaner if the command line could be expressed as:
|
|
801
|
+
</p>
|
|
802
|
+
<pre>
|
|
803
|
+
myapp -f file1 file2
|
|
804
|
+
</pre>
|
|
805
|
+
<p>
|
|
806
|
+
Well, no longer do you have to suffer with thirty-year old option parser
|
|
807
|
+
technology. <tt>OptionParser</tt>
|
|
808
|
+
permits multiple arguments per option flag and the number of arguments can
|
|
809
|
+
be defined to be variable.
|
|
810
|
+
</p>
|
|
811
|
+
<p>
|
|
812
|
+
To define an option that takes 1 or more arguments, the following can be
|
|
813
|
+
done:
|
|
814
|
+
</p>
|
|
815
|
+
<pre>
|
|
816
|
+
opt = Option.new(:names => "--file", :arity => [1,-1])
|
|
817
|
+
</pre>
|
|
818
|
+
<p>
|
|
819
|
+
Let’s say the option required at least two arguments, but not more
|
|
820
|
+
than five. This is defined with:
|
|
821
|
+
</p>
|
|
822
|
+
<pre>
|
|
823
|
+
opt = Option.new(:names => "--file", :arity => [2,5])
|
|
824
|
+
OptionParser.new(opt).parse
|
|
825
|
+
|
|
826
|
+
% myapp --file file1 # exception raised
|
|
827
|
+
% myapp --file file1 file2 # ok
|
|
828
|
+
% myapp --file file1 file2 file3 # ok
|
|
829
|
+
% myapp --file f1 f2 f3 f4 f5 f6 # f6 remains on the command line
|
|
830
|
+
</pre>
|
|
831
|
+
<p>
|
|
832
|
+
This ability is handy on occassions where an option argument is
|
|
833
|
+
‘optional’.
|
|
834
|
+
</p>
|
|
835
|
+
<pre>
|
|
836
|
+
myapp --custom # no args, uses $HOME/.myapprc
|
|
837
|
+
myapp --custom my_custom_file # uses my_custom_file
|
|
838
|
+
</pre>
|
|
839
|
+
<p>
|
|
840
|
+
This type of option is defined by:
|
|
841
|
+
</p>
|
|
842
|
+
<pre>
|
|
843
|
+
opt = Option.new(:names => "--custom", :arity => [0,1])
|
|
844
|
+
</pre>
|
|
845
|
+
<p>
|
|
846
|
+
If the <tt>:arity</tt> is not satisfied, an exception is raised.
|
|
847
|
+
</p>
|
|
848
|
+
<h3>Actions</h3>
|
|
849
|
+
<p>
|
|
850
|
+
The option properties <tt>:opt_found</tt> and <tt>:opt_not_found</tt> are
|
|
851
|
+
the source of the value returned for an option when it is parsed. These
|
|
852
|
+
properties can be either an object or a proc/lambda. If they are an object,
|
|
853
|
+
then the stored object is simply returned. If they are lambdas, then the
|
|
854
|
+
stored value is the return value of the proc/lambda. So, the following will
|
|
855
|
+
have the same result:
|
|
856
|
+
</p>
|
|
857
|
+
<pre>
|
|
858
|
+
opt_debug = Option.new(:flag
|
|
859
|
+
:names => %w(--debug -d),
|
|
860
|
+
:opt_found => true,
|
|
861
|
+
:opt_not_found => false
|
|
862
|
+
)
|
|
863
|
+
|
|
864
|
+
opt_debug = Option.new(:flag
|
|
865
|
+
:names => %w(--debug -d),
|
|
866
|
+
:opt_found => lambda { true },
|
|
867
|
+
:opt_not_found => lambda { false }
|
|
868
|
+
)
|
|
869
|
+
</pre>
|
|
870
|
+
<p>
|
|
871
|
+
Notice that there is no need to set an instance variable to a default
|
|
872
|
+
value. Normally one does:
|
|
873
|
+
</p>
|
|
874
|
+
<pre>
|
|
875
|
+
@debug = false
|
|
876
|
+
# option setup
|
|
877
|
+
... parse the commandline
|
|
878
|
+
@debug = true if parse_results["--debug"]
|
|
879
|
+
</pre>
|
|
880
|
+
<p>
|
|
881
|
+
But with <tt>OptionParser</tt>, one
|
|
882
|
+
has the capability of doing the following:
|
|
883
|
+
</p>
|
|
884
|
+
<pre>
|
|
885
|
+
opt_debug = Option.new(:flag, :names => %w(--debug -d))
|
|
886
|
+
... parse the commandline
|
|
887
|
+
@debug = option_data[:debug] # value is set without need for default
|
|
888
|
+
|
|
889
|
+
# or
|
|
890
|
+
|
|
891
|
+
opt_debug = Option.new(:flag
|
|
892
|
+
:names => %w(--debug -d),
|
|
893
|
+
:opt_found => lambda { @debug = true },
|
|
894
|
+
:opt_not_found => lambda { @debug = false }
|
|
895
|
+
)
|
|
896
|
+
# do nothing, variable already set.
|
|
897
|
+
</pre>
|
|
898
|
+
<p>
|
|
899
|
+
I find this much easier to manage than having to worry about setting
|
|
900
|
+
default behaviour. Now that we know how to create options, let’s move
|
|
901
|
+
on to the commandline parser.
|
|
902
|
+
</p>
|
|
903
|
+
<h2>OptionParser</h2>
|
|
904
|
+
<p>
|
|
905
|
+
Once the options are defined, we load them into an <tt>OptionParser</tt> and
|
|
906
|
+
parse the command line. The syntax for creating an <tt>OptionParser</tt>
|
|
907
|
+
object is:
|
|
908
|
+
</p>
|
|
909
|
+
<pre>
|
|
910
|
+
OptionParser.new(prop_flags, option)
|
|
911
|
+
OptionParser.new(prop_flags, [options])
|
|
912
|
+
OptionParser.new(option)
|
|
913
|
+
OptionParser.new([options])
|
|
914
|
+
</pre>
|
|
915
|
+
<p>
|
|
916
|
+
where the possible property flags are:
|
|
917
|
+
</p>
|
|
918
|
+
<pre>
|
|
919
|
+
:posix
|
|
920
|
+
:unknown_options_action => :collect | :ignore | :raise
|
|
921
|
+
</pre>
|
|
922
|
+
<p>
|
|
923
|
+
If you want to parse posix, you must specify so. <tt>OptionParser</tt> will
|
|
924
|
+
not assume posix mode just because all of the options are posix options.
|
|
925
|
+
This allows you to use posix only options but not require the strict
|
|
926
|
+
parsing rules.
|
|
927
|
+
</p>
|
|
928
|
+
<p>
|
|
929
|
+
Below are a few examples of creating an <tt>OptionParser</tt>
|
|
930
|
+
object:
|
|
931
|
+
</p>
|
|
932
|
+
<pre>
|
|
933
|
+
opt = Option.new(:flag, :names => %w(-h))
|
|
934
|
+
op1 = OptionParser.new(:posix, opt)
|
|
935
|
+
op2 = OptionParser.new(opt)
|
|
936
|
+
</pre>
|
|
937
|
+
<p>
|
|
938
|
+
or
|
|
939
|
+
</p>
|
|
940
|
+
<pre>
|
|
941
|
+
opts = []
|
|
942
|
+
opts << Option.new(:flag, :names => %w(--help h))
|
|
943
|
+
opts << Option.new(:flag, :names => %w(--debug d))
|
|
944
|
+
</pre>
|
|
945
|
+
<p>
|
|
946
|
+
Options may be added to an <tt>OptionParser</tt> by
|
|
947
|
+
three different methods:
|
|
948
|
+
</p>
|
|
949
|
+
<pre>
|
|
950
|
+
# Options added as arguments during OptionParser construction
|
|
951
|
+
op = OptionParser.new(opt1, opt2)
|
|
952
|
+
op = OptionParser.new([opt1, opt2])
|
|
953
|
+
</pre>
|
|
954
|
+
<p>
|
|
955
|
+
or
|
|
956
|
+
</p>
|
|
957
|
+
<pre>
|
|
958
|
+
# Options added in a block constructor
|
|
959
|
+
op = OptionParser.new { |o| o << opts }
|
|
960
|
+
</pre>
|
|
961
|
+
<p>
|
|
962
|
+
or
|
|
963
|
+
</p>
|
|
964
|
+
<pre>
|
|
965
|
+
# Options added to an existing OptionParser object
|
|
966
|
+
op = OptionParser.new
|
|
967
|
+
op << opts
|
|
968
|
+
</pre>
|
|
969
|
+
<h3>Parsing the Command Line</h3>
|
|
970
|
+
<p>
|
|
971
|
+
Parsing the command line is as simple as calling <tt>#parse</tt>:
|
|
972
|
+
</p>
|
|
973
|
+
<pre>
|
|
974
|
+
option_data = op.parse
|
|
975
|
+
</pre>
|
|
976
|
+
<h3>Printing an Option Summary</h3>
|
|
977
|
+
<p>
|
|
978
|
+
A <tt>OptionParser</tt> with
|
|
979
|
+
a complete set of options added to it defines the human interface that your
|
|
980
|
+
application presents to a user. Therefore, the parser should be able to
|
|
981
|
+
provide a nicely formatted summary for the user.
|
|
982
|
+
</p>
|
|
983
|
+
<p>
|
|
984
|
+
An example is shown below with its corresponding output:
|
|
985
|
+
</p>
|
|
986
|
+
<pre>
|
|
987
|
+
require 'rubygems'
|
|
988
|
+
require 'commandline/optionparser'
|
|
989
|
+
include CommandLine
|
|
990
|
+
puts OptionParser.new { |o|
|
|
991
|
+
o << Option.new(:flag, :names => %w[--debug -d])
|
|
992
|
+
o << Option.new(:flag, :names => %w[--help -h],
|
|
993
|
+
:opt_description => "Prints this page.")
|
|
994
|
+
o << Option.new(:names => %w[--ouput -o],
|
|
995
|
+
:opt_description => "Defines the output file.",
|
|
996
|
+
:arg_description => "output_file")
|
|
997
|
+
o << Option.new(:names => %w[--a-long-opt --with-many-names -a -A],
|
|
998
|
+
:arity => [2,-1],
|
|
999
|
+
:opt_description => "Your really long description here.",
|
|
1000
|
+
:arg_description => "file1 file2 [file3 ...]")
|
|
1001
|
+
}.to_s
|
|
1002
|
+
</pre>
|
|
1003
|
+
<p>
|
|
1004
|
+
Generates the output:
|
|
1005
|
+
</p>
|
|
1006
|
+
<pre>
|
|
1007
|
+
OPTIONS
|
|
1008
|
+
|
|
1009
|
+
--debug,-d
|
|
1010
|
+
Sets debug to true.
|
|
1011
|
+
|
|
1012
|
+
--help,-h
|
|
1013
|
+
Prints this page.
|
|
1014
|
+
|
|
1015
|
+
--ouput,-o output_file
|
|
1016
|
+
Defines the output file.
|
|
1017
|
+
|
|
1018
|
+
--a-long-opt,--with-many-names,-a,-A file1 file2 [file3 ...]
|
|
1019
|
+
Your really long description here.
|
|
1020
|
+
</pre>
|
|
1021
|
+
<h2>Option Data</h2>
|
|
1022
|
+
<p>
|
|
1023
|
+
The <tt>OptionData</tt> is the return value of <tt>OptionParser#parse</tt>.
|
|
1024
|
+
The parsing results for each option are accessed with the bracket notation
|
|
1025
|
+
#[].
|
|
1026
|
+
</p>
|
|
1027
|
+
<pre>
|
|
1028
|
+
opt = Option.new(:posix,
|
|
1029
|
+
:names => %w(-r),
|
|
1030
|
+
:opt_found => OptionParser::GET_ARGS)
|
|
1031
|
+
od = OptionParser.new(:posix, opt).parse(["-rubygems"])
|
|
1032
|
+
od["-r"] #=> "ubygems"
|
|
1033
|
+
|
|
1034
|
+
od = OptionParser.new(:posix, opt).parse(["-r", "ubygems"])
|
|
1035
|
+
od["-r"] #=> "ubygems"
|
|
1036
|
+
</pre>
|
|
1037
|
+
<p>
|
|
1038
|
+
<tt>OptionData</tt> behaves similar to a hash object in that the parsed
|
|
1039
|
+
option data is accessed with #[] where the key is the first item in the
|
|
1040
|
+
:names array of each option. An option cannot access its parsed values
|
|
1041
|
+
using just any of its names.
|
|
1042
|
+
</p>
|
|
1043
|
+
<pre>
|
|
1044
|
+
od = OptionParser.new { |o|
|
|
1045
|
+
o << Option.new(:flag, :names => %w(--valid --notvalid))
|
|
1046
|
+
o << Option.new(:flag, :names => %w(--first --second))
|
|
1047
|
+
}.parse(%w(--notvalid --second))
|
|
1048
|
+
od["--valid"] #=> true
|
|
1049
|
+
od["--first"] #=> true
|
|
1050
|
+
od["--notvalid"] #=> CommandLine::OptionData::UnknownOptionError
|
|
1051
|
+
od["--second"] #=> CommandLine::OptionData::UnknownOptionError
|
|
1052
|
+
</pre>
|
|
1053
|
+
<h3>Built-in Data Handlers</h3>
|
|
1054
|
+
<p>
|
|
1055
|
+
OptionParser has
|
|
1056
|
+
built-in data handlers for handling common scenarios. These lambdas can
|
|
1057
|
+
save a lot of typing.
|
|
1058
|
+
</p>
|
|
1059
|
+
<h3>GET_ARG_ARRAY</h3>
|
|
1060
|
+
<p>
|
|
1061
|
+
This is useful for options that take a variable number of arguments. It
|
|
1062
|
+
returns all the arguments in an array.
|
|
1063
|
+
</p>
|
|
1064
|
+
<pre>
|
|
1065
|
+
# GET_ARG_ARRAY returns all arguments in an array, even if no
|
|
1066
|
+
# arguments are present. This is not to be confused with the option
|
|
1067
|
+
# occuring multiple times on the command line.
|
|
1068
|
+
opt = Option.new(:names => %w(--file),
|
|
1069
|
+
:argument_arity => [0,-1],
|
|
1070
|
+
:opt_found => OptionParser::GET_ARG_ARRAY)
|
|
1071
|
+
#:opt_found => :collect) # would this be better?
|
|
1072
|
+
od = OptionParser.new(opt).parse(%w(--file))
|
|
1073
|
+
od["--file"] #=> []
|
|
1074
|
+
od = OptionParser.new(opt).parse(%w(--file=file))
|
|
1075
|
+
od["--file"] #=> ["file"]
|
|
1076
|
+
od = OptionParser.new(opt).parse(%w(--file=file1 --file file2))
|
|
1077
|
+
od["--file"] #=> ["file2"]
|
|
1078
|
+
od = OptionParser.new(opt).parse(%w(--file=file1 file2))
|
|
1079
|
+
od["--file"] #=> ["file1", "file2"]
|
|
1080
|
+
od = OptionParser.new(opt).parse(%w(--file file1 file2))
|
|
1081
|
+
od["--file"] #=> ["file1", "file2"]
|
|
1082
|
+
</pre>
|
|
1083
|
+
<h3>GET_ARGS</h3>
|
|
1084
|
+
<p>
|
|
1085
|
+
This is a ‘smart’ option getter. If no arguments are found, it
|
|
1086
|
+
returns true. If a single argument is found, it returns that argument. If
|
|
1087
|
+
more than one argument is found, it returns an array of those arguments.
|
|
1088
|
+
</p>
|
|
1089
|
+
<pre>
|
|
1090
|
+
opt = Option.new(:names => %w(--file),
|
|
1091
|
+
:argument_arity => [0,-1],
|
|
1092
|
+
:opt_found => OptionParser::GET_ARGS)
|
|
1093
|
+
#:opt_found => :smart_collect) # would this be better?
|
|
1094
|
+
od = OptionParser.new(opt).parse(%w(--file))
|
|
1095
|
+
od["--file"] #=> true
|
|
1096
|
+
od = OptionParser.new(opt).parse(%w(--file=file))
|
|
1097
|
+
od["--file"] #=> "file"
|
|
1098
|
+
od = OptionParser.new(opt).parse(%w(--file=file1 --file file2))
|
|
1099
|
+
od["--file"] #=> "file2"
|
|
1100
|
+
od = OptionParser.new(opt).parse(%w(--file=file1 file2))
|
|
1101
|
+
od["--file"] #=> ["file1", "file2"]
|
|
1102
|
+
od = OptionParser.new(opt).parse(%w(--file file1 file2))
|
|
1103
|
+
od["--file"] #=> ["file1", "file2"]
|
|
1104
|
+
</pre>
|
|
1105
|
+
<p>
|
|
1106
|
+
And, for those oxymoronic non-optional options:
|
|
1107
|
+
</p>
|
|
1108
|
+
<pre>
|
|
1109
|
+
opt = Option.new(:names => %w(--not-really-an-option),
|
|
1110
|
+
:opt_not_found => OptionParser::OPT_NOT_FOUND_BUT_REQUIRED
|
|
1111
|
+
)
|
|
1112
|
+
OptionParser.new(opt).parse([]) #=> OptionParser::MissingRequiredOptionError
|
|
1113
|
+
</pre>
|
|
1114
|
+
<h3><tt>OptionData</tt></h3>
|
|
1115
|
+
<p>
|
|
1116
|
+
We have just shown that after parsing a command line, the result of each
|
|
1117
|
+
option is found from OptionData. The values that remain on the command line
|
|
1118
|
+
are assigned to <tt>args</tt>. Other attributes of <tt>OptionData</tt> are:
|
|
1119
|
+
</p>
|
|
1120
|
+
<pre>
|
|
1121
|
+
od.argv # the original command line
|
|
1122
|
+
od.unknown_options # If OptionParser was told to :collect unknown options
|
|
1123
|
+
od.args # arguments not claimed by any option
|
|
1124
|
+
od.not_parsed # arguments following a '--' on the command line
|
|
1125
|
+
od.cmd # not yet implemented - but a cvs like command
|
|
1126
|
+
</pre>
|
|
1127
|
+
<a name="traditional"/>
|
|
1128
|
+
<hr size="2"></hr><h1>Traditional Option Parsing Schemes</h1>
|
|
1129
|
+
<p>
|
|
1130
|
+
This section is a brief overview of traditional command line parsing.
|
|
1131
|
+
</p>
|
|
1132
|
+
<p>
|
|
1133
|
+
Command line options traditionally occur in three flavors:
|
|
1134
|
+
</p>
|
|
1135
|
+
<ul>
|
|
1136
|
+
<li><em>Unix</em> (or POSIX.2)
|
|
1137
|
+
|
|
1138
|
+
</li>
|
|
1139
|
+
<li><em>Gnu</em>
|
|
1140
|
+
|
|
1141
|
+
</li>
|
|
1142
|
+
<li><em>X Toolkit</em>
|
|
1143
|
+
|
|
1144
|
+
</li>
|
|
1145
|
+
</ul>
|
|
1146
|
+
<p>
|
|
1147
|
+
Below is a summary of these schemes. <em>(Note: I did not invent these
|
|
1148
|
+
traditional parsing conventions. Most of the information contained below
|
|
1149
|
+
was pulled from internet resources and I have quoted these resources where
|
|
1150
|
+
possible.)</em>
|
|
1151
|
+
</p>
|
|
1152
|
+
<h2>Unix Style (POSIX)</h2>
|
|
1153
|
+
<p>
|
|
1154
|
+
The Unix style command line options are a single character preceded by a
|
|
1155
|
+
single dash (hyphen character). In general, lowercase options are preferred
|
|
1156
|
+
with their uppercase counterparts being the special case variant.
|
|
1157
|
+
</p>
|
|
1158
|
+
<h3>Mode Flag</h3>
|
|
1159
|
+
<p>
|
|
1160
|
+
If an option does not take an argument, then it is a mode-flag.
|
|
1161
|
+
</p>
|
|
1162
|
+
<h3>Optional Separation Between the Option Flag and Its Argument</h3>
|
|
1163
|
+
<p>
|
|
1164
|
+
If the option takes an argument, the argument follows it with optional
|
|
1165
|
+
white space separating the two. For example, the following forms are both
|
|
1166
|
+
valid:
|
|
1167
|
+
</p>
|
|
1168
|
+
<pre>
|
|
1169
|
+
sort -k 5
|
|
1170
|
+
sort -k5
|
|
1171
|
+
</pre>
|
|
1172
|
+
<h3>Grouping</h3>
|
|
1173
|
+
<p>
|
|
1174
|
+
A mode-flag can be grouped together with other mode-flags behind a single
|
|
1175
|
+
dash. For example:
|
|
1176
|
+
</p>
|
|
1177
|
+
<pre>
|
|
1178
|
+
tar -c -v -f
|
|
1179
|
+
</pre>
|
|
1180
|
+
<p>
|
|
1181
|
+
is equivalent to:
|
|
1182
|
+
</p>
|
|
1183
|
+
<pre>
|
|
1184
|
+
tar -cvf
|
|
1185
|
+
</pre>
|
|
1186
|
+
<p>
|
|
1187
|
+
If grouping is done, the last option in a group can be an option that takes
|
|
1188
|
+
an argument. For example
|
|
1189
|
+
</p>
|
|
1190
|
+
<pre>
|
|
1191
|
+
sort -r -n -k 5
|
|
1192
|
+
</pre>
|
|
1193
|
+
<p>
|
|
1194
|
+
can be written as
|
|
1195
|
+
</p>
|
|
1196
|
+
<pre>
|
|
1197
|
+
sort -rnk 5
|
|
1198
|
+
</pre>
|
|
1199
|
+
<p>
|
|
1200
|
+
but not
|
|
1201
|
+
</p>
|
|
1202
|
+
<pre>
|
|
1203
|
+
sort -rkn 5
|
|
1204
|
+
</pre>
|
|
1205
|
+
<p>
|
|
1206
|
+
because the ‘5’ argument belongs to the ‘k’ option
|
|
1207
|
+
flag.
|
|
1208
|
+
</p>
|
|
1209
|
+
<h3>Option Parsing Termination</h3>
|
|
1210
|
+
<p>
|
|
1211
|
+
It is convention that a double hyphen is a signal to stop option
|
|
1212
|
+
interpretation and to read the remaining statements on the command line
|
|
1213
|
+
literally. So, a command such as:
|
|
1214
|
+
</p>
|
|
1215
|
+
<pre>
|
|
1216
|
+
app -- -x -y -z
|
|
1217
|
+
</pre>
|
|
1218
|
+
<p>
|
|
1219
|
+
will not ‘see’ the three mode-flags. Instead, they will be
|
|
1220
|
+
treated as arguments to the application:
|
|
1221
|
+
</p>
|
|
1222
|
+
<pre>
|
|
1223
|
+
#args = ["-x", "-y", "-z"]
|
|
1224
|
+
</pre>
|
|
1225
|
+
<h3>POSIX Summary</h3>
|
|
1226
|
+
<ol>
|
|
1227
|
+
<li>An option is a hyphen followed by a single alphanumeric character.
|
|
1228
|
+
|
|
1229
|
+
</li>
|
|
1230
|
+
<li>An option may require an argument which must follow the option with an
|
|
1231
|
+
optional space in between.
|
|
1232
|
+
|
|
1233
|
+
<pre>
|
|
1234
|
+
-r ubygems
|
|
1235
|
+
-rubygems
|
|
1236
|
+
-r=ubygems # not ok. '=' is Gnu style
|
|
1237
|
+
</pre>
|
|
1238
|
+
</li>
|
|
1239
|
+
<li>Options that do not require arguments can be grouped after a hyphen.
|
|
1240
|
+
|
|
1241
|
+
</li>
|
|
1242
|
+
<li>Options can appear in any order.
|
|
1243
|
+
|
|
1244
|
+
</li>
|
|
1245
|
+
<li>Options can appear multiple times.
|
|
1246
|
+
|
|
1247
|
+
</li>
|
|
1248
|
+
<li>Options precede other nonoption arguments. TODO: Test for this
|
|
1249
|
+
|
|
1250
|
+
</li>
|
|
1251
|
+
<li>The — argument terminates options.
|
|
1252
|
+
|
|
1253
|
+
</li>
|
|
1254
|
+
<li>The - option is used to represent the standard input stream.
|
|
1255
|
+
|
|
1256
|
+
</li>
|
|
1257
|
+
</ol>
|
|
1258
|
+
<h3>References</h3>
|
|
1259
|
+
<p>
|
|
1260
|
+
<a
|
|
1261
|
+
href="http://www.mkssoftware.com/docs/man1/getopts.1.asp">www.mkssoftware.com/docs/man1/getopts.1.asp</a>
|
|
1262
|
+
</p>
|
|
1263
|
+
<h2>Gnu Style</h2>
|
|
1264
|
+
<p>
|
|
1265
|
+
The Gnu style command line options provide support for option words (or
|
|
1266
|
+
keywords), yet still maintain compatibility with the Unix style options.
|
|
1267
|
+
The options in this style are sometimes referred to as
|
|
1268
|
+
<em>long_options</em> and the Unix style options as <em>short_options</em>.
|
|
1269
|
+
The compatibility is maintained by preceding the <em>long_options</em> with
|
|
1270
|
+
two dashes. The option word must be two or more characters.
|
|
1271
|
+
</p>
|
|
1272
|
+
<h3>Separation Between the Option Flag and Its Argument</h3>
|
|
1273
|
+
<p>
|
|
1274
|
+
Gnu style options cannot be grouped. For options that have an argument, the
|
|
1275
|
+
argument follows the option with either whitespace or an ’=’.
|
|
1276
|
+
For example, the following are equivalent:
|
|
1277
|
+
</p>
|
|
1278
|
+
<pre>
|
|
1279
|
+
app --with-optimizer yes
|
|
1280
|
+
app --with-optimizer=yes
|
|
1281
|
+
</pre>
|
|
1282
|
+
<h3>Option Parsing Termination</h3>
|
|
1283
|
+
<p>
|
|
1284
|
+
Similar to the <em>Unix</em> style double-hyphen ’- -’, the
|
|
1285
|
+
<em>Gnu</em> style has a triple-hyphen ’- - -’ to signal that
|
|
1286
|
+
option parsing be halted and to treat the remaining text as arguments (that
|
|
1287
|
+
is, read literally from the command line)
|
|
1288
|
+
</p>
|
|
1289
|
+
<pre>
|
|
1290
|
+
app --- -x -y -z
|
|
1291
|
+
args = ["-x", "-y", "-z"]
|
|
1292
|
+
</pre>
|
|
1293
|
+
<h3>Mixing <em>Gnu</em> and <em>Unix</em> Styles</h3>
|
|
1294
|
+
<p>
|
|
1295
|
+
The <em>Gnu</em> and the <em>Unix</em> option types can be mixed on the
|
|
1296
|
+
same commandline. The following are equivalent:
|
|
1297
|
+
</p>
|
|
1298
|
+
<pre>
|
|
1299
|
+
app -a -b --with-c
|
|
1300
|
+
app -ab --with-c
|
|
1301
|
+
app -ba --with-c
|
|
1302
|
+
app --with-c -ab
|
|
1303
|
+
</pre>
|
|
1304
|
+
<h2>X Toolkit Style</h2>
|
|
1305
|
+
<p>
|
|
1306
|
+
The X Toolkit style uses the single hyphen followed by a keyword option.
|
|
1307
|
+
This style is not compatible with the <em>Unix</em> or the <em>Gnu</em>
|
|
1308
|
+
option types. In most situations this is OK since these options will be
|
|
1309
|
+
filtered from the command line before passing them to an application.
|
|
1310
|
+
</p>
|
|
1311
|
+
<h3>’-’ and STDIN</h3>
|
|
1312
|
+
<p>
|
|
1313
|
+
It is convention that a bare hypen indicates to read from stdin.
|
|
1314
|
+
</p>
|
|
1315
|
+
<h2>The OptionParser Style</h2>
|
|
1316
|
+
<p>
|
|
1317
|
+
The CommandLine::OptionParser does not
|
|
1318
|
+
care what style you use. It is designed for maximum flexiblity so it may be
|
|
1319
|
+
used within any organiziation to meet their standards.
|
|
1320
|
+
</p>
|
|
1321
|
+
<h3>Multiple Option Names</h3>
|
|
1322
|
+
<p> OptionParser does
|
|
1323
|
+
not place restrictions on the number of options. The only restriction is
|
|
1324
|
+
that an option name begin with a hyphen ’-’. A definitely
|
|
1325
|
+
conjured example of this freedom is:
|
|
1326
|
+
</p>
|
|
1327
|
+
<pre>
|
|
1328
|
+
:names => %w(
|
|
1329
|
+
--file --File --f --F -file -File -f -F
|
|
1330
|
+
)
|
|
1331
|
+
</pre>
|
|
1332
|
+
<h3>Prefix Matching</h3>
|
|
1333
|
+
<p>
|
|
1334
|
+
Although not encouraged, some prefer the ability to truncate option words
|
|
1335
|
+
to their first unique match. For example, an application that support this
|
|
1336
|
+
style and accepts the following two option words:
|
|
1337
|
+
</p>
|
|
1338
|
+
<pre>
|
|
1339
|
+
["--foos", "--fbars"]
|
|
1340
|
+
</pre>
|
|
1341
|
+
<p>
|
|
1342
|
+
will accept any of the following as valid options
|
|
1343
|
+
</p>
|
|
1344
|
+
<pre>
|
|
1345
|
+
app --fo
|
|
1346
|
+
app --foo
|
|
1347
|
+
app --foos
|
|
1348
|
+
</pre>
|
|
1349
|
+
<p>
|
|
1350
|
+
for the "—foos" option flag since it can be determined that
|
|
1351
|
+
"—fo" will only match "—foos" and not
|
|
1352
|
+
"—fbars".
|
|
1353
|
+
</p>
|
|
1354
|
+
<h3>Repeated Arguments</h3>
|
|
1355
|
+
<p>
|
|
1356
|
+
A common question is how an option parser should respond when an option is
|
|
1357
|
+
specified on the command line multiple times. This is true for mode flags,
|
|
1358
|
+
but especially true for options that require an argument, For example, what
|
|
1359
|
+
should happen when the following is given:
|
|
1360
|
+
</p>
|
|
1361
|
+
<pre>
|
|
1362
|
+
app -f file1 -f file2
|
|
1363
|
+
</pre>
|
|
1364
|
+
<p>
|
|
1365
|
+
Should the parser flag this as an error or should it accept both arguments.
|
|
1366
|
+
</p>
|
|
1367
|
+
<p> OptionParser gives
|
|
1368
|
+
you the choice of whether it raises an exception when an option is seen
|
|
1369
|
+
more than once, or it just passes the data onto the user.
|
|
1370
|
+
</p>
|
|
1371
|
+
<p>
|
|
1372
|
+
How the data is handled is up to the user, but it typically boils down to
|
|
1373
|
+
either Append, Replace or Raise. This is described in more detail in the
|
|
1374
|
+
usage section.
|
|
1375
|
+
</p>
|
|
1376
|
+
<h2>CVS Mode</h2>
|
|
1377
|
+
<p>
|
|
1378
|
+
CVS is a common application with a unique command line structure. The cvs
|
|
1379
|
+
application commandline can be given options, but requires a command. This
|
|
1380
|
+
command can also be given options. This means that there are two sets of
|
|
1381
|
+
options, one set for the cvs application and one set for the cvs-command.
|
|
1382
|
+
Some example formats are:
|
|
1383
|
+
</p>
|
|
1384
|
+
<pre>
|
|
1385
|
+
cvs [cvs-options]
|
|
1386
|
+
cvs [cvs-options] command [command-options-and-arguments]
|
|
1387
|
+
|
|
1388
|
+
cvs -r update
|
|
1389
|
+
cvs -r update .
|
|
1390
|
+
cvs edit -p file
|
|
1391
|
+
</pre>
|
|
1392
|
+
<p>
|
|
1393
|
+
To handle this, the first unclaimed argument is treated as a command and
|
|
1394
|
+
the options and option-arguments that follow belong to that command. More
|
|
1395
|
+
on how this is handled in the usage section.
|
|
1396
|
+
</p>
|
|
1397
|
+
<h2>Option Grouping</h2>
|
|
1398
|
+
<p>
|
|
1399
|
+
A conflict can occur where a grouping of single letter Unix options has the
|
|
1400
|
+
value as a word option preceded by a single dash. For this reason, it is
|
|
1401
|
+
customary to use the double-dash notation for word options. Unless
|
|
1402
|
+
double-dashes are enforced for word options, OptionParser will
|
|
1403
|
+
check for possible name conflicts and raise an exception if it finds one.
|
|
1404
|
+
</p>
|
|
1405
|
+
|
|
1406
|
+
</td></tr>
|
|
1407
|
+
</table>
|
|
1408
|
+
</table>
|
|
1409
|
+
</body>
|
|
1410
|
+
</html>
|