rbcurse-core 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/README.md +69 -0
  2. data/VERSION +1 -0
  3. data/examples/abasiclist.rb +151 -0
  4. data/examples/alpmenu.rb +46 -0
  5. data/examples/app.sample +17 -0
  6. data/examples/atree.rb +100 -0
  7. data/examples/common/file.rb +45 -0
  8. data/examples/data/README.markdown +9 -0
  9. data/examples/data/brew.txt +38 -0
  10. data/examples/data/color.2 +37 -0
  11. data/examples/data/gemlist.txt +60 -0
  12. data/examples/data/lotr.txt +12 -0
  13. data/examples/data/ports.txt +136 -0
  14. data/examples/data/table.txt +37 -0
  15. data/examples/data/tasks.csv +88 -0
  16. data/examples/data/tasks.txt +27 -0
  17. data/examples/data/todo.txt +10 -0
  18. data/examples/data/todocsv.csv +28 -0
  19. data/examples/data/unix1.txt +21 -0
  20. data/examples/data/unix2.txt +11 -0
  21. data/examples/dbdemo.rb +487 -0
  22. data/examples/dirtree.rb +90 -0
  23. data/examples/newtabbedwindow.rb +100 -0
  24. data/examples/newtesttabp.rb +92 -0
  25. data/examples/tabular.rb +132 -0
  26. data/examples/tasks.rb +167 -0
  27. data/examples/term2.rb +83 -0
  28. data/examples/testkeypress.rb +72 -0
  29. data/examples/testlistbox.rb +158 -0
  30. data/examples/testmessagebox.rb +140 -0
  31. data/examples/testree.rb +106 -0
  32. data/examples/testwsshortcuts.rb +66 -0
  33. data/examples/testwsshortcuts2.rb +127 -0
  34. data/lib/rbcurse.rb +8 -0
  35. data/lib/rbcurse/core/docs/index.txt +73 -0
  36. data/lib/rbcurse/core/include/action.rb +40 -0
  37. data/lib/rbcurse/core/include/appmethods.rb +112 -0
  38. data/lib/rbcurse/core/include/bordertitle.rb +41 -0
  39. data/lib/rbcurse/core/include/chunk.rb +182 -0
  40. data/lib/rbcurse/core/include/io.rb +953 -0
  41. data/lib/rbcurse/core/include/listcellrenderer.rb +140 -0
  42. data/lib/rbcurse/core/include/listeditable.rb +317 -0
  43. data/lib/rbcurse/core/include/listscrollable.rb +590 -0
  44. data/lib/rbcurse/core/include/listselectable.rb +264 -0
  45. data/lib/rbcurse/core/include/multibuffer.rb +83 -0
  46. data/lib/rbcurse/core/include/orderedhash.rb +77 -0
  47. data/lib/rbcurse/core/include/ractionevent.rb +67 -0
  48. data/lib/rbcurse/core/include/rchangeevent.rb +27 -0
  49. data/lib/rbcurse/core/include/rhistory.rb +62 -0
  50. data/lib/rbcurse/core/include/rinputdataevent.rb +47 -0
  51. data/lib/rbcurse/core/include/vieditable.rb +170 -0
  52. data/lib/rbcurse/core/system/colormap.rb +163 -0
  53. data/lib/rbcurse/core/system/keyboard.rb +150 -0
  54. data/lib/rbcurse/core/system/keydefs.rb +30 -0
  55. data/lib/rbcurse/core/system/ncurses.rb +218 -0
  56. data/lib/rbcurse/core/system/panel.rb +162 -0
  57. data/lib/rbcurse/core/system/window.rb +901 -0
  58. data/lib/rbcurse/core/util/ansiparser.rb +117 -0
  59. data/lib/rbcurse/core/util/app.rb +1235 -0
  60. data/lib/rbcurse/core/util/basestack.rb +407 -0
  61. data/lib/rbcurse/core/util/bottomline.rb +1850 -0
  62. data/lib/rbcurse/core/util/colorparser.rb +71 -0
  63. data/lib/rbcurse/core/util/focusmanager.rb +31 -0
  64. data/lib/rbcurse/core/util/padreader.rb +189 -0
  65. data/lib/rbcurse/core/util/rcommandwindow.rb +587 -0
  66. data/lib/rbcurse/core/util/rdialogs.rb +619 -0
  67. data/lib/rbcurse/core/util/viewer.rb +149 -0
  68. data/lib/rbcurse/core/util/widgetshortcuts.rb +505 -0
  69. data/lib/rbcurse/core/widgets/applicationheader.rb +102 -0
  70. data/lib/rbcurse/core/widgets/box.rb +58 -0
  71. data/lib/rbcurse/core/widgets/divider.rb +310 -0
  72. data/lib/rbcurse/core/widgets/keylabelprinter.rb +178 -0
  73. data/lib/rbcurse/core/widgets/rcombo.rb +238 -0
  74. data/lib/rbcurse/core/widgets/rcontainer.rb +415 -0
  75. data/lib/rbcurse/core/widgets/rlink.rb +30 -0
  76. data/lib/rbcurse/core/widgets/rlist.rb +723 -0
  77. data/lib/rbcurse/core/widgets/rmenu.rb +939 -0
  78. data/lib/rbcurse/core/widgets/rmenulink.rb +22 -0
  79. data/lib/rbcurse/core/widgets/rmessagebox.rb +373 -0
  80. data/lib/rbcurse/core/widgets/rprogress.rb +118 -0
  81. data/lib/rbcurse/core/widgets/rtabbedpane.rb +615 -0
  82. data/lib/rbcurse/core/widgets/rtabbedwindow.rb +68 -0
  83. data/lib/rbcurse/core/widgets/rtextarea.rb +920 -0
  84. data/lib/rbcurse/core/widgets/rtextview.rb +780 -0
  85. data/lib/rbcurse/core/widgets/rtree.rb +787 -0
  86. data/lib/rbcurse/core/widgets/rwidget.rb +3040 -0
  87. data/lib/rbcurse/core/widgets/scrollbar.rb +143 -0
  88. data/lib/rbcurse/core/widgets/statusline.rb +94 -0
  89. data/lib/rbcurse/core/widgets/tabular.rb +264 -0
  90. data/lib/rbcurse/core/widgets/tabularwidget.rb +1211 -0
  91. data/lib/rbcurse/core/widgets/textpad.rb +516 -0
  92. data/lib/rbcurse/core/widgets/tree/treecellrenderer.rb +150 -0
  93. data/lib/rbcurse/core/widgets/tree/treemodel.rb +428 -0
  94. metadata +156 -0
@@ -0,0 +1,143 @@
1
+ require 'rbcurse/core/util/app'
2
+ #include Ncurses # FFI 2011-09-8
3
+ include RubyCurses
4
+
5
+ # This paints a vertical white bar given row and col, and length. It also calculates and prints
6
+ # a small bar over this based on relaetd objects list.length and current_index.
7
+ # Typically, after setup one would keep updating only current_index from the repaint method
8
+ # of caller or in the traversal event. This would look best if the listbox also has a reverse video border, or none.
9
+ # @example
10
+ # lb = list_box ....
11
+ # sb = Scrollbar.new @form, :row => lb.row, :col => lb.col, :length => lb.height, :list_length => lb.row_count, :current_index => 0
12
+ # .... later as user traverses
13
+ # sb.current_index = lb.current_index
14
+ # sb = Scrollbar.new @form, :parent => list
15
+ #
16
+ # At a later stage, we will integrate this with lists and tables, so it will happen automatically.
17
+ #
18
+ # @since 1.2.0 UNTESTED
19
+ module RubyCurses
20
+ class Scrollbar < Widget
21
+ # row to start, same as listbox, required.
22
+ dsl_property :row
23
+ # column to start, same as listbox, required.
24
+ dsl_property :col
25
+ # how many rows is this (should be same as listboxes height, required.
26
+ dsl_property :length
27
+ # vertical or horizontal currently only VERTICAL
28
+ dsl_property :orientation
29
+ # initialize based on parent's values
30
+ dsl_property :parent
31
+ # which row is focussed, current_index of listbox, required.
32
+ dsl_property :current_index
33
+ # how many total rows of data does the list have, same as @list.length, required.
34
+ dsl_property :list_length
35
+
36
+ # TODO: if parent passed, we shold bind to ON_ENTER and get current_index, so no extra work is required.
37
+
38
+ def initialize form, config={}, &block
39
+
40
+ # setting default first or else Widget will place its BW default
41
+ #@color, @bgcolor = ColorMap.get_colors_for_pair $bottomcolor
42
+ super
43
+ @color_pair = get_color $datacolor, @color, @bgcolor
44
+ @scroll_pair = get_color $bottomcolor, :green, :white
45
+ #$log.debug "SCROLLBAR COLOR cp #{@color_pair} sp #{@scroll_pair} " if $log.debug?
46
+ @window = form.window
47
+ @editable = false
48
+ @focusable = false
49
+ @repaint_required = true
50
+ @orientation = :V
51
+ if @parent
52
+ @parent.bind :ENTER_ROW do |p|
53
+ # parent must implement row_count, and have a @current_index
54
+ raise StandardError, "Parent must implement row_count" unless p.respond_to? :row_count
55
+ self.current_index = p.current_index
56
+ @repaint_required = true #requred otherwise at end when same value sent, prop handler
57
+ # will not be fired (due to optimization).
58
+ end
59
+ # in some cases, on leaving a listbox or other component redraws itself to reduce
60
+ # selected or highlighted object, so the scrollbar gets overwritten. We need to repaint it.
61
+ @parent.bind :LEAVE do |p|
62
+ @repaint_required = true
63
+ end
64
+ end
65
+ end
66
+
67
+ ##
68
+ # repaint the scrollbar
69
+ # Taking the data from parent as late as possible in case parent resized, or
70
+ # moved around by a container.
71
+ def repaint
72
+ if @parent
73
+ @row = @parent.row+1
74
+ @col = @parent.col + @parent.width - 1
75
+ @length = @parent.height - 2
76
+ @list_length = @parent.row_count
77
+ @current_index ||= @parent.current_index
78
+ @border_attrib ||= @parent.border_attrib
79
+ end
80
+ raise ArgumentError, "current_index must be provided" unless @current_index
81
+ raise ArgumentError, "list_length must be provided" unless @list_length
82
+ my_win = @form ? @form.window : @target_window
83
+ @graphic = my_win unless @graphic
84
+ return unless @repaint_required
85
+
86
+ # first print a right side vertical line
87
+ #bc = $bottomcolor # dark blue
88
+ bc = $datacolor
89
+ bordercolor = @border_color || bc
90
+ borderatt = @border_attrib || Ncurses::A_REVERSE
91
+ #$log.debug "SCROLL bordercolor #{bordercolor} , #{borderatt} " if $log.debug?
92
+
93
+
94
+ @graphic.attron(Ncurses.COLOR_PAIR(bordercolor) | borderatt)
95
+ #$log.debug " XXX SCROLL #{@row} #{@col} #{@length} "
96
+ @graphic.mvvline(@row+0, @col, 1, @length-0)
97
+ @graphic.attroff(Ncurses.COLOR_PAIR(bordercolor) | borderatt)
98
+
99
+ # now calculate and paint the scrollbar
100
+ pht = @length
101
+ listlen = @list_length * 1.0
102
+ @current_index = 0 if @current_index < 0
103
+ @current_index = listlen-1 if @current_index >= listlen
104
+ sclen = (pht/listlen)* @length
105
+ sclen = 1 if sclen < 1 # sometimes 0.7 for large lists 100 items 2011-10-1
106
+ scloc = (@current_index/listlen)* @length
107
+ scloc = (@length - sclen) if scloc > @length - sclen # don't exceed end
108
+ if @current_index == @list_length - 1
109
+ scloc = @length - sclen + 0 # earlier 1, but removed since sclen min 1 2011-10-1
110
+ end
111
+ @graphic.attron(Ncurses.COLOR_PAIR(@scroll_pair) | borderatt)
112
+ r = @row + scloc
113
+ c = @col + 0
114
+ #$log.debug " XXX SCROLLBAR #{r} #{c} #{sclen} "
115
+ @graphic.mvvline(r, c, 1, sclen)
116
+ @graphic.attroff(Ncurses.COLOR_PAIR(@scroll_pair) | borderatt)
117
+ @repaint_required = false
118
+ end
119
+ ##
120
+ ##
121
+ # ADD HERE
122
+ end
123
+ end
124
+ if __FILE__ == $PROGRAM_NAME
125
+ App.new do
126
+ r = 5
127
+ len = 20
128
+ list = []
129
+ 0.upto(100) { |v| list << "#{v} scrollable data" }
130
+ lb = list_box "A list", :list => list
131
+ #sb = Scrollbar.new @form, :row => r, :col => 20, :length => len, :list_length => 50, :current_index => 0
132
+ rb = Scrollbar.new @form, :parent => lb
133
+ #hline :width => 20, :row => len+r
134
+ #keypress do |ch|
135
+ #case ch
136
+ #when :down
137
+ #sb.current_index += 1
138
+ #when :up
139
+ #sb.current_index -= 1
140
+ #end
141
+ #end
142
+ end
143
+ end
@@ -0,0 +1,94 @@
1
+ require 'rbcurse'
2
+
3
+ module RubyCurses
4
+
5
+ #
6
+ # A vim-like application status bar that can display time and various other statuses
7
+ # at the bottom, typically above the dock (3rd line from last).
8
+ #
9
+ class StatusLine < Widget
10
+
11
+ def initialize form, config={}, &block
12
+ if form.window.height == 0
13
+ @row = Ncurses.LINES-3 # fix, what about smaller windows, use window dimensions and watch out for 0,0
14
+ else
15
+ @row = form.window.height-3 # fix, what about smaller windows, use window dimensions and watch out for 0,0
16
+ end
17
+ # in root windows FIXME
18
+ @col = 0
19
+ super
20
+ @focusable = false
21
+ @editable = false
22
+ @command = nil
23
+ @repaint_required = true
24
+ bind(:PROPERTY_CHANGE) { |e| @color_pair = nil ; }
25
+ end
26
+ #
27
+ # command that returns a string that populates the status line (left aligned)
28
+ # @see :right
29
+ # See dbdemo.rb
30
+ # e.g.
31
+ # @l.command { "%-20s [DB: %-s | %-s ]" % [ Time.now, $current_db || "None", $current_table || "----"] }
32
+ #
33
+ def command *args, &blk
34
+ @command = blk
35
+ @args = args
36
+ end
37
+ alias :left :command
38
+
39
+ #
40
+ # Procudure for text to be right aligned in statusline
41
+ def right *args, &blk
42
+ @right_text = blk
43
+ @right_args = args
44
+ end
45
+
46
+ # NOTE: I have not put a check of repaint_required, so this will print on each key-stroke OR
47
+ # rather whenever form.repaint is called.
48
+ def repaint
49
+ @color_pair ||= get_color($datacolor, @color, @bgcolor)
50
+ len = @form.window.width
51
+ len = Ncurses.COLS if len == 0
52
+
53
+ # first print dashes through
54
+ @form.window.printstring @row, @col, "%s" % "-" * len, @color_pair, Ncurses::A_REVERSE
55
+
56
+ # now call the block to get current values
57
+ if @command
58
+ ftext = @command.call(self, @args)
59
+ else
60
+ status = $status_message ? $status_message.value : ""
61
+ #ftext = " %-20s | %s" % [Time.now, status] # should we print a default value just in case user doesn't
62
+ ftext = status # should we print a default value just in case user doesn't
63
+ end
64
+ if ftext =~ /#\[/
65
+ @form.window.printstring_formatted @row, @col, ftext, $datacolor, Ncurses::A_REVERSE
66
+ else
67
+ @form.window.printstring @row, @col, ftext, $datacolor, Ncurses::A_REVERSE
68
+ end
69
+ # move this to formatted FIXME
70
+ #@form.window.printstring_or_chunks @row, @col, ftext, $datacolor, Ncurses::A_REVERSE
71
+
72
+ if @right_text
73
+ ftext = @right_text.call(self, @right_args)
74
+ if ftext =~ /#\[/
75
+ @form.window.printstring_formatted_right @row, nil, ftext, $datacolor, Ncurses::A_REVERSE
76
+ else
77
+ c = len - ftext.length
78
+ @form.window.printstring @row, c, ftext, $datacolor, Ncurses::A_REVERSE
79
+ end
80
+ else
81
+ t = Time.now
82
+ tt = t.strftime "%F %H:%M:%S"
83
+ ftext = "#[fg=green,bg=blue] %-20s" % [tt] # print a default
84
+ @form.window.printstring_formatted_right @row, nil, ftext, $datacolor, Ncurses::A_REVERSE
85
+ end
86
+
87
+ @repaint_required = false
88
+ end
89
+ def handle_keys ch
90
+ return :UNHANDLED
91
+ end
92
+
93
+ end # class
94
+ end # module
@@ -0,0 +1,264 @@
1
+ #!/usr/bin/env ruby -w
2
+ =begin
3
+ * Name : A Quick take on tabular data. Readonly.
4
+ * Description : To show tabular data inside a control, rather than going by the huge
5
+ Table object, I want to create a simple, minimal table data generator.
6
+ This will be thrown into a TextView for the user to navigate, select
7
+ etc.
8
+ I would use this applications where the tabular data is fairly fixed
9
+ not where i want the user to select columns, move them, expand etc.
10
+ * :
11
+ * Author : rkumar
12
+ * Date :
13
+ * License :
14
+ Same as Ruby's License (http://www.ruby-lang.org/LICENSE.txt)
15
+
16
+ =end
17
+
18
+ #
19
+ # A simple tabular data generator. Given table data in arrays and a column heading row in arrays, it
20
+ # quickely generates tabular data. It only takes left and right alignment of columns into account.
21
+ # You may specify individual column widths. Else it will take the widths of the column names you supply
22
+ # in the startup array. You are encouraged to supply column widths.
23
+ # If no columns are specified, and no widths are given, it take the widths of the first row
24
+ # as a model to determine column widths.
25
+ #
26
+ module RubyCurses
27
+
28
+ class Tabular
29
+ GUESSCOLUMNS = 20
30
+
31
+ def yield_or_eval &block
32
+ return unless block
33
+ if block.arity > 0
34
+ yield self
35
+ else
36
+ self.instance_eval(&block)
37
+ end
38
+ end
39
+ # stores column info internally
40
+ class ColumnInfo < Struct.new(:name, :w, :align)
41
+ end
42
+ # an array of column titles
43
+ attr_reader :columns
44
+ # boolean, does user want lines numbered
45
+ attr_accessor :numbering
46
+ # x is the + character used a field delim in separators
47
+ # y is the field delim used in data rows, default is pipe or bar
48
+ attr_accessor :x, :y
49
+
50
+ # takes first optional argument as array of column names
51
+ # second optional argument as array of data arrays
52
+ # @yield self
53
+ #
54
+ def initialize cols=nil, *args, &block
55
+ @chash = {}
56
+ @cw = {}
57
+ @calign = {}
58
+ @separ = @columns = @numbering = nil
59
+ @y = '|'
60
+ @x = '+'
61
+ self.columns = cols if cols
62
+ if !args.empty?
63
+ puts "ARGS after shift #{args} "
64
+ if !args.empty?
65
+ self.data = args
66
+ end
67
+ end
68
+ yield_or_eval(&block) if block_given?
69
+ end
70
+ #
71
+ # set columns names
72
+ # @param [Array<String>] column names, preferably padded out to width for column
73
+ def columns=(array)
74
+ $log.debug "tabular got columns #{array.count} #{array.inspect} " if $log
75
+ @columns = array
76
+ @columns.each_with_index { |c,i|
77
+ @chash[i] = ColumnInfo.new(c, c.to_s.length)
78
+ @cw[i] ||= c.to_s.length
79
+ #@calign[i] ||= :left # 2011-09-27 prevent setting later on
80
+ }
81
+ end
82
+ alias :headings= :columns=
83
+ #
84
+ # set data as an array of arrays
85
+ # @param [Array<Array>] data as array of arrays
86
+ def data=(list)
87
+ puts "got data: #{list.size} " if !$log
88
+ puts list if !$log
89
+ @list = list
90
+ end
91
+
92
+ # add a row of data
93
+ # @param [Array] an array containing entries for each column
94
+ def add array
95
+ $log.debug "tabular got add #{array.count} #{array.inspect} " if $log
96
+ @list ||= []
97
+ @list << array
98
+ end
99
+ alias :<< :add
100
+ alias :add_row :add
101
+
102
+ # set width of a given column
103
+ # @param [Number] column offset, starting 0
104
+ # @param [Number] width
105
+ def column_width colindex, width
106
+ @cw[colindex] ||= width
107
+ if @chash[colindex].nil?
108
+ @chash[colindex] = ColumnInfo.new("", width)
109
+ else
110
+ @chash[colindex].w = width
111
+ end
112
+ @chash
113
+ end
114
+
115
+ # set alignment of given column offset
116
+ # @param [Number] column offset, starting 0
117
+ # @param [Symbol] :left, :right
118
+ def align_column colindex, lrc
119
+ raise ArgumentError, "wrong alignment value sent" if ![:right, :left, :center].include? lrc
120
+ @calign[colindex] ||= lrc
121
+ if @chash[colindex].nil?
122
+ @chash[colindex] = ColumnInfo.new("", nil, lrc)
123
+ else
124
+ @chash[colindex].align = lrc
125
+ end
126
+ @chash
127
+ end
128
+
129
+ #
130
+ # Now returns an array with formatted data
131
+ # @return [Array<String>] array of formatted data
132
+ def render
133
+ buffer = []
134
+ _guess_col_widths
135
+ rows = @list.size.to_s.length
136
+ @rows = rows
137
+ _prepare_format
138
+
139
+ str = ""
140
+ if @numbering
141
+ str = " "*(rows+1)+@y
142
+ end
143
+ str << @fmstr % @columns
144
+ buffer << str
145
+ #puts "-" * str.length
146
+ buffer << separator
147
+ if @list
148
+ if @numbering
149
+ @fmstr = "%#{rows}d "+ @y + @fmstr
150
+ end
151
+ #@list.each { |e| puts e.join(@y) }
152
+ count = 0
153
+ @list.each_with_index { |r,i|
154
+ value = convert_value_to_text r, count
155
+ buffer << value
156
+ count += 1
157
+ }
158
+ end
159
+ buffer
160
+ end
161
+ def convert_value_to_text r, count
162
+ if r == :separator
163
+ return separator
164
+ end
165
+ if @numbering
166
+ r.insert 0, count+1
167
+ end
168
+ return @fmstr % r;
169
+ end
170
+ # use this for printing out on terminal
171
+ # @example
172
+ # puts t.to_s
173
+ def to_s
174
+ render().join "\n"
175
+ end
176
+ def add_separator
177
+ @list << :separator
178
+ end
179
+ def separator
180
+ return @separ if @separ
181
+ str = ""
182
+ if @numbering
183
+ str = "-"*(@rows+1)+@x
184
+ end
185
+ @cw.each_pair { |k,v| str << "-" * (v+1) + @x }
186
+ @separ = str.chop
187
+ end
188
+ private
189
+ def _guess_col_widths #:nodoc:
190
+ @list.each_with_index { |r, i|
191
+ break if i > GUESSCOLUMNS
192
+ next if r == :separator
193
+ r.each_with_index { |c, j|
194
+ x = c.to_s.length
195
+ if @cw[j].nil?
196
+ @cw[j] = x
197
+ else
198
+ @cw[j] = x if x > @cw[j]
199
+ end
200
+ }
201
+ }
202
+ end
203
+ def _prepare_format #:nodoc:
204
+ @fmtstr = nil
205
+ fmt = []
206
+ @cw.each_with_index { |c, i|
207
+ w = @cw[i]
208
+ case @calign[i]
209
+ when :right
210
+ fmt << "%#{w}s "
211
+ else
212
+ fmt << "%-#{w}s "
213
+ end
214
+ }
215
+ @fmstr = fmt.join(@y)
216
+ puts "format: #{@fmstr} "
217
+ end
218
+ end
219
+ end
220
+
221
+ if __FILE__ == $PROGRAM_NAME
222
+ include RubyCurses
223
+ $log = nil
224
+ t = Tabular.new(['a', 'b'], [1, 2], [3, 4])
225
+ puts t.to_s
226
+ puts
227
+ t = Tabular.new([" Name ", " Number ", " Email "])
228
+ t.add %w{ rahul 32 r@ruby.org }
229
+ t << %w{ _why 133 j@gnu.org }
230
+ t << %w{ Jane 1331 jane@gnu.org }
231
+ t.column_width 1, 10
232
+ t.align_column 1, :right
233
+ puts t.to_s
234
+ puts
235
+
236
+ s = Tabular.new do |b|
237
+ b.columns = %w{ country continent text }
238
+ b << ["india","asia","a warm country" ]
239
+ b << ["japan","asia","a cool country" ]
240
+ b << ["russia","europe","a hot country" ]
241
+ b.column_width 2, 30
242
+ end
243
+ puts s.to_s
244
+ puts
245
+ puts "::::"
246
+ puts
247
+ s = Tabular.new do |b|
248
+ b.columns = %w{ place continent text }
249
+ b << ["india","asia","a warm country" ]
250
+ b << ["japan","asia","a cool country" ]
251
+ b << ["russia","europe","a hot country" ]
252
+ b << ["sydney","australia","a dry country" ]
253
+ b << ["canberra","australia","a dry country" ]
254
+ b << ["ross island","antarctica","a dry country" ]
255
+ b << ["mount terror","antarctica","a windy country" ]
256
+ b << ["mt erebus","antarctica","a cold place" ]
257
+ b << ["siberia","russia","an icy city" ]
258
+ b << ["new york","USA","a fun place" ]
259
+ b.column_width 0, 12
260
+ b.column_width 1, 12
261
+ b.numbering = true
262
+ end
263
+ puts s.to_s
264
+ end