highline 1.6.2 → 1.6.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -70,11 +70,29 @@ class HighLine
70
70
  def []( color_tag )
71
71
  @scheme[to_symbol(color_tag)]
72
72
  end
73
+
74
+ # Retrieve the original form of the scheme
75
+ def definition( color_tag )
76
+ style = @scheme[to_symbol(color_tag)]
77
+ style && style.list
78
+ end
79
+
80
+ # Retrieve the keys in the scheme
81
+ def keys
82
+ @scheme.keys
83
+ end
73
84
 
74
85
  # Allow the scheme to be set like a Hash.
75
86
  def []=( color_tag, constants )
76
- @scheme[to_symbol(color_tag)] = constants.map { |c| to_constant(c) }
87
+ @scheme[to_symbol(color_tag)] = HighLine::Style.new(:name=>color_tag.to_s.downcase.to_sym,
88
+ :list=>constants, :no_index=>true)
89
+ end
90
+
91
+ # Retrieve the color scheme hash (in original definition format)
92
+ def to_hash
93
+ @scheme.inject({}) { |hsh, pair| key, value = pair; hsh[key] = value.list; hsh }
77
94
  end
95
+
78
96
 
79
97
  private
80
98
 
@@ -86,7 +104,7 @@ class HighLine
86
104
  # Return a normalized representation of a color setting.
87
105
  def to_constant( v )
88
106
  v = v.to_s if v.is_a?(Symbol)
89
- if v.is_a?(String) then
107
+ if v.is_a?(::String) then
90
108
  HighLine.const_get(v.upcase)
91
109
  else
92
110
  v
@@ -178,7 +178,7 @@ class HighLine
178
178
  @index = style
179
179
 
180
180
  # Default settings.
181
- if @index == :none or @index.is_a?(String)
181
+ if @index == :none or @index.is_a?(::String)
182
182
  @index_suffix = " "
183
183
  @select_by = :name
184
184
  end
@@ -289,6 +289,7 @@ class HighLine
289
289
  # Pathname:: Same as File, save that a Pathname object is
290
290
  # returned.
291
291
  # String:: Answer is converted with Kernel.String().
292
+ # HighLine::String:: Answer is converted with HighLine::String()
292
293
  # Regexp:: Answer is fed to Regexp.new().
293
294
  # Symbol:: The method to_sym() is called on answer and
294
295
  # the result returned.
@@ -301,6 +302,8 @@ class HighLine
301
302
  def convert( answer_string )
302
303
  if @answer_type.nil?
303
304
  answer_string
305
+ elsif @answer_type == HighLine::String
306
+ HighLine::String(answer_string)
304
307
  elsif [Float, Integer, String].include?(@answer_type)
305
308
  Kernel.send(@answer_type.to_s.to_sym, answer_string)
306
309
  elsif @answer_type == Symbol
@@ -0,0 +1,98 @@
1
+ # Extensions for class String
2
+ #
3
+ # HighLine::String is a subclass of String with convenience methods added for colorization.
4
+ #
5
+ # Available convenience methods include:
6
+ # * 'color' method e.g. highline_string.color(:bright_blue, :underline)
7
+ # * colors e.g. highline_string.magenta
8
+ # * RGB colors e.g. highline_string.rgb_ff6000
9
+ # or highline_string.rgb(255,96,0)
10
+ # * background colors e.g. highline_string.on_magenta
11
+ # * RGB background colors e.g. highline_string.on_rgb_ff6000
12
+ # or highline_string.on_rgb(255,96,0)
13
+ # * styles e.g. highline_string.underline
14
+ #
15
+ # Additionally, convenience methods can be chained, for instance the following are equivalent:
16
+ # highline_string.bright_blue.blink.underline
17
+ # highline_string.color(:bright_blue, :blink, :underline)
18
+ # HighLine.color(highline_string, :bright_blue, :blink, :underline)
19
+ #
20
+ # For those less squeamish about possible conflicts, the same convenience methods can be
21
+ # added to the builtin String class, as follows:
22
+ #
23
+ # require 'highline'
24
+ # Highline.colorize_strings
25
+
26
+ class HighLine
27
+ def self.String(s)
28
+ HighLine::String.new(s)
29
+ end
30
+
31
+ module StringExtensions
32
+ def self.included(base)
33
+ HighLine::COLORS.each do |color|
34
+ base.class_eval <<-END
35
+ def #{color.downcase}
36
+ color(:#{color.downcase})
37
+ end
38
+ END
39
+ base.class_eval <<-END
40
+ def on_#{color.downcase}
41
+ on(:#{color.downcase})
42
+ end
43
+ END
44
+ HighLine::STYLES.each do |style|
45
+ base.class_eval <<-END
46
+ def #{style.downcase}
47
+ color(:#{style.downcase})
48
+ end
49
+ END
50
+ end
51
+ end
52
+
53
+ base.class_eval do
54
+ def color(*args)
55
+ self.class.new(HighLine.color(self, *args))
56
+ end
57
+ alias_method :foreground, :color
58
+
59
+ def on(arg)
60
+ color(('on_' + arg.to_s).to_sym)
61
+ end
62
+
63
+ def uncolor
64
+ self.class.new(HighLine.uncolor(self))
65
+ end
66
+
67
+ def rgb(*colors)
68
+ color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
69
+ raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
70
+ color("rgb_#{color_code}".to_sym)
71
+ end
72
+
73
+ def on_rgb(*colors)
74
+ color_code = colors.map{|color| color.is_a?(Numeric) ? '%02x'%color : color.to_s}.join
75
+ raise "Bad RGB color #{colors.inspect}" unless color_code =~ /^[a-fA-F0-9]{6}/
76
+ color("on_rgb_#{color_code}".to_sym)
77
+ end
78
+
79
+ # TODO Chain existing method_missing
80
+ def method_missing(method, *args, &blk)
81
+ if method.to_s =~ /^(on_)?rgb_([0-9a-fA-F]{6})$/
82
+ color(method)
83
+ else
84
+ raise NoMethodError, "undefined method `#{method}' for #<#{self.class}:#{'%#x'%self.object_id}>"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ class HighLine::String < ::String
92
+ include StringExtensions
93
+ end
94
+
95
+ def self.colorize_strings
96
+ ::String.send(:include, StringExtensions)
97
+ end
98
+ end
@@ -0,0 +1,184 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # color_scheme.rb
4
+ #
5
+ # Created by Richard LeBer on 2011-06-27.
6
+ # Copyright 2011. All rights reserved
7
+ #
8
+ # This is Free Software. See LICENSE and COPYING for details
9
+
10
+ class HighLine
11
+
12
+ def self.Style(*args)
13
+ args = args.compact.flatten
14
+ if args.size==1
15
+ arg = args.first
16
+ if arg.is_a?(Style)
17
+ Style.list[arg.name] || Style.index(arg)
18
+ elsif arg.is_a?(::String) && arg =~ /^\e\[/ # arg is a code
19
+ if styles = Style.code_index[arg]
20
+ styles.first
21
+ else
22
+ Style.new(:code=>arg)
23
+ end
24
+ elsif style = Style.list[arg]
25
+ style
26
+ elsif HighLine.color_scheme && HighLine.color_scheme[arg]
27
+ HighLine.color_scheme[arg]
28
+ elsif arg.is_a?(Hash)
29
+ Style.new(arg)
30
+ elsif arg.to_s.downcase =~ /^rgb_([a-f0-9]{6})$/
31
+ Style.rgb($1)
32
+ elsif arg.to_s.downcase =~ /^on_rgb_([a-f0-9]{6})$/
33
+ Style.rgb($1).on
34
+ else
35
+ raise NameError, "#{arg.inspect} is not a defined Style"
36
+ end
37
+ else
38
+ name = args
39
+ Style.list[name] || Style.new(:list=>args)
40
+ end
41
+ end
42
+
43
+ class Style
44
+
45
+ def self.index(style)
46
+ if style.name
47
+ @@styles ||= {}
48
+ @@styles[style.name] = style
49
+ end
50
+ if !style.list
51
+ @@code_index ||= {}
52
+ @@code_index[style.code] ||= []
53
+ @@code_index[style.code].reject!{|indexed_style| indexed_style.name == style.name}
54
+ @@code_index[style.code] << style
55
+ end
56
+ style
57
+ end
58
+
59
+ def self.rgb_hex(*colors)
60
+ colors.map do |color|
61
+ color.is_a?(Numeric) ? '%02x'%color : color.to_s
62
+ end.join
63
+ end
64
+
65
+ def self.rgb_parts(hex)
66
+ hex.scan(/../).map{|part| part.to_i(16)}
67
+ end
68
+
69
+ def self.rgb(*colors)
70
+ hex = rgb_hex(*colors)
71
+ name = ('rgb_' + hex).to_sym
72
+ if style = list[name]
73
+ style
74
+ else
75
+ parts = rgb_parts(hex)
76
+ new(:name=>name, :code=>"\e[38;5;#{rgb_number(parts)}m", :rgb=>parts)
77
+ end
78
+ end
79
+
80
+ def self.rgb_number(*parts)
81
+ parts = parts.flatten
82
+ 16 + parts.inject(0) {|kode, part| kode*6 + (part/256.0*6.0).floor}
83
+ end
84
+
85
+ def self.ansi_rgb_to_hex(ansi_number)
86
+ raise "Invalid ANSI rgb code #{ansi_number}" unless (16..231).include?(ansi_number)
87
+ parts = (ansi_number-16).to_s(6).rjust(3,'0').scan(/./).map{|d| (d.to_i*255.0/6.0).ceil}
88
+ rgb_hex(*parts)
89
+ end
90
+
91
+ def self.list
92
+ @@styles ||= {}
93
+ end
94
+
95
+ def self.code_index
96
+ @@code_index ||= {}
97
+ end
98
+
99
+ def self.uncolor(string)
100
+ string.gsub(/\e\[\d+(;\d+)*m/, '')
101
+ end
102
+
103
+ attr_reader :name, :code, :list
104
+ attr_accessor :rgb, :builtin
105
+
106
+ # Single color/styles have :name, :code, :rgb (possibly), :builtin
107
+ # Compound styles have :name, :list, :builtin
108
+ def initialize(defn = {})
109
+ @definition = defn
110
+ @name = defn[:name]
111
+ @code = defn[:code]
112
+ @rgb = defn[:rgb]
113
+ @list = defn[:list]
114
+ @builtin = defn[:builtin]
115
+ if @rgb
116
+ hex = self.class.rgb_hex(@rgb)
117
+ rgb = self.class.rgb_parts(hex)
118
+ @name ||= 'rgb_' + hex
119
+ elsif @list
120
+ @name ||= @list
121
+ end
122
+ self.class.index self unless defn[:no_index]
123
+ end
124
+
125
+ def dup
126
+ self.class.new(@definition)
127
+ end
128
+
129
+ def to_hash
130
+ @definition
131
+ end
132
+
133
+ def color(string)
134
+ code + string + HighLine::CLEAR
135
+ end
136
+
137
+ def code
138
+ if @list
139
+ @list.map{|element| HighLine.Style(element).code}.join
140
+ else
141
+ @code
142
+ end
143
+ end
144
+
145
+ def red
146
+ @rgb && @rgb[0]
147
+ end
148
+
149
+ def green
150
+ @rgb && @rgb[1]
151
+ end
152
+
153
+ def blue
154
+ @rgb && @rgb[2]
155
+ end
156
+
157
+ def variant(new_name, options={})
158
+ raise "Cannot create a variant of a style list (#{inspect})" if @list
159
+ new_code = options[:code] || code
160
+ if options[:increment]
161
+ raise "Unexpected code in #{inspect}" unless new_code =~ /^(.*?)(\d+)(.*)/
162
+ new_code = $1 + ($2.to_i + options[:increment]).to_s + $3
163
+ end
164
+ new_rgb = options[:rgb] || @rgb
165
+ new_style = self.class.new(self.to_hash.merge(:name=>new_name, :code=>new_code, :rgb=>new_rgb))
166
+ end
167
+
168
+ def on
169
+ new_name = ('on_'+@name.to_s).to_sym
170
+ self.class.list[new_name] ||= variant(new_name, :increment=>10)
171
+ end
172
+
173
+ def bright
174
+ raise "Cannot create a bright variant of a style list (#{inspect})" if @list
175
+ new_name = ('bright_'+@name.to_s).to_sym
176
+ if style = self.class.list[new_name]
177
+ style
178
+ else
179
+ new_rgb = @rgb == [0,0,0] ? [128, 128, 128] : @rgb.map {|color| color==0 ? 0 : [color+128,255].min }
180
+ variant(new_name, :increment=>60, :rgb=>new_rgb)
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,34 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # string_methods.rb
4
+ #
5
+ # Created by Richard LeBer 2011-06-27
6
+ #
7
+ # This is Free Software. See LICENSE and COPYING for details.
8
+ #
9
+ # String class convenience methods
10
+
11
+ module StringMethods
12
+ def test_color
13
+ assert_equal("\e[34mstring\e[0m", @string.color(:blue))
14
+ assert_equal("\e[1m\e[47mstring\e[0m", @string.color(:bold,:on_white))
15
+ assert_equal("\e[45mstring\e[0m", @string.on(:magenta))
16
+ assert_equal("\e[36mstring\e[0m", @string.cyan)
17
+ assert_equal("\e[41m\e[5mstring\e[0m\e[0m", @string.blink.on_red)
18
+ assert_equal("\e[38;5;137mstring\e[0m", @string.color(:rgb_906030))
19
+ assert_equal("\e[38;5;101mstring\e[0m", @string.rgb('606030'))
20
+ assert_equal("\e[38;5;107mstring\e[0m", @string.rgb('60','90','30'))
21
+ assert_equal("\e[38;5;107mstring\e[0m", @string.rgb(96,144,48))
22
+ assert_equal("\e[38;5;173mstring\e[0m", @string.rgb_c06030)
23
+ assert_equal("\e[48;5;137mstring\e[0m", @string.color(:on_rgb_906030))
24
+ assert_equal("\e[48;5;101mstring\e[0m", @string.on_rgb('606030'))
25
+ assert_equal("\e[48;5;107mstring\e[0m", @string.on_rgb('60','90','30'))
26
+ assert_equal("\e[48;5;107mstring\e[0m", @string.on_rgb(96,144,48))
27
+ assert_equal("\e[48;5;173mstring\e[0m", @string.on_rgb_c06030)
28
+ end
29
+
30
+ def test_uncolor
31
+ colored_string = HighLine::String("\e[38;5;137mstring\e[0m")
32
+ assert_equal "string", colored_string.uncolor
33
+ end
34
+ end
@@ -46,6 +46,48 @@ class TestColorScheme < Test::Unit::TestCase
46
46
  @terminal.say("This should be <%= color('warning yellow', 'WarNing') %>.")
47
47
  assert_equal("This should be \e[1m\e[33mwarning yellow\e[0m.\n",@output.string)
48
48
  @output.rewind
49
+
50
+ # Check that keys are available, and as expected
51
+ assert_equal ["critical", "error", "warning", "notice", "info", "debug", "row_even", "row_odd"].sort,
52
+ HighLine.color_scheme.keys.sort
53
+
54
+ # Color scheme doesn't care if we use symbols or strings, and is case-insensitive
55
+ warning1 = HighLine.color_scheme[:warning]
56
+ warning2 = HighLine.color_scheme["warning"]
57
+ warning3 = HighLine.color_scheme[:wArning]
58
+ warning4 = HighLine.color_scheme["warniNg"]
59
+ assert_instance_of HighLine::Style, warning1
60
+ assert_instance_of HighLine::Style, warning2
61
+ assert_instance_of HighLine::Style, warning3
62
+ assert_instance_of HighLine::Style, warning4
63
+ assert_equal warning1, warning2
64
+ assert_equal warning1, warning3
65
+ assert_equal warning1, warning4
66
+
67
+ # Nonexistent keys return nil
68
+ assert_nil HighLine.color_scheme[:nonexistent]
69
+
70
+ # Same as above, for definitions
71
+ defn1 = HighLine.color_scheme.definition(:warning)
72
+ defn2 = HighLine.color_scheme.definition("warning")
73
+ defn3 = HighLine.color_scheme.definition(:wArning)
74
+ defn4 = HighLine.color_scheme.definition("warniNg")
75
+ assert_instance_of Array, defn1
76
+ assert_instance_of Array, defn2
77
+ assert_instance_of Array, defn3
78
+ assert_instance_of Array, defn4
79
+ assert_equal [:bold, :yellow], defn1
80
+ assert_equal [:bold, :yellow], defn2
81
+ assert_equal [:bold, :yellow], defn3
82
+ assert_equal [:bold, :yellow], defn4
83
+ assert_nil HighLine.color_scheme.definition(:nonexistent)
84
+
85
+ color_scheme_hash = HighLine.color_scheme.to_hash
86
+ assert_instance_of Hash, color_scheme_hash
87
+ assert_equal ["critical", "error", "warning", "notice", "info", "debug", "row_even", "row_odd"].sort,
88
+ color_scheme_hash.keys.sort
89
+ assert_instance_of Array, HighLine.color_scheme.definition(:warning)
90
+ assert_equal [:bold, :yellow], HighLine.color_scheme.definition(:warning)
49
91
 
50
92
  # turn it back off, should raise an exception
51
93
  HighLine.color_scheme = @old_color_scheme
@@ -198,6 +198,28 @@ class TestHighLine < Test::Unit::TestCase
198
198
 
199
199
  @output.truncate(@output.rewind)
200
200
 
201
+ @terminal.say("This should be <%= NONE %>none<%= CLEAR %>!")
202
+ assert_equal("This should be \e[38mnone\e[0m!\n", @output.string)
203
+
204
+ @output.truncate(@output.rewind)
205
+
206
+ @terminal.say("This should be <%= RGB_906030 %>rgb_906030<%= CLEAR %>!")
207
+ assert_equal("This should be \e[38;5;137mrgb_906030\e[0m!\n", @output.string)
208
+
209
+ @output.truncate(@output.rewind)
210
+
211
+ @terminal.say("This should be <%= ON_RGB_C06030 %>on_rgb_c06030<%= CLEAR %>!")
212
+ assert_equal("This should be \e[48;5;173mon_rgb_c06030\e[0m!\n", @output.string)
213
+
214
+ @output.truncate(@output.rewind)
215
+
216
+ # Does class method work, too?
217
+ @terminal.say("This should be <%= HighLine.color('reverse underlined magenta', :reverse, :underline, :magenta) %>!")
218
+ assert_equal( "This should be \e[7m\e[4m\e[35mreverse underlined magenta\e[0m!\n",
219
+ @output.string )
220
+
221
+ @output.truncate(@output.rewind)
222
+
201
223
  # turn off color
202
224
  old_setting = HighLine.use_color?
203
225
  assert_nothing_raised(Exception) { HighLine.use_color = false }
@@ -205,6 +227,27 @@ class TestHighLine < Test::Unit::TestCase
205
227
  assert_equal("This should be cyan!\n", @output.string)
206
228
  HighLine.use_color = old_setting
207
229
  end
230
+
231
+ def test_uncolor
232
+ # instance method
233
+ assert_equal( "This should be reverse underlined magenta!\n",
234
+ @terminal.uncolor("This should be \e[7m\e[4m\e[35mreverse underlined magenta\e[0m!\n")
235
+ )
236
+
237
+ @output.truncate(@output.rewind)
238
+
239
+ # class method
240
+ assert_equal( "This should be reverse underlined magenta!\n",
241
+ HighLine.uncolor("This should be \e[7m\e[4m\e[35mreverse underlined magenta\e[0m!\n")
242
+ )
243
+
244
+ @output.truncate(@output.rewind)
245
+
246
+ # RGB color
247
+ assert_equal( "This should be rgb_906030!\n",
248
+ @terminal.uncolor("This should be \e[38;5;137mrgb_906030\e[0m!\n")
249
+ )
250
+ end
208
251
 
209
252
  def test_confirm
210
253
  @input << "junk.txt\nno\nsave.txt\ny\n"
@@ -284,6 +327,9 @@ class TestHighLine < Test::Unit::TestCase
284
327
  def test_files
285
328
  @input << "#{File.basename(__FILE__)[0, 5]}\n"
286
329
  @input.rewind
330
+
331
+ assert_equal "tc_hi\n",@input.read
332
+ @input.rewind
287
333
 
288
334
  file = @terminal.ask("Select a file: ", File) do |q|
289
335
  q.directory = File.expand_path(File.dirname(__FILE__))
@@ -342,8 +388,8 @@ class TestHighLine < Test::Unit::TestCase
342
388
  answers )
343
389
  assert_equal("Age: Father's Age: Wife's Age: ", @output.string)
344
390
  end
345
-
346
- def test_lists
391
+
392
+ def test_lists
347
393
  digits = %w{Zero One Two Three Four Five Six Seven Eight Nine}
348
394
  erb_digits = digits.dup
349
395
  erb_digits[erb_digits.index("Five")] = "<%= color('Five', :blue) %%>"
@@ -368,7 +414,7 @@ class TestHighLine < Test::Unit::TestCase
368
414
  @terminal.say("<%= list(#{digits.inspect}, :columns_down, 3) %>")
369
415
  assert_equal( "Zero Four Eight\n" +
370
416
  "One Five Nine \n" +
371
- "Two Six \n" +
417
+ "Two Six \n" +
372
418
  "Three Seven\n",
373
419
  @output.string )
374
420
 
@@ -387,7 +433,7 @@ class TestHighLine < Test::Unit::TestCase
387
433
 
388
434
  @terminal.say("<%= list(#{colums_of_twenty.inspect}, :columns_down) %>")
389
435
  assert_equal( "12345678901234567890 12345678901234567890 " +
390
- "12345678901234567890\n" +
436
+ "12345678901234567890\n" +
391
437
  "12345678901234567890 12345678901234567890\n",
392
438
  @output.string )
393
439
 
@@ -409,6 +455,89 @@ class TestHighLine < Test::Unit::TestCase
409
455
  "12345678901234567890\n" +
410
456
  "12345678901234567890\n",
411
457
  @output.string )
458
+
459
+ @output.truncate(@output.rewind)
460
+
461
+ wide = %w[0123456789 a b c d e f g h i j k l m n o p q r s t u v w x y z]
462
+
463
+ @terminal.say("<%= list( #{wide.inspect}, :uneven_columns_across ) %>")
464
+ assert_equal( "0123456789 a b c d e f g h i j k l m n o " +
465
+ "p q r s t u v w\n" +
466
+ "x y z\n",
467
+ @output.string )
468
+
469
+ @output.truncate(@output.rewind)
470
+
471
+ @terminal.say("<%= list( #{wide.inspect}, :uneven_columns_across, 10 ) %>")
472
+ assert_equal( "0123456789 a b c d e f g h i\n" +
473
+ "j k l m n o p q r s\n" +
474
+ "t u v w x y z\n",
475
+ @output.string )
476
+
477
+ @output.truncate(@output.rewind)
478
+
479
+ @terminal.say("<%= list( #{wide.inspect}, :uneven_columns_down ) %>")
480
+ assert_equal( "0123456789 b d f h j l n p r t v x z\n" +
481
+ "a c e g i k m o q s u w y\n",
482
+ @output.string )
483
+
484
+ @output.truncate(@output.rewind)
485
+
486
+ @terminal.say("<%= list( #{wide.inspect}, :uneven_columns_down, 10 ) %>")
487
+ assert_equal( "0123456789 c f i l o r u x\n" +
488
+ "a d g j m p s v y\n" +
489
+ "b e h k n q t w z\n",
490
+ @output.string )
491
+ end
492
+
493
+ def test_lists_with_zero_items
494
+ modes = [nil, :rows, :inline, :columns_across, :columns_down]
495
+ modes.each do |mode|
496
+ result = @terminal.list([], mode)
497
+ assert_equal("", result)
498
+ end
499
+ end
500
+
501
+ def test_lists_with_one_item
502
+ items = ['Zero']
503
+ modes = { nil => "Zero\n",
504
+ :rows => "Zero\n",
505
+ :inline => "Zero",
506
+ :columns_across => "Zero\n",
507
+ :columns_down => "Zero\n" }
508
+
509
+ modes.each do |mode, expected|
510
+ result = @terminal.list(items, mode)
511
+ assert_equal(expected, result)
512
+ end
513
+ end
514
+
515
+ def test_lists_with_two_items
516
+ items = ['Zero', 'One']
517
+ modes = { nil => "Zero\nOne\n",
518
+ :rows => "Zero\nOne\n",
519
+ :inline => "Zero or One",
520
+ :columns_across => "Zero One \n",
521
+ :columns_down => "Zero One \n" }
522
+
523
+ modes.each do |mode, expected|
524
+ result = @terminal.list(items, mode)
525
+ assert_equal(expected, result)
526
+ end
527
+ end
528
+
529
+ def test_lists_with_three_items
530
+ items = ['Zero', 'One', 'Two']
531
+ modes = { nil => "Zero\nOne\nTwo\n",
532
+ :rows => "Zero\nOne\nTwo\n",
533
+ :inline => "Zero, One or Two",
534
+ :columns_across => "Zero One Two \n",
535
+ :columns_down => "Zero One Two \n" }
536
+
537
+ modes.each do |mode, expected|
538
+ result = @terminal.list(items, mode)
539
+ assert_equal(expected, result)
540
+ end
412
541
  end
413
542
 
414
543
  def test_mode