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,451 @@
1
+ require 'test/unit'
2
+ require 's4t-utils'
3
+ require 'builder'
4
+ require 'user-choices'
5
+ include S4tUtils
6
+ set_test_paths(__FILE__)
7
+ require 'tempfile'
8
+
9
+
10
+ # The general contract of these objects.
11
+ class TestAbstractSource < Test::Unit::TestCase
12
+ include UserChoices
13
+
14
+ class SubHash < UserChoices::AbstractSource
15
+
16
+ # New never takes arguments. Class-specific initialization is done
17
+ # with an appropriately-named method.
18
+ #
19
+ # That method must return self and set up the external_name hash
20
+ # so that all symbols handled by this object can be given an external
21
+ # name.
22
+ def only_symbol(symbol, external_name, value)
23
+ @external_names[symbol] = external_name
24
+ @symbol = symbol
25
+ @value = value
26
+ self
27
+ end
28
+
29
+ # After fill(), values have been read, but not checked.
30
+ def fill; self[@symbol] = @value; end
31
+
32
+ def source; "the test hash"; end
33
+
34
+ end
35
+
36
+ def test_specific_initializer_notes_external_names
37
+ sh = SubHash.new.only_symbol(:sym, "name", "val")
38
+ assert_equal('name', sh.external_names[:sym])
39
+ end
40
+
41
+ def test_filling_sets_values
42
+ sh = SubHash.new.only_symbol(:sym, "name", "val")
43
+ sh.fill
44
+ assert_equal('val', sh[:sym])
45
+ end
46
+
47
+ def test_will_do_conversion_when_told
48
+ sh = SubHash.new.only_symbol(:sym, "name", "1")
49
+ sh.fill
50
+
51
+ conversions = { :sym => [Conversion.for(:integer)] }
52
+ sh.apply(conversions)
53
+ assert_equal(1, sh[:sym])
54
+ end
55
+
56
+ # Checking - really just want to know that the error message comes out right.
57
+
58
+ def test_will_do_integer_error_checking_when_told
59
+ sh = SubHash.new.only_symbol(:sym, "name", "val")
60
+ sh.fill
61
+
62
+ conversions = { :sym => [Conversion.for(:integer)] }
63
+ assert_raises_with_matching_message(StandardError,
64
+ /^Error in the test hash: name's value must be an integer, and 'val' doesn't look right/) {
65
+ sh.apply(conversions)
66
+ }
67
+ end
68
+
69
+
70
+ def test_will_do_boolean_error_checking_when_told
71
+ sh = SubHash.new.only_symbol(:sym, "name", "val")
72
+ sh.fill
73
+
74
+ conversions = { :sym => [Conversion.for(:boolean)] }
75
+ assert_raises_with_matching_message(StandardError,
76
+ /^Error in the test hash: name's value must be a boolean, and 'val' doesn't look right/) {
77
+ sh.apply(conversions)
78
+ }
79
+ end
80
+
81
+
82
+ def test_will_do_alternative_error_checking_when_told
83
+ sh = SubHash.new.only_symbol(:sym, "name", "val")
84
+ sh.fill
85
+
86
+ conversions = { :sym => [Conversion.for(["foo", "bar"])] }
87
+ assert_raises_with_matching_message(StandardError,
88
+ /^Error in the test hash: name's value must be one of 'foo' or 'bar', and 'val' doesn't look right/) {
89
+ sh.apply(conversions)
90
+ }
91
+ end
92
+
93
+
94
+ def test_will_do_exact_length_checking_when_told
95
+ sh = SubHash.new.only_symbol(:sym, "name", ["one", "two"])
96
+ sh.fill
97
+
98
+ conversions = { :sym => [Conversion.for([:string]), # actually not needed.
99
+ Conversion.for(:length => 5)] }
100
+ assert_raises_with_matching_message(StandardError,
101
+ /^Error in the test hash: name's value must be of length 5, and \["one", "two"\] doesn't look right/) {
102
+ sh.apply(conversions)
103
+ }
104
+ end
105
+
106
+
107
+ def test_will_do_range_length_checking_when_told
108
+ sh = SubHash.new.only_symbol(:sym, "name", ["one", "two"])
109
+ sh.fill
110
+
111
+ conversions = { :sym => [Conversion.for([:string]), # actually not needed.
112
+ Conversion.for(:length => 3..5)] }
113
+ assert_raises_with_matching_message(StandardError,
114
+ /^Error in the test hash: name's value must be a list whose length is in this range: 3..5, and \["one", "two"\] doesn't look right/) {
115
+ sh.apply(conversions)
116
+ }
117
+ end
118
+
119
+
120
+
121
+ def test_it_is_ok_for_key_not_to_appear
122
+ sh = SubHash.new.only_symbol(:sym, "name", "val")
123
+ sh.fill
124
+
125
+ conversions = { :another => [Conversion.for(:integer)] }
126
+ sh.apply(conversions)
127
+ assert_equal('val', sh[:sym])
128
+ assert_equal(nil, sh[:another])
129
+ end
130
+
131
+ end
132
+
133
+ class DefaultSourceTest < Test::Unit::TestCase
134
+ include UserChoices
135
+
136
+ def setup
137
+ @choices = DefaultSource.new.use_hash(:a => 'a')
138
+ @choices.fill
139
+ end
140
+
141
+ def test_default_values_are_created_with_key_not_string
142
+ assert_equal(1, @choices.size)
143
+ assert_equal('a', @choices[:a])
144
+ assert_equal(':a', @choices.external_names[:a])
145
+ end
146
+
147
+ def test_nil_is_default_default
148
+ assert_nil(@choices[:foo])
149
+ end
150
+
151
+
152
+ def test_error_message_will_look_good
153
+ assert_raises_with_matching_message(StandardError,
154
+ /^Error in the default values: :a's value/) {
155
+ @choices.apply( :a => [Conversion.for(:integer)])
156
+ }
157
+ end
158
+
159
+ def test_value_conversions_are_from_strings
160
+ c = DefaultSource.new.use_hash(:a => '5')
161
+ c.fill
162
+
163
+ c.apply(:a => [Conversion.for(:integer)])
164
+ assert_equal(5, c[:a])
165
+ end
166
+
167
+ end
168
+
169
+ class EnvironmentSourceTest < Test::Unit::TestCase
170
+ include UserChoices
171
+
172
+ def test_the_environment_args_of_interest_can_be_described_by_prefix
173
+ with_environment_vars('amazon_option' => "1") do
174
+ choices = EnvironmentSource.new.with_prefix('amazon_')
175
+ choices.fill
176
+ assert_true(choices.has_key?(:option))
177
+ assert_equal('1', choices[:option])
178
+ end
179
+ end
180
+
181
+ def test_the_environment_args_can_use_empty_string_as_the_prefix
182
+ # Though it's a silly thing to do.
183
+ with_environment_vars('amazon_option' => "1") do
184
+ choices = EnvironmentSource.new.with_prefix('')
185
+ choices.fill
186
+ assert_true(choices.has_key?(:amazon_option))
187
+ assert_equal('1', choices[:amazon_option])
188
+ end
189
+ end
190
+
191
+ def test_the_environment_args_of_interest_can_be_listed_explicitly
192
+ with_environment_vars('amazon_option' => "1",
193
+ 'root' => 'ok',
194
+ '~' => 'ok, too') do
195
+ choices = EnvironmentSource.new.mapping(:option => 'amazon_option',
196
+ :root => 'root',
197
+ :home => '~')
198
+ choices.fill
199
+ assert_equal(3, choices.size)
200
+ assert_equal('1', choices[:option])
201
+ assert_equal('ok', choices[:root])
202
+ assert_equal('ok, too', choices[:home])
203
+ end
204
+ end
205
+
206
+ def test_can_also_combine_both_forms
207
+ with_environment_vars('amazon_o' => "1",
208
+ 'other_option' => 'still found') do
209
+ choices = EnvironmentSource.new.with_prefix('amazon_').mapping(:other => 'other_option')
210
+ choices.fill
211
+
212
+ assert_equal(2, choices.size)
213
+ assert_equal('1', choices[:o])
214
+ assert_equal('still found', choices[:other])
215
+ end
216
+ end
217
+
218
+ def test_the_order_of_combination_does_not_matter
219
+ with_environment_vars('amazon_o' => "1",
220
+ 'other_option' => 'still found') do
221
+ choices = EnvironmentSource.new.mapping(:other => 'other_option').with_prefix('amazon_')
222
+ choices.fill
223
+
224
+ assert_equal(2, choices.size)
225
+ assert_equal('1', choices[:o])
226
+ assert_equal('still found', choices[:other])
227
+ end
228
+ end
229
+
230
+ def test_unmentioned_environment_vars_are_ignored
231
+ with_environment_vars('unfound' => "1") do
232
+ choices = EnvironmentSource.new.with_prefix("my_")
233
+ choices.fill
234
+ assert_true(choices.empty?)
235
+ end
236
+ end
237
+
238
+ def test_nil_is_default
239
+ with_environment_vars('found' => "1") do
240
+ choices = EnvironmentSource.new.mapping(:option => 'f')
241
+ choices.fill
242
+ assert_nil(choices[:foo])
243
+ assert_nil(choices[:option]) # for fun
244
+ end
245
+ end
246
+
247
+ def test_value_checking_is_set_up_properly
248
+ with_environment_vars('amazon_option' => "1") do
249
+ assert_raises_with_matching_message(StandardError,
250
+ /^Error in the environment: amazon_option's value/) {
251
+ choices = EnvironmentSource.new.with_prefix('amazon_')
252
+ choices.fill
253
+ choices.apply(:option => [Conversion.for(:boolean)])
254
+ }
255
+ end
256
+ end
257
+
258
+ def test_value_conversion_is_set_up_properly
259
+ with_environment_vars('a' => "1", 'names' => 'foo,bar') do
260
+ choices = EnvironmentSource.new.mapping(:a => 'a', :names => 'names')
261
+ choices.fill
262
+ choices.apply(:a => [Conversion.for(:integer)],
263
+ :names => [Conversion.for([:string])])
264
+ assert_equal(1, choices[:a])
265
+ assert_equal(['foo', 'bar'], choices[:names])
266
+ end
267
+ end
268
+
269
+
270
+ end
271
+
272
+ # Common behavior for all config files. Using XML as an example.
273
+ class FileSourceTestCase < Test::Unit::TestCase
274
+ include UserChoices
275
+
276
+ def setup
277
+ builder = Builder::XmlMarkup.new(:indent => 2)
278
+ @some_xml = builder.config {
279
+ builder.reverse("true")
280
+ builder.maximum("53")
281
+ builder.host('a.com')
282
+ builder.host('b.com')
283
+ }
284
+ end
285
+
286
+
287
+ def test_config_file_need_not_exist
288
+ assert_false(File.exist?(".amazonrc"))
289
+ choices = XmlConfigFileSource.new.from_file(".amazonrc")
290
+
291
+ assert_true(choices.empty?)
292
+ end
293
+
294
+
295
+ def test_config_file_value_checking_is_set_up_properly
296
+ with_local_config_file(".amazonrc", @some_xml) do
297
+ assert_raises_with_matching_message(StandardError,
298
+ %r{Error in configuration file ./.amazonrc: maximum's value.*'low'.*'high'}) {
299
+ choices = XmlConfigFileSource.new.from_file(".amazonrc")
300
+ choices.fill
301
+ choices.apply(:maximum => [Conversion.for(['low', 'high'])])
302
+ }
303
+ end
304
+ end
305
+
306
+
307
+ def test_value_conversions_are_set_up_properly
308
+ with_local_config_file('.amazonrc', @some_xml) do
309
+ choices = XmlConfigFileSource.new.from_file('.amazonrc')
310
+ choices.fill
311
+ choices.apply(:maximum => [Conversion.for(:integer)])
312
+ assert_equal(53, choices[:maximum])
313
+ end
314
+ end
315
+
316
+ def test_complete_paths_to_config_file_are_allowed
317
+ tempfile = Tempfile.new('path-test')
318
+ tempfile.puts(@some_xml)
319
+ tempfile.close
320
+ choices = XmlConfigFileSource.new.from_complete_path(tempfile.path)
321
+ choices.fill
322
+ assert_equal('53', choices[:maximum])
323
+ end
324
+
325
+
326
+
327
+ def test_unmentioned_values_are_nil
328
+ with_local_config_file('.amazonrc', @some_xml) do
329
+ choices = XmlConfigFileSource.new.from_file('.amazonrc')
330
+ choices.fill
331
+ assert_nil(choices[:unmentioned])
332
+ end
333
+ end
334
+
335
+ def test_dashed_choice_names_are_underscored
336
+ with_local_config_file('.amazonrc', "<config><the-name>5</the-name></config>") do
337
+ choices = XmlConfigFileSource.new.from_file('.amazonrc')
338
+ choices.fill
339
+ assert_equal('5', choices[:the_name])
340
+ end
341
+ end
342
+
343
+
344
+ end
345
+
346
+
347
+
348
+ class XmlConfigFileSourceTestCase < Test::Unit::TestCase
349
+ include UserChoices
350
+
351
+ def setup
352
+ builder = Builder::XmlMarkup.new(:indent => 2)
353
+ @some_xml = builder.config {
354
+ builder.reverse("true")
355
+ builder.maximum("53")
356
+ builder.host('a.com')
357
+ builder.host('b.com')
358
+ }
359
+ end
360
+
361
+ def test_xml_config_file_normal_use
362
+ with_local_config_file('.amazonrc', @some_xml) {
363
+ choices = XmlConfigFileSource.new.from_file(".amazonrc")
364
+ choices.fill
365
+ choices.apply(:reverse => [Conversion.for(:boolean)],
366
+ :maximum => [Conversion.for(:integer)])
367
+
368
+ assert_equal(3, choices.size)
369
+ assert_equal(true, choices[:reverse])
370
+ assert_equal(53, choices[:maximum])
371
+ assert_equal(['a.com', 'b.com'], choices[:host])
372
+ }
373
+ end
374
+
375
+ def test_config_file_with_bad_xml
376
+ with_local_config_file('.amazonrc',"<malformed></xml>") {
377
+ assert_raise_with_matching_message(REXML::ParseException,
378
+ %r{Badly formatted configuration file ./.amazonrc: .*Missing end tag}) do
379
+ XmlConfigFileSource.new.from_file(".amazonrc")
380
+ end
381
+ }
382
+ end
383
+
384
+
385
+ end
386
+
387
+
388
+ class YamlConfigFileSourceTestCase < Test::Unit::TestCase
389
+ include UserChoices
390
+
391
+ def setup
392
+ @some_yaml = "
393
+ | ---
394
+ | reverse: true
395
+ | maximum: 53
396
+ | host:
397
+ | - a.com
398
+ | - b.com
399
+ | list-arg: 1,2, 3
400
+ ".without_pretty_indentation('|')
401
+ end
402
+
403
+ def test_string_assurance
404
+ choices = YamlConfigFileSource.new
405
+ a = [1]
406
+ choices.ensure_element_is_string(a, 0)
407
+ assert_equal(["1"], a)
408
+
409
+ h = {'foo' => false }
410
+ choices.ensure_element_is_string(h, 'foo')
411
+ assert_equal({'foo' => 'false'}, h)
412
+
413
+ a = [1, 2.0, true, 'already']
414
+ choices.ensure_array_values_are_strings(a)
415
+ assert_equal(['1', '2.0', 'true', 'already'], a)
416
+
417
+ h = {'1' => '2', 'false' => true, 99 => 100 }
418
+ choices.ensure_hash_values_are_strings(h)
419
+ assert_equal({'1' => '2', 'false' => 'true', 99 => '100' }, h)
420
+
421
+ h = {'1' => '2', 'false' => [1, true], 99 => {100 => true}}
422
+ choices.ensure_hash_values_are_strings(h)
423
+ assert_equal({'1' => '2', 'false' => ['1', 'true'], 99 => {100 => 'true'} }, h)
424
+ end
425
+
426
+ def test_yaml_config_file_normal_use
427
+ with_local_config_file('.amazonrc', @some_yaml) {
428
+ choices = YamlConfigFileSource.new.from_file(".amazonrc")
429
+ choices.fill
430
+
431
+ assert_equal(4, choices.size)
432
+ assert_equal("true", choices[:reverse])
433
+ assert_equal("53", choices[:maximum])
434
+ assert_equal(['a.com', 'b.com'], choices[:host])
435
+ assert_equal("1,2, 3", choices[:list_arg])
436
+ }
437
+ end
438
+
439
+ def test_config_file_with_bad_yaml
440
+ with_local_config_file('.amazonrc',"foo:\n\tfred") {
441
+ assert_raise_with_matching_message(ArgumentError,
442
+ %r{Badly formatted configuration file ./.amazonrc: .*syntax error}) do
443
+ pp YamlConfigFileSource.new.from_file(".amazonrc"), 'should never have been reached'
444
+ end
445
+ }
446
+ end
447
+
448
+
449
+
450
+
451
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+
8
+ class Test::Unit::TestCase
9
+ end