qoobaa-user-choices 1.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/LICENSE +39 -0
  4. data/README.rdoc +7 -0
  5. data/Rakefile +56 -0
  6. data/VERSION +1 -0
  7. data/examples/older/README.txt +133 -0
  8. data/examples/older/command-line.rb +46 -0
  9. data/examples/older/default-values.rb +41 -0
  10. data/examples/older/multiple-sources.rb +58 -0
  11. data/examples/older/postprocess.rb +39 -0
  12. data/examples/older/switches.rb +44 -0
  13. data/examples/older/two-args.rb +31 -0
  14. data/examples/older/types.rb +61 -0
  15. data/examples/tutorial/css/LICENSE.txt +1 -0
  16. data/examples/tutorial/css/bg2.gif +0 -0
  17. data/examples/tutorial/css/left.gif +0 -0
  18. data/examples/tutorial/css/left_on.gif +0 -0
  19. data/examples/tutorial/css/main.css +242 -0
  20. data/examples/tutorial/css/right.gif +0 -0
  21. data/examples/tutorial/css/right_on.gif +0 -0
  22. data/examples/tutorial/css/tvline.gif +0 -0
  23. data/examples/tutorial/css/von-foerster.jpg +0 -0
  24. data/examples/tutorial/css/von-foerster2.jpg +0 -0
  25. data/examples/tutorial/index.html +703 -0
  26. data/examples/tutorial/tutorial1.rb +41 -0
  27. data/examples/tutorial/tutorial2.rb +44 -0
  28. data/examples/tutorial/tutorial3.rb +47 -0
  29. data/examples/tutorial/tutorial4.rb +47 -0
  30. data/examples/tutorial/tutorial5.rb +35 -0
  31. data/examples/tutorial/tutorial6.rb +35 -0
  32. data/examples/tutorial/tutorial7.rb +41 -0
  33. data/lib/user-choices.rb +131 -0
  34. data/lib/user-choices/arglist-strategies.rb +179 -0
  35. data/lib/user-choices/builder.rb +118 -0
  36. data/lib/user-choices/command-line-source.rb +224 -0
  37. data/lib/user-choices/command.rb +42 -0
  38. data/lib/user-choices/conversions.rb +169 -0
  39. data/lib/user-choices/ruby-extensions.rb +20 -0
  40. data/lib/user-choices/sources.rb +278 -0
  41. data/lib/user-choices/version.rb +3 -0
  42. data/test/arglist_strategy_test.rb +42 -0
  43. data/test/builder_test.rb +631 -0
  44. data/test/command_line_source_test.rb +443 -0
  45. data/test/conversion_test.rb +172 -0
  46. data/test/source_test.rb +451 -0
  47. data/test/test_helper.rb +9 -0
  48. data/test/user_choices_slow_test.rb +276 -0
  49. data/user-choices.gemspec +104 -0
  50. metadata +122 -0
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require 'user-choices'
5
+
6
+ class SwitchExample < UserChoices::Command
7
+
8
+ def add_sources(builder)
9
+ builder.add_source(UserChoices::CommandLineSource, :usage,
10
+ "Usage: ruby #{$0} [options] args...",
11
+ "There may be 2-4 arguments.")
12
+
13
+ end
14
+
15
+ # Switches are slightly different than options. (The difference is
16
+ # in how they're invoked, as either --switch or --no-switch.) Almost
17
+ # certainly, you want the switch to be of type :boolean and have a
18
+ # default.
19
+ def add_choices(builder)
20
+ builder.add_choice(:switch,
21
+ :default => false,
22
+ :type => :boolean) { | command_line |
23
+ command_line.uses_switch("--switch", "-s")
24
+ }
25
+
26
+ # You control the allowable length of a choice with the :length
27
+ # keyword argument. It applies to command-line arglists, lists given
28
+ # in configuration files, and the like.
29
+ builder.add_choice(:args, :length => 2..4) { | command_line |
30
+ command_line.uses_arglist
31
+ }
32
+ end
33
+
34
+ def execute
35
+ pp @user_choices
36
+ end
37
+ end
38
+
39
+
40
+ if $0 == __FILE__
41
+ S4tUtils.with_pleasant_exceptions do
42
+ SwitchExample.new.execute
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require 'user-choices'
5
+
6
+ class TwoArgExample < UserChoices::Command
7
+
8
+ def add_sources(builder)
9
+ builder.add_source(UserChoices::CommandLineSource, :usage,
10
+ "Usage: ruby #{$0} [options] infile outfile")
11
+
12
+ end
13
+
14
+ def add_choices(builder)
15
+ # You can specify an exact number of array elements required.
16
+ builder.add_choice(:args, :length => 2) { | command_line |
17
+ command_line.uses_arglist
18
+ }
19
+ end
20
+
21
+ def execute
22
+ pp @user_choices
23
+ end
24
+ end
25
+
26
+
27
+ if $0 == __FILE__
28
+ S4tUtils.with_pleasant_exceptions do
29
+ TwoArgExample.new.execute
30
+ end
31
+ end
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pp'
4
+ require 'user-choices'
5
+ include UserChoices
6
+
7
+ class TypesExample < Command
8
+
9
+ def add_sources(builder)
10
+ builder.add_source(CommandLineSource, :usage,
11
+ "Usage: ruby #{$0} [options] arg")
12
+ end
13
+
14
+ def add_choices(builder)
15
+ # This is how you restrict an option argument to one of a list of
16
+ # strings.
17
+ builder.add_choice(:a_or_b,
18
+ :type => ['a', 'b']) { | command_line |
19
+ command_line.uses_option("--a-or-b CHOICE",
20
+ "CHOICE is either 'a' or 'b'")
21
+ }
22
+
23
+ # This is how you insist that an option argument be an integer
24
+ # (in string form). If correctly formatted, the string is turned
25
+ # into an integer. Note that the default value can be either a
26
+ # string or an integer.
27
+ builder.add_choice(:must_be_integer,
28
+ :default => 0,
29
+ :type => :integer) { | command_line |
30
+ command_line.uses_option("--must-be-integer INT")
31
+ }
32
+
33
+ # This is how to tell the builder that the argument is a
34
+ # comma-separated list of options. The declaration is not required
35
+ # for command lines, or lists in a configuration file. Those are
36
+ # already broken out into their constituent elements in the source
37
+ # text, so the builder doesn't have to split a string at comma
38
+ # boundaries. You can declare the type if you want, though.
39
+
40
+ builder.add_choice(:option_list, :type => [:string], :length => 2) { | command_line |
41
+ command_line.uses_option("--option-list OPT,OPT",
42
+ "Comma-separated list of exactly two options.")
43
+ }
44
+
45
+
46
+ builder.add_choice(:arg) { | command_line |
47
+ command_line.uses_arg
48
+ }
49
+ end
50
+
51
+ def execute
52
+ pp @user_choices
53
+ end
54
+ end
55
+
56
+
57
+ if $0 == __FILE__
58
+ S4tUtils.with_pleasant_exceptions do
59
+ TypesExample.new.execute
60
+ end
61
+ end
@@ -0,0 +1 @@
1
+ This work is public domain.This work is public domain.
Binary file
Binary file
Binary file
@@ -0,0 +1,242 @@
1
+ #header {
2
+ width:750px;
3
+ height:150px;
4
+ color:#fff;
5
+ font-size:50px;
6
+ letter-spacing:-2px;
7
+ margin:0;
8
+ }
9
+
10
+ .highlight {
11
+ color:#F1Ca3f;
12
+ }
13
+
14
+ #headerLeft {
15
+ background-color:#eaeaea;
16
+ height:150px;
17
+ width:150px;
18
+ float:left;
19
+ background:url("von-foerster.jpg") no-repeat !important;
20
+ }
21
+
22
+ #headerRight {
23
+ background-color:#78300A;
24
+ color:#fff;
25
+ height:150px;
26
+ margin-left:155px;
27
+ background:url("tvline.gif") repeat !important;
28
+ }
29
+
30
+ #headerRight h1 {
31
+ padding-top:25px;
32
+ padding-left:10px;
33
+ font-size:1.2em;
34
+ letter-spacing:-4px;
35
+ line-height:.6em;
36
+ margin:0;
37
+ }
38
+
39
+ #headerRight h2 {
40
+ padding-top:15px;
41
+ padding-left:10px;
42
+ font-size:0.4em;
43
+ letter-spacing:-1px;
44
+ line-height:1.2em;
45
+ margin:0;
46
+ }
47
+
48
+ body {
49
+ font-family:verdana;
50
+ font-size:12px;
51
+ margin:0;
52
+ padding:0;
53
+ }
54
+
55
+ #pageBody {
56
+ background-color:orange;
57
+ font-family:verdana;
58
+ margin:0;
59
+ padding:20px;
60
+ }
61
+
62
+ #inlineTOC {
63
+ float: right;
64
+ list-style: none;
65
+ background: #EBC851;
66
+ margin-left: 1em;
67
+ margin-bottom: 5pt;
68
+ /* include-source: url(inlinetoc.html); */
69
+ }
70
+
71
+ #inlineTOC ul {
72
+ list-style-type: none;
73
+ padding-right: 1em;
74
+ padding-left: 1em;
75
+ }
76
+
77
+ #inlineTOC a {
78
+ font-weight:700;
79
+ color:#765;
80
+ text-decoration:none;
81
+ }
82
+
83
+ #inlineTOC A:hover {
84
+ color:#333;
85
+ }
86
+
87
+
88
+
89
+ #container {
90
+ width:750px;
91
+ height:auto;
92
+ background-color:#FFF;
93
+ margin:0 auto auto;
94
+ padding:0;
95
+ }
96
+
97
+ #nav {
98
+ width:80%;
99
+ font-family:Verdana, sans-serif;
100
+ margin:2em;
101
+ padding:5px;
102
+ }
103
+
104
+ #nav ul,#nav li {
105
+ display:inline;
106
+ color:#339;
107
+ font-weight:700;
108
+ margin:0;
109
+ padding:0;
110
+ }
111
+
112
+ #nav li a {
113
+ height:25px;
114
+ width:25px;
115
+ background-color:red;
116
+ border:1px solid #000;
117
+ }
118
+
119
+ #logo {
120
+ background-color:#FFF;
121
+ text-align:left;
122
+ width:750px;
123
+ height:auto;
124
+ padding-bottom:10px;
125
+ padding-left:5px;
126
+ font-size:30px;
127
+ }
128
+
129
+ #content {
130
+ margin-top:50px;
131
+ font-size:14px;
132
+ text-decoration:none;
133
+ width:750px;
134
+ height:auto;
135
+ border-bottom:1px solid #eaeaea;
136
+ line-height:160%;
137
+ }
138
+
139
+ #content h2 {
140
+ color:#000;
141
+ font-size:15px;
142
+ padding-left:2px;
143
+ }
144
+
145
+
146
+ blockquote {
147
+ background-color:#f2f2f2;
148
+ width:auto;
149
+ margin-left:25px;
150
+ margin-right:25px;
151
+ display:block;
152
+ padding:0.5em 0.5em 0.5em 1em;
153
+ }
154
+
155
+ #footer {
156
+ color:gray;
157
+ font-size:10px;
158
+ text-decoration:none;
159
+ padding-top:5px;
160
+ }
161
+
162
+ img.right {
163
+ float:right;
164
+ margin-left:5px;
165
+ padding:5px;
166
+ }
167
+
168
+ img.left {
169
+ float:left;
170
+ margin-right:5px;
171
+ padding:5px;
172
+ }
173
+
174
+ img.center {
175
+ display: block;
176
+ margin-left: auto;
177
+ margin-right: auto
178
+ }
179
+
180
+ .normal {
181
+ color:gray;
182
+ text-decoration:none;
183
+ }
184
+
185
+ #outer-container {
186
+ background-color:#fff;
187
+ width:790px;
188
+ border:1px solid #888;
189
+ margin:auto;
190
+ padding:15px 0;
191
+ }
192
+
193
+ #centerNav {
194
+ padding-left:203px;
195
+ }
196
+
197
+ #headerNav {
198
+ margin-top:5px;
199
+ font-size:93%;
200
+ background-color: #F1Ca3f;
201
+ float:left;
202
+ width:100%;
203
+ line-height:normal;
204
+ padding-bottom:-1px;
205
+ }
206
+
207
+ #headerNav UL {
208
+ list-style-type:none;
209
+ margin:0;
210
+ padding:10px 10px 0;
211
+ }
212
+
213
+ #headerNav LI {
214
+ background:url(left.gif) no-repeat left top;
215
+ float:left;
216
+ margin:0;
217
+ padding:0 0 0 9px;
218
+ }
219
+
220
+ #headerNav A {
221
+ display:block;
222
+ font-weight:700;
223
+ background:url(right.gif) no-repeat right top;
224
+ color:#765;
225
+ text-decoration:none;
226
+ float:none;
227
+ padding:5px 15px 4px 6px;
228
+ }
229
+
230
+ #headerNav A:hover {
231
+ color:#333;
232
+ }
233
+
234
+ #headerNav #current {
235
+ background-image:url(left_on.gif);
236
+ }
237
+
238
+ #headerNav #current A {
239
+ background-image:url(right_on.gif);
240
+ padding-bottom:5px;
241
+ color:#333;
242
+ }
Binary file
Binary file
Binary file
@@ -0,0 +1,703 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
7
+
8
+ <title>Using User-Choices</title>
9
+ <link rel="stylesheet" type="text/css" media="screen" href="css/main.css" />
10
+
11
+ </head>
12
+
13
+ <body>
14
+ <div id="pageBody">
15
+ <div id="outer-container">
16
+ <div id="container">
17
+ <div id="header">
18
+ <div id="headerLeft"></div>
19
+ <div id="headerRight"><h1>User Choices</h1><span class="highlight"><h2>Act always to increase the number of choices <br /> &mdash; Heinz von Foerster</h2></span></div>
20
+ </div>
21
+ <div id="headerNav">
22
+ <div id="centerNav">
23
+ <ul>
24
+ <li id="current"><a href="index.html">Home</a></li>
25
+ <li><a href="http://user-choices.rubyforge.org/rdoc/">RDoc</a></li>
26
+ <li><a href="http://rubyforge.org/frs/?group_id=4192">Download</a></li>
27
+ <li><a href="http://rubyforge.org/mail/?group_id=4192">Mailing Lists</a></li>
28
+ </ul>
29
+ </div>
30
+ </div>
31
+ <div id="content">
32
+
33
+
34
+
35
+
36
+ <p>
37
+ Suppose you have a command-line application that uses some number of, oh, let's say "connections". Most of the time, a user will want the same number of connections, so you'll let them set a personal default in a <strong>configuration file</strong>. Sometimes they want to change the default. Maybe they'll want a one-time change; for that, a <strong>command-line option</strong> is best. But sometimes they'll want to make the change for an entire login session; for that, setting an <strong>environment variable</strong> is most convenient.
38
+ </p>
39
+ <p>
40
+ <strong>The User-Choices gem gives your code a unified interface to all those sources.</strong> Your code can obey the user's choices without having to bother (much) about how she made them.
41
+ </p>
42
+
43
+ <p>
44
+ This tutorial explains how to set up that interface. See also the <a href="http://user-choices.rubyforge.org/rdoc/" title="user-choices API">API documentation</a>. You can get the source from the <a href="http://rubyforge.org/frs/?group_id=4192" title="RubyForge: User Choices: Project Filelist">downloads page</a> or, less directly, through the <a href="http://rubyforge.org/projects/user-choices" title="RubyForge: User Choices: Project Info">project page</a>.
45
+ </p>
46
+ <a href="#using">1. Using the choices during execution</a><br />
47
+ <a href="#sources">2. Defining the sources</a><br />
48
+ &nbsp;&nbsp;&nbsp;&nbsp;<a href="#environmentsource">Environment variables</a><br />
49
+ &nbsp;&nbsp;&nbsp;&nbsp;<a href="#yamlsource">YAML files</a><br />
50
+ &nbsp;&nbsp;&nbsp;&nbsp;<a href="#xmlsource">XML files</a><br />
51
+ &nbsp;&nbsp;&nbsp;&nbsp;<a href="#commandlinesource">The command line</a><br />
52
+ <a href="#choices">3. Defining the choices</a><br />
53
+ &nbsp;&nbsp;&nbsp;&nbsp;<a href="#keywordargs">3.1 Keyword arguments for <code>add_choice</code></a><br />
54
+ &nbsp;&nbsp;&nbsp;&nbsp;<a href="#cmdline">3.2 Extra behavior for the command line</a><br />
55
+ <a href="#postprocessing">4. Optionally touching up choices before execution</a><br />
56
+ <a href="#notes">5. Notes</a><br />
57
+ <p>
58
+
59
+ </p>
60
+
61
+
62
+ <h2><a name="using">1. Using the choices during execution</a></h2>
63
+ <p>
64
+ Your program will use a variant of the <a href="http://en.wikipedia.org/wiki/Command_pattern" title="Command pattern - Wikipedia, the free encyclopedia">Command pattern</a>. Its rough structure will look like this:
65
+ </p>
66
+
67
+ <blockquote><table bgcolor="white" border="0"><tr><td>
68
+ <code>
69
+ require 'user-choices' <br />
70
+ &nbsp; <br />
71
+ class TutorialExample &lt; UserChoices:<font style="color: #800020;">:Command</font> <br />
72
+ &nbsp;&nbsp;include UserChoices <br />
73
+ &nbsp; <br />
74
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">add_sources(builder)</font>... <br />
75
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">add_choices(builder)</font>... <br />
76
+ <br />
77
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">execute</font> <br />
78
+ &nbsp;&nbsp;&nbsp;&nbsp;puts "There are <font style="color: #800020;">#{<font style="color: #806000;">@user_choices</font>[<font style="color: #800020;">:connections</font>]} connections."</font> <br />
79
+ &nbsp;&nbsp;&nbsp;&nbsp;pp <font style="color: #806000;">@user_choices</font> <br />
80
+ &nbsp;&nbsp;<font style="color: #002FBD;">end</font> <br />
81
+ <font style="color: #002FBD;">end</font> <br />
82
+ &nbsp; <br />
83
+ &nbsp; <br />
84
+ if $0 == __FILE__ <br />
85
+ &nbsp;&nbsp;TutorialExample.new.execute <br />
86
+ <font style="color: #002FBD;">end</font> <br />
87
+ </code>
88
+
89
+ </td></tr></table></blockquote>
90
+
91
+ <p>
92
+ Your entire program runs within the <code>execute</code> method of your <code>Command</code> object. The instance variable <code>@user_choices</code> is a hash whose keys are symbols you've used to name the choices. Its values are the user's choices.
93
+ </p>
94
+
95
+ <p>
96
+ Within <code>add_choices</code> I've set up the choices to default to 0, so if I were to run the program without making any choices, I'd get this result:
97
+ </p>
98
+
99
+ <blockquote>
100
+ <code>
101
+ $ ruby <a href="tutorial1.rb">tutorial1.rb</a><br/>
102
+ There are 0 connections.<br/>
103
+ {:connections=>0}<br/>
104
+ </code>
105
+ </blockquote>
106
+
107
+ <p>In the <code>add_sources</code> method, I've also told <code>TutorialExample</code> to obey a <code>.myprog-config.yml</code> file in my home directory. Suppose it looks like this:</p>
108
+
109
+ <blockquote>
110
+ <code>
111
+ connections: 19
112
+ </code>
113
+ </blockquote>
114
+
115
+ <p>In that case, the output would be:</p>
116
+
117
+ <blockquote>
118
+ <code>
119
+ $ ruby tutorial1.rb<br/>
120
+ There are 19 connections.<br/>
121
+ {:connections=>19} <br/>
122
+ </code>
123
+ </blockquote>
124
+
125
+ <p>
126
+ The configuration file value took precedence over the default. An environment variable's value can, in turn, take precedence over that:
127
+ </p>
128
+
129
+ <blockquote>
130
+ <code>
131
+ $ (export <strong>myprog_connections=3</strong>; ruby tutorial1.rb) <br/>
132
+ There are 3 connections. <br/>
133
+ {:connections=>3} <br/>
134
+ </code>
135
+ </blockquote>
136
+
137
+ <p>
138
+ And a command-line choice can take precedence over the environment:
139
+ </p>
140
+
141
+ <blockquote>
142
+ <code>
143
+ $ (export myprog_connections=3; ruby tutorial1.rb <b>--connections 999</b>) <br/>
144
+ There are 999 connections. <br/>
145
+ {:connections=>999} <br/>
146
+ </code>
147
+ </blockquote>
148
+
149
+ <p>Part of the point of User-Choices is reasonably helpful error messages. For example, here's the result of a bad value for the number of connections:
150
+ </p>
151
+ <blockquote>
152
+ <code>
153
+ > (export <strong>myprog_connections=hi</strong>; ruby tutorial1.rb)<br />
154
+ Error in the environment: myprog_connections's value must be an integer, and 'hi' doesn't look right.<br />
155
+ </code></blockquote>
156
+
157
+ <p>Notice that the error messsage is in terms of the source (the environment variable "myprog_connections", not the internal symbol <code>:connections</code>).
158
+ </p>
159
+ <p>
160
+ In the case of a command-line error, more help text is printed:</p>
161
+
162
+ <blockquote>
163
+ <code>
164
+ $ ruby tutorial1.rb <strong>--connections hi</strong> <br />
165
+ Error in the command line: --connections's value must be an integer, and 'hi' doesn't look right. <br />
166
+ Usage: ruby tutorial1.rb [options] <br />
167
+ <br />
168
+ Options: <br />
169
+ -c, --connections COUNT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Number of connections to open. <br />
170
+ -?, -h, --help&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Show this message. <br /> </code></blockquote>
171
+
172
+
173
+ <h2><a name="sources">2. Defining the sources</a></h2>
174
+ <p>
175
+ The different sources for the tutorial program are configured in <code>add_sources</code>:</p>
176
+
177
+ <blockquote><table bgcolor="white" border="0"><tr><td>
178
+ <code>
179
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">add_sources</font>(builder) <br />
180
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_source(CommandLineSource, <font style="color: #800020;">:usage</font>, <br />
181
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Usage ruby #{$0} [options]")<br />
182
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_source(EnvironmentSource, <font style="color: #800020;">:with_prefix</font>, "myprog_") <br />
183
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_source(YamlConfigFileSource, <font style="color: #800020;">:from_file</font>, ".myprog-config.yml") <br />
184
+ &nbsp;&nbsp;<font style="color: #002FBD;">end</font> <br />
185
+ &nbsp; <br />
186
+ </code>
187
+
188
+ </td></tr></table></blockquote>
189
+
190
+ <p>Behind the scenes, User-Choices creates a <code>ChoicesBuilder</code> object it hands to the configuration method <code>add_sources</code>. To harvest choices from a new source, you identify it to the <code>builder</code> with an <code>add_source</code> call. The calls should be made in precedence order, highest to lowest. A source for default values comes automatically, so you don't need to list it.
191
+ </p>
192
+ <p>
193
+ The sources are distinguished by the names of classes. Each class takes different arguments. Notice that the arguments are in a weird pseudo-keyword style:</p>
194
+ <blockquote>
195
+ builder.add_source(<i>ClassName</i>, <font style="color: #800020;">:<i>symbol</i></font>, <i>one or more args</i>, <font style="color: #800020;">:<i>symbol</i></font>, <i>one or more args</i>, ...)
196
+ </blockquote>
197
+
198
+ <p>I make no apologies. Well, maybe one or two.</p>
199
+
200
+ <dl>
201
+ <dt><b><a name="environmentsource">EnvironmentSource</a></b></dt>
202
+ <dd>
203
+ <p>
204
+ There are two ways of specifying which environment variables should be considered choices for this program.
205
+ </p>
206
+ <ul>
207
+ <li>
208
+ <p>
209
+ <b><code>builder.add_source(EnvironmentSource, <font style="color: #800020;">:with_prefix</font>, "prefix")</code></b> says that any environment variable beginning with the prefix is a user choice that matters to this program. The symbol-name of the choice is constructed from the environment variable name, less the prefix. So if the prefix is "amazon_", the environment variable "amazon_login" produces choice <font style="color: #800020;">:login</font>.
210
+ </p>
211
+ </li>
212
+ <li>
213
+ <p>
214
+ <b><code>builder.add_source(EnvironmentSource, <font style="color: #800020;">:mapping</font>, <i>hash</i>)</code></b> gives an explicit map between choice names and environment variable names. So if the hash is <code>{<font style="color: #800020;">:home</font> => "HOME", <font style="color: #800020;">:shell_level</font> => "SHLVL"}</code>, the program would (on my machine) have <code>@user_choices[<font style="color: #800020;">:home</font>]</code> be "/Users/marick" and <code>@user_choices[<font style="color: #800020;">:shell_level</font>]</code> be 1.
215
+ </p>
216
+ </li>
217
+ </ul>
218
+ <p>
219
+ You can use both ways by chaining them together:
220
+ </p>
221
+
222
+ <blockquote><table bgcolor="white" border="0"><tr><td>
223
+ <code>
224
+ &nbsp;&nbsp;&nbsp;builder.add_source(EnvironmentSource, <font style="color: #800020;">:with_prefix</font>, "prefix_", <font style="color: #800020;">:mapping</font>, {<font style="color: #800020;">:home</font> => "HOME" }) <br />
225
+ </code>
226
+
227
+ </td></td></table></blockquote>
228
+
229
+ </dd>
230
+
231
+ <dt><b><a name="yamlsource">YamlConfigFileSource</a></b></dt>
232
+ <dd>
233
+ <p>
234
+ <b><code>builder.add_source(YamlConfigFileSource, <font style="color: #800020;">:from_file</font>, "filename")</code></b> says that the user choices are in a <a href="http://yaml.org/" title="YAML Ain't Markup Language">YAML</a> file named "filename" in the user's home directory. The home directory is found the same way RubyGems finds it.
235
+ </p>
236
+ <p>
237
+ You can use <b><font style="color: #800020;">:from_complete_path</font></b> if your YAML file isn't in the home directory. In that case, the next argument is a path to the YAML file. It can be either relative or absolute.
238
+ </p>
239
+ <p>
240
+ YAML files should contain a single level of keys and values. The values can be numbers, strings, and arrays of numbers or strings. Here is an acceptable file:
241
+ </p>
242
+ <blockquote>
243
+ ordinary_choice: 2<br/>
244
+ names:<br/>
245
+ &nbsp;&nbsp; - dawn<br/>
246
+ &nbsp;&nbsp; - paul<br/>
247
+ &nbsp;&nbsp; - sophie<br/>
248
+
249
+ </blockquote>
250
+ <p>
251
+ The keys are turned into symbols and become the choice names. The above file produces <font style="color: #800020;">:ordinary_choice</font> and <font style="color: #800020;">:names</font>. If the key has a dash in it, that's converted to an underscore.</p>
252
+ <p> The values, by default, are strings (or arrays of strings), though that can be overridden when the choice is described.
253
+ </p>
254
+ <p>
255
+ The results of more complicated files are undefined.
256
+ </p>
257
+ </dd>
258
+
259
+ <dt><b><a name="xmlsource">XmlConfigFileSource</a></b></dt>
260
+ <dd>
261
+ <p> <b><code>builder.add_source(XmlConfigFileSource, <font style="color: #800020;">:from_file</font>, "filename")</code></b> says that the user choices are in a XML file named "filename" in the user's home directory. The home directory is found the same way RubyGems finds it.
262
+ </p>
263
+ <p>
264
+ You can use <b><font style="color: #800020;">:from_complete_path</font></b> if your XML file isn't in the home directory. In that case, the next argument is a path to the XML file. It can be either relative or absolute.
265
+ </p>
266
+ <p>
267
+ Here is an acceptable XML file:
268
+ </p>
269
+ <blockquote>
270
+ &lt;config&gt; <br />
271
+ &nbsp;&nbsp;&nbsp;&lt;ordinary_choice&gt;2&lt;/ordinary_choice&gt; <br />
272
+ &nbsp;&nbsp;&nbsp;&lt;names&gt;dawn&lt;/names&gt; <br />
273
+ &nbsp;&nbsp;&nbsp;&lt;names&gt;paul&lt;/names&gt; <br />
274
+ &nbsp;&nbsp;&nbsp;&lt;names&gt;sophie&lt;/names&gt; <br />
275
+ &lt;/config&gt; <br />
276
+ </blockquote>
277
+ <p>
278
+ The root tag (<code>&lt;config&gt;</code>) is irrelevant. Name it what you like. The tag names are converted into choice symbols, so <code>&lt;ordinary_choice&gt;</code> becomes <font style="color: #800020;">:ordinary_choice</font>. If the tag name contains a dash, it's converted into an underscore.
279
+ </p>
280
+ <p>
281
+ Tag text contents have whitespace stripped off, then become string choice values. (This default typing can be changed in <code>add_choices</code>.) If you want an array of values, you repeat the tag multiple times (as in &lt;names&gt; above).
282
+ </p>
283
+ <p>
284
+ The results of more complicated files are undefined.
285
+ </p>
286
+
287
+ </dd>
288
+
289
+ <dt><b><a name="commandlinesource">CommandLineSource</a></b></dt>
290
+ <dd>
291
+ <p>
292
+ User-Choices uses <a href="http://www.ruby-doc.org/stdlib/" title="Ruby Standard Library Documentation: OptionParser">OptionParser</a> to handle command lines. Arguments to <code>builder.add_source</code> and (later) <code>builder.add_choice</code> are passed along to <code>OptionParser</code> to help it do its work. Part of its work is generating helpful output to show on request or in the case of a user error, and the <code>add_source</code> call helps with that.
293
+ </p>
294
+ <p>
295
+
296
+ <b><code>builder.add_source(CommandLineSource, <font style="color: #800020;">:usage</font>, <em>"line"...</em>)</code></b> gives <code>OptionParser</code> lines to print before it describes command-line options. Here's a typical example:
297
+ </p>
298
+
299
+ <blockquote><table bgcolor="white" border="0"><tr><td>
300
+ <code>
301
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_source(CommandLineSource, <font style="color: #800020;">:usage</font>, <br />
302
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Usage: ruby <font style="color: #800020;">#{$0} [options] input-file output-file",</font> <br />
303
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Encode the input file into the output file.") <br />
304
+ &nbsp; <br />
305
+ </code>
306
+
307
+ </td></tr></table></blockquote>
308
+ </dd>
309
+ </dl>
310
+
311
+
312
+
313
+
314
+
315
+
316
+
317
+
318
+ <h2><a name="choices">3. Defining the choices</a></h2>
319
+ <p>
320
+ Once the sources of choices have been named, each different choice needs to be described. Here's the description for the tutorial program:
321
+ </p>
322
+ <blockquote><table bgcolor="white" border="0"><tr><td>
323
+ <code>
324
+ <font style="color: #002FBD;">def</font> <font style="color: #600080;">add_choices</font>(builder) <br />
325
+ &nbsp;&nbsp;builder.add_choice(<font style="color: #800020;">:connections</font>, <font style="color: #800020;">:type</font>=><font style="color: #800020;">:integer</font>, :<font style="color: #800020;">default</font>=>0) { | command_line | <br />
326
+ &nbsp;&nbsp;&nbsp;&nbsp;command_line.uses_option("-c", "--connections COUNT", <br />
327
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Number of connections to open.") <br />
328
+ &nbsp;&nbsp;} <br />
329
+ <font style="color: #002FBD;">end</font> <br />
330
+ </code>
331
+
332
+ </td></tr></table></blockquote>
333
+ <p>
334
+ In this case, there's one choice (<font style="color: #800020;">:connections</font>). The <font style="color: #800020;">:type</font> keyword arguments tells User-Choices to convert a string fetched from any defined source (in this case, the command line) into an integer. The <font style="color: #800020;">:default</font> keyword argument gives a value to use if the user doesn't give one on the command line.
335
+ </p>
336
+
337
+ <p>The block argument is used to do additional setup for the command line. That'll be explained <a href="#cmdline">shortly</a>.
338
+ </p>
339
+
340
+
341
+ <h3><a name="keywordargs"/>3.1 Keyword arguments for <code>add_choice</code></a></h3>
342
+ <ul>
343
+ <li><p>
344
+ The <b><font style="color: #800020;">:type</font></b>
345
+ keyword describes type checking and conversion that
346
+ should be done. If no <font
347
+ style="color: #800020;">:type</font> argument is
348
+ given, the choice stays a string.
349
+ </p>
350
+
351
+ <p>
352
+ Default choices are handled generously. Suppose a particular
353
+ choice is to be an integer. You can specify the default value as
354
+ either the string <code>"1"</code> (in which case it will be converted to an
355
+ integer) or the integer <code>1</code> (in which case it will be left alone).
356
+ </p>
357
+
358
+ <p>
359
+ A <code>StandardError</code> is raised if the conversion can't be done.
360
+ </p>
361
+ <p>
362
+ Normal YAML parsing converts text into native types. (A YAML line like "count: 1" is automatically parsed into <code>{"count" => 1}</code>.) These conversions <em>do not happen</em> in User-Choices because there's no equivalent for other sources like XML.)
363
+ </p>
364
+ <dl>
365
+ <dt><font style="color: #800020;">:type</font> => <b><font style="color: #800020;">:integer</font></b></dt>
366
+ <dd><p>
367
+ Convert the string into an integer. Accepts whatever <code>String#to_i</code> does.
368
+ </p></dd>
369
+
370
+ <dt><font style="color: #800020;">:type</font> => <b><font style="color: #800020;">:boolean</font></b></dt>
371
+ <dd><p>
372
+ Convert the string into either <code>true</code> or <code>false</code>. The string must be one of "true" or "false" (case-insensitive).
373
+ </p></dd>
374
+
375
+ <dt><font style="color: #800020;">:type</font>
376
+ => <b><font style="color: #800020;">:string</font></b></dt>
377
+ <dd><p>
378
+ Leave the string alone. Since that's
379
+ the default behavior, this case is only for
380
+ convenience.
381
+ </p></dd>
382
+
383
+ <dt><font style="color: #800020;">:type</font> => <b><font style="color: #800020;">[:string]</font></b></dt>
384
+
385
+ <dd><p>
386
+ The string is split at comma boundaries to become an array of strings. Whitespace is <em>not</em> stripped. This type need only be declared when the data could come from a command-line argument of this form: <code>--names a,b,c</code> or an environment variable like <code>NAMES="a,b,c"</code>. YAML and XML files describe the data so that User-Choices doesn't need help to know you want an array.
387
+ </p></dd>
388
+
389
+ <dt><font style="color: #800020;">:type</font> => <i>["one", "two", ...]</i></dt>
390
+ <dd><p>
391
+ The value chosen must be one of the given strings. There's no conversion.
392
+ </p></dd>
393
+
394
+
395
+
396
+ </dl>
397
+ </li>
398
+
399
+ <li><p>
400
+ The <b><font style="color: #800020;">:length</font></b> keyword applies only when the given value is converted to an array. It takes either an integer or range. A <code>StandardError</code> with a helpful message is raised if the actual length doesn't match.
401
+ </p></li>
402
+
403
+ <li><p>
404
+ The <b><font style="color: #800020;">:default</font></b> keyword gives a default value for a choice. That value is type-checked if a type is given. (But note that type-checking succeeds if the default value is already of the correct type. There's no need to use <code>"1"</code> for a choice of type :integer. You can use the more natural <code>1</code>. )
405
+ </p>
406
+ <p>
407
+ If no default is given, and no value is specified in any source, the choice-symbol (e.g., <font style="color: #800020;">:connections</font>) is not a key in the <code>@user_choices</code> hash (and so <code>@user_choices[<font style="color: #800020;">:connections</font>]</code> would be <code>nil</code> and <code>@user_choices.has_key?(<font style="color: #800020;">:connections</font>)</code> would be <code>false</code>).
408
+
409
+ </p></li>
410
+ </ul>
411
+ <h3><a name="cmdline">3.2 Extra behavior for the command line</a></h3>
412
+ <p>
413
+ The block given to <code>:add_choice</code> serves as a front end to <a href="http://www.ruby-doc.org/stdlib/" title="Ruby Standard Library Documentation: OptionParser">OptionParser</a>. It also lets you treat command-line arguments as just another kind of user choice (rather than having to mess around with <code>ARGV</code>).
414
+ </p>
415
+ <p>
416
+ Within the block, you can send these messages to the block's argument:
417
+ </p>
418
+
419
+ <dl>
420
+ <dt><b>uses_option(<i>string</i>...)</b></dt>
421
+ <dd>
422
+ <p>
423
+ The strings are passed on to <code>OptionParser#on</code>. There are quite possibly variations that don't work well. (If you find any, <a href="mailto:marick@exampler.com">send me mail</a>.) The common variation that definitely works looks like this:
424
+ </p>
425
+
426
+ <blockquote><table bgcolor="white" border="0"><tr><td>
427
+ <code>
428
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;command_line.uses_option("-c", "--connections COUNT", <br />
429
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Number of connections to open.") <br />
430
+ </code>
431
+
432
+ </td></tr></table></blockquote>
433
+ <p>The first argument is the short form of the option, the second the long form, and any remaining lines are documentation to print in the help text. Given the above, any of these are acceptable:
434
+ </p>
435
+
436
+ <blockquote><code>
437
+ $ ruby tutorial1.rb -c 2 <br />
438
+ $ ruby tutorial1.rb -c2 <br />
439
+ $ ruby tutorial1.rb --connections 2 <br />
440
+ $ ruby tutorial1.rb --connections=2 <br />
441
+ $ ruby tutorial1.rb --conn 2 <br />
442
+ </code></blockquote>
443
+
444
+ </dd>
445
+
446
+ <dt><b>uses_switch("-<i>s</i>", "--<i>switch</i>", <i>string</i>...)</b></dt>
447
+ <dd>
448
+ <p>
449
+ Switches are almost like options, but they don't take arguments. If the switch is given, the user choice is "true". If its inverse (see below) is given, the choice is "false". Otherwise, the default is used. Here's a typical example:
450
+ </p>
451
+
452
+ <blockquote><table bgcolor="white" border="0"><tr><td>
453
+ <code>
454
+ &nbsp;&nbsp;builder.add_choice(<font style="color: #800020;">:ssh</font>, <font style="color: #800020;">:type</font>=><font style="color: #800020;">:boolean</font>, :<font style="color: #800020;">default</font>=>false) { | command_line | <br />
455
+ &nbsp;&nbsp;&nbsp;&nbsp;command_line.uses_switch("-s", "--ssh", <br />
456
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Use ssh to open connection.") <br />
457
+ &nbsp;&nbsp;} <br />
458
+ </code>
459
+
460
+ </td></tr></table></blockquote>
461
+ <p>
462
+ A user tells the program to use SSH like this:
463
+ </p>
464
+
465
+
466
+ <blockquote><code>
467
+ $ ruby <a href="tutorial2.rb">tutorial2.rb</a> --ssh<br />
468
+ SSH should be used. <br />
469
+ $ ruby tutorial2.rb --s file <br />
470
+ SSH should be used. <br />
471
+ </code></blockquote>
472
+
473
+ <p>SSH is turned off like this:</p>
474
+
475
+ <blockquote><code>
476
+ $ ruby tutorial2.rb --no-ssh <br />
477
+ SSH should not be used. <br />
478
+ </code></blockquote>
479
+
480
+ <p>
481
+ (Turning the switch off is pointless in this case, since the default is <code>false</code>.)
482
+ </p>
483
+ <p>
484
+ The documentation explains both options this way:
485
+
486
+ </p>
487
+ <blockquote><code>
488
+ $ ruby tutorial2.rb --help <br />
489
+ Usage: ruby tutorial2.rb [options]<br />
490
+ <br />
491
+ Options: <br />
492
+ -c, --connections COUNT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Number of connections to open. <br />
493
+ <b>-s, --[no-]ssh&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Use ssh to open connection.</b> <br />
494
+ -?, -h, --help&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Show this message. <br />
495
+ </code></blockquote>
496
+
497
+ </dd>
498
+
499
+ <dt><b>uses_arglist</b></dt>
500
+ <dd>
501
+ <p>
502
+ The command line argument list can be treated as another choice:
503
+ </p>
504
+
505
+ <blockquote><table bgcolor="white" border="0"><tr><td>
506
+ <code>
507
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_choice(<font style="color: #800020;">:files</font>) { | command_line | <br />
508
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;command_line.uses_arglist <br />
509
+ &nbsp;&nbsp;&nbsp;&nbsp;} <br />
510
+ </code>
511
+
512
+ </td></tr></table></blockquote>
513
+
514
+ <blockquote><code>
515
+ $ ruby <a href="tutorial3.rb">tutorial3.rb</a> arg1 arg2 <br />
516
+ SSH should not be used. <br />
517
+ There are 19 connections. <br />
518
+ {<b>:files=>["arg1", "arg2"]</b>, :ssh=>false, :connections=>19} <br />
519
+ </code></blockquote>
520
+
521
+ <p>
522
+ What should happen if no command-line arguments are given? If that were to be treated as choosing the empty array, lesser priority sources could never affect the outcome. Since everything is typically of lower priority than the command line, that would make it pointless for a configuration file, say, ever to specify any values for the choice. So, instead, an empty argument list is treated just like a command-line option that's not mentioned: nothing is put into the <code>@user-choices</code> array.
523
+ </p>
524
+ <p>
525
+ As an example of how this works, consider this YAML file:
526
+ </p>
527
+
528
+ <blockquote><code>
529
+ connections: 19 <br />
530
+ files: <br />
531
+ &nbsp;&nbsp; - one <br />
532
+ &nbsp;&nbsp; - two <br />
533
+ </code></blockquote>
534
+
535
+ <p>
536
+ Any command-line arguments will take precedence:
537
+ </p>
538
+
539
+ <blockquote><code>
540
+ $ ruby tutorial3.rb <strong>cmd</strong> <br />
541
+ SSH should not be used. <br />
542
+ There are 19 connections. <br />
543
+ {<b>:files=>["cmd"]</b>, :ssh=>false, :connections=>19} <br />
544
+ </code></blockquote>
545
+
546
+ <p>
547
+ But an empty command line will yield to the YAML file:
548
+ </p>
549
+ <blockquote><code>
550
+ $ ruby tutorial3.rb <br />
551
+ SSH should not be used. <br />
552
+ There are 19 connections. <br />
553
+ {<b>:files=>["one", "two"]</b>, :ssh=>false, :connections=>19} <br />
554
+ </code></blockquote>
555
+
556
+ <p>
557
+ There is no need to <font style="color: #800020;">:type</font> the choice as a [<font style="color: #800020;">:string</font>], since that's obvious from context. If you want to limit the length of the argument list, you can add a <font style="color: #800020;">:length</font>:
558
+ </p>
559
+
560
+ <blockquote><table bgcolor="white" border="0"><tr><td>
561
+ <code>
562
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_choice(<font style="color: #800020;">:files</font>, <b><font style="color: #800020;">:length</font> => 1..2</b>) { | command_line | <br />
563
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;command_line.uses_arglist <br />
564
+ &nbsp;&nbsp;&nbsp;&nbsp;} <br />
565
+ </code>
566
+
567
+ </td></tr></table></blockquote>
568
+
569
+ <blockquote><code>
570
+ $ ruby <a href="tutorial4.rb">tutorial4.rb</a> 1 2 3 <br />
571
+ <b>Error in the command line: 3 arguments given, 1 or 2 expected.</b> <br />
572
+ Usage: ruby tutorial4.rb [options] file1 [file2] <br />
573
+ <br />
574
+ Options: <br />
575
+ -c, --connections COUNT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Number of connections to open. <br />
576
+ -s, --[no-]ssh&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Use ssh to open connection. <br />
577
+ -?, -h, --help&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Show this message. <br />
578
+ </code></blockquote>
579
+ <p>
580
+ What happens in this case if the user gives no arguments on the command line, considering that the <font style="color: #800020;">:length</font> asks for one or two? It is <em>not</em> an error because the YAML file supplies two arguments:
581
+ </p>
582
+ <blockquote><code>
583
+ $ ruby tutorial4.rb <br />
584
+ SSH should not be used. <br />
585
+ There are 19 connections. <br />
586
+ {:files=>["one", "two"], :ssh=>false, :connections=>19} <br />
587
+ </code></blockquote>
588
+ </dd>
589
+ <dt><b>uses_arg</b></dt>
590
+ <dd>
591
+ <p>
592
+ Sometimes the argument list must have exactly one member. In that case, it's annoying to have to take that argument out of the array. <code>users_arg</code> does that for you, returning the single argument directly. Giving two or more arguments produces an error. If the user supplies no arguments on the command line, some other source must provide it. If no other source does, User-Choices raises a <code>StandardError</code> with a nice error message.
593
+ </p>
594
+
595
+ <blockquote><table bgcolor="white" border="0"><tr><td>
596
+ <code>
597
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">add_choices</font>(builder) <br />
598
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_choice(<font style="color: #800020;">:infile</font>) { | command_line | <br />
599
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>command_line.uses_arg</b> <br />
600
+ &nbsp;&nbsp;&nbsp;&nbsp;} <br />
601
+ &nbsp;&nbsp;<font style="color: #002FBD;">end</font> <br />
602
+ </code>
603
+
604
+ </td></td></table></blockquote>
605
+
606
+ <blockquote><code>
607
+ $ ruby <a href="tutorial5.rb">tutorial5.rb</a> 1 <br />
608
+ {:infile=>"1"} <br />
609
+ $ ruby tutorial5.rb <br />
610
+ Error in the command line: 0 arguments given, 1 expected. <br />
611
+ Usage: ruby tutorial5.rb infile <br />
612
+ <br />
613
+ Options: <br />
614
+ -?, -h, --help&nbsp;&nbsp;&nbsp;Show this message. <br />
615
+ </code></blockquote>
616
+ </dd>
617
+
618
+ <dt><b>uses_optional_arg</b></dt>
619
+ <dd>
620
+ <p>
621
+ This is like <code>uses_arg</code> except that it's OK for the user to provide no argument (either on the command line or some other source). In that case, the choice symbol doesn't appear as a key in the result.
622
+ </p>
623
+
624
+ <blockquote><table bgcolor="white" border="0"><tr><td>
625
+ <code>
626
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">add_choices</font>(builder) <br />
627
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_choice(<font style="color: #800020;">:infile</font>) { | command_line | <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>command_line.uses_optional_arg</b> <br />
628
+ &nbsp;&nbsp;&nbsp;&nbsp;} <br />
629
+ &nbsp;&nbsp;<font style="color: #002FBD;">end</font> <br />
630
+ </code>
631
+
632
+ </td></td></table></blockquote>
633
+
634
+ <blockquote><code>
635
+ $ ruby <a href="tutorial6.rb">tutorial6.rb</a> <br />
636
+ {} <br />
637
+ </code></blockquote>
638
+ </dd>
639
+
640
+ </dl>
641
+
642
+
643
+ <h2><a name="postprocessing">4. Optionally touching up choices before execution</a></h2>
644
+ <p>
645
+ Consider this declaration:
646
+ </p>
647
+
648
+ <blockquote><table bgcolor="white" border="0"><tr><td>
649
+ <code>
650
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">add_sources</font>(builder) <br />
651
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_source(CommandLineSource, <font style="color: #800020;">:usage</font>, <br />
652
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Usage: ruby <font style="color: #800020;">#{$0} <strong>infile outfile</strong>")</font> <br />
653
+ &nbsp;&nbsp;<font style="color: #002FBD;">end</font> <br />
654
+ &nbsp; <br />
655
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">add_choices</font>(builder) <br />
656
+ &nbsp;&nbsp;&nbsp;&nbsp;builder.add_choice(<font style="color: #800020;">:files</font>, <font style="color: #800020;">:length</font> => 2) { | command_line | <br />
657
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;command_line.<strong>uses_arglist</strong> <br />
658
+ &nbsp;&nbsp;&nbsp;&nbsp;} <br />
659
+ &nbsp;&nbsp;<font style="color: #002FBD;">end</font> <br />
660
+ </code>
661
+
662
+ </td></tr></table></blockquote>
663
+
664
+ <p>
665
+ What you want is two <code>@user_choices</code> elements, something like <code>@user_choices[<font style="color: #800020;">:infile</font>]</code> and <code>@user_choices[<font style="color: #800020;">:outfile</font>]</code>. But there's no way to associate names with individual arglist elements, just with the whole thing.
666
+ </p>
667
+
668
+ <p>The solution to the problem is a postprocessing step that allows you to modify <code>@user_choices</code> before your program starts its work. That's done like this:
669
+ </p>
670
+ <blockquote><table bgcolor="white" border="0"><tr><td>
671
+ <code>
672
+ &nbsp;&nbsp;<font style="color: #002FBD;">def</font> <font style="color: #600080;">postprocess_user_choices</font> <br />
673
+ &nbsp;&nbsp;&nbsp;&nbsp;<font style="color: #806000;">@user_choices</font>[<font style="color: #800020;">:infile</font>] = <font style="color: #806000;">@user_choices</font>[<font style="color: #800020;">:files</font>][0] <br />
674
+ &nbsp;&nbsp;&nbsp;&nbsp;<font style="color: #806000;">@user_choices</font>[<font style="color: #800020;">:outfile</font>] = <font style="color: #806000;">@user_choices</font>[<font style="color: #800020;">:files</font>][1] <br />
675
+ &nbsp;&nbsp;<font style="color: #002FBD;">end</font> <br />
676
+ </code>
677
+
678
+ </td></tr></table></blockquote>
679
+
680
+ <blockquote><code>
681
+ $ ruby <a href="tutorial7.rb">tutorial7.rb</a> one two <br />
682
+ {:outfile=>"two", :files=>["one", "two"], :infile=>"one"} <br /> </code></blockquote>
683
+
684
+ <p>There's no need to call <code>postprocess_user_choices</code> yourself. It's done automatically.</p>
685
+
686
+ <h2><a name="notes">5. Notes</a></h2>
687
+ <ul>
688
+ <li>
689
+ <p>
690
+ Right now, a source can provide an element to <code>@user_choices</code> even if that element is never named as a choice in <code>add_choices</code>. I'm not sure if that's good, bad, or indifferent.
691
+ </p>
692
+ </li>
693
+ </ul>
694
+
695
+
696
+
697
+ </div>
698
+ </div>
699
+ </div>
700
+ </div>
701
+
702
+ </body>
703
+ </html>