qoobaa-user-choices 1.1.7
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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +39 -0
- data/README.rdoc +7 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/examples/older/README.txt +133 -0
- data/examples/older/command-line.rb +46 -0
- data/examples/older/default-values.rb +41 -0
- data/examples/older/multiple-sources.rb +58 -0
- data/examples/older/postprocess.rb +39 -0
- data/examples/older/switches.rb +44 -0
- data/examples/older/two-args.rb +31 -0
- data/examples/older/types.rb +61 -0
- data/examples/tutorial/css/LICENSE.txt +1 -0
- data/examples/tutorial/css/bg2.gif +0 -0
- data/examples/tutorial/css/left.gif +0 -0
- data/examples/tutorial/css/left_on.gif +0 -0
- data/examples/tutorial/css/main.css +242 -0
- data/examples/tutorial/css/right.gif +0 -0
- data/examples/tutorial/css/right_on.gif +0 -0
- data/examples/tutorial/css/tvline.gif +0 -0
- data/examples/tutorial/css/von-foerster.jpg +0 -0
- data/examples/tutorial/css/von-foerster2.jpg +0 -0
- data/examples/tutorial/index.html +703 -0
- data/examples/tutorial/tutorial1.rb +41 -0
- data/examples/tutorial/tutorial2.rb +44 -0
- data/examples/tutorial/tutorial3.rb +47 -0
- data/examples/tutorial/tutorial4.rb +47 -0
- data/examples/tutorial/tutorial5.rb +35 -0
- data/examples/tutorial/tutorial6.rb +35 -0
- data/examples/tutorial/tutorial7.rb +41 -0
- data/lib/user-choices.rb +131 -0
- data/lib/user-choices/arglist-strategies.rb +179 -0
- data/lib/user-choices/builder.rb +118 -0
- data/lib/user-choices/command-line-source.rb +224 -0
- data/lib/user-choices/command.rb +42 -0
- data/lib/user-choices/conversions.rb +169 -0
- data/lib/user-choices/ruby-extensions.rb +20 -0
- data/lib/user-choices/sources.rb +278 -0
- data/lib/user-choices/version.rb +3 -0
- data/test/arglist_strategy_test.rb +42 -0
- data/test/builder_test.rb +631 -0
- data/test/command_line_source_test.rb +443 -0
- data/test/conversion_test.rb +172 -0
- data/test/source_test.rb +451 -0
- data/test/test_helper.rb +9 -0
- data/test/user_choices_slow_test.rb +276 -0
- data/user-choices.gemspec +104 -0
- metadata +122 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brian Marick on 2007-08-09.
|
4
|
+
# Copyright (c) 2007. All rights reserved.
|
5
|
+
|
6
|
+
# See the tutorial for explanations.
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
require 'user-choices'
|
10
|
+
|
11
|
+
# See the tutorial for explanations.
|
12
|
+
|
13
|
+
class TutorialExample < UserChoices::Command
|
14
|
+
include UserChoices
|
15
|
+
|
16
|
+
def add_sources(builder)
|
17
|
+
builder.add_source(CommandLineSource, :usage,
|
18
|
+
"Usage: ruby #{$0} [options]")
|
19
|
+
builder.add_source(EnvironmentSource, :with_prefix, "myprog_")
|
20
|
+
builder.add_source(YamlConfigFileSource, :from_file, ".myprog-config.yml")
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_choices(builder)
|
24
|
+
builder.add_choice(:connections, :type=>:integer, :default=>0) { | command_line |
|
25
|
+
command_line.uses_option("-c", "--connections COUNT",
|
26
|
+
"Number of connections to open.")
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute
|
31
|
+
puts "There are #{@user_choices[:connections]} connections."
|
32
|
+
pp @user_choices
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
if $0 == __FILE__
|
38
|
+
S4tUtils.with_pleasant_exceptions do
|
39
|
+
TutorialExample.new.execute
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brian Marick on 2007-08-09.
|
4
|
+
# Copyright (c) 2007. All rights reserved.
|
5
|
+
|
6
|
+
# See the tutorial for explanations.
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
require 'user-choices'
|
10
|
+
|
11
|
+
class TutorialExample < UserChoices::Command
|
12
|
+
include UserChoices
|
13
|
+
|
14
|
+
def add_sources(builder)
|
15
|
+
builder.add_source(CommandLineSource, :usage,
|
16
|
+
"Usage: ruby #{$0} [options] file1 [file2]")
|
17
|
+
builder.add_source(EnvironmentSource, :with_prefix, "myprog_")
|
18
|
+
builder.add_source(YamlConfigFileSource, :from_file, ".myprog-config.yml")
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_choices(builder)
|
22
|
+
builder.add_choice(:connections, :type=>:integer, :default=>0) { | command_line |
|
23
|
+
command_line.uses_option("-c", "--connections COUNT",
|
24
|
+
"Number of connections to open.")
|
25
|
+
}
|
26
|
+
builder.add_choice(:ssh, :type=>:boolean, :default=>false) { | command_line |
|
27
|
+
command_line.uses_switch("-s", "--ssh",
|
28
|
+
"Use ssh to open connection.")
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def execute
|
33
|
+
puts format("SSH %s be used.", @user_choices[:ssh] ? "should" : "should not")
|
34
|
+
puts "There are #{@user_choices[:connections]} connections."
|
35
|
+
pp @user_choices
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
if $0 == __FILE__
|
41
|
+
S4tUtils.with_pleasant_exceptions do
|
42
|
+
TutorialExample.new.execute
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brian Marick on 2007-08-09.
|
4
|
+
# Copyright (c) 2007. All rights reserved.
|
5
|
+
|
6
|
+
# See the tutorial for explanations.
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
require 'user-choices'
|
10
|
+
|
11
|
+
class TutorialExample < UserChoices::Command
|
12
|
+
include UserChoices
|
13
|
+
|
14
|
+
def add_sources(builder)
|
15
|
+
builder.add_source(CommandLineSource, :usage,
|
16
|
+
"Usage: ruby #{$0} [options] file1 [file2]")
|
17
|
+
builder.add_source(EnvironmentSource, :with_prefix, "myprog_")
|
18
|
+
builder.add_source(YamlConfigFileSource, :from_file, ".myprog-config.yml")
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_choices(builder)
|
22
|
+
builder.add_choice(:connections, :type=>:integer, :default=>0) { | command_line |
|
23
|
+
command_line.uses_option("-c", "--connections COUNT",
|
24
|
+
"Number of connections to open.")
|
25
|
+
}
|
26
|
+
builder.add_choice(:ssh, :type=>:boolean, :default=>false) { | command_line |
|
27
|
+
command_line.uses_switch("-s", "--ssh",
|
28
|
+
"Use ssh to open connection.")
|
29
|
+
}
|
30
|
+
builder.add_choice(:files) { | command_line |
|
31
|
+
command_line.uses_arglist
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def execute
|
36
|
+
puts format("SSH %s be used.", @user_choices[:ssh] ? "should" : "should not")
|
37
|
+
puts "There are #{@user_choices[:connections]} connections."
|
38
|
+
pp @user_choices
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
if $0 == __FILE__
|
44
|
+
S4tUtils.with_pleasant_exceptions do
|
45
|
+
TutorialExample.new.execute
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brian Marick on 2007-08-09.
|
4
|
+
# Copyright (c) 2007. All rights reserved.
|
5
|
+
|
6
|
+
# See the tutorial for explanations.
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
require 'user-choices'
|
10
|
+
|
11
|
+
class TutorialExample < UserChoices::Command
|
12
|
+
include UserChoices
|
13
|
+
|
14
|
+
def add_sources(builder)
|
15
|
+
builder.add_source(CommandLineSource, :usage,
|
16
|
+
"Usage: ruby #{$0} [options] file1 [file2]")
|
17
|
+
builder.add_source(EnvironmentSource, :with_prefix, "myprog_")
|
18
|
+
builder.add_source(YamlConfigFileSource, :from_file, ".myprog-config.yml")
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_choices(builder)
|
22
|
+
builder.add_choice(:connections, :type=>:integer, :default=>0) { | command_line |
|
23
|
+
command_line.uses_option("-c", "--connections COUNT",
|
24
|
+
"Number of connections to open.")
|
25
|
+
}
|
26
|
+
builder.add_choice(:ssh, :type=>:boolean, :default=>false) { | command_line |
|
27
|
+
command_line.uses_switch("-s", "--ssh",
|
28
|
+
"Use ssh to open connection.")
|
29
|
+
}
|
30
|
+
builder.add_choice(:files, :length => 1..2) { | command_line |
|
31
|
+
command_line.uses_arglist
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
def execute
|
36
|
+
puts format("SSH %s be used.", @user_choices[:ssh] ? "should" : "should not")
|
37
|
+
puts "There are #{@user_choices[:connections]} connections."
|
38
|
+
pp @user_choices
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
if $0 == __FILE__
|
44
|
+
S4tUtils.with_pleasant_exceptions do
|
45
|
+
TutorialExample.new.execute
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brian Marick on 2007-08-09.
|
4
|
+
# Copyright (c) 2007. All rights reserved.
|
5
|
+
|
6
|
+
# See the tutorial for explanations.
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
require 'user-choices'
|
10
|
+
|
11
|
+
class TutorialExample < UserChoices::Command
|
12
|
+
include UserChoices
|
13
|
+
|
14
|
+
def add_sources(builder)
|
15
|
+
builder.add_source(CommandLineSource, :usage,
|
16
|
+
"Usage: ruby #{$0} infile")
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_choices(builder)
|
20
|
+
builder.add_choice(:infile) { | command_line |
|
21
|
+
command_line.uses_arg
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
pp @user_choices
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
if $0 == __FILE__
|
32
|
+
S4tUtils.with_pleasant_exceptions do
|
33
|
+
TutorialExample.new.execute
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brian Marick on 2007-08-09.
|
4
|
+
# Copyright (c) 2007. All rights reserved.
|
5
|
+
|
6
|
+
# See the tutorial for explanations.
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
require 'user-choices'
|
10
|
+
|
11
|
+
class TutorialExample < UserChoices::Command
|
12
|
+
include UserChoices
|
13
|
+
|
14
|
+
def add_sources(builder)
|
15
|
+
builder.add_source(CommandLineSource, :usage,
|
16
|
+
"Usage: ruby #{$0} infile")
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_choices(builder)
|
20
|
+
builder.add_choice(:infile) { | command_line |
|
21
|
+
command_line.uses_optional_arg
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
pp @user_choices
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
if $0 == __FILE__
|
32
|
+
S4tUtils.with_pleasant_exceptions do
|
33
|
+
TutorialExample.new.execute
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brian Marick on 2007-08-09.
|
4
|
+
# Copyright (c) 2007. All rights reserved.
|
5
|
+
|
6
|
+
# See the tutorial for explanations.
|
7
|
+
|
8
|
+
require 'pp'
|
9
|
+
require 'user-choices'
|
10
|
+
|
11
|
+
class TutorialExample < UserChoices::Command
|
12
|
+
include UserChoices
|
13
|
+
|
14
|
+
def add_sources(builder)
|
15
|
+
builder.add_source(CommandLineSource, :usage,
|
16
|
+
"Usage: ruby #{$0} infile outfile")
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_choices(builder)
|
20
|
+
builder.add_choice(:files, :length => 2) { | command_line |
|
21
|
+
command_line.uses_arglist
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def postprocess_user_choices
|
26
|
+
@user_choices[:infile] = @user_choices[:files][0]
|
27
|
+
@user_choices[:outfile] = @user_choices[:files][1]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def execute
|
32
|
+
pp @user_choices
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
if $0 == __FILE__
|
38
|
+
S4tUtils.with_pleasant_exceptions do
|
39
|
+
TutorialExample.new.execute
|
40
|
+
end
|
41
|
+
end
|
data/lib/user-choices.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'user-choices/arglist-strategies'
|
2
|
+
require 'user-choices/builder'
|
3
|
+
require 'user-choices/command'
|
4
|
+
require 'user-choices/command-line-source'
|
5
|
+
require "user-choices/conversions"
|
6
|
+
require "user-choices/ruby-extensions"
|
7
|
+
require 'user-choices/sources'
|
8
|
+
require 'user-choices/version'
|
9
|
+
|
10
|
+
=begin rdoc
|
11
|
+
|
12
|
+
UserChoices provides a unified interface to more than one source of
|
13
|
+
user choices: the command line, environment variables, configuration
|
14
|
+
files, and the choice to use program defaults. A typical usage defines allowable choices
|
15
|
+
within the framework of a Command object:
|
16
|
+
|
17
|
+
class Example < Command
|
18
|
+
|
19
|
+
# The sources are the various places in which the user can
|
20
|
+
# describe her choices to the program.
|
21
|
+
|
22
|
+
def add_sources(builder)
|
23
|
+
builder.add_source(...)
|
24
|
+
...
|
25
|
+
end
|
26
|
+
|
27
|
+
# Each individual choice is named with a symbol that is common
|
28
|
+
# to all sources.
|
29
|
+
def add_choices(builder)
|
30
|
+
builder.add_choice(:choice, ...) { | command_line | ... }
|
31
|
+
end
|
32
|
+
|
33
|
+
# Immediately after recording the choices, the program can
|
34
|
+
# add new (derived ones) or do any other once-per-program
|
35
|
+
# initialization.
|
36
|
+
def postprocess_user_choices
|
37
|
+
... @user_choices ...
|
38
|
+
end
|
39
|
+
|
40
|
+
# Perform the command.
|
41
|
+
def execute
|
42
|
+
...
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
...
|
47
|
+
CommandLineExample.new.execute
|
48
|
+
...
|
49
|
+
|
50
|
+
= Describing sources
|
51
|
+
|
52
|
+
Sources are described by ChoicesBuilder#add_source.
|
53
|
+
|
54
|
+
EnvironmentSource describes the use of environment variables as sources. The following says that all environment variables beginning with "amazon_" are choices about this program.
|
55
|
+
|
56
|
+
builder.add_source(EnvironmentSource, :with_prefix, "amazon_")
|
57
|
+
|
58
|
+
XmlConfigFileSource points to a configuration file with choices.
|
59
|
+
|
60
|
+
builder.add_source(XmlConfigFileSource, :from_file, "ms-config.xml")
|
61
|
+
|
62
|
+
CommandLineSource uses the command line options and
|
63
|
+
arguments as a source of choices. The following gives the usage line
|
64
|
+
for the script:
|
65
|
+
|
66
|
+
builder.add_source(CommandLineSource, :usage,
|
67
|
+
"Usage ruby #{$0} [options] names...")
|
68
|
+
|
69
|
+
= Describing choices
|
70
|
+
|
71
|
+
The end result of the process is a hash mapping choices to chosen
|
72
|
+
values. Choices are named by symbols. They are described by
|
73
|
+
ChoicesBuilder#add_choice. Here are simple examples that
|
74
|
+
don't involve the command line.
|
75
|
+
|
76
|
+
The first just names a choice.
|
77
|
+
|
78
|
+
builder.add_choice(:ordinary_choice)
|
79
|
+
|
80
|
+
The second gives a default value:
|
81
|
+
|
82
|
+
builder.add_choice(:ordinary_choice,
|
83
|
+
:default => "eaargh")
|
84
|
+
|
85
|
+
The second gives a default value and a type. The type is used to check the value and, if appropriate, to convert the value away from a string. Note that the default is always a string regardless of the type.
|
86
|
+
|
87
|
+
builder.add_choice(:on,
|
88
|
+
:default => "false",
|
89
|
+
:type => :boolean)
|
90
|
+
|
91
|
+
= Command line options
|
92
|
+
|
93
|
+
ChoicesBuilder#add_choice passes a
|
94
|
+
CommandLineSource object to a block. That can be used to
|
95
|
+
describe the command line. The syntax is the same as OptionParser.
|
96
|
+
|
97
|
+
In the following, <tt>ordinary_choice</tt> can be specified with either the <tt>-o</tt> or <tt>--ordinary-choice</tt> options. The strings also appear in help messages (automatically produced from <tt>ruby script --help</tt>).
|
98
|
+
|
99
|
+
builder.add_choice(:ordinary_choice,
|
100
|
+
:default => 'default') { | command_line |
|
101
|
+
command_line.uses_option("-o", "--ordinary-choice CHOICE",
|
102
|
+
"CHOICE can be any string.")
|
103
|
+
}
|
104
|
+
|
105
|
+
The command line's argument list (everything that's not an option) can
|
106
|
+
be bundled up into another choice. Here, the arguments become an array
|
107
|
+
named by <tt>:names</tt>:
|
108
|
+
|
109
|
+
builder.add_choice(:names) { | command_line |
|
110
|
+
command_line.uses_arglist
|
111
|
+
}
|
112
|
+
|
113
|
+
= Using choices
|
114
|
+
|
115
|
+
Most often, choices are used within the context of a Command object. They are stored in a hash named by instance variable <tt>@user_choices</tt> (or accessor +user_choices+).
|
116
|
+
|
117
|
+
class AffinityTripCommand < Command
|
118
|
+
...
|
119
|
+
def execute
|
120
|
+
starting_url = @strategy.url_for(self.user_choices[:isbn])
|
121
|
+
take_trip(starting_url, self.user_choices[:trip_steps])
|
122
|
+
end
|
123
|
+
|
124
|
+
You can construct the hash directly with ChoicesBuilder#build. That's
|
125
|
+
not needed or used when using the Command object.
|
126
|
+
|
127
|
+
=end
|
128
|
+
|
129
|
+
module UserChoices
|
130
|
+
end
|
131
|
+
|
@@ -0,0 +1,179 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Created by Brian Marick on 2007-08-10.
|
4
|
+
# Copyright (c) 2007. All rights reserved.
|
5
|
+
|
6
|
+
require 'user-choices/ruby-extensions'
|
7
|
+
|
8
|
+
module UserChoices # :nodoc:
|
9
|
+
|
10
|
+
# Arglists cause complications, mainly because a command's arglist is
|
11
|
+
# never optional. If you ever want it to be ignored, for example, you have to treat it
|
12
|
+
# specially. An AbstractArglistStrategy is a sequence of messages that can
|
13
|
+
# cope with those sort of complications. These messages are called at the
|
14
|
+
# appropriate time by a CommandLineSource.
|
15
|
+
#
|
16
|
+
# * <b>AbstractArglistStrategy#fill</b> takes the arglist and converts it to
|
17
|
+
# the value of some choice symbol. The name should remind you of AbstractSource#fill.
|
18
|
+
# * There may be conversions that make sense for values (for this choice symbol) when
|
19
|
+
# those values do <i>not</i> come from an arglist, but not when they do.
|
20
|
+
# <b>AbstractArglistStrategy#claim_conversions</b> squirrels them away to protect
|
21
|
+
# them from more generic processing. They are then specially processed by
|
22
|
+
# AbstractArglistStrategy#apply_claimed_conversions.
|
23
|
+
# * After conversions, there may still be work to do. There may be some special
|
24
|
+
# reconciling required to the entire collection of choices. (The final result
|
25
|
+
# may depend on what value the arglist provided and what value some other source
|
26
|
+
# provided.) <b>AbstractArglistStrategy#adjust</b> does that work.
|
27
|
+
class AbstractArglistStrategy # :nodoc:
|
28
|
+
|
29
|
+
attr_reader :choice
|
30
|
+
|
31
|
+
# A strategy applies an argument list named _choice_ that is a key
|
32
|
+
# in the <i>value_holder</i>. It's hackish, but don't give the _choice_ in
|
33
|
+
# the case where there should be no arglist (and thus no choice symbol to
|
34
|
+
# attach it to).
|
35
|
+
def initialize(value_holder, choice=nil)
|
36
|
+
@value_holder = value_holder
|
37
|
+
@choice = choice
|
38
|
+
end
|
39
|
+
|
40
|
+
# This method takes the argument list, an array, and puts it into
|
41
|
+
# the <code>value_holder</code>.
|
42
|
+
def fill(arglist); subclass_responsibility; end
|
43
|
+
|
44
|
+
# Given _conversions_map_, a list of Conversion, select which apply to the arglist,
|
45
|
+
# removing them from the hash.
|
46
|
+
def claim_conversions(conversions_map)
|
47
|
+
@claimed_conversions = []
|
48
|
+
end
|
49
|
+
|
50
|
+
# Apply the claimed conversions to the value previously stored in claim_conversions.
|
51
|
+
def apply_claimed_conversions
|
52
|
+
# None claimed by default
|
53
|
+
end
|
54
|
+
|
55
|
+
# Apply any effects of changes to the arglist to the result for all the choices.
|
56
|
+
def adjust(all_choices)
|
57
|
+
# By default, do nothing.
|
58
|
+
end
|
59
|
+
|
60
|
+
# public for testing.
|
61
|
+
def arglist_arity_error(length, arglist_arity) # :nodoc:
|
62
|
+
plural = length==1 ? '' : 's'
|
63
|
+
expected = case arglist_arity
|
64
|
+
when Integer
|
65
|
+
arglist_arity.to_s
|
66
|
+
when Range
|
67
|
+
if arglist_arity.end == arglist_arity.begin.succ
|
68
|
+
"#{arglist_arity.begin} or #{arglist_arity.end}"
|
69
|
+
else
|
70
|
+
arglist_arity.in_words
|
71
|
+
end
|
72
|
+
else
|
73
|
+
arglist_arity.inspect
|
74
|
+
end
|
75
|
+
"#{length} argument#{plural} given, #{expected} expected."
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def claim_length_check(conversions_map)
|
82
|
+
@length_check = conversions_map[@choice].find { |c| c.does_length_check? }
|
83
|
+
if @length_check
|
84
|
+
conversions_map[@choice].reject { |c| c.does_length_check? }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
# An AbstractArglistStrategy that rejects any non-empty arglist.
|
92
|
+
class NoArguments < AbstractArglistStrategy # :nodoc:
|
93
|
+
def fill(arglist)
|
94
|
+
user_claims(arglist.length == 0) do
|
95
|
+
"No arguments are allowed."
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
# The arglist is to be treated as a list, possibly with a Conversion that
|
102
|
+
# limits its length. It defers processing of an empty arglist until the
|
103
|
+
# last possible moment and only does it if there's no other value for the
|
104
|
+
# choice symbol.
|
105
|
+
class ArbitraryArglist < AbstractArglistStrategy # :nodoc:
|
106
|
+
def fill(arglist)
|
107
|
+
@value_holder[@choice] = arglist unless arglist.empty?
|
108
|
+
end
|
109
|
+
|
110
|
+
def claim_conversions(conversions_map)
|
111
|
+
claim_length_check(conversions_map)
|
112
|
+
end
|
113
|
+
|
114
|
+
def apply_claimed_conversions
|
115
|
+
apply_length_check
|
116
|
+
end
|
117
|
+
|
118
|
+
def adjust(all_choices)
|
119
|
+
return if @value_holder[@choice]
|
120
|
+
return if all_choices.has_key?(@choice)
|
121
|
+
|
122
|
+
all_choices[@choice] = []
|
123
|
+
@value_holder[@choice] = all_choices[@choice]
|
124
|
+
apply_length_check
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def apply_length_check
|
130
|
+
return unless @length_check
|
131
|
+
return unless @value_holder[@choice]
|
132
|
+
|
133
|
+
value = @value_holder[@choice]
|
134
|
+
user_claims(@length_check.suitable?(value)) {
|
135
|
+
arglist_arity_error(value.length, @length_check.required_length)
|
136
|
+
}
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# General handling for cases where the Arglist isn't treated as a list, but
|
141
|
+
# rather as a single (possibly optional) element. Subclasses handle the
|
142
|
+
# optional/non-optional case.
|
143
|
+
class NonListStrategy < AbstractArglistStrategy # :nodoc:
|
144
|
+
def arity; subclass_responsibility; end
|
145
|
+
|
146
|
+
def fill(arglist)
|
147
|
+
case arglist.length
|
148
|
+
when 0
|
149
|
+
# This is not considered an error because another source might fill in the value.
|
150
|
+
when 1
|
151
|
+
@value_holder[@choice] = arglist[0]
|
152
|
+
else user_is_bewildered(arglist_arity_error(arglist.length, self.arity))
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def claim_conversions(conversions_map)
|
157
|
+
claim_length_check(conversions_map)
|
158
|
+
user_denies(@length_check) {
|
159
|
+
"Don't specify the length of an argument list when it's not treated as an array."
|
160
|
+
}
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
class OneRequiredArg < NonListStrategy # :nodoc:
|
166
|
+
def arity; 1; end
|
167
|
+
|
168
|
+
def adjust(all_choices)
|
169
|
+
return if all_choices.has_key?(@choice)
|
170
|
+
user_is_bewildered(arglist_arity_error(0,1))
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
class OneOptionalArg < NonListStrategy # :nodoc:
|
176
|
+
def arity; 0..1; end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|