s0nspark-choice 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ module Choice
2
+ module Version #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 3
6
+ STRING = [MAJOR, MINOR, TINY] * '.'
7
+ end
8
+ end
@@ -0,0 +1,187 @@
1
+ module Choice
2
+ # This module writes to the screen. As of now, its only real use is writing
3
+ # the help screen.
4
+ module Writer #:nodoc: all
5
+
6
+ # Some constants used for printing and line widths
7
+ SHORT_LENGTH = 6
8
+ SHORT_BREAK_LENGTH = 2
9
+ LONG_LENGTH = 29
10
+ PRE_DESC_LENGTH = SHORT_LENGTH + SHORT_BREAK_LENGTH + LONG_LENGTH
11
+
12
+
13
+ # The main method. Takes a hash of arguments with the following possible
14
+ # keys, running them through the appropriate method:
15
+ # banner, header, options, footer
16
+ #
17
+ # Can also be told where to print (default STDOUT) and not to exit after
18
+ # printing the help screen, which it does by default.
19
+ def self.help(args, target = STDOUT, dont_exit = false)
20
+ # Set our printing target.
21
+ self.target = target
22
+
23
+ # The banner method needs to know about the passed options if it's going
24
+ # to do its magic. Only really needs :options if :banner is nil.
25
+ banner(args[:banner], args[:options])
26
+
27
+ # Run these three methods, passing in the appropriate hash element.
28
+ %w[header options footer].each do |meth|
29
+ send(meth, args[meth.to_sym])
30
+ end
31
+
32
+ # Exit. Unless you don't want to.
33
+ exit unless dont_exit
34
+ end
35
+
36
+ class <<self
37
+ private
38
+
39
+ # Print a passed banner or assemble the default banner, which is usage.
40
+ def banner(banner, options)
41
+ if banner
42
+ puts banner
43
+ else
44
+ # Usage needs to know about the defined options.
45
+ usage(options)
46
+ end
47
+ end
48
+
49
+ # Print our header, which is just lines after the banner and before the
50
+ # options block. Needs an array, prints each element as a line.
51
+ def header(header)
52
+ if header.is_a?(Array) and header.size > 0
53
+ header.each { |line| puts line }
54
+ end
55
+ end
56
+
57
+ # Print out the options block by going through each option and printing
58
+ # it as a line (or more). Expects an array.
59
+ def options(options)
60
+ # Do nothing if there's nothing to do.
61
+ return if options.nil? || !options.size
62
+
63
+ # If the option is a hash, run it through option_line. Otherwise
64
+ # just print it out as is.
65
+ options.each do |name, option|
66
+ if option.respond_to?(:to_h)
67
+ option_line(option.to_h)
68
+ else
69
+ puts name
70
+ end
71
+ end
72
+ end
73
+
74
+ # The heavy lifting: print a line for an option. Has intimate knowledge
75
+ # of what keys are expected.
76
+ def option_line(option)
77
+ # Expect a hash
78
+ return unless option.is_a?(Hash)
79
+
80
+ # Make this easier on us
81
+ short = option['short']
82
+ long = option['long']
83
+ line = ''
84
+
85
+ # Get the short part.
86
+ line << sprintf("%#{SHORT_LENGTH}s", short)
87
+ line << sprintf("%-#{SHORT_BREAK_LENGTH}s", (',' if short && long))
88
+
89
+ # Get the long part.
90
+ line << sprintf("%-#{LONG_LENGTH}s", long)
91
+
92
+ # Print what we have so far
93
+ print line
94
+
95
+ # If there's a desc, print it.
96
+ if option['desc']
97
+ # If the line is too long, spill over to the next line
98
+ if line.length > PRE_DESC_LENGTH
99
+ puts
100
+ print " " * PRE_DESC_LENGTH
101
+ end
102
+
103
+ puts option['desc'].shift
104
+
105
+ # If there is more than one desc line, print each one in succession
106
+ # as separate lines.
107
+ option['desc'].each do |desc|
108
+ puts ' '*37 + desc
109
+ end
110
+
111
+ else
112
+ # No desc, just print a newline.
113
+ puts
114
+
115
+ end
116
+ end
117
+
118
+ # Expects an array, prints each element as a line.
119
+ def footer(footer)
120
+ footer.each { |line| puts line } unless footer.nil?
121
+ end
122
+
123
+ # Prints the usage statement, e.g. Usage prog.rb [-abc]
124
+ # Expects an array.
125
+ def usage(options)
126
+ # Really we just need an enumerable.
127
+ return unless options.respond_to?(:each)
128
+
129
+ # Start off the options with a dash.
130
+ opts = '-'
131
+
132
+ # Figure out the option shorts.
133
+ options.dup.each do |option|
134
+ # We really need an array here.
135
+ next unless option.is_a?(Array)
136
+
137
+ # Grab the hash of the last element, which should be the second
138
+ # element.
139
+ option = option.last.to_h
140
+
141
+ # Add the short to the options string.
142
+ opts << option['short'].sub('-','') if option['short']
143
+ end
144
+
145
+ # Figure out if we actually got any options.
146
+ opts = if opts =~ /^-(.+)/
147
+ " [#{opts}]"
148
+ end.to_s
149
+
150
+ # Print it out, with our newly aquired options string.
151
+ puts "Usage: #{program}" << opts
152
+ end
153
+
154
+ # Figure out the name of this program based on what was run.
155
+ def program
156
+ (/(\/|\\)/ =~ $0) ? File.basename($0) : $0
157
+ end
158
+
159
+ # Set where we print.
160
+ def target=(target)
161
+ @@target = target
162
+ end
163
+
164
+ # Where do we print?
165
+ def target
166
+ @@target
167
+ end
168
+
169
+ public
170
+ # Fake puts
171
+ def puts(str = nil)
172
+ str = '' if str.nil?
173
+ print(str + "\n")
174
+ end
175
+
176
+ # Fake printf
177
+ def printf(format, *args)
178
+ print(sprintf(format, *args))
179
+ end
180
+
181
+ # Fake print -- just add to target, which may not be STDOUT.
182
+ def print(str)
183
+ target << str
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,231 @@
1
+ $VERBOSE = nil
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_helper')
4
+
5
+ require "choice"
6
+
7
+ class TestChoice < Test::Unit::TestCase
8
+
9
+ def setup
10
+ Choice.reset!
11
+ Choice.dont_exit_on_help = true
12
+ Choice.send(:class_variable_set, '@@choices', true)
13
+ end
14
+
15
+ def test_choices
16
+ Choice.options do
17
+ header "Tell me about yourself?"
18
+ header ""
19
+ option :band do
20
+ short "-b"
21
+ long "--band=BAND"
22
+ cast String
23
+ desc "Your favorite band."
24
+ validate /\w+/
25
+ end
26
+ option :animal do
27
+ short "-a"
28
+ long "--animal=ANIMAL"
29
+ cast String
30
+ desc "Your favorite animal."
31
+ end
32
+ footer ""
33
+ footer "--help This message"
34
+ end
35
+
36
+ band = 'LedZeppelin'
37
+ animal = 'Reindeer'
38
+
39
+ args = ['-b', band, "--animal=#{animal}"]
40
+ Choice.args = args
41
+
42
+ assert_equal band, Choice.choices['band']
43
+ assert_equal animal, Choice.choices[:animal]
44
+ assert_equal ["Tell me about yourself?", ""], Choice.header
45
+ assert_equal ["", "--help This message"], Choice.footer
46
+ end
47
+
48
+ def test_failed_parse
49
+ assert Hash.new, Choice.parse
50
+ end
51
+
52
+ HELP_STRING = ''
53
+ def test_help
54
+ Choice.output_to(HELP_STRING)
55
+
56
+ Choice.options do
57
+ banner "Usage: choice [-mu]"
58
+ header ""
59
+ option :meal do
60
+ short '-m'
61
+ desc 'Your favorite meal.'
62
+ end
63
+
64
+ separator ""
65
+ separator "And you eat it with..."
66
+
67
+ option :utencil do
68
+ short "-u"
69
+ long "--utencil[=UTENCIL]"
70
+ desc "Your favorite eating utencil."
71
+ end
72
+ end
73
+
74
+ Choice.args = ['-m', 'lunch', '--help']
75
+
76
+ help_string = <<-HELP
77
+ Usage: choice [-mu]
78
+
79
+ -m Your favorite meal.
80
+
81
+ And you eat it with...
82
+ -u, --utencil[=UTENCIL] Your favorite eating utencil.
83
+ HELP
84
+
85
+ assert_equal help_string, HELP_STRING
86
+ end
87
+
88
+ UNKNOWN_STRING = ''
89
+ def test_unknown_argument
90
+ Choice.output_to(UNKNOWN_STRING)
91
+
92
+ Choice.options do
93
+ banner "Usage: choice [-mu]"
94
+ header ""
95
+ option :meal do
96
+ short '-m'
97
+ desc 'Your favorite meal.'
98
+ end
99
+
100
+ separator ""
101
+ separator "And you eat it with..."
102
+
103
+ option :utencil do
104
+ short "-u"
105
+ long "--utencil[=UTENCIL]"
106
+ desc "Your favorite eating utencil."
107
+ end
108
+ end
109
+
110
+ Choice.args = ['-m', 'lunch', '--motorcycles']
111
+
112
+ help_string = <<-HELP
113
+ Usage: choice [-mu]
114
+
115
+ -m Your favorite meal.
116
+
117
+ And you eat it with...
118
+ -u, --utencil[=UTENCIL] Your favorite eating utencil.
119
+ HELP
120
+
121
+ assert_equal help_string, UNKNOWN_STRING
122
+ end
123
+
124
+ REQUIRED_STRING = ''
125
+ def test_required_argument
126
+ Choice.output_to(REQUIRED_STRING)
127
+
128
+ Choice.options do
129
+ banner "Usage: choice [-mu]"
130
+ header ""
131
+ option :meal, :required => true do
132
+ short '-m'
133
+ desc 'Your favorite meal.'
134
+ end
135
+
136
+ separator ""
137
+ separator "And you eat it with..."
138
+
139
+ option :utencil do
140
+ short "-u"
141
+ long "--utencil[=UTENCIL]"
142
+ desc "Your favorite eating utencil."
143
+ end
144
+ end
145
+
146
+ Choice.args = ['-u', 'spork']
147
+
148
+ help_string = <<-HELP
149
+ Usage: choice [-mu]
150
+
151
+ -m Your favorite meal.
152
+
153
+ And you eat it with...
154
+ -u, --utencil[=UTENCIL] Your favorite eating utencil.
155
+ HELP
156
+
157
+ assert_equal help_string, REQUIRED_STRING
158
+ end
159
+
160
+ def test_shorthand_choices
161
+ Choice.options do
162
+ header "Tell me about yourself?"
163
+ header ""
164
+ options :band => { :short => "-b", :long => "--band=BAND", :cast => String, :desc => ["Your favorite band.", "Something cool."],
165
+ :validate => /\w+/ },
166
+ :animal => { :short => "-a", :long => "--animal=ANIMAL", :cast => String, :desc => "Your favorite animal." }
167
+
168
+ footer ""
169
+ footer "--help This message"
170
+ end
171
+
172
+ band = 'LedZeppelin'
173
+ animal = 'Reindeer'
174
+
175
+ args = ['-b', band, "--animal=#{animal}"]
176
+ Choice.args = args
177
+
178
+ assert_equal band, Choice.choices['band']
179
+ assert_equal animal, Choice.choices[:animal]
180
+ assert_equal ["Tell me about yourself?", ""], Choice.header
181
+ assert_equal ["", "--help This message"], Choice.footer
182
+ end
183
+
184
+ def test_args_of
185
+ suits = %w[clubs diamonds spades hearts]
186
+ stringed_numerics = (1..13).to_a.map { |a| a.to_s }
187
+ valid_cards = stringed_numerics + %w[jack queen king ace]
188
+ cards = {}
189
+ stringed_numerics.each { |n| cards[n] = n }
190
+ cards.merge!('1' => 'ace', '11' => 'jack', '12' => 'queen', '13' => 'king')
191
+
192
+ Choice.options do
193
+ header "Gambling is fun again! Pick a card and a suit (or two), then see if you win!"
194
+ header ""
195
+ header "Options:"
196
+
197
+ option :suit, :required => true do
198
+ short '-s'
199
+ long '--suit *SUITS'
200
+ desc "The suit you wish to choose. Required. You can pass in more than one, even."
201
+ desc " Valid suits: #{suits * ' '}"
202
+ valid suits
203
+ end
204
+
205
+ separator ''
206
+
207
+ option :card, :required => true do
208
+ short '-c'
209
+ long '--card CARD'
210
+ desc "The card you wish to gamble on. Required. Only one, please."
211
+ desc " Valid cards: 1 - 13, jack, queen, king, ace"
212
+ valid valid_cards
213
+ cast String
214
+ end
215
+
216
+ #cheat! to test --option=
217
+ option :autowin do
218
+ short '-a'
219
+ long '--autowin=PLAYER'
220
+ desc 'The person who should automatically win every time'
221
+ desc 'Beware: raises the suspitions of other players'
222
+ end
223
+ end
224
+
225
+ args = ["-c", "king", "--suit", "clubs", "diamonds", "spades", "hearts", "--autowin", "Grant"]
226
+ Choice.args = args
227
+ assert_equal ["king"], Choice.args_of("-c")
228
+ assert_equal ["clubs", "diamonds", "spades", "hearts"], Choice.args_of("--suit")
229
+ assert_equal ["Grant"], Choice.args_of("--autowin")
230
+ end
231
+ end
@@ -0,0 +1,77 @@
1
+
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_helper')
3
+
4
+ require 'choice/lazyhash'
5
+
6
+ class TestLazyHash < Test::Unit::TestCase
7
+
8
+ def test_symbol
9
+ name = 'Igor'
10
+ age = 41
11
+
12
+ hash = Choice::LazyHash.new
13
+ hash['name'] = name
14
+ hash[:age] = age
15
+
16
+ assert_equal name, hash[:name]
17
+ assert_equal age, hash[:age]
18
+ end
19
+
20
+ def test_string
21
+ name = "Frank Stein"
22
+ age = 30
23
+
24
+ hash = Choice::LazyHash.new
25
+ hash[:name] = name
26
+ hash['age'] = age
27
+
28
+ assert_equal name, hash['name']
29
+ assert_equal age, hash['age']
30
+ end
31
+
32
+ def test_store_and_fetch
33
+ name = 'Jimini Jeremiah'
34
+ job = 'Interior Decorator'
35
+
36
+ hash = Choice::LazyHash.new
37
+ hash.store('name', name)
38
+ hash.store(:job, job)
39
+
40
+ assert_equal name, hash.fetch(:name)
41
+ assert_equal job, hash.fetch('job')
42
+ end
43
+
44
+ def test_messages
45
+ star = 'Sol'
46
+ planet = 'Mars'
47
+
48
+ hash = Choice::LazyHash.new
49
+ hash.star = star
50
+ hash.planet = planet
51
+
52
+ assert_equal star, hash.star
53
+ assert_equal planet, hash.planet
54
+ end
55
+
56
+ def test_from_hash
57
+ state = 'Nebraska'
58
+ country = 'Mexico'
59
+
60
+ hash = { :state => state, :country => country }
61
+ lazy = Choice::LazyHash.new(hash)
62
+
63
+ assert_equal state, lazy['state']
64
+ assert_equal country, lazy[:country]
65
+ end
66
+
67
+ def test_to_lazyhash
68
+ hash = { :name => 'Jimmy', :age => 25 }
69
+ lazy = hash.to_lazyhash
70
+
71
+ assert_equal hash[:name], lazy.name
72
+ assert_equal hash[:name], lazy[:name]
73
+ assert_equal hash[:age], lazy.age
74
+ assert_equal hash[:age], lazy[:age]
75
+ end
76
+
77
+ end