jyurek-prawn-layout 0.8.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,285 @@
1
+ # encoding: utf-8
2
+
3
+ # cell.rb : Table support functions
4
+ #
5
+ # Copyright June 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ module Prawn
9
+
10
+ class Document
11
+ # Builds and renders a Table::Cell. A cell is essentially a
12
+ # special-purpose bounding box designed for flowing text within a bordered
13
+ # area. For available options, see Table::Cell#new.
14
+ #
15
+ # Prawn::Document.generate("cell.pdf") do
16
+ # cell [100,500],
17
+ # :width => 200,
18
+ # :text => "The rain in Spain falls mainly on the plains"
19
+ # end
20
+ #
21
+ def cell(point, options={})
22
+ Prawn::Table::Cell.new(
23
+ options.merge(:document => self, :point => point)).draw
24
+ end
25
+ end
26
+
27
+ class Table
28
+ # A cell is a special-purpose bounding box designed to flow text within a
29
+ # bordered area. This is used by Prawn's Document::Table implementation but
30
+ # can also be used standalone for drawing text boxes via Document#cell
31
+ #
32
+ class Cell
33
+
34
+ # Creates a new cell object. Generally used indirectly via Document#cell
35
+ #
36
+ # Of the available options listed below, <tt>:point</tt>, <tt>:width</tt>,
37
+ # and <tt>:text</tt> must be provided. If you are not using the
38
+ # Document#cell shortcut, the <tt>:document</tt> must also be provided.
39
+ #
40
+ # <tt>:point</tt>:: Absolute [x,y] coordinate of the top-left corner of the cell.
41
+ # <tt>:document</tt>:: The Prawn::Document object to render on.
42
+ # <tt>:text</tt>:: The text to be flowed within the cell
43
+ # <tt>:text_color</tt>:: The color of the text to be displayed
44
+ # <tt>:width</tt>:: The width in PDF points of the cell.
45
+ # <tt>:height</tt>:: The height in PDF points of the cell.
46
+ # <tt>:horizontal_padding</tt>:: The horizontal padding in PDF points
47
+ # <tt>:vertical_padding</tt>:: The vertical padding in PDF points
48
+ # <tt>:padding</tt>:: Overrides both horizontal and vertical padding
49
+ # <tt>:align</tt>:: One of <tt>:left</tt>, <tt>:right</tt>, <tt>:center</tt>
50
+ # <tt>:borders</tt>:: An array of sides which should have a border. Any of <tt>:top</tt>, <tt>:left</tt>, <tt>:right</tt>, <tt>:bottom</tt>
51
+ # <tt>:border_width</tt>:: The border line width. Defaults to 1.
52
+ # <tt>:border_style</tt>:: One of <tt>:all</tt>, <tt>:no_top</tt>, <tt>:no_bottom</tt>, <tt>:sides</tt>, <tt>:none</tt>, <tt>:bottom_only</tt>. Defaults to :all.
53
+ # <tt>:border_color</tt>:: The color of the cell border.
54
+ # <tt>:font_size</tt>:: The font size for the cell text.
55
+ # <tt>:font_style</tt>:: The font style for the cell text.
56
+ #
57
+ def initialize(options={})
58
+ @point = options[:point]
59
+ @document = options[:document]
60
+ @text = options[:text].to_s
61
+ @text_color = options[:text_color]
62
+ @width = options[:width]
63
+ @height = options[:height]
64
+ @borders = options[:borders]
65
+ @border_width = options[:border_width] || 1
66
+ @border_style = options[:border_style] || :all
67
+ @border_color = options[:border_color]
68
+ @background_color = options[:background_color]
69
+ @align = options[:align] || :left
70
+ @font_size = options[:font_size]
71
+ @font_style = options[:font_style]
72
+
73
+ @horizontal_padding = options[:horizontal_padding] || 0
74
+ @vertical_padding = options[:vertical_padding] || 0
75
+
76
+ if options[:padding]
77
+ @horizontal_padding = @vertical_padding = options[:padding]
78
+ end
79
+
80
+ end
81
+
82
+ attr_accessor :point, :border_style, :border_width, :background_color,
83
+ :document, :horizontal_padding, :vertical_padding, :align,
84
+ :borders, :text_color, :border_color, :font_size, :font_style
85
+
86
+ attr_writer :height, :width #:nodoc:
87
+
88
+ # Returns the cell's text as a string.
89
+ #
90
+ def to_s
91
+ @text
92
+ end
93
+
94
+ # The width of the text area excluding the horizonal padding
95
+ #
96
+ def text_area_width
97
+ width - 2*@horizontal_padding
98
+ end
99
+
100
+ # The width of the cell in PDF points
101
+ #
102
+ def width
103
+ @width || (@document.width_of(@text, :size => @font_size)) + 2*@horizontal_padding
104
+ end
105
+
106
+ # The height of the cell in PDF points
107
+ #
108
+ def height
109
+ @height || text_area_height + 2*@vertical_padding
110
+ end
111
+
112
+ # The height of the text area excluding the vertical padding
113
+ #
114
+ def text_area_height
115
+ text_height = 0
116
+ if @font_size
117
+ @document.font_size(@font_size) do
118
+ text_height = @document.height_of(@text, :width => text_area_width)
119
+ end
120
+ else
121
+ text_height = @document.height_of(@text, :width => text_area_width)
122
+ end
123
+ text_height
124
+ end
125
+
126
+ # Draws the cell onto the PDF document
127
+ #
128
+ def draw
129
+ margin = @border_width / 2.0
130
+
131
+ if @background_color
132
+ old_color = @document.fill_color || "000000"
133
+ @document.fill_color(@background_color)
134
+ h = borders.include?(:bottom) ?
135
+ height - ( 2 * margin ) : height + margin
136
+ @document.fill_rectangle [x, y ], width, h
137
+
138
+ @document.fill_color(old_color)
139
+ end
140
+
141
+ if @border_width > 0
142
+ @document.mask(:line_width) do
143
+ @document.line_width = @border_width
144
+
145
+ @document.mask(:stroke_color) do
146
+ @document.stroke_color @border_color if @border_color
147
+
148
+ if borders.include?(:left)
149
+ @document.stroke_line [x, y + margin],
150
+ [x, y - height - margin ]
151
+ end
152
+
153
+ if borders.include?(:right)
154
+ @document.stroke_line(
155
+ [x + width, y + margin],
156
+ [x + width, y - height - margin] )
157
+ end
158
+
159
+ if borders.include?(:top)
160
+ @document.stroke_line(
161
+ [ x, y ],
162
+ [ x + width, y ])
163
+ end
164
+
165
+ if borders.include?(:bottom)
166
+ @document.stroke_line [x, y - height ],
167
+ [x + width, y - height]
168
+ end
169
+ end
170
+
171
+ end
172
+
173
+ borders
174
+
175
+ end
176
+
177
+ @document.bounding_box( [x + @horizontal_padding,
178
+ y - @vertical_padding],
179
+ :width => text_area_width,
180
+ :height => height - @vertical_padding) do
181
+ @document.move_down((@document.font.line_gap +
182
+ @document.font.descender) / 2)
183
+
184
+ options = {:align => @align, :final_gap => false}
185
+
186
+ options[:size] = @font_size if @font_size
187
+ options[:style] = @font_style if @font_style
188
+
189
+ old_color = @document.fill_color || "000000"
190
+ @document.fill_color @text_color if @text_color
191
+ @document.text @text, options
192
+ @document.fill_color old_color
193
+ end
194
+ end
195
+
196
+ private
197
+
198
+ # x-position of the cell
199
+ def x
200
+ @point[0]
201
+ end
202
+
203
+ # y-position of the cell
204
+ def y
205
+ @point[1]
206
+ end
207
+
208
+ def borders
209
+ @borders ||= case @border_style
210
+ when :all
211
+ [:top,:left,:right,:bottom]
212
+ when :sides
213
+ [:left,:right]
214
+ when :no_top
215
+ [:left,:right,:bottom]
216
+ when :no_bottom
217
+ [:left,:right,:top]
218
+ when :bottom_only
219
+ [:bottom]
220
+ when :none
221
+ []
222
+ end
223
+ end
224
+
225
+ end
226
+
227
+ class CellBlock #:nodoc:
228
+
229
+ # Not sure if this class is something I want to expose in the public API.
230
+
231
+ def initialize(document)
232
+ @document = document
233
+ @cells = []
234
+ @width = 0
235
+ @height = 0
236
+ end
237
+
238
+ attr_reader :width, :height, :cells
239
+ attr_accessor :background_color, :text_color, :border_color
240
+
241
+ def <<(cell)
242
+ @cells << cell
243
+ @height = cell.height if cell.height > @height
244
+ @width += cell.width
245
+ self
246
+ end
247
+
248
+ def draw
249
+ y = @document.y
250
+ x = @document.bounds.left_side
251
+
252
+ @cells.each do |e|
253
+ e.point = [x - @document.bounds.absolute_left,
254
+ y - @document.bounds.absolute_bottom]
255
+ e.height = @height
256
+ e.background_color ||= @background_color
257
+ e.text_color ||= @text_color
258
+ e.border_color ||= @border_color
259
+ e.draw
260
+ x += e.width
261
+ end
262
+
263
+ @document.y = y - @height
264
+ end
265
+
266
+ def border_width
267
+ @cells[0].border_width
268
+ end
269
+
270
+ def border_style=(s)
271
+ @cells.each { |e| e.border_style = s }
272
+ end
273
+
274
+ def align=(align)
275
+ @cells.each { |e| e.align = align }
276
+ end
277
+
278
+ def border_style
279
+ @cells[0].border_style
280
+ end
281
+
282
+ end
283
+ end
284
+
285
+ end
data/spec/grid_spec.rb ADDED
@@ -0,0 +1,85 @@
1
+ # encoding: utf-8
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
3
+
4
+ describe "A document's grid" do
5
+ before do
6
+ @pdf = Prawn::Document.new
7
+ end
8
+
9
+ it "should allow definition of a grid" do
10
+ @pdf.define_grid(:columns => 5, :rows => 8, :gutter => 0.1)
11
+ @pdf.grid.columns.should == 5
12
+ @pdf.grid.rows.should == 8
13
+ @pdf.grid.gutter.should == 0.1
14
+ end
15
+
16
+ describe "when a grid is defined" do
17
+ before do
18
+ @num_columns = 5
19
+ @num_rows = 8
20
+ @gutter = 10.0
21
+ @pdf.define_grid(
22
+ :columns => @num_columns,
23
+ :rows => @num_rows,
24
+ :gutter => @gutter
25
+ )
26
+ end
27
+
28
+ it "should compute the column width" do
29
+ (@pdf.grid.column_width * @num_columns.to_f +
30
+ @gutter * (@num_columns - 1).to_f).should == @pdf.bounds.width
31
+ end
32
+
33
+ it "should compute the row height" do
34
+ (@pdf.grid.row_height * @num_rows.to_f +
35
+ @gutter * (@num_rows - 1).to_f).should == @pdf.bounds.height
36
+ end
37
+
38
+ it "should give the edges of a grid box" do
39
+ grid_width = (@pdf.bounds.width.to_f -
40
+ (@gutter * (@num_columns - 1).to_f )) / @num_columns.to_f
41
+ grid_height = (@pdf.bounds.height.to_f -
42
+ (@gutter * (@num_rows - 1).to_f ))/ @num_rows.to_f
43
+
44
+ exp_tl_x = (grid_width + @gutter.to_f) * 4.0
45
+ exp_tl_y = @pdf.bounds.height.to_f - (grid_height + @gutter.to_f)
46
+
47
+ @pdf.grid(1,4).top_left.should == [exp_tl_x, exp_tl_y]
48
+ @pdf.grid(1,4).top_right.should == [exp_tl_x + grid_width, exp_tl_y]
49
+ @pdf.grid(1,4).bottom_left.should == [exp_tl_x, exp_tl_y - grid_height]
50
+ @pdf.grid(1,4).bottom_right.should == [exp_tl_x + grid_width, exp_tl_y - grid_height]
51
+ end
52
+
53
+ it "should give the edges of a multiple grid boxes" do
54
+ # Hand verified. Cheating a bit. Don't tell.
55
+ @pdf.grid([1,3], [2,5]).top_left.should == [330.0, 628.75]
56
+ @pdf.grid([1,3], [2,5]).top_right.should == [650.0, 628.75]
57
+ @pdf.grid([1,3], [2,5]).bottom_left.should == [330.0, 456.25]
58
+ @pdf.grid([1,3], [2,5]).bottom_right.should == [650.0, 456.25]
59
+ end
60
+
61
+ it "should draw outlines without changing global default colors to grid color" do
62
+ @pdf.grid.show_all('cccccc')
63
+
64
+ colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
65
+ colors.fill_color.should.not == [0.8,0.8,0.8]
66
+ colors.stroke_color.should.not == [0.8,0.8,0.8]
67
+
68
+ # Hardcoded default color as I haven't been able to come up with a stable converter
69
+ # between fill_color without lots code.
70
+ colors.fill_color.should == [0.0,0.0,0.0]
71
+ colors.stroke_color.should == [0.0,0.0,0.0]
72
+ end
73
+
74
+ it "should draw outlines without curent color settings" do
75
+ @pdf.fill_color "ccff00"
76
+ @pdf.stroke_color "ffcc00"
77
+
78
+ @pdf.grid.show_all
79
+
80
+ colors = PDF::Inspector::Graphics::Color.analyze(@pdf.render)
81
+ colors.fill_color.should == [0.8,1.0,0.0]
82
+ colors.stroke_color.should == [1.0,0.8,0.0]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ puts "Prawn specs: Running on Ruby Version: #{RUBY_VERSION}"
4
+
5
+ require "rubygems"
6
+ require "test/spec"
7
+ require "mocha"
8
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
9
+
10
+ $LOAD_PATH << File.join(File.dirname(__FILE__), %w[.. vendor prawn-core lib])
11
+ require "prawn/core"
12
+ require "prawn/layout"
13
+ $LOAD_PATH << File.join(Prawn::BASEDIR, 'vendor','pdf-inspector','lib')
14
+
15
+ Prawn.debug = true
16
+
17
+ gem 'pdf-reader', ">=0.7.3"
18
+ require "pdf/reader"
19
+ require "pdf/inspector"
20
+
21
+ def create_pdf(klass=Prawn::Document)
22
+ @pdf = klass.new(:left_margin => 0,
23
+ :right_margin => 0,
24
+ :top_margin => 0,
25
+ :bottom_margin => 0)
26
+ end
@@ -0,0 +1,337 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "A table's width" do
6
+ it "should equal sum(column_widths)" do
7
+ pdf = Prawn::Document.new
8
+ table = Prawn::Table.new( [%w[ a b c ], %w[d e f]], pdf,
9
+ :column_widths => { 0 => 50, 1 => 100, 2 => 150 })
10
+
11
+ table.width.should == 300
12
+ end
13
+ it "should calculate unspecified column widths even " +
14
+ "with colspan cells declared" do
15
+ pdf = Prawn::Document.new
16
+ hpad, fs = 3, 5
17
+ columns = 3
18
+
19
+ data = [ [ { :text => 'foo', :colspan => 2 }, "foobar" ],
20
+ [ "foo", "foo", "foo" ] ]
21
+ table = Prawn::Table.new( data, pdf,
22
+ :horizontal_padding => hpad,
23
+ :font_size => fs )
24
+
25
+ col0_width = pdf.width_of("foo", :size => fs) # cell 1, 0
26
+ col1_width = pdf.width_of("foo", :size => fs) # cell 1, 1
27
+ col2_width = pdf.width_of("foobar", :size => fs) # cell 0, 1 (at col 2)
28
+
29
+ table.width.should == col0_width.ceil + col1_width.ceil +
30
+ col2_width.ceil + 2*columns*hpad
31
+ end
32
+
33
+ it "should calculate unspecified column widths as "+
34
+ "(max(string_width).ceil + 2*horizontal_padding)" do
35
+ pdf = Prawn::Document.new
36
+ hpad, fs = 3, 12
37
+ columns = 2
38
+ table = Prawn::Table.new( [%w[ foo b ], %w[d foobar]], pdf,
39
+ :horizontal_padding => hpad, :font_size => fs)
40
+
41
+ col0_width = pdf.width_of("foo", :size => fs)
42
+ col1_width = pdf.width_of("foobar", :size => fs)
43
+
44
+ table.width.should == col0_width.ceil + col1_width.ceil + 2*columns*hpad
45
+ end
46
+
47
+ it "should allow mixing autocalculated and preset"+
48
+ "column widths within a single table" do
49
+
50
+ pdf = Prawn::Document.new
51
+ hpad, fs = 10, 6
52
+ stretchy_columns = 2
53
+
54
+ col0_width = 50
55
+ col1_width = pdf.width_of("foo", :size => fs)
56
+ col2_width = pdf.width_of("foobar", :size => fs)
57
+ col3_width = 150
58
+
59
+ table = Prawn::Table.new( [%w[snake foo b apple],
60
+ %w[kitten d foobar banana]], pdf,
61
+ :horizontal_padding => hpad, :font_size => fs,
62
+ :column_widths => { 0 => col0_width, 3 => col3_width } )
63
+
64
+ table.width.should == col1_width.ceil + col2_width.ceil +
65
+ 2*stretchy_columns*hpad +
66
+ col0_width.ceil + col3_width.ceil
67
+
68
+ end
69
+
70
+ it "should not exceed the maximum width of the margin_box" do
71
+
72
+ pdf = Prawn::Document.new
73
+ expected_width = pdf.margin_box.width
74
+
75
+ data = [
76
+ ['This is a column with a lot of text that should comfortably exceed '+
77
+ 'the width of a normal document margin_box width', 'Some more text',
78
+ 'and then some more', 'Just a bit more to be extra sure']
79
+ ]
80
+
81
+ table = Prawn::Table.new(data, pdf)
82
+
83
+ table.width.should == expected_width
84
+
85
+ end
86
+
87
+ it "should not exceed the maximum width of the margin_box even with manual widths specified" do
88
+
89
+ pdf = Prawn::Document.new
90
+ expected_width = pdf.margin_box.width
91
+
92
+ data = [
93
+ ['This is a column with a lot of text that should comfortably exceed '+
94
+ 'the width of a normal document margin_box width', 'Some more text',
95
+ 'and then some more', 'Just a bit more to be extra sure']
96
+ ]
97
+
98
+
99
+ table = Prawn::Table.new(data, pdf, :column_widths => { 1 => 100 })
100
+
101
+ table.width.should == expected_width
102
+
103
+ end
104
+
105
+ it "should be the width of the :width parameter" do
106
+
107
+ pdf = Prawn::Document.new
108
+ expected_width = 300
109
+
110
+ table = Prawn::Table.new( [%w[snake foo b apple],
111
+ %w[kitten d foobar banana]], pdf,
112
+ :width => expected_width
113
+ )
114
+
115
+ table.width.should == expected_width
116
+
117
+ end
118
+
119
+ it "should not exceed the :width option" do
120
+
121
+ pdf = Prawn::Document.new
122
+ expected_width = 400
123
+
124
+ data = [
125
+ ['This is a column with a lot of text that should comfortably exceed '+
126
+ 'the width of a normal document margin_box width', 'Some more text',
127
+ 'and then some more', 'Just a bit more to be extra sure']
128
+ ]
129
+
130
+ table = Prawn::Table.new(data, pdf, :width => expected_width)
131
+
132
+ table.width.should == expected_width
133
+
134
+ end
135
+
136
+ it "should not exceed the :width option even with manual widths specified" do
137
+
138
+ pdf = Prawn::Document.new
139
+ expected_width = 400
140
+
141
+ data = [
142
+ ['This is a column with a lot of text that should comfortably exceed '+
143
+ 'the width of a normal document margin_box width', 'Some more text',
144
+ 'and then some more', 'Just a bit more to be extra sure']
145
+ ]
146
+
147
+ table = Prawn::Table.new(data, pdf, :column_widths => { 1 => 100 }, :width => expected_width)
148
+
149
+ table.width.should == expected_width
150
+
151
+ end
152
+
153
+ end
154
+
155
+ describe "A table's height" do
156
+
157
+ before :each do
158
+ data = [["foo"],["bar"],["baaaz"]]
159
+ pdf = Prawn::Document.new
160
+ @num_rows = data.length
161
+
162
+ @vpad = 4
163
+ origin = pdf.y
164
+ pdf.table data, :vertical_padding => @vpad
165
+
166
+ @table_height = origin - pdf.y
167
+
168
+ @font_height = pdf.font.height
169
+ end
170
+
171
+ it "should have a height of n rows" do
172
+ @table_height.should.be.close(
173
+ @num_rows*@font_height + 2*@vpad*@num_rows, 0.001 )
174
+ end
175
+
176
+ end
177
+
178
+ describe "A table's content" do
179
+
180
+ it "should not cause an error if rendering the very first row causes a page break" do
181
+ Prawn::Document.new( :page_layout => :portrait ) do
182
+ arr = Array(1..5).collect{|i| ["cell #{i}"] }
183
+
184
+ move_down( y - (bounds.absolute_bottom + 3) )
185
+
186
+ lambda {
187
+ table( arr,
188
+ :font_size => 9,
189
+ :horizontal_padding => 3,
190
+ :vertical_padding => 3,
191
+ :border_width => 0.05,
192
+ :border_style => :none,
193
+ :row_colors => %w{ffffff eeeeee},
194
+ :column_widths => {0 =>110},
195
+ :position => :left,
196
+ :headers => ["exploding header"],
197
+ :align => :left,
198
+ :align_headers => :center)
199
+ }.should.not.raise
200
+ end
201
+ end
202
+
203
+ it "should output content cell by cell, row by row" do
204
+ data = [["foo","bar"],["baz","bang"]]
205
+ @pdf = Prawn::Document.new
206
+ @pdf.table(data)
207
+ output = PDF::Inspector::Text.analyze(@pdf.render)
208
+ output.strings.should == data.flatten
209
+ end
210
+
211
+ it "should add headers to output when specified" do
212
+ data = [["foo","bar"],["baz","bang"]]
213
+ headers = %w[a b]
214
+ @pdf = Prawn::Document.new
215
+ @pdf.table(data, :headers => headers)
216
+ output = PDF::Inspector::Text.analyze(@pdf.render)
217
+ output.strings.should == headers + data.flatten
218
+ end
219
+
220
+ it "should repeat headers across pages" do
221
+ data = [["foo","bar"]]*30
222
+ headers = ["baz","foobar"]
223
+ @pdf = Prawn::Document.new
224
+ @pdf.table(data, :headers => headers)
225
+ output = PDF::Inspector::Text.analyze(@pdf.render)
226
+ output.strings.should == headers + data.flatten[0..-3] + headers +
227
+ data.flatten[-2..-1]
228
+ end
229
+
230
+ it "should allow empty fields" do
231
+ lambda {
232
+ data = [["foo","bar"],["baz",""]]
233
+ @pdf = Prawn::Document.new
234
+ @pdf.table(data)
235
+ }.should.not.raise
236
+ end
237
+
238
+ it "should paginate for large tables" do
239
+ # 30 rows fit on the table with default setting, 31 exceed.
240
+ data = [["foo"]] * 31
241
+ pdf = Prawn::Document.new
242
+
243
+ pdf.table data
244
+ pdf.page_count.should == 2
245
+
246
+ pdf.table data
247
+ pdf.page_count.should == 3
248
+ end
249
+
250
+ it "should accurately count columns from data" do
251
+ # First data row may contain colspan which would hide true column count
252
+ data = [["Name:",{:text => "Some very long name", :colspan => 5}]]
253
+ pdf = Prawn::Document.new
254
+ table = Prawn::Table.new data, pdf
255
+ table.column_widths.length.should == 6
256
+ end
257
+
258
+ it "should allow array syntax for :row_colors" do
259
+ data = [["foo"], ["bar"], ['baz']]
260
+ pdf = Prawn::Document.new
261
+
262
+ # fill_color() is used to retrieve fill color; ignore it
263
+ pdf.stubs(:fill_color)
264
+
265
+ # Verify that fill_color is called in proper sequence for row colors.
266
+ seq = sequence('row_colors')
267
+ %w[cccccc ffffff cccccc].each do |color|
268
+ pdf.expects(:fill_color).with(color).in_sequence(seq)
269
+ end
270
+
271
+ pdf.table(data, :row_colors => ['cccccc', 'ffffff'])
272
+ end
273
+
274
+ it "should allow hash syntax for :row_colors" do
275
+ data = [["foo"], ["bar"], ['baz']]
276
+ pdf = Prawn::Document.new
277
+
278
+ # fill_color() is used to retrieve fill color; ignore it
279
+ pdf.stubs(:fill_color)
280
+
281
+ # Verify that fill_color is called in proper sequence for row colors.
282
+ seq = sequence('row_colors')
283
+ %w[cccccc dddddd eeeeee].each do |color|
284
+ pdf.expects(:fill_color).with(color).in_sequence(seq)
285
+ end
286
+
287
+ pdf.table(data, :row_colors => {0 => 'cccccc', 1 => 'dddddd',
288
+ 2 => 'eeeeee'})
289
+ end
290
+ end
291
+
292
+ describe "An invalid table" do
293
+
294
+ before(:each) do
295
+ @pdf = Prawn::Document.new
296
+ @bad_data = ["Single Nested Array"]
297
+ end
298
+
299
+ it "should raise error when invalid table data is given" do
300
+ assert_raises(Prawn::Errors::InvalidTableData) do
301
+ @pdf.table(@bad_data)
302
+ end
303
+ end
304
+
305
+ it "should raise an EmptyTableError with empty table data" do
306
+ lambda {
307
+ data = []
308
+ @pdf = Prawn::Document.new
309
+ @pdf.table(data)
310
+ }.should.raise( Prawn::Errors::EmptyTable )
311
+ end
312
+
313
+ it "should raise an EmptyTableError with nil table data" do
314
+ lambda {
315
+ data = nil
316
+ @pdf = Prawn::Document.new
317
+ @pdf.table(data)
318
+ }.should.raise( Prawn::Errors::EmptyTable )
319
+ end
320
+
321
+ end
322
+
323
+ describe "A table, in a column box" do
324
+
325
+ it "should flow to the next column rather than always the next page" do
326
+ pdf = Prawn::Document.new do
327
+ column_box [0, cursor], :width => bounds.width, :columns => 2 do
328
+ # 35 rows fit on two columns but not one
329
+ table [["data"]] * 35
330
+ end
331
+ end
332
+
333
+ pdf.page_count.should == 1
334
+ end
335
+
336
+ end
337
+