text-table 1.0.0

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 ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## NETBEANS
17
+ nbproject
18
+
19
+ ## PROJECT::GENERAL
20
+ coverage
21
+ rdoc
22
+ pkg
23
+
24
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Aaron Tinio
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,171 @@
1
+ = text-table
2
+
3
+ A feature-rich, easy-to-use plain text table formatter.
4
+
5
+
6
+ == Introduction
7
+
8
+ Allows you to easily create and format plain text tables,
9
+ useful when working with the terminal
10
+ or when you want to quickly print formatted tables to a dot-matrix printer.
11
+
12
+ This project was heavily inspired by visionmedia's terminal-table, and to a lesser-extent, by prawn, ruport and hirb.
13
+ I initially wanted to add more features to terminal-table (footer, separators between rows, etc)
14
+ and to fix a then alignment issue with spanned columns.
15
+ Instead of forking terminal-table, I've decided to start a new project primarily as an exercise,
16
+ and to be able to model-out the classes differently.
17
+
18
+
19
+ == Install
20
+
21
+ If you haven't yet,
22
+
23
+ gem install gemcutter
24
+ gem tubmle
25
+
26
+ Then,
27
+
28
+ gem install text-table
29
+
30
+
31
+ == Calling the <tt>to_text_table</tt> Method
32
+
33
+ Just call the <tt>to_text_table</tt> method on Arrays (and other Enumerables).
34
+
35
+ require 'rubygems'
36
+ require 'text-table'
37
+
38
+ array = [
39
+ ['Student', 'Mid-Terms', 'Finals'],
40
+ ['Sam', 94, 93],
41
+ ['Jane', 92, 99],
42
+ ['Average', 93, 96]
43
+ ]
44
+
45
+ puts array.to_text_table
46
+
47
+ # +---------+-----------+--------+
48
+ # | Student | Mid-Terms | Finals |
49
+ # | Sam | 94 | 93 |
50
+ # | Jane | 92 | 99 |
51
+ # | Average | 93 | 96 |
52
+ # +---------+-----------+--------+
53
+
54
+ You could specify that the first row is the table heading.
55
+
56
+ puts array.to_text_table(:first_row_is_head => true)
57
+
58
+ # +---------+-----------+--------+
59
+ # | Student | Mid-Terms | Finals |
60
+ # +---------+-----------+--------+
61
+ # | Sam | 94 | 93 |
62
+ # | Jane | 92 | 99 |
63
+ # | Average | 93 | 96 |
64
+ # +---------+-----------+--------+
65
+
66
+ You could also specify that the last row is the table footer.
67
+
68
+ puts array.to_text_table(:first_row_is_head => true, :last_row_is_foot => true)
69
+
70
+ # +---------+-----------+--------+
71
+ # | Student | Mid-Terms | Finals |
72
+ # +---------+-----------+--------+
73
+ # | Sam | 94 | 93 |
74
+ # | Jane | 92 | 99 |
75
+ # +---------+-----------+--------+
76
+ # | Average | 93 | 96 |
77
+ # +---------+-----------+--------+
78
+
79
+
80
+ == Creating a New Text::Table Object
81
+
82
+ You could create a Text::Table object by passing an options hash:
83
+
84
+ table = Text::Table.new(:head => ['A', 'B'], :rows => [['a1', 'b1'], ['a2', 'b2']])
85
+
86
+ Or by passing a block:
87
+
88
+ table = Text::Table.new do |t|
89
+ t.head = ['A', 'B']
90
+ t.rows = [['a1', 'b1']]
91
+ t.rows << ['a2', 'b2']
92
+ end
93
+
94
+ table.to_s
95
+
96
+ # +----+----+
97
+ # | A | B |
98
+ # +----+----+
99
+ # | a1 | b1 |
100
+ # | a2 | b2 |
101
+ # +----+----+
102
+
103
+
104
+ == Aligning Cells and Spanning Columns
105
+
106
+ Alignment and column span can be specified by passing a cell as a Hash object.
107
+ The acceptable aligments are <tt>:left</tt> (default), <tt>:center</tt> and <tt>:right</tt>.
108
+
109
+ table = Text::Table.new do |t|
110
+ t.head = ['Heading A', 'Heading B']
111
+ t.rows = []
112
+ t.rows << ['a1', 'b1']
113
+ t.rows << ['a2', {:value => 'b2', :align => :right}]
114
+ t.rows << ['a3', 'b3']
115
+ t.rows << [{:value => 'a4', :colspan => 2, :align => :center}]
116
+ end
117
+
118
+ puts table
119
+
120
+ # +-----------+-----------+
121
+ # | Heading A | Heading B |
122
+ # +-----------+-----------+
123
+ # | a1 | b1 |
124
+ # | a2 | b2 |
125
+ # | a3 | b3 |
126
+ # | a4 |
127
+ # +-----------+-----------+
128
+
129
+
130
+ == Adding a Separator
131
+
132
+ You can add a separator by inserting <tt>:separator</tt> symbols between the rows.
133
+
134
+ Text::Table.new :rows => [
135
+ ['a', 'b'],
136
+ ['c', 'd'],
137
+ :separator,
138
+ ['e', 'f'],
139
+ :separator,
140
+ ['g', 'h']
141
+ ]
142
+
143
+ # +---+---+
144
+ # | a | b |
145
+ # | c | d |
146
+ # +---+---+
147
+ # | e | f |
148
+ # +---+---+
149
+ # | g | h |
150
+ # +---+---+
151
+
152
+
153
+ == Other Options
154
+
155
+ Cell padding and table boundaries can be modified.
156
+
157
+ Text::Table.new :rows => [['a', 'b'], ['c', 'd']],
158
+ :horizontal_padding => 3,
159
+ :vertical_boundary => '=',
160
+ :horizontal_boundary => ':',
161
+ :boundary_intersection => 'O'
162
+
163
+ # O=======O=======O
164
+ # : a : b :
165
+ # : c : d :
166
+ # O=======O=======O
167
+
168
+
169
+ == Copyright
170
+
171
+ Copyright (c) 2009 Aaron Tinio. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "text-table"
8
+ gem.summary = %Q{A feature-rich, easy-to-use plain text table formatter.}
9
+ gem.description = %Q{Allows you to easily create and format plain text tables, useful when working with the terminal or when you want to quickly print formatted tables to a dot-matrix printer.}
10
+ gem.email = "aptinio@yahoo.com"
11
+ gem.homepage = "http://github.com/aptinio/text-table"
12
+ gem.authors = ["Aaron Tinio"]
13
+ gem.add_development_dependency "rspec", ">= 1.2.9"
14
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'spec/rake/spectask'
22
+ Spec::Rake::SpecTask.new(:spec) do |spec|
23
+ spec.libs << 'lib' << 'spec'
24
+ spec.spec_files = FileList['spec/**/*_spec.rb']
25
+ end
26
+
27
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.pattern = 'spec/**/*_spec.rb'
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "text-table #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/lib/text-table.rb ADDED
@@ -0,0 +1,3 @@
1
+ %w(table row cell enumerable).each do |lib|
2
+ require File.join(File.dirname(__FILE__), 'text-table', lib)
3
+ end
@@ -0,0 +1,51 @@
1
+ module Text #:nodoc:
2
+ class Table
3
+ class Cell
4
+
5
+ # The object whose <tt>to_s</tt> method is called when rendering the cell.
6
+ #
7
+ attr_accessor :value
8
+
9
+ # Text alignment. Acceptable values are <tt>:left</tt> (default),
10
+ # <tt>:center</tt> and <tt>:right</tt>
11
+ #
12
+ attr_accessor :align
13
+
14
+ # Positive integer specifying the number of columns spanned
15
+ #
16
+ attr_accessor :colspan
17
+ attr_reader :row #:nodoc:
18
+
19
+ def initialize(options = {}) #:nodoc:
20
+ @value = options[:value].to_s
21
+ @row = options[:row]
22
+ @align = options[:align ] || :left
23
+ @colspan = options[:colspan] || 1
24
+ end
25
+
26
+ def to_s #:nodoc:
27
+ ([' ' * table.horizontal_padding]*2).join case align
28
+ when :left
29
+ value.ljust cell_width
30
+ when :right
31
+ value.rjust cell_width
32
+ when :center
33
+ value.center cell_width
34
+ end
35
+ end
36
+
37
+ def table #:nodoc:
38
+ row.table
39
+ end
40
+
41
+ def column_index #:nodoc:
42
+ row.cells[0...row.cells.index(self)].map(&:colspan).reduce(0, :+)
43
+ end
44
+
45
+ def cell_width #:nodoc:
46
+ colspan.times.map {|i| table.column_widths[column_index + i]}.reduce(:+) + (colspan - 1)*(2*table.horizontal_padding + table.horizontal_boundary.length)
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,58 @@
1
+ module Enumerable
2
+
3
+ # Returns a new Text::Table object with the elements as the rows.
4
+ #
5
+ # ==== Options
6
+ # <tt>:first_row_is_head</tt>:: when set to <tt>true</tt>, the first row becomes the table heading
7
+ # <tt>:last_row_is_foot</tt>:: when set to <tt>true</tt>, the last row becomes the table footer
8
+ #
9
+ # ==== Examples
10
+ #
11
+ # require 'rubygems'
12
+ # require 'text-table'
13
+ #
14
+ # array = [
15
+ # ['Student', 'Mid-Terms', 'Finals'],
16
+ # ['Sam', 94, 93],
17
+ # ['Jane', 92, 99],
18
+ # ['Average', 93, 96]
19
+ # ]
20
+ #
21
+ # puts array.to_text_table
22
+ #
23
+ # # +---------+-----------+--------+
24
+ # # | Student | Mid-Terms | Finals |
25
+ # # | Sam | 94 | 93 |
26
+ # # | Jane | 92 | 99 |
27
+ # # | Average | 93 | 96 |
28
+ # # +---------+-----------+--------+
29
+ #
30
+ # puts array.to_text_table(:first_row_is_head => true)
31
+ #
32
+ # # +---------+-----------+--------+
33
+ # # | Student | Mid-Terms | Finals |
34
+ # # +---------+-----------+--------+
35
+ # # | Sam | 94 | 93 |
36
+ # # | Jane | 92 | 99 |
37
+ # # | Average | 93 | 96 |
38
+ # # +---------+-----------+--------+
39
+ #
40
+ # puts array.to_text_table(:first_row_is_head => true, :last_row_is_foot => true)
41
+ #
42
+ # # +---------+-----------+--------+
43
+ # # | Student | Mid-Terms | Finals |
44
+ # # +---------+-----------+--------+
45
+ # # | Sam | 94 | 93 |
46
+ # # | Jane | 92 | 99 |
47
+ # # +---------+-----------+--------+
48
+ # # | Average | 93 | 96 |
49
+ # # +---------+-----------+--------+
50
+ #
51
+ def to_text_table(options = {})
52
+ table = Text::Table.new :rows => self.to_a.dup
53
+ table.head = table.rows.shift if options[:first_row_is_head]
54
+ table.foot = table.rows.pop if options[:last_row_is_foot]
55
+ table
56
+ end
57
+ alias_method :to_table, :to_text_table unless method_defined? :to_table
58
+ end
@@ -0,0 +1,31 @@
1
+ module Text #:nodoc:
2
+ class Table
3
+
4
+ # A Text::Table::Row belongs to a Text::Table object and can have many Text::Table::Cell objects.
5
+ # It handles the rendering of rows and inserted separators.
6
+ #
7
+ class Row
8
+ attr_reader :table #:nodoc:
9
+ attr_reader :cells #:nodoc:
10
+
11
+ def initialize(row_input, table) #:nodoc:
12
+ @table = table
13
+ row_input = [row_input].flatten
14
+ @cells = row_input.first == :separator ? :separator : row_input.map do |cell_input|
15
+ Cell.new(cell_input.is_a?(Hash) ? cell_input.merge(:row => self) : {:value => cell_input}.merge(:row => self))
16
+ end
17
+ end
18
+
19
+ def to_s #:nodoc:
20
+ if cells == :separator
21
+ table.separator
22
+ else
23
+ ([table.horizontal_boundary] * 2).join(
24
+ cells.map(&:to_s).join table.horizontal_boundary
25
+ ) + "\n"
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,170 @@
1
+ module Text #:nodoc:
2
+ class Table
3
+
4
+ # An array of table headers
5
+ #
6
+ attr_accessor :head
7
+
8
+ # An array of arrays (rows or separators)
9
+ #
10
+ attr_accessor :rows
11
+
12
+ # An array representing the foot of the table
13
+
14
+ attr_accessor :foot
15
+
16
+ # The vertical boundary. Default is "<tt>-</tt>"
17
+ #
18
+ attr_accessor :vertical_boundary
19
+
20
+ # The horizontal boundary. Default is "<tt>|</tt>"
21
+ #
22
+ attr_accessor :horizontal_boundary
23
+
24
+ # The boundary intersection. Default is "<tt>+</tt>"
25
+ #
26
+ attr_accessor :boundary_intersection
27
+
28
+ # The amount of padding (spaces) added to the left and right of cell contents. Default is <tt>1</tt>
29
+ #
30
+ attr_accessor :horizontal_padding
31
+
32
+ # You could create a Text::Table object by passing an options hash:
33
+ #
34
+ # table = Text::Table.new(:head => ['A', 'B'], :rows => [['a1', 'b1'], ['a2', 'b2']])
35
+ #
36
+ # Or by passing a block:
37
+ #
38
+ # table = Text::Table.new do |t|
39
+ # t.head = ['A', 'B']
40
+ # t.rows = [['a1', 'b1']]
41
+ # t.rows << ['a2', 'b2']
42
+ # end
43
+ #
44
+ # table.to_s
45
+ #
46
+ # # +----+----+
47
+ # # | A | B |
48
+ # # +----+----+
49
+ # # | a1 | b1 |
50
+ # # | a2 | b2 |
51
+ # # +----+----+
52
+ #
53
+ #
54
+ # ==== Aligning Cells and Spanning Columns
55
+ #
56
+ # Alignment and column span can be specified by passing a cell as a Hash object.
57
+ # The acceptable aligments are <tt>:left</tt> (default), <tt>:center</tt> and <tt>:right</tt>.
58
+ #
59
+ # table = Text::Table.new do |t|
60
+ # t.head = ['Heading A', 'Heading B']
61
+ # t.rows = []
62
+ # t.rows << ['a1', 'b1']
63
+ # t.rows << ['a2', {:value => 'b2', :align => :right}]
64
+ # t.rows << ['a3', 'b3']
65
+ # t.rows << [{:value => 'a4', :colspan => 2, :align => :center}]
66
+ # end
67
+ #
68
+ # puts table
69
+ #
70
+ # # +-----------+-----------+
71
+ # # | Heading A | Heading B |
72
+ # # +-----------+-----------+
73
+ # # | a1 | b1 |
74
+ # # | a2 | b2 |
75
+ # # | a3 | b3 |
76
+ # # | a4 |
77
+ # # +-----------+-----------+
78
+ #
79
+ #
80
+ # ==== Adding a Separator
81
+ #
82
+ # You can add a separator by inserting <tt>:separator</tt> symbols between the rows.
83
+ #
84
+ # Text::Table.new :rows => [
85
+ # ['a', 'b'],
86
+ # ['c', 'd'],
87
+ # :separator,
88
+ # ['e', 'f'],
89
+ # :separator,
90
+ # ['g', 'h']
91
+ # ]
92
+ #
93
+ # # +---+---+
94
+ # # | a | b |
95
+ # # | c | d |
96
+ # # +---+---+
97
+ # # | e | f |
98
+ # # +---+---+
99
+ # # | g | h |
100
+ # # +---+---+
101
+ #
102
+ #
103
+ # ==== Other Options
104
+ #
105
+ # Cell padding and table boundaries can be modified.
106
+ #
107
+ # Text::Table.new :rows => [['a', 'b'], ['c', 'd']],
108
+ # :horizontal_padding => 3,
109
+ # :vertical_boundary => '=',
110
+ # :horizontal_boundary => ':',
111
+ # :boundary_intersection => 'O'
112
+ #
113
+ # # O=======O=======O
114
+ # # : a : b :
115
+ # # : c : d :
116
+ # # O=======O=======O
117
+ #
118
+ def initialize(options = {})
119
+ @vertical_boundary = options[:vertical_boundary ] || '-'
120
+ @horizontal_boundary = options[:horizontal_boundary ] || '|'
121
+ @boundary_intersection = options[:boundary_intersection] || '+'
122
+ @horizontal_padding = options[:horizontal_padding ] || 1
123
+ @head = options[:head]
124
+ @rows = options[:rows]
125
+ @foot = options[:foot]
126
+ yield self if block_given?
127
+ end
128
+
129
+ def text_table_rows #:nodoc:
130
+ rows.to_a.map {|row_input| Row.new(row_input, self)}
131
+ end
132
+
133
+ def text_table_head #:nodoc:
134
+ Row.new(head, self) if head
135
+ end
136
+
137
+ def text_table_foot #:nodoc:
138
+ Row.new(foot, self) if foot
139
+ end
140
+
141
+ def all_text_table_rows #:nodoc:
142
+ all = text_table_rows
143
+ all.unshift text_table_head if head
144
+ all << text_table_foot if foot
145
+ all
146
+ end
147
+
148
+ def column_widths #:nodoc:
149
+ all_text_table_rows.reject {|row| row.cells == :separator}.map do |row|
150
+ row.cells.map {|cell| [(cell.value.length/cell.colspan.to_f).ceil] * cell.colspan}.flatten
151
+ end.transpose.map(&:max)
152
+ end
153
+
154
+ def separator #:nodoc:
155
+ ([@boundary_intersection] * 2).join(
156
+ column_widths.map {|column_width| @vertical_boundary * (column_width + 2*@horizontal_padding)}.join @boundary_intersection
157
+ ) + "\n"
158
+ end
159
+
160
+ # Renders a pretty plain-text table.
161
+ #
162
+ def to_s
163
+ rendered_rows = [separator] + text_table_rows.map(&:to_s) + [separator]
164
+ rendered_rows.unshift [separator, text_table_head.to_s] if head
165
+ rendered_rows << [text_table_foot.to_s, separator] if foot
166
+ rendered_rows.join
167
+ end
168
+
169
+ end
170
+ end
data/spec/cell_spec.rb ADDED
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Text::Table::Cell do
4
+ before(:each) do
5
+ @table = Text::Table.new :rows => [[1, {:value => 2, :colspan => 2}, 3]]
6
+ @cell = @table.text_table_rows.first.cells.first
7
+ end
8
+
9
+ it "should be left justified by default" do
10
+ @cell.align.should == :left
11
+ end
12
+
13
+ it "should span 1 column by default" do
14
+ @cell.colspan == 1
15
+ end
16
+
17
+ it "should return correct column index" do
18
+ @table.text_table_rows.first.cells[0].column_index.should == 0
19
+ @table.text_table_rows.first.cells[1].column_index.should == 1
20
+ @table.text_table_rows.first.cells[2].column_index.should == 3
21
+ end
22
+
23
+ end
24
+
@@ -0,0 +1,95 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Enumerable do
4
+ before(:each) do
5
+ @arr = [
6
+ [11, 2, 3333],
7
+ [44, 56, 6],
8
+ [7, 888, 99],
9
+ ]
10
+ @hsh = {
11
+ :k => 'vv',
12
+ :kk => 'v',
13
+ 'k' => :vv
14
+ }
15
+ end
16
+
17
+ describe Array do
18
+ it "to Text::Table" do
19
+ @arr.to_text_table.to_s.should == <<-EOS.deindent
20
+ +----+-----+------+
21
+ | 11 | 2 | 3333 |
22
+ | 44 | 56 | 6 |
23
+ | 7 | 888 | 99 |
24
+ +----+-----+------+
25
+ EOS
26
+ end
27
+
28
+ it "to Text::Table using flat array" do
29
+ [11, 44, 7].to_text_table.to_s.should == <<-EOS.deindent
30
+ +----+
31
+ | 11 |
32
+ | 44 |
33
+ | 7 |
34
+ +----+
35
+ EOS
36
+ end
37
+
38
+ it "to Text::Table, setting first row as head" do
39
+ @arr.to_text_table(:first_row_is_head => true).to_s.should == <<-EOS.deindent
40
+ +----+-----+------+
41
+ | 11 | 2 | 3333 |
42
+ +----+-----+------+
43
+ | 44 | 56 | 6 |
44
+ | 7 | 888 | 99 |
45
+ +----+-----+------+
46
+ EOS
47
+ end
48
+
49
+ it "to Text::Table, setting last row as foot" do
50
+ @arr.to_text_table(:last_row_is_foot => true).to_s.should == <<-EOS.deindent
51
+ +----+-----+------+
52
+ | 11 | 2 | 3333 |
53
+ | 44 | 56 | 6 |
54
+ +----+-----+------+
55
+ | 7 | 888 | 99 |
56
+ +----+-----+------+
57
+ EOS
58
+ end
59
+ end
60
+
61
+ describe Hash do
62
+ it "to Text::Table" do
63
+ @hsh.to_text_table.to_s.should == <<-EOS.deindent
64
+ +----+----+
65
+ | k | vv |
66
+ | kk | v |
67
+ | k | vv |
68
+ +----+----+
69
+ EOS
70
+ end
71
+
72
+ it "to Text::Table, setting first row as head" do
73
+ @hsh.to_text_table(:first_row_is_head => true).to_s.should == <<-EOS.deindent
74
+ +----+----+
75
+ | k | vv |
76
+ +----+----+
77
+ | kk | v |
78
+ | k | vv |
79
+ +----+----+
80
+ EOS
81
+ end
82
+
83
+ it "to Text::Table, setting last row as foot" do
84
+ @hsh.to_text_table(:last_row_is_foot => true).to_s.should == <<-EOS.deindent
85
+ +----+----+
86
+ | k | vv |
87
+ | kk | v |
88
+ +----+----+
89
+ | k | vv |
90
+ +----+----+
91
+ EOS
92
+ end
93
+ end
94
+ end
95
+
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,15 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'text-table'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
10
+
11
+ class String
12
+ def deindent
13
+ gsub /^[ \t]*/, ''
14
+ end
15
+ end
@@ -0,0 +1,349 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Text::Table do
4
+ before(:each) do
5
+ @rows = [
6
+ [11, 2, 3333],
7
+ [44, 56, 6],
8
+ [7, 888, 99],
9
+ ]
10
+ @head = %w( a b c )
11
+ @foot = %w( x y z )
12
+ @table = Text::Table.new :rows => @rows, :head => @head
13
+ end
14
+
15
+ it "should accept rows" do
16
+ @table = Text::Table.new :rows => @rows
17
+ @table.rows.should == @rows
18
+ end
19
+
20
+ it 'should allow setting of rows inside a block' do
21
+ @table = Text::Table.new do |t|
22
+ t.rows = @rows
23
+ end
24
+ @table.rows.should == @rows
25
+ end
26
+
27
+ it 'should accept rows with options' do
28
+ @table = Text::Table.new :rows => @rows, :horizontal_padding => 2
29
+ @table.rows.should == @rows
30
+ @table.horizontal_padding.should == 2
31
+ end
32
+
33
+ it 'should allow setting of options inside a block' do
34
+ @table = Text::Table.new do |t|
35
+ t.horizontal_padding = 2
36
+ end
37
+ @table.horizontal_padding.should == 2
38
+ end
39
+
40
+ it 'should determine the proper column widths' do
41
+ @table.column_widths.should == [2, 3, 4]
42
+ end
43
+
44
+ it 'should render tables with no headings properly' do
45
+ @table = Text::Table.new :rows => @rows
46
+ @table.to_s.should == <<-EOS.deindent
47
+ +----+-----+------+
48
+ | 11 | 2 | 3333 |
49
+ | 44 | 56 | 6 |
50
+ | 7 | 888 | 99 |
51
+ +----+-----+------+
52
+ EOS
53
+ end
54
+
55
+ it 'should render tables with headings properly' do
56
+ @table.to_s.should == <<-EOS.deindent
57
+ +----+-----+------+
58
+ | a | b | c |
59
+ +----+-----+------+
60
+ | 11 | 2 | 3333 |
61
+ | 44 | 56 | 6 |
62
+ | 7 | 888 | 99 |
63
+ +----+-----+------+
64
+ EOS
65
+ end
66
+
67
+ it 'should render tables with footers properly' do
68
+ @table.foot = @foot
69
+ @table.to_s.should == <<-EOS.deindent
70
+ +----+-----+------+
71
+ | a | b | c |
72
+ +----+-----+------+
73
+ | 11 | 2 | 3333 |
74
+ | 44 | 56 | 6 |
75
+ | 7 | 888 | 99 |
76
+ +----+-----+------+
77
+ | x | y | z |
78
+ +----+-----+------+
79
+ EOS
80
+ end
81
+
82
+ it 'should render tables with centered headings properly' do
83
+ @table = Text::Table.new :rows => @rows, :head => [
84
+ {:value => 'a', :align => :center},
85
+ {:value => 'b', :align => :center},
86
+ {:value => 'c', :align => :center},
87
+ ]
88
+ @table.to_s.should == <<-EOS.deindent
89
+ +----+-----+------+
90
+ | a | b | c |
91
+ +----+-----+------+
92
+ | 11 | 2 | 3333 |
93
+ | 44 | 56 | 6 |
94
+ | 7 | 888 | 99 |
95
+ +----+-----+------+
96
+ EOS
97
+ end
98
+
99
+ it 'should render tables with right-justified headings properly' do
100
+ @table = Text::Table.new :rows => @rows, :head => [
101
+ {:value => 'a', :align => :right},
102
+ {:value => 'b', :align => :right},
103
+ {:value => 'c', :align => :right},
104
+ ]
105
+ @table.to_s.should == <<-EOS.deindent
106
+ +----+-----+------+
107
+ | a | b | c |
108
+ +----+-----+------+
109
+ | 11 | 2 | 3333 |
110
+ | 44 | 56 | 6 |
111
+ | 7 | 888 | 99 |
112
+ +----+-----+------+
113
+ EOS
114
+ end
115
+
116
+ it 'should render tables with centered cells properly' do
117
+ @table = Text::Table.new :head => @head, :rows => @rows.map{|row| row.map{|cell| {:value => cell, :align => :center}}}
118
+ @table.to_s.should == <<-EOS.deindent
119
+ +----+-----+------+
120
+ | a | b | c |
121
+ +----+-----+------+
122
+ | 11 | 2 | 3333 |
123
+ | 44 | 56 | 6 |
124
+ | 7 | 888 | 99 |
125
+ +----+-----+------+
126
+ EOS
127
+ end
128
+
129
+ it 'should render tables with right-justified cells properly' do
130
+ @table = Text::Table.new :head => @head, :rows => @rows.map{|row| row.map{|cell| {:value => cell, :align => :right}}}
131
+ @table.to_s.should == <<-EOS.deindent
132
+ +----+-----+------+
133
+ | a | b | c |
134
+ +----+-----+------+
135
+ | 11 | 2 | 3333 |
136
+ | 44 | 56 | 6 |
137
+ | 7 | 888 | 99 |
138
+ +----+-----+------+
139
+ EOS
140
+ end
141
+
142
+ it 'should render rows with cells spanning 2 columns' do
143
+ @table = Text::Table.new :rows => @rows
144
+ @table.rows << [1, {:value => 2, :colspan => 2}]
145
+ @table.to_s.should == <<-EOS.deindent
146
+ +----+-----+------+
147
+ | 11 | 2 | 3333 |
148
+ | 44 | 56 | 6 |
149
+ | 7 | 888 | 99 |
150
+ | 1 | 2 |
151
+ +----+-----+------+
152
+ EOS
153
+ end
154
+
155
+ it 'should render rows with 1st cell spanning 2 columns' do
156
+ @table = Text::Table.new :rows => @rows
157
+ @table.rows << [{:value => 333, :colspan => 2}, 1]
158
+ @table.to_s.should == <<-EOS.deindent
159
+ +----+-----+------+
160
+ | 11 | 2 | 3333 |
161
+ | 44 | 56 | 6 |
162
+ | 7 | 888 | 99 |
163
+ | 333 | 1 |
164
+ +----+-----+------+
165
+ EOS
166
+ end
167
+
168
+ it 'should render rows with cells spanning 3 columns' do
169
+ @table = Text::Table.new :rows => @rows
170
+ @table.rows << [{:value => 333, :colspan => 3}]
171
+ @table.to_s.should == <<-EOS.deindent
172
+ +----+-----+------+
173
+ | 11 | 2 | 3333 |
174
+ | 44 | 56 | 6 |
175
+ | 7 | 888 | 99 |
176
+ | 333 |
177
+ +----+-----+------+
178
+ EOS
179
+ end
180
+
181
+ it 'should render rows with centered cells spanning 2 columns' do
182
+ @table = Text::Table.new :rows => @rows
183
+ @table.rows << [1, {:value => 2, :colspan => 2, :align => :center}]
184
+ @table.to_s.should == <<-EOS.deindent
185
+ +----+-----+------+
186
+ | 11 | 2 | 3333 |
187
+ | 44 | 56 | 6 |
188
+ | 7 | 888 | 99 |
189
+ | 1 | 2 |
190
+ +----+-----+------+
191
+ EOS
192
+ end
193
+
194
+ it 'should render rows with 1st cell spanning 2 columns' do
195
+ @table = Text::Table.new :rows => @rows
196
+ @table.rows << [{:value => 333, :colspan => 2, :align => :center}, 1]
197
+ @table.to_s.should == <<-EOS.deindent
198
+ +----+-----+------+
199
+ | 11 | 2 | 3333 |
200
+ | 44 | 56 | 6 |
201
+ | 7 | 888 | 99 |
202
+ | 333 | 1 |
203
+ +----+-----+------+
204
+ EOS
205
+ end
206
+
207
+ it 'should render rows with centered cells spanning 3 columns' do
208
+ @table = Text::Table.new :rows => @rows
209
+ @table.rows << [{:value => 333, :colspan => 3, :align => :center}]
210
+ @table.to_s.should == <<-EOS.deindent
211
+ +----+-----+------+
212
+ | 11 | 2 | 3333 |
213
+ | 44 | 56 | 6 |
214
+ | 7 | 888 | 99 |
215
+ | 333 |
216
+ +----+-----+------+
217
+ EOS
218
+ end
219
+
220
+ it 'should render rows with right-justified cells spanning 2 columns' do
221
+ @table = Text::Table.new :rows => @rows
222
+ @table.rows << [1, {:value => 2, :colspan => 2, :align => :right}]
223
+ @table.to_s.should == <<-EOS.deindent
224
+ +----+-----+------+
225
+ | 11 | 2 | 3333 |
226
+ | 44 | 56 | 6 |
227
+ | 7 | 888 | 99 |
228
+ | 1 | 2 |
229
+ +----+-----+------+
230
+ EOS
231
+ end
232
+
233
+ it 'should render rows with 1st cell spanning 2 columns' do
234
+ @table = Text::Table.new :rows => @rows
235
+ @table.rows << [{:value => 333, :colspan => 2, :align => :right}, 1]
236
+ @table.to_s.should == <<-EOS.deindent
237
+ +----+-----+------+
238
+ | 11 | 2 | 3333 |
239
+ | 44 | 56 | 6 |
240
+ | 7 | 888 | 99 |
241
+ | 333 | 1 |
242
+ +----+-----+------+
243
+ EOS
244
+ end
245
+
246
+ it 'should render rows with right-justified cells spanning 3 columns' do
247
+ @table = Text::Table.new :rows => @rows
248
+ @table.rows << [{:value => 333, :colspan => 3, :align => :right}]
249
+ @table.to_s.should == <<-EOS.deindent
250
+ +----+-----+------+
251
+ | 11 | 2 | 3333 |
252
+ | 44 | 56 | 6 |
253
+ | 7 | 888 | 99 |
254
+ | 333 |
255
+ +----+-----+------+
256
+ EOS
257
+ end
258
+
259
+ it "should allow adding of separators between rows" do
260
+ @table = Text::Table.new :rows => @rows
261
+ @table.rows << :separator
262
+ @table.rows << [1, 2, 3]
263
+ @table.rows << :separator
264
+ @table.rows << [{:value => 5, :colspan => 3, :align => :right}]
265
+ @table.to_s.should == <<-EOS.deindent
266
+ +----+-----+------+
267
+ | 11 | 2 | 3333 |
268
+ | 44 | 56 | 6 |
269
+ | 7 | 888 | 99 |
270
+ +----+-----+------+
271
+ | 1 | 2 | 3 |
272
+ +----+-----+------+
273
+ | 5 |
274
+ +----+-----+------+
275
+ EOS
276
+ end
277
+
278
+ it 'should render horizontal boundaries correctly' do
279
+ @table.horizontal_boundary = ':'
280
+ @table.to_s.should == <<-EOS.deindent
281
+ +----+-----+------+
282
+ : a : b : c :
283
+ +----+-----+------+
284
+ : 11 : 2 : 3333 :
285
+ : 44 : 56 : 6 :
286
+ : 7 : 888 : 99 :
287
+ +----+-----+------+
288
+ EOS
289
+ end
290
+
291
+ it 'should render vertical boundaries correctly' do
292
+ @table.vertical_boundary = '='
293
+ @table.to_s.should == <<-EOS.deindent
294
+ +====+=====+======+
295
+ | a | b | c |
296
+ +====+=====+======+
297
+ | 11 | 2 | 3333 |
298
+ | 44 | 56 | 6 |
299
+ | 7 | 888 | 99 |
300
+ +====+=====+======+
301
+ EOS
302
+ end
303
+
304
+ it 'should render boundary interserctions properly' do
305
+ @table.boundary_intersection = '*'
306
+ @table.to_s.should == <<-EOS.deindent
307
+ *----*-----*------*
308
+ | a | b | c |
309
+ *----*-----*------*
310
+ | 11 | 2 | 3333 |
311
+ | 44 | 56 | 6 |
312
+ | 7 | 888 | 99 |
313
+ *----*-----*------*
314
+ EOS
315
+ end
316
+
317
+ it 'should render double horizontal boundaries properly' do
318
+ @table.horizontal_boundary = '||'
319
+ @table.boundary_intersection = '**'
320
+ @table.to_s.should == <<-EOS.deindent
321
+ **----**-----**------**
322
+ || a || b || c ||
323
+ **----**-----**------**
324
+ || 11 || 2 || 3333 ||
325
+ || 44 || 56 || 6 ||
326
+ || 7 || 888 || 99 ||
327
+ **----**-----**------**
328
+ EOS
329
+ end
330
+
331
+ it 'should render double horizontal boundaries with spanned cells properly' do
332
+ @table.horizontal_boundary = '||'
333
+ @table.boundary_intersection = '**'
334
+ @table.rows << :separator
335
+ @table.rows << [{:value => 2, :colspan => 2, :align => :right}, 1]
336
+ @table.to_s.should == <<-EOS.deindent
337
+ **----**-----**------**
338
+ || a || b || c ||
339
+ **----**-----**------**
340
+ || 11 || 2 || 3333 ||
341
+ || 44 || 56 || 6 ||
342
+ || 7 || 888 || 99 ||
343
+ **----**-----**------**
344
+ || 2 || 1 ||
345
+ **----**-----**------**
346
+ EOS
347
+ end
348
+
349
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: text-table
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Tinio
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-12-21 00:00:00 +08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ description: Allows you to easily create and format plain text tables, useful when working with the terminal or when you want to quickly print formatted tables to a dot-matrix printer.
26
+ email: aptinio@yahoo.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.rdoc
34
+ files:
35
+ - .document
36
+ - .gitignore
37
+ - LICENSE
38
+ - README.rdoc
39
+ - Rakefile
40
+ - VERSION
41
+ - lib/text-table.rb
42
+ - lib/text-table/cell.rb
43
+ - lib/text-table/enumerable.rb
44
+ - lib/text-table/row.rb
45
+ - lib/text-table/table.rb
46
+ - spec/cell_spec.rb
47
+ - spec/enumerable_spec.rb
48
+ - spec/spec.opts
49
+ - spec/spec_helper.rb
50
+ - spec/table_spec.rb
51
+ has_rdoc: true
52
+ homepage: http://github.com/aptinio/text-table
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --charset=UTF-8
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.5
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: A feature-rich, easy-to-use plain text table formatter.
79
+ test_files:
80
+ - spec/spec_helper.rb
81
+ - spec/cell_spec.rb
82
+ - spec/table_spec.rb
83
+ - spec/enumerable_spec.rb