user-choices 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/History.txt +17 -0
  2. data/LICENSE.txt +34 -0
  3. data/Manifest.txt +40 -0
  4. data/README.txt +1 -0
  5. data/Rakefile +19 -0
  6. data/Rakefile.hoe +24 -0
  7. data/examples/older/README.txt +133 -0
  8. data/examples/older/command-line.rb +51 -0
  9. data/examples/older/default-values.rb +47 -0
  10. data/examples/older/multiple-sources.rb +63 -0
  11. data/examples/older/postprocess.rb +45 -0
  12. data/examples/older/switches.rb +50 -0
  13. data/examples/older/two-args.rb +37 -0
  14. data/examples/older/types.rb +67 -0
  15. data/examples/tutorial/index.html +648 -0
  16. data/examples/tutorial/tutorial1.rb +48 -0
  17. data/examples/tutorial/tutorial2.rb +52 -0
  18. data/examples/tutorial/tutorial3.rb +55 -0
  19. data/examples/tutorial/tutorial4.rb +55 -0
  20. data/examples/tutorial/tutorial5.rb +42 -0
  21. data/examples/tutorial/tutorial6.rb +42 -0
  22. data/examples/tutorial/tutorial7.rb +48 -0
  23. data/lib/user-choices/arglist-strategies.rb +178 -0
  24. data/lib/user-choices/builder.rb +89 -0
  25. data/lib/user-choices/command-line-source.rb +220 -0
  26. data/lib/user-choices/command.rb +42 -0
  27. data/lib/user-choices/conversions.rb +154 -0
  28. data/lib/user-choices/ruby-extensions.rb +20 -0
  29. data/lib/user-choices/sources.rb +269 -0
  30. data/lib/user-choices/version.rb +3 -0
  31. data/lib/user-choices.rb +131 -0
  32. data/setup.rb +1585 -0
  33. data/test/arglist-strategy-tests.rb +42 -0
  34. data/test/builder-tests.rb +569 -0
  35. data/test/command-line-source-tests.rb +443 -0
  36. data/test/conversion-tests.rb +157 -0
  37. data/test/set-standalone-test-paths.rb +5 -0
  38. data/test/source-tests.rb +442 -0
  39. data/test/user-choices-slowtests.rb +274 -0
  40. data/user-choices.tmproj +575 -0
  41. metadata +138 -0
@@ -0,0 +1,443 @@
1
+ load "set-standalone-test-paths.rb" unless $started_from_rakefile
2
+ require 'test/unit'
3
+ require 's4t-utils'
4
+ require 'builder'
5
+ require 'user-choices'
6
+ include S4tUtils
7
+
8
+ ### Handling of options with arguments ###
9
+
10
+ class CommandLineTestCase < Test::Unit::TestCase
11
+ include UserChoices
12
+
13
+ def setup
14
+ @cmd_line = CommandLineSource.new
15
+ end
16
+
17
+ def default_test
18
+ end
19
+ end
20
+
21
+ class OPTIONS_CommandLineTests < CommandLineTestCase
22
+ def test_options_can_be_given_in_the_command_line
23
+ with_command_args('--given-option value') {
24
+ @cmd_line.uses_option(:given_option, "--given-option VALUE")
25
+ @cmd_line.fill
26
+
27
+ assert_true(@cmd_line.has_key?(:given_option))
28
+ assert_equal("value", @cmd_line[:given_option])
29
+
30
+ assert_false(@cmd_line.has_key?(:unspecified_option))
31
+ assert_equal(nil, @cmd_line[:unspecified_option])
32
+ }
33
+ end
34
+
35
+ def test_the_specification_can_describe_options_that_are_not_given
36
+ # They're really /optional/.
37
+ with_command_args('') {
38
+ @cmd_line.uses_option(:unused_option, "--unused-option VALUE")
39
+ @cmd_line.fill
40
+
41
+ assert_false(@cmd_line.has_key?(:unused_option))
42
+ assert_equal(nil, @cmd_line[:unused_option])
43
+ }
44
+ end
45
+
46
+ def test_options_can_have_one_letter_abbreviations
47
+ with_command_args('-s s-value --option=option-value') {
48
+ @cmd_line.uses_option(:option, "-o", "--option=VALUE")
49
+ @cmd_line.uses_option(:something, "-s", "--something=VALUE")
50
+ @cmd_line.fill
51
+
52
+ assert_equal("s-value", @cmd_line[:something])
53
+ assert_equal("option-value", @cmd_line[:option])
54
+ }
55
+ end
56
+
57
+
58
+
59
+ def test_command_line_list_of_possible_values_checking
60
+ with_command_args("-n true") do
61
+ @cmd_line.uses_option(:north_west, "-n", "--north-west=VALUE")
62
+ @cmd_line.fill
63
+ output = capturing_stderr do
64
+ assert_wants_to_exit do
65
+ @cmd_line.apply({:north_west => [Conversion.for(['low', 'high'])]})
66
+ end
67
+ end
68
+ assert_match(%r{Error in the command line: --north-west's value}, output)
69
+ end
70
+ end
71
+
72
+ def test_command_line_integer_value_checking
73
+ with_command_args("--day-count-max=2d3") do
74
+ @cmd_line.uses_option(:day_count_max, "--day-count-max=VALUE")
75
+ @cmd_line.fill
76
+ output = capturing_stderr do
77
+ assert_wants_to_exit do
78
+ @cmd_line.apply({:day_count_max => [Conversion.for(:integer)]})
79
+ end
80
+ end
81
+ assert_match(/^Error in the command line: --day-count-max's value/, output)
82
+ end
83
+ end
84
+
85
+
86
+ def test_integer_conversion
87
+ with_command_args("--day-count-max 23") do
88
+ @cmd_line.uses_option(:day_count_max, "--day-count-max=VALUE")
89
+ @cmd_line.fill
90
+ @cmd_line.apply({:day_count_max => [Conversion.for(:integer)]})
91
+ assert_equal(23, @cmd_line[:day_count_max])
92
+ end
93
+ end
94
+
95
+ def test_array_value_conversion_with_proper_multivalue_declaration
96
+ with_command_args("--hosts localhost,foo.com") do
97
+ @cmd_line.uses_option(:hosts, "--hosts HOST,HOST")
98
+ @cmd_line.fill
99
+ @cmd_line.apply({:hosts => [Conversion.for([:string])]})
100
+ assert_equal(['localhost', 'foo.com'],
101
+ @cmd_line[:hosts])
102
+ end
103
+ end
104
+
105
+ def test_array_value_conversion_without_proper_multivalue_declaration_still_works
106
+ with_command_args("--hosts localhost,foo.com") do
107
+ @cmd_line.uses_option(:hosts, "--hosts HOSTS...")
108
+ @cmd_line.fill
109
+ @cmd_line.apply({:hosts => [Conversion.for([:string])]})
110
+ assert_equal(['localhost', 'foo.com'],
111
+ @cmd_line[:hosts])
112
+ end
113
+ end
114
+
115
+ end
116
+
117
+
118
+
119
+ ### Boolean switches ###
120
+
121
+ # Note that switches are string-valued for consistency with
122
+ # other sources (like environment variables).
123
+ class SWITCHES_CommandLineTest < CommandLineTestCase
124
+
125
+ def test_boolean_switches_are_accepted
126
+ with_command_args("--c") do
127
+ @cmd_line.uses_switch(:csv, "-c", "--csv")
128
+ @cmd_line.fill
129
+ assert_equal("true", @cmd_line[:csv])
130
+
131
+ # ... but they can be converted into booleans
132
+ @cmd_line.apply({:csv => [Conversion.for(:boolean)]})
133
+ assert_equal(true, @cmd_line[:csv])
134
+ end
135
+ end
136
+
137
+ def test_unmentioned_switches_have_no_value
138
+ with_command_args("") do
139
+ @cmd_line.uses_switch(:csv, "-c", "--csv")
140
+ @cmd_line.fill
141
+ assert_false(@cmd_line.has_key?(:csv))
142
+ end
143
+ end
144
+
145
+ def test_switches_can_be_explicitly_false
146
+ with_command_args("--no-csv") do
147
+ @cmd_line.uses_switch(:csv, "-c", "--csv")
148
+ @cmd_line.fill
149
+ assert_equal("false", @cmd_line[:csv])
150
+ end
151
+ end
152
+ end
153
+
154
+
155
+ ### Argument Lists ###
156
+
157
+ # Arguments lists are treated as another option.
158
+ class ARGLISTS_CommandLineTest < CommandLineTestCase
159
+
160
+ def test_by_default_arglists_are_not_allowed
161
+ # Note that the error check is done at fill time, not apply time.
162
+ with_command_args("one") {
163
+ output = capturing_stderr do
164
+ assert_wants_to_exit do
165
+ @cmd_line.fill
166
+ end
167
+ end
168
+
169
+ assert_match(/^Error in the command line: No arguments are allowed./, output)
170
+ }
171
+ end
172
+
173
+ def test_empty_arglists_are_OK_if_arglist_not_described
174
+ with_command_args("") {
175
+ output = capturing_stderr do
176
+ @cmd_line.fill
177
+ end
178
+ assert_equal("", output) # No error message
179
+ }
180
+ end
181
+
182
+ def test_arglist_after_options_can_turned_into_an_option
183
+ with_command_args("--unused unused arg1 arg2") {
184
+ @cmd_line.uses_option(:unused, "--unused VALUE") # just for grins
185
+ @cmd_line.uses_arglist(:args)
186
+ @cmd_line.fill
187
+ assert_true(@cmd_line.has_key?(:args))
188
+ assert_equal(["arg1", "arg2"], @cmd_line[:args])
189
+ }
190
+ end
191
+
192
+ def test_arglist_can_check_allowable_number_of_arguments
193
+ with_command_args("--unused unused arg1 arg2") {
194
+ @cmd_line.uses_option(:unused, "--unused VALUE") # just for grins
195
+ @cmd_line.uses_arglist(:args)
196
+ @cmd_line.fill
197
+ @cmd_line.apply({:args => [Conversion.for({:length => 2})]})
198
+ assert_true(@cmd_line.has_key?(:args))
199
+ assert_equal(["arg1", "arg2"], @cmd_line[:args])
200
+ }
201
+ end
202
+
203
+ def test_error_if_exact_arglist_number_is_wrong
204
+ with_command_args("arg1 arg2") {
205
+ @cmd_line.uses_arglist(:args)
206
+ @cmd_line.fill
207
+ output = capturing_stderr do
208
+ assert_wants_to_exit do
209
+ @cmd_line.apply({:args => [Conversion.for({:length => 3})]})
210
+ end
211
+ end
212
+ assert_match(/^Error in the command line:.*2 arguments given, 3 expected./, output)
213
+ }
214
+ end
215
+
216
+ def test_arglist_arity_can_be_a_range
217
+ with_command_args("arg1 arg2") {
218
+ @cmd_line.uses_arglist(:args)
219
+ @cmd_line.fill
220
+ @cmd_line.apply({:args => [Conversion.for({:length => 1..2})]})
221
+ assert_true(@cmd_line.has_key?(:args))
222
+ assert_equal(["arg1", "arg2"], @cmd_line[:args])
223
+ }
224
+ end
225
+
226
+
227
+ def test_error_if_arglist_does_not_match_range
228
+ with_command_args("arg1 arg2") {
229
+ @cmd_line.uses_arglist(:args)
230
+ @cmd_line.fill
231
+ output = capturing_stderr do
232
+ assert_wants_to_exit do
233
+ @cmd_line.apply({:args => [Conversion.for({:length => 3..6})]})
234
+ end
235
+ end
236
+ assert_match(/^Error in the command line:.*2 arguments given, 3 to 6 expected./, output)
237
+ }
238
+ end
239
+
240
+ def test_arglist_external_name_is_friendly
241
+ @cmd_line.uses_arglist(:fred)
242
+ assert_equal("the argument list", @cmd_line.external_names[:fred])
243
+ end
244
+
245
+ def test_deep_copy_of_conversion_map
246
+ map = { :choice => [Conversion.for([:string]), Conversion.for(:length => 3)]}
247
+ copy = @cmd_line.deep_copy(map)
248
+ assert_not_equal(map[:choice].collect { |c| c.object_id },
249
+ copy[:choice].collect { |c| c.object_id })
250
+ assert_true(copy[:choice][0].class.described_by?([:string]))
251
+ assert_true(copy[:choice][1].class.described_by?(:length => 3))
252
+
253
+ map.delete(:choice)
254
+ assert_false(map.has_key?(:choice))
255
+ assert_true(copy.has_key?(:choice))
256
+ end
257
+ end
258
+
259
+ class ARG_CommandLineTest < CommandLineTestCase
260
+ include UserChoices
261
+
262
+
263
+ def test_a_singleton_arg_will_not_be_in_a_list
264
+ with_command_args("arg-only") {
265
+ @cmd_line.uses_option(:unused, "--unused VALUE") # just for grins
266
+ @cmd_line.uses_arg(:arg)
267
+ @cmd_line.fill
268
+ assert_true(@cmd_line.has_key?(:arg))
269
+ assert_equal("arg-only", @cmd_line[:arg])
270
+ }
271
+ end
272
+
273
+ def test_singleton_args_are_incompatible_with_length_checks
274
+ # Because the missing argument might be filled in by other chained sources.
275
+ with_command_args("1") {
276
+ @cmd_line.uses_arg(:arg)
277
+ @cmd_line.fill
278
+ assert_raises_with_matching_message(StandardError, "Don't specify the length of an argument list when it's not treated as an array.") {
279
+ @cmd_line.apply({:arg => [Conversion.for(:length => 1)]})
280
+ }
281
+ }
282
+ end
283
+
284
+
285
+
286
+ def test_extra_singleton_args_generate_errors
287
+ # Note that it's caught in the 'fill' step.
288
+ with_command_args("1 2") {
289
+ @cmd_line.uses_arg(:arg)
290
+ output = capturing_stderr do
291
+ assert_wants_to_exit do
292
+ @cmd_line.fill
293
+ end
294
+ end
295
+ assert_match(/^Error in the command line: .*2 arguments given, 1 expected/, output)
296
+ }
297
+ end
298
+
299
+ def test_singleton_arguments_can_be_optional
300
+ with_command_args("") {
301
+ @cmd_line.uses_optional_arg(:arg)
302
+ @cmd_line.fill
303
+ assert_false(@cmd_line.has_key?(:arg))
304
+ assert_equal(nil, @cmd_line[:arg])
305
+ }
306
+ end
307
+
308
+ def test_optional_arguments_can_be_given
309
+ with_command_args("only") {
310
+ @cmd_line.uses_optional_arg(:arg)
311
+ @cmd_line.fill
312
+ assert_equal('only', @cmd_line[:arg])
313
+ }
314
+ end
315
+
316
+
317
+ def test_that_optional_singleton_arguments_still_precludes_two
318
+ # Note that the error check is done at fill time, not apply time.
319
+ with_command_args("one two") {
320
+ @cmd_line.uses_optional_arg(:arg)
321
+ output = capturing_stderr do
322
+ assert_wants_to_exit do
323
+ @cmd_line.fill
324
+ end
325
+ end
326
+ assert_match(/^Error in the command line:.*2 arguments given, 0 or 1 expected./, output)
327
+ }
328
+ end
329
+
330
+ def test_arg_external_name_is_friendly
331
+ @cmd_line.uses_arg(:fred)
332
+ assert_equal("the argument list", @cmd_line.external_names[:fred])
333
+ end
334
+
335
+
336
+ def test_optional_arg_external_name_is_friendly
337
+ @cmd_line.uses_optional_arg(:fred)
338
+ assert_equal("the argument list", @cmd_line.external_names[:fred])
339
+ end
340
+
341
+ end
342
+
343
+ ### Option-Handling Style ###
344
+
345
+ class OPTION_STYLE_CommandLineTest < CommandLineTestCase
346
+ include UserChoices
347
+
348
+ def define(klass)
349
+ @cmd_line = klass.new
350
+ @cmd_line.uses_switch(:switch, "--switch")
351
+ @cmd_line.uses_arglist(:args)
352
+ @cmd_line.fill
353
+ end
354
+
355
+ def test_default_style_is_permutation
356
+ with_command_args('3 --switch 5') {
357
+ define(CommandLineSource)
358
+ assert_equal('true', @cmd_line[:switch])
359
+ assert_equal(['3', '5'], @cmd_line[:args])
360
+ }
361
+ end
362
+
363
+ def test_subclass_allows_all_options_before_arguments
364
+ with_command_args('3 --switch 5') {
365
+ define(PosixCommandLineSource)
366
+ assert_equal(nil, @cmd_line[:switch])
367
+ assert_equal(['3', '--switch', '5'], @cmd_line[:args])
368
+ }
369
+ end
370
+
371
+ def test_choosing_posix_parsing_does_not_override_environment_variable
372
+ with_environment_vars('POSIXLY_CORRECT' => 'hello') do
373
+ with_command_args('3 --switch 5') {
374
+ define(PosixCommandLineSource)
375
+ assert_equal('hello', ENV['POSIXLY_CORRECT'])
376
+ }
377
+ end
378
+ end
379
+
380
+ end
381
+
382
+ ### Error Handling ###
383
+
384
+ # Additional commandline-specific error checking.
385
+ class ERROR_CommandLineTest < CommandLineTestCase
386
+ include UserChoices
387
+
388
+ def test_invalid_option_produces_error_message_and_exit
389
+ with_command_args('--doofus 3') {
390
+ output = capturing_stderr do
391
+ assert_wants_to_exit do
392
+ @cmd_line.uses_option(:doofus, "--option VALUE")
393
+ @cmd_line.fill
394
+ end
395
+ end
396
+
397
+ assert_match(/invalid option.*doofus/, output)
398
+ }
399
+ end
400
+
401
+ def test_error_is_identified_as_coming_from_the_command_line
402
+ with_command_args('--doofus') {
403
+ output = capturing_stderr do
404
+ assert_wants_to_exit do
405
+ @cmd_line.uses_option(:doofus, "--doofus VALUE")
406
+ @cmd_line.fill
407
+ end
408
+ end
409
+
410
+ assert_match(/^Error in the command line:.*missing argument.*doofus/, output)
411
+ }
412
+ end
413
+
414
+ def test_errors_cause_usage_style_output
415
+ with_command_args('wanted --wanted') {
416
+ output = capturing_stderr do
417
+ assert_wants_to_exit do
418
+ default_isbn = "343"
419
+ @cmd_line.help_banner("Usage: ruby prog [options] [isbn]",
420
+ "This and further strings are optional.")
421
+ @cmd_line.uses_option(:option, "-o", "--option=VALUE",
422
+ "Message about option",
423
+ "More about option")
424
+ @cmd_line.fill
425
+ end
426
+ end
427
+
428
+ lines = output.split($/)
429
+ # puts output
430
+ assert_match(/^Error in the command line: /, lines[0])
431
+ assert_equal("Usage: ruby prog [options] [isbn]", lines[1])
432
+ assert_match(/This and further/, lines[2])
433
+ assert_match(/\s*/, lines[3])
434
+ assert_match(/Options:/, lines[4])
435
+ assert_match(/-o.*--option=VALUE.*Message about option/, lines[5])
436
+ assert_match(/More about option/, lines[6])
437
+ assert_match(/--help.*Show this message/, lines.last)
438
+ }
439
+ end
440
+
441
+ end
442
+
443
+
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Created by Brian Marick on 2007-08-06.
4
+ # Copyright (c) 2007. All rights reserved.
5
+
6
+ load "set-standalone-test-paths.rb" unless $started_from_rakefile
7
+ require 'test/unit'
8
+ require 's4t-utils'
9
+ require 'user-choices'
10
+ include S4tUtils
11
+
12
+
13
+ class TestDefaultsAndTypes < Test::Unit::TestCase
14
+ include UserChoices
15
+
16
+ def test_correct_conversion_objects_are_chosen
17
+ start = []
18
+ Conversion.record_for(:integer, start)
19
+ Conversion.record_for(:boolean, start)
20
+ Conversion.record_for([:string], start)
21
+ Conversion.record_for(["one", "two"], start)
22
+ Conversion.record_for({:length => 1}, start)
23
+ Conversion.record_for({:length => 1..2}, start)
24
+
25
+ assert_equal([ConversionToInteger, ConversionToBoolean,
26
+ SplittingConversion, ChoiceCheckingConversion,
27
+ ExactLengthConversion, RangeLengthConversion],
28
+ start.collect { |c| c.class })
29
+ end
30
+
31
+ def test_nil_conversion_tags_do_nothing
32
+ start = []
33
+ Conversion.record_for(nil, start)
34
+ assert_equal([], start)
35
+ end
36
+
37
+ def test_integer_conversion_checking
38
+ c2i = Conversion.for(:integer)
39
+ assert_true(c2i.suitable?("034"))
40
+ assert_false(c2i.suitable?("0x1d"))
41
+ assert_false(c2i.suitable?(["0x1d"]))
42
+ assert_equal('an integer', c2i.description)
43
+ end
44
+
45
+ def test_integer_conversion
46
+ c2i = Conversion.for(:integer)
47
+ assert_equal(12, c2i.convert("12"))
48
+ end
49
+
50
+ def test_it_is_ok_for_integers_already_to_be_converted
51
+ c2i = Conversion.for(:integer)
52
+ assert_true(c2i.suitable?(12))
53
+ assert_equal(12, c2i.convert(12))
54
+ end
55
+
56
+
57
+
58
+ def test_boolean_conversion_checking
59
+ c2b = Conversion.for(:boolean)
60
+ assert_true(c2b.suitable?("true"))
61
+ assert_true(c2b.suitable?("false"))
62
+ # Case insensitive
63
+ assert_true(c2b.suitable?("False"))
64
+ assert_true(c2b.suitable?("TRUE"))
65
+
66
+ assert_false(c2b.suitable?("tru"))
67
+ assert_false(c2b.suitable?(1))
68
+ assert_equal('a boolean', c2b.description)
69
+ end
70
+
71
+ def test_boolean_conversion
72
+ c = Conversion.for(:boolean)
73
+ assert_equal(false, c.convert("FalsE"))
74
+ assert_equal(true, c.convert("true"))
75
+ end
76
+
77
+ def test_it_is_ok_for_booleans_already_to_be_converted
78
+ c = Conversion.for(:boolean)
79
+ assert_true(c.suitable?(true))
80
+ assert_equal(false, c.convert(false))
81
+ end
82
+
83
+
84
+
85
+
86
+
87
+ def test_any_string_is_accepted_for_splitting_conversion
88
+ s = Conversion.for([:string])
89
+ assert_true(s.suitable?("tru calling"))
90
+ assert_true(s.suitable?("fa,se"))
91
+ assert_false(s.suitable?(1))
92
+ end
93
+
94
+ def test_splitting
95
+ c = Conversion.for([:string])
96
+ assert_equal(["one"], c.convert("one"))
97
+ assert_equal(["one", "two"], c.convert("one,two"))
98
+ # Whitespace NOT ignored
99
+ assert_equal(["one", " two"], c.convert("one, two"))
100
+ end
101
+
102
+ def test_it_is_ok_for_values_already_to_be_split
103
+ c = Conversion.for([:string])
104
+ assert_true(c.suitable?(["one", "two"]))
105
+ assert_equal(["one", "two"], c.convert(["one", "two"]))
106
+ end
107
+
108
+
109
+
110
+
111
+ def test_choice_checking_conversion
112
+ cc = Conversion.for(["foo", "bar"])
113
+ assert_true(cc.suitable?("foo"))
114
+ assert_true(cc.suitable?("bar"))
115
+
116
+ assert_false(cc.suitable?("fred"))
117
+ # Case sensitive
118
+ assert_false(cc.suitable?("FOO"))
119
+ assert_equal("one of 'foo' or 'bar'", cc.description)
120
+ end
121
+
122
+ def test_choice_checking_does_no_conversion
123
+ cc = Conversion.for(["foo", "bar"])
124
+ assert_equal("foo", cc.convert("foo"))
125
+ end
126
+
127
+
128
+ def test_length_conversion_with_exact_length
129
+ c = Conversion.for(:length => 1)
130
+ assert_true(c.suitable?([1]))
131
+ assert_false(c.suitable?([]))
132
+ assert_false(c.suitable?([1, 2]))
133
+ assert_false(c.suitable?("not array"))
134
+
135
+ assert_equal("of length 1", c.description)
136
+ end
137
+
138
+ def test_length_conversion_with_exact_length_does_no_conversion
139
+ c = Conversion.for(:length => 1)
140
+ assert_equal(["foo"], c.convert(["foo"]))
141
+ end
142
+
143
+ def test_length_conversion_with_range
144
+ c = Conversion.for(:length => 0..1)
145
+ assert_true(c.suitable?([1]))
146
+ assert_true(c.suitable?([]))
147
+ assert_false(c.suitable?([1, 2]))
148
+
149
+ assert_equal("a list whose length is in this range: 0..1", c.description)
150
+ end
151
+
152
+ def test_length_conversion_with_range_does_no_conversion
153
+ c = Conversion.for(:length => 0..1)
154
+ assert_equal(["foo"], c.convert(["foo"]))
155
+ end
156
+
157
+ end
@@ -0,0 +1,5 @@
1
+ require 'pathname'
2
+
3
+ PACKAGE_ROOT = Pathname.new(__FILE__).parent.parent.to_s
4
+ $:.unshift("#{PACKAGE_ROOT}/lib")
5
+ require 's4t-utils/load-path-auto-adjuster'