s0nspark-choice 0.1.4

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.
@@ -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