prawn-table-continued 1.0.0.rc1
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.
- checksums.yaml +7 -0
- data/COPYING +2 -0
- data/GPLv2 +340 -0
- data/GPLv3 +674 -0
- data/Gemfile +3 -0
- data/LICENSE +56 -0
- data/lib/prawn/table/cell/image.rb +69 -0
- data/lib/prawn/table/cell/in_table.rb +33 -0
- data/lib/prawn/table/cell/span_dummy.rb +93 -0
- data/lib/prawn/table/cell/subtable.rb +66 -0
- data/lib/prawn/table/cell/text.rb +155 -0
- data/lib/prawn/table/cell.rb +787 -0
- data/lib/prawn/table/cells.rb +261 -0
- data/lib/prawn/table/column_width_calculator.rb +182 -0
- data/lib/prawn/table/version.rb +5 -0
- data/lib/prawn/table.rb +711 -0
- data/manual/contents.rb +13 -0
- data/manual/example_helper.rb +8 -0
- data/manual/images/prawn.png +0 -0
- data/manual/images/stef.jpg +0 -0
- data/manual/table/basic_block.rb +53 -0
- data/manual/table/before_rendering_page.rb +26 -0
- data/manual/table/cell_border_lines.rb +24 -0
- data/manual/table/cell_borders_and_bg.rb +31 -0
- data/manual/table/cell_dimensions.rb +36 -0
- data/manual/table/cell_text.rb +38 -0
- data/manual/table/column_widths.rb +30 -0
- data/manual/table/content_and_subtables.rb +39 -0
- data/manual/table/creation.rb +27 -0
- data/manual/table/filtering.rb +36 -0
- data/manual/table/flow_and_header.rb +17 -0
- data/manual/table/image_cells.rb +33 -0
- data/manual/table/position.rb +29 -0
- data/manual/table/row_colors.rb +20 -0
- data/manual/table/span.rb +30 -0
- data/manual/table/style.rb +33 -0
- data/manual/table/table.rb +52 -0
- data/manual/table/width.rb +27 -0
- data/prawn-table.gemspec +36 -0
- data/spec/cell_spec.rb +652 -0
- data/spec/extensions/encoding_helpers.rb +11 -0
- data/spec/extensions/file_fixture_helper.rb +15 -0
- data/spec/fixtures/files/prawn.png +0 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/table/span_dummy_spec.rb +26 -0
- data/spec/table_spec.rb +1626 -0
- metadata +234 -0
data/spec/table_spec.rb
ADDED
@@ -0,0 +1,1626 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# run rspec -t issue:XYZ to run tests for a specific github issue
|
4
|
+
# or rspec -t unresolved to run tests for all unresolved issues
|
5
|
+
|
6
|
+
|
7
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
8
|
+
|
9
|
+
require_relative "../lib/prawn/table"
|
10
|
+
require 'set'
|
11
|
+
|
12
|
+
describe "Prawn::Table" do
|
13
|
+
|
14
|
+
describe "converting data to Cell objects" do
|
15
|
+
before(:each) do
|
16
|
+
@pdf = Prawn::Document.new
|
17
|
+
@table = @pdf.table([%w[R0C0 R0C1], %w[R1C0 R1C1]])
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return a Prawn::Table" do
|
21
|
+
expect(@table).to be_a_kind_of Prawn::Table
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should flatten the data into the @cells array in row-major order" do
|
25
|
+
expect(@table.cells.map { |c| c.content }).to eq %w[R0C0 R0C1 R1C0 R1C1]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should add row and column numbers to each cell" do
|
29
|
+
c = @table.cells.to_a.first
|
30
|
+
expect(c.row).to eq 0
|
31
|
+
expect(c.column).to eq 0
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow empty fields" do
|
35
|
+
expect {
|
36
|
+
data = [["foo","bar"],["baz",""]]
|
37
|
+
@pdf.table(data)
|
38
|
+
}.to_not raise_error
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should allow a table with a header but no body" do
|
42
|
+
expect { @pdf.table([["Header"]], :header => true) }.to_not raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should accurately count columns from data" do
|
46
|
+
# First data row may contain colspan which would hide true column count
|
47
|
+
data = [["Name:", {:content => "Some very long name", :colspan => 5}]]
|
48
|
+
pdf = Prawn::Document.new
|
49
|
+
table = Prawn::Table.new data, pdf
|
50
|
+
expect(table.column_widths.length).to eq 6
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "headers should allow for rowspan" do
|
55
|
+
it "should remember rowspans accross multiple pages", :issue => 721 do
|
56
|
+
pdf = Prawn::Document.new({:page_size => "A4", :page_layout => :portrait})
|
57
|
+
rows = [ [{:content=>"The\nNumber", :rowspan=>2}, {:content=>"Prefixed", :colspan=>2} ],
|
58
|
+
["A's", "B's"] ]
|
59
|
+
|
60
|
+
(1..50).each do |n|
|
61
|
+
rows.push( ["#{n}", "A#{n}", "B#{n}"] )
|
62
|
+
end
|
63
|
+
|
64
|
+
pdf.table( rows, :header=>2 ) do
|
65
|
+
row(0..1).style :background_color=>"FFFFCC"
|
66
|
+
end
|
67
|
+
|
68
|
+
#ensure that the header on page 1 is identical to the header on page 0
|
69
|
+
output = PDF::Inspector::Page.analyze(pdf.render)
|
70
|
+
expect(output.pages[0][:strings][0..4]).to eq output.pages[1][:strings][0..4]
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should respect an explicit set table with", :issue => 6 do
|
74
|
+
data = [[{ :content => "Current Supplier: BLINKY LIGHTS COMPANY", :colspan => 4 }],
|
75
|
+
["Current Supplier: BLINKY LIGHTS COMPANY", "611 kWh X $.090041", "$", "55.02"]]
|
76
|
+
pdf = Prawn::Document.new
|
77
|
+
table = Prawn::Table.new data, pdf, :width => pdf.bounds.width
|
78
|
+
expect(table.column_widths.inject{|sum,x| sum + x }).to eq pdf.bounds.width
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "Text may be longer than the available space in a row on a single page" do
|
83
|
+
it "should not glitch the layout if there is too much text to fit onto a single row on a single page", :unresolved, :issue => 562 do
|
84
|
+
pdf = Prawn::Document.new({:page_size => "A4", :page_layout => :portrait})
|
85
|
+
|
86
|
+
table_data = Array.new
|
87
|
+
text = 'This will be a very long text. ' * 5
|
88
|
+
table_data.push([{:content => text, :rowspan => 2}, 'b', 'c'])
|
89
|
+
table_data.push(['b','c'])
|
90
|
+
|
91
|
+
column_widths = [50, 60, 400]
|
92
|
+
|
93
|
+
table = Prawn::Table.new table_data, pdf,:column_widths => column_widths
|
94
|
+
|
95
|
+
#render the table onto the pdf
|
96
|
+
table.draw
|
97
|
+
|
98
|
+
#expected behavior would be for the long text to be cut off or an exception to be raised
|
99
|
+
#thus we only expect a single page
|
100
|
+
expect(pdf.page_count).to eq 1
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "You can explicitly set the column widths and use a colspan > 1" do
|
105
|
+
|
106
|
+
it "should tolerate floating point rounding errors < 0.000000001" do
|
107
|
+
data=[["a", "b ", "c ", "d", "e", "f", "g", "h", "i", "j", "k", "l"],
|
108
|
+
[{:content=>"Foobar", :colspan=>12}]
|
109
|
+
]
|
110
|
+
#we need values with lots of decimals so that arithmetic errors will occur
|
111
|
+
#the values are not arbitrary but where found converting mm to pdf pt
|
112
|
+
column_widths=[137, 40, 40, 54.69291338582678, 54.69291338582678,
|
113
|
+
54.69291338582678, 54.69291338582678, 54.69291338582678,
|
114
|
+
54.69291338582678, 54.69291338582678, 54.69291338582678,
|
115
|
+
54.69291338582678]
|
116
|
+
|
117
|
+
pdf = Prawn::Document.new({:page_size => 'A4', :page_layout => :landscape})
|
118
|
+
table = Prawn::Table.new data, pdf, :column_widths => column_widths
|
119
|
+
expect(table.column_widths).to eq column_widths
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should work with two different given colspans", :issue => 628 do
|
123
|
+
data = [
|
124
|
+
[" ", " ", " "],
|
125
|
+
[{:content=>" ", :colspan=>3}],
|
126
|
+
[" ", {:content=>" ", :colspan=>2}]
|
127
|
+
]
|
128
|
+
column_widths = [60, 240, 60]
|
129
|
+
pdf = Prawn::Document.new
|
130
|
+
#the next line raised an Prawn::Errors::CannotFit exception before issue 628 was fixed
|
131
|
+
table = Prawn::Table.new data, pdf, :column_widths => column_widths
|
132
|
+
expect(table.column_widths).to eq column_widths
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should work with a colspan > 1 with given column_widths (issue #407)" do
|
136
|
+
#normal entries in line 1
|
137
|
+
data = [
|
138
|
+
[ '','',''],
|
139
|
+
[ { :content => "", :colspan => 3 } ],
|
140
|
+
[ "", "", "" ],
|
141
|
+
]
|
142
|
+
pdf = Prawn::Document.new
|
143
|
+
table = Prawn::Table.new data, pdf, :column_widths => [100 , 200, 240]
|
144
|
+
|
145
|
+
#colspan entry in line 1
|
146
|
+
data = [
|
147
|
+
[ { :content => "", :colspan => 3 } ],
|
148
|
+
[ "", "", "" ],
|
149
|
+
]
|
150
|
+
pdf = Prawn::Document.new
|
151
|
+
table = Prawn::Table.new data, pdf, :column_widths => [100 , 200, 240]
|
152
|
+
|
153
|
+
#mixed entries in line 1
|
154
|
+
data = [
|
155
|
+
[ { :content => "", :colspan =>2 }, "" ],
|
156
|
+
[ "", "", "" ],
|
157
|
+
]
|
158
|
+
pdf = Prawn::Document.new
|
159
|
+
table = Prawn::Table.new data, pdf, :column_widths => [100 , 200, 240]
|
160
|
+
|
161
|
+
data = [['', '', {:content => '', :colspan => 2}, '',''],
|
162
|
+
['',{:content => '', :colspan => 5}]
|
163
|
+
]
|
164
|
+
pdf = Prawn::Document.new
|
165
|
+
table = Prawn::Table.new data, pdf, :column_widths => [50 , 100, 50, 50, 50, 50]
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should not increase column width when rendering a subtable",
|
170
|
+
:unresolved, :issue => 612 do
|
171
|
+
|
172
|
+
pdf = Prawn::Document.new
|
173
|
+
|
174
|
+
first = {:content=>"Foooo fo foooooo",:width=>50,:align=>:center}
|
175
|
+
second = {:content=>"Foooo",:colspan=>2,:width=>70,:align=>:center}
|
176
|
+
third = {:content=>"fooooooooooo, fooooooooooooo, fooo, foooooo fooooo",:width=>50,:align=>:center}
|
177
|
+
fourth = {:content=>"Bar",:width=>20,:align=>:center}
|
178
|
+
|
179
|
+
table_content = [[
|
180
|
+
first,
|
181
|
+
[[second],[third,fourth]]
|
182
|
+
]]
|
183
|
+
|
184
|
+
table = Prawn::Table.new table_content, pdf
|
185
|
+
expect(table.column_widths).to eq [50.0, 70.0]
|
186
|
+
end
|
187
|
+
|
188
|
+
it "illustrates issue #710", :issue => 710 do
|
189
|
+
partial_width = 40
|
190
|
+
pdf = Prawn::Document.new({page_size: "LETTER", page_layout: :portrait})
|
191
|
+
col_widths = [
|
192
|
+
50,
|
193
|
+
partial_width, partial_width, partial_width, partial_width
|
194
|
+
]
|
195
|
+
|
196
|
+
day_header = [{
|
197
|
+
content: "Monday, August 5th, A.S. XLIX",
|
198
|
+
colspan: 5,
|
199
|
+
}]
|
200
|
+
|
201
|
+
times = [{
|
202
|
+
content: "Loc",
|
203
|
+
colspan: 1,
|
204
|
+
}, {
|
205
|
+
content: "8:00",
|
206
|
+
colspan: 4,
|
207
|
+
}]
|
208
|
+
|
209
|
+
data = [ day_header ] + [ times ]
|
210
|
+
|
211
|
+
#raised a Prawn::Errors::CannotFit:
|
212
|
+
#Table's width was set larger than its contents' maximum width (max width 210, requested 218.0)
|
213
|
+
table = Prawn::Table.new data, pdf, :column_widths => col_widths
|
214
|
+
end
|
215
|
+
|
216
|
+
it "illustrate issue #533" do
|
217
|
+
data = [['', '', '', '', '',''],
|
218
|
+
['',{:content => '', :colspan => 5}]]
|
219
|
+
pdf = Prawn::Document.new
|
220
|
+
table = Prawn::Table.new data, pdf, :column_widths => [50, 200, 40, 40, 50, 50]
|
221
|
+
end
|
222
|
+
|
223
|
+
it "illustrates issue #502" do
|
224
|
+
pdf = Prawn::Document.new
|
225
|
+
first = {:content=>"Foooo fo foooooo",:width=>50,:align=>:center}
|
226
|
+
second = {:content=>"Foooo",:colspan=>2,:width=>70,:align=>:center}
|
227
|
+
third = {:content=>"fooooooooooo, fooooooooooooo, fooo, foooooo fooooo",:width=>50,:align=>:center}
|
228
|
+
fourth = {:content=>"Bar",:width=>20,:align=>:center}
|
229
|
+
table_content = [[
|
230
|
+
first,
|
231
|
+
[[second],[third,fourth]]
|
232
|
+
]]
|
233
|
+
pdf.move_down(20)
|
234
|
+
table = Prawn::Table.new table_content, pdf
|
235
|
+
pdf.table(table_content)
|
236
|
+
end
|
237
|
+
|
238
|
+
#https://github.com/prawnpdf/prawn/issues/407#issuecomment-28556698
|
239
|
+
it "correctly computes column widths with empty cells + colspan" do
|
240
|
+
data = [['', ''],
|
241
|
+
[{:content => '', :colspan => 2}]
|
242
|
+
]
|
243
|
+
pdf = Prawn::Document.new
|
244
|
+
|
245
|
+
table = Prawn::Table.new data, pdf, :column_widths => [50, 200]
|
246
|
+
expect(table.column_widths).to eq [50.0, 200.0]
|
247
|
+
end
|
248
|
+
|
249
|
+
it "illustrates a variant of problem in issue #407 - comment 28556698" do
|
250
|
+
pdf = Prawn::Document.new
|
251
|
+
table_data = [["a", "b", "c"], [{:content=>"d", :colspan=>3}]]
|
252
|
+
column_widths = [50, 60, 400]
|
253
|
+
|
254
|
+
# Before we fixed #407, this line incorrectly raise a CannotFit error
|
255
|
+
pdf.table(table_data, :column_widths => column_widths)
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should not allow oversized subtables when parent column width is constrained" do
|
259
|
+
pdf = Prawn::Document.new
|
260
|
+
child_1 = pdf.make_table([['foo'*100]])
|
261
|
+
child_2 = pdf.make_table([['foo']])
|
262
|
+
expect {
|
263
|
+
pdf.table([[child_1], [child_2]], column_widths: [pdf.bounds.width/2] * 2)
|
264
|
+
}.to raise_error(Prawn::Errors::CannotFit)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "#initialize" do
|
269
|
+
before(:each) do
|
270
|
+
@pdf = Prawn::Document.new
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should instance_eval a 0-arg block" do
|
274
|
+
initializer = double
|
275
|
+
expect(initializer).to receive(:kick).once
|
276
|
+
|
277
|
+
@pdf.table([["a"]]) do
|
278
|
+
initializer.kick
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should call a 1-arg block with the document as the argument" do
|
283
|
+
initializer = double
|
284
|
+
expect(initializer).to receive(:kick).once
|
285
|
+
|
286
|
+
@pdf.table([["a"]]) do |doc|
|
287
|
+
expect(doc).to be_a_kind_of(Prawn::Table)
|
288
|
+
initializer.kick
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should proxy cell methods to #cells" do
|
293
|
+
table = @pdf.table([["a"]], :cell_style => { :padding => 11 })
|
294
|
+
expect(table.cells[0, 0].padding).to eq [11, 11, 11, 11]
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should set row and column length" do
|
298
|
+
table = @pdf.table([["a", "b", "c"], ["d", "e", "f"]])
|
299
|
+
expect(table.row_length).to eq 2
|
300
|
+
expect(table.column_length).to eq 3
|
301
|
+
end
|
302
|
+
|
303
|
+
it "should generate a text cell based on a String" do
|
304
|
+
t = @pdf.table([["foo"]])
|
305
|
+
expect(t.cells[0,0]).to be_a_kind_of(Prawn::Table::Cell::Text)
|
306
|
+
end
|
307
|
+
|
308
|
+
it "should pass through a text cell" do
|
309
|
+
c = Prawn::Table::Cell::Text.new(@pdf, [0,0], :content => "foo")
|
310
|
+
t = @pdf.table([[c]])
|
311
|
+
expect(t.cells[0,0]).to eq c
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
describe "cell accessors" do
|
316
|
+
before(:each) do
|
317
|
+
@pdf = Prawn::Document.new
|
318
|
+
@table = @pdf.table([%w[R0C0 R0C1], %w[R1C0 R1C1]])
|
319
|
+
end
|
320
|
+
|
321
|
+
it "should select rows by number or range" do
|
322
|
+
expect(@table.row(0).map(&:content)).to match_array %w[R0C0 R0C1]
|
323
|
+
expect(@table.rows(0..1).map(&:content)).to match_array %w[R0C0 R0C1 R1C0 R1C1]
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should select rows by array" do
|
327
|
+
expect(@table.rows([0, 1]).map(&:content)).to match_array %w[R0C0 R0C1 R1C0 R1C1]
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should allow negative row selectors" do
|
331
|
+
expect(@table.row(-1).map(&:content)).to match_array %w[R1C0 R1C1]
|
332
|
+
expect(@table.rows(-2..-1).map(&:content)).to match_array %w[R0C0 R0C1 R1C0 R1C1]
|
333
|
+
expect(@table.rows(0..-1).map(&:content)).to match_array %w[R0C0 R0C1 R1C0 R1C1]
|
334
|
+
end
|
335
|
+
|
336
|
+
it "should select columns by number or range" do
|
337
|
+
expect(@table.column(0).map(&:content)).to match_array %w[R0C0 R1C0]
|
338
|
+
expect(@table.columns(0..1).map(&:content)).to match_array %w[R0C0 R0C1 R1C0 R1C1]
|
339
|
+
end
|
340
|
+
|
341
|
+
it "should select columns by array" do
|
342
|
+
expect(@table.columns([0, 1]).map(&:content)).to match_array %w[R0C0 R0C1 R1C0 R1C1]
|
343
|
+
end
|
344
|
+
|
345
|
+
it "should allow negative column selectors" do
|
346
|
+
expect(@table.column(-1).map(&:content)).to match_array %w[R0C1 R1C1]
|
347
|
+
expect(@table.columns(-2..-1).map(&:content)).to match_array %w[R0C0 R0C1 R1C0 R1C1]
|
348
|
+
expect(@table.columns(0..-1).map(&:content)).to match_array %w[R0C0 R0C1 R1C0 R1C1]
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should allow rows and columns to be combined" do
|
352
|
+
expect(@table.row(0).column(1).map { |c| c.content }).to eq ["R0C1"]
|
353
|
+
end
|
354
|
+
|
355
|
+
it "should accept a filter block, returning a cell proxy" do
|
356
|
+
expect(@table.cells.filter { |c| c.content =~ /R0/ }.column(1).map{ |c|
|
357
|
+
c.content }).to eq ["R0C1"]
|
358
|
+
end
|
359
|
+
|
360
|
+
it "should accept the [] method, returning a Cell or nil" do
|
361
|
+
expect(@table.cells[0, 0].content).to eq "R0C0"
|
362
|
+
expect(@table.cells[12, 12]).to be_nil
|
363
|
+
end
|
364
|
+
|
365
|
+
it "should proxy unknown methods to the cells" do
|
366
|
+
@table.cells.height = 200
|
367
|
+
@table.row(1).height = 100
|
368
|
+
|
369
|
+
expect(@table.cells[0, 0].height).to eq 200
|
370
|
+
expect(@table.cells[1, 0].height).to eq 100
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should ignore non-setter methods" do
|
374
|
+
expect {
|
375
|
+
@table.cells.content_width
|
376
|
+
}.to raise_error(NoMethodError)
|
377
|
+
end
|
378
|
+
|
379
|
+
it "skips cells that don't respond to the given method" do
|
380
|
+
table = @pdf.make_table([[{:content => "R0", :colspan => 2}],
|
381
|
+
%w[R1C0 R1C1]])
|
382
|
+
expect {
|
383
|
+
table.row(0).font_style = :bold
|
384
|
+
}.to_not raise_error
|
385
|
+
end
|
386
|
+
|
387
|
+
it "should accept the style method, proxying its calls to the cells" do
|
388
|
+
@table.cells.style(:height => 200, :width => 200)
|
389
|
+
@table.column(0).style(:width => 100)
|
390
|
+
|
391
|
+
expect(@table.cells[0, 1].width).to eq 200
|
392
|
+
expect(@table.cells[1, 0].height).to eq 200
|
393
|
+
expect(@table.cells[1, 0].width).to eq 100
|
394
|
+
end
|
395
|
+
|
396
|
+
it "style method should accept a block, passing each cell to be styled" do
|
397
|
+
@table.cells.style { |c| c.height = 200 }
|
398
|
+
expect(@table.cells[0, 1].height).to eq 200
|
399
|
+
end
|
400
|
+
|
401
|
+
it "should return the width of selected columns for #width" do
|
402
|
+
c0_width = @table.column(0).map{ |c| c.width }.max
|
403
|
+
c1_width = @table.column(1).map{ |c| c.width }.max
|
404
|
+
|
405
|
+
expect(@table.column(0).width).to eq c0_width
|
406
|
+
expect(@table.column(1).width).to eq c1_width
|
407
|
+
|
408
|
+
expect(@table.columns(0..1).width).to eq c0_width + c1_width
|
409
|
+
expect(@table.cells.width).to eq c0_width + c1_width
|
410
|
+
end
|
411
|
+
|
412
|
+
it "should return the height of selected rows for #height" do
|
413
|
+
r0_height = @table.row(0).map{ |c| c.height }.max
|
414
|
+
r1_height = @table.row(1).map{ |c| c.height }.max
|
415
|
+
|
416
|
+
expect(@table.row(0).height).to eq r0_height
|
417
|
+
expect(@table.row(1).height).to eq r1_height
|
418
|
+
|
419
|
+
expect(@table.rows(0..1).height).to eq r0_height + r1_height
|
420
|
+
expect(@table.cells.height).to eq r0_height + r1_height
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe "layout" do
|
425
|
+
before(:each) do
|
426
|
+
@pdf = Prawn::Document.new
|
427
|
+
@long_text = "The quick brown fox jumped over the lazy dogs. " * 5
|
428
|
+
end
|
429
|
+
|
430
|
+
describe "width" do
|
431
|
+
it "should raise_error an error if the given width is outside of range" do
|
432
|
+
expect {
|
433
|
+
@pdf.table([["foo"]], :width => 1)
|
434
|
+
}.to raise_error(Prawn::Errors::CannotFit)
|
435
|
+
|
436
|
+
expect {
|
437
|
+
@pdf.table([[@long_text]], :width => @pdf.bounds.width + 100)
|
438
|
+
}.to raise_error(Prawn::Errors::CannotFit)
|
439
|
+
end
|
440
|
+
|
441
|
+
it "should accept the natural width for small tables" do
|
442
|
+
pad = 10 # default padding
|
443
|
+
@table = @pdf.table([["a"]])
|
444
|
+
expect(@table.width).to eq @table.cells[0, 0].natural_content_width + pad
|
445
|
+
end
|
446
|
+
|
447
|
+
it "width should == sum(column_widths)" do
|
448
|
+
table = Prawn::Table.new([%w[ a b c ], %w[d e f]], @pdf) do
|
449
|
+
column(0).width = 50
|
450
|
+
column(1).width = 100
|
451
|
+
column(2).width = 150
|
452
|
+
end
|
453
|
+
expect(table.width).to eq 300
|
454
|
+
end
|
455
|
+
|
456
|
+
it "should accept Numeric for column_widths" do
|
457
|
+
table = Prawn::Table.new([%w[ a b c ], %w[d e f]], @pdf) do |t|
|
458
|
+
t.column_widths = 50
|
459
|
+
end
|
460
|
+
expect(table.width).to eq 150
|
461
|
+
end
|
462
|
+
|
463
|
+
it "should calculate unspecified column widths as "+
|
464
|
+
"(max(string_width) + 2*horizontal_padding)" do
|
465
|
+
hpad, fs = 3, 12
|
466
|
+
columns = 2
|
467
|
+
table = Prawn::Table.new( [%w[ foo b ], %w[d foobar]], @pdf,
|
468
|
+
:cell_style => { :padding => hpad, :size => fs } )
|
469
|
+
|
470
|
+
col0_width = @pdf.width_of("foo", :size => fs)
|
471
|
+
col1_width = @pdf.width_of("foobar", :size => fs)
|
472
|
+
|
473
|
+
expect(table.width).to eq col0_width + col1_width + 2*columns*hpad
|
474
|
+
end
|
475
|
+
|
476
|
+
it "should allow mixing autocalculated and preset"+
|
477
|
+
"column widths within a single table" do
|
478
|
+
hpad, fs = 10, 6
|
479
|
+
stretchy_columns = 2
|
480
|
+
|
481
|
+
col0_width = 50
|
482
|
+
col1_width = @pdf.width_of("foo", :size => fs)
|
483
|
+
col2_width = @pdf.width_of("foobar", :size => fs)
|
484
|
+
col3_width = 150
|
485
|
+
|
486
|
+
table = Prawn::Table.new( [%w[snake foo b apple],
|
487
|
+
%w[kitten d foobar banana]], @pdf,
|
488
|
+
:cell_style => { :padding => hpad, :size => fs }) do
|
489
|
+
|
490
|
+
column(0).width = col0_width
|
491
|
+
column(3).width = col3_width
|
492
|
+
end
|
493
|
+
|
494
|
+
expect(table.width).to eq col1_width + col2_width +
|
495
|
+
2*stretchy_columns*hpad +
|
496
|
+
col0_width + col3_width
|
497
|
+
end
|
498
|
+
|
499
|
+
it "should preserve all manually requested column widths" do
|
500
|
+
col0_width = 50
|
501
|
+
col1_width = 20
|
502
|
+
col3_width = 60
|
503
|
+
|
504
|
+
table = Prawn::Table.new( [["snake", "foo", "b",
|
505
|
+
"some long, long text that will wrap"],
|
506
|
+
%w[kitten d foobar banana]], @pdf,
|
507
|
+
:width => 150) do
|
508
|
+
|
509
|
+
column(0).width = col0_width
|
510
|
+
column(1).width = col1_width
|
511
|
+
column(3).width = col3_width
|
512
|
+
end
|
513
|
+
|
514
|
+
table.draw
|
515
|
+
|
516
|
+
expect(table.column(0).width).to eq col0_width
|
517
|
+
expect(table.column(1).width).to eq col1_width
|
518
|
+
expect(table.column(3).width).to eq col3_width
|
519
|
+
end
|
520
|
+
|
521
|
+
it "should_not exceed the maximum width of the margin_box" do
|
522
|
+
expected_width = @pdf.margin_box.width
|
523
|
+
data = [
|
524
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
525
|
+
'the width of a normal document margin_box width', 'Some more text',
|
526
|
+
'and then some more', 'Just a bit more to be extra sure']
|
527
|
+
]
|
528
|
+
table = Prawn::Table.new(data, @pdf)
|
529
|
+
|
530
|
+
expect(table.width).to eq expected_width
|
531
|
+
end
|
532
|
+
|
533
|
+
it "should_not exceed the maximum width of the margin_box even with" +
|
534
|
+
"manual widths specified" do
|
535
|
+
expected_width = @pdf.margin_box.width
|
536
|
+
data = [
|
537
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
538
|
+
'the width of a normal document margin_box width', 'Some more text',
|
539
|
+
'and then some more', 'Just a bit more to be extra sure']
|
540
|
+
]
|
541
|
+
table = Prawn::Table.new(data, @pdf) { column(1).width = 100 }
|
542
|
+
|
543
|
+
expect(table.width).to eq expected_width
|
544
|
+
end
|
545
|
+
|
546
|
+
it "scales down only the non-preset column widths when the natural width" +
|
547
|
+
"exceeds the maximum width of the margin_box" do
|
548
|
+
expected_width = @pdf.margin_box.width
|
549
|
+
data = [
|
550
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
551
|
+
'the width of a normal document margin_box width', 'Some more text',
|
552
|
+
'and then some more', 'Just a bit more to be extra sure']
|
553
|
+
]
|
554
|
+
table = Prawn::Table.new(data, @pdf) { column(1).width = 100; column(3).width = 50 }
|
555
|
+
|
556
|
+
expect(table.width).to eq expected_width
|
557
|
+
expect(table.column_widths[1]).to eq 100
|
558
|
+
expect(table.column_widths[3]).to eq 50
|
559
|
+
end
|
560
|
+
|
561
|
+
it "should allow width to be reset even after it has been calculated" do
|
562
|
+
@table = @pdf.table([[@long_text]])
|
563
|
+
@table.width
|
564
|
+
@table.width = 100
|
565
|
+
expect(@table.width).to eq 100
|
566
|
+
end
|
567
|
+
|
568
|
+
it "should shrink columns evenly when two equal columns compete" do
|
569
|
+
@table = @pdf.table([["foo", @long_text], [@long_text, "foo"]])
|
570
|
+
expect(@table.cells[0, 0].width).to eq @table.cells[0, 1].width
|
571
|
+
end
|
572
|
+
|
573
|
+
it "should grow columns evenly when equal deficient columns compete" do
|
574
|
+
@table = @pdf.table([["foo", "foobar"], ["foobar", "foo"]], :width => 500)
|
575
|
+
expect(@table.cells[0, 0].width).to eq @table.cells[0, 1].width
|
576
|
+
end
|
577
|
+
|
578
|
+
it "should respect manual widths" do
|
579
|
+
@table = @pdf.table([%w[foo bar baz], %w[baz bar foo]], :width => 500) do
|
580
|
+
column(1).width = 60
|
581
|
+
end
|
582
|
+
expect(@table.column(1).width).to eq 60
|
583
|
+
expect(@table.column(0).width).to eq @table.column(2).width
|
584
|
+
end
|
585
|
+
|
586
|
+
it "should allow table cells to be resized in block" do
|
587
|
+
# if anything goes wrong, a CannotFit error will be raised
|
588
|
+
|
589
|
+
@pdf.table([%w[1 2 3 4 5]]) do |t|
|
590
|
+
t.width = 40
|
591
|
+
t.cells.size = 8
|
592
|
+
t.cells.padding = 0
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
it "should be the width of the :width parameter" do
|
597
|
+
expected_width = 300
|
598
|
+
table = Prawn::Table.new( [%w[snake foo b apple],
|
599
|
+
%w[kitten d foobar banana]], @pdf,
|
600
|
+
:width => expected_width)
|
601
|
+
|
602
|
+
expect(table.width).to eq expected_width
|
603
|
+
end
|
604
|
+
|
605
|
+
it "should_not exceed the :width option" do
|
606
|
+
expected_width = 400
|
607
|
+
data = [
|
608
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
609
|
+
'the width of a normal document margin_box width', 'Some more text',
|
610
|
+
'and then some more', 'Just a bit more to be extra sure']
|
611
|
+
]
|
612
|
+
table = Prawn::Table.new(data, @pdf, :width => expected_width)
|
613
|
+
|
614
|
+
expect(table.width).to eq expected_width
|
615
|
+
end
|
616
|
+
|
617
|
+
it "should_not exceed the :width option even with manual widths specified" do
|
618
|
+
expected_width = 400
|
619
|
+
data = [
|
620
|
+
['This is a column with a lot of text that should comfortably exceed '+
|
621
|
+
'the width of a normal document margin_box width', 'Some more text',
|
622
|
+
'and then some more', 'Just a bit more to be extra sure']
|
623
|
+
]
|
624
|
+
table = Prawn::Table.new(data, @pdf, :width => expected_width) do
|
625
|
+
column(1).width = 100
|
626
|
+
end
|
627
|
+
|
628
|
+
expect(table.width).to eq expected_width
|
629
|
+
end
|
630
|
+
|
631
|
+
it "should calculate unspecified column widths even " +
|
632
|
+
"with colspan cells declared" do
|
633
|
+
pdf = Prawn::Document.new
|
634
|
+
hpad, fs = 3, 5
|
635
|
+
columns = 3
|
636
|
+
|
637
|
+
data = [ [ { :content => 'foo', :colspan => 2 }, "foobar" ],
|
638
|
+
[ "foo", "foo", "foo" ] ]
|
639
|
+
table = Prawn::Table.new( data, pdf,
|
640
|
+
:cell_style => {
|
641
|
+
:padding_left => hpad, :padding_right => hpad,
|
642
|
+
:size => fs
|
643
|
+
})
|
644
|
+
|
645
|
+
col0_width = pdf.width_of("foo", :size => fs) # cell 1, 0
|
646
|
+
col1_width = pdf.width_of("foo", :size => fs) # cell 1, 1
|
647
|
+
col2_width = pdf.width_of("foobar", :size => fs) # cell 0, 1 (at col 2)
|
648
|
+
|
649
|
+
expect(table.width).to eq col0_width + col1_width +
|
650
|
+
col2_width + 2*columns*hpad
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
describe "height" do
|
655
|
+
it "should set all cells in a row to the same height" do
|
656
|
+
@table = @pdf.table([["foo", @long_text]])
|
657
|
+
expect(@table.cells[0, 0].height).to eq @table.cells[0, 1].height
|
658
|
+
end
|
659
|
+
|
660
|
+
it "should move y-position to the bottom of the table after drawing" do
|
661
|
+
old_y = @pdf.y
|
662
|
+
table = @pdf.table([["foo"]])
|
663
|
+
expect(@pdf.y).to eq old_y - table.height
|
664
|
+
end
|
665
|
+
|
666
|
+
it "should_not wrap unnecessarily" do
|
667
|
+
# Test for FP errors and glitches
|
668
|
+
t = @pdf.table([["Bender Bending Rodriguez"]])
|
669
|
+
h = @pdf.height_of("one line")
|
670
|
+
expect(t.height - 10).to be < h*1.5
|
671
|
+
end
|
672
|
+
|
673
|
+
it "should have a height of n rows" do
|
674
|
+
data = [["foo"],["bar"],["baaaz"]]
|
675
|
+
|
676
|
+
vpad = 4
|
677
|
+
origin = @pdf.y
|
678
|
+
@pdf.table data, :cell_style => { :padding => vpad }
|
679
|
+
|
680
|
+
table_height = origin - @pdf.y
|
681
|
+
font_height = @pdf.font.height
|
682
|
+
line_gap = @pdf.font.line_gap
|
683
|
+
|
684
|
+
num_rows = data.length
|
685
|
+
expect(table_height).to be_within(0.001).of(
|
686
|
+
num_rows * font_height + 2*vpad*num_rows )
|
687
|
+
end
|
688
|
+
|
689
|
+
end
|
690
|
+
|
691
|
+
describe "position" do
|
692
|
+
it "should center tables with :position => :center" do
|
693
|
+
expect(@pdf).to receive(:bounding_box).with([(@pdf.bounds.width - 500) / 2.0, anything], kind_of(Hash))
|
694
|
+
|
695
|
+
@pdf.table([["foo"]], :column_widths => 500, :position => :center)
|
696
|
+
end
|
697
|
+
|
698
|
+
it "should right-align tables with :position => :right" do
|
699
|
+
expect(@pdf).to receive(:bounding_box).with([@pdf.bounds.width - 500, anything], kind_of(Hash))
|
700
|
+
|
701
|
+
@pdf.table([["foo"]], :column_widths => 500, :position => :right)
|
702
|
+
end
|
703
|
+
|
704
|
+
it "should accept a Numeric" do
|
705
|
+
expect(@pdf).to receive(:bounding_box).with([123, anything], kind_of(Hash))
|
706
|
+
|
707
|
+
@pdf.table([["foo"]], :column_widths => 500, :position => 123)
|
708
|
+
end
|
709
|
+
|
710
|
+
it "should raise_error an ArgumentError on unknown :position" do
|
711
|
+
expect {
|
712
|
+
@pdf.table([["foo"]], :position => :bratwurst)
|
713
|
+
}.to raise_error(ArgumentError)
|
714
|
+
end
|
715
|
+
end
|
716
|
+
|
717
|
+
end
|
718
|
+
|
719
|
+
describe "Multi-page tables" do
|
720
|
+
it "should flow to the next page when hitting the bottom of the bounds" do
|
721
|
+
expect(Prawn::Document.new { table([["foo"]] * 30) }.page_count).to eq 1
|
722
|
+
expect(Prawn::Document.new { table([["foo"]] * 31) }.page_count).to eq 2
|
723
|
+
expect(
|
724
|
+
Prawn::Document.new { table([["foo"]] * 31); table([["foo"]] * 35) }.page_count
|
725
|
+
).to eq 3
|
726
|
+
end
|
727
|
+
|
728
|
+
it "should respect the containing bounds" do
|
729
|
+
expect(
|
730
|
+
Prawn::Document.new do
|
731
|
+
bounding_box([0, cursor], :width => bounds.width, :height => 72) do
|
732
|
+
table([["foo"]] * 4)
|
733
|
+
end
|
734
|
+
end.page_count
|
735
|
+
).to eq 2
|
736
|
+
end
|
737
|
+
|
738
|
+
it "should_not start a new page before finishing out a row" do
|
739
|
+
expect(
|
740
|
+
Prawn::Document.new do
|
741
|
+
table([[ (1..80).map{ |i| "Line #{i}" }.join("\n"), "Column 2" ]])
|
742
|
+
end.page_count
|
743
|
+
).to eq 1
|
744
|
+
end
|
745
|
+
|
746
|
+
it "should only start new page on long cells if it would gain us height" do
|
747
|
+
expect(
|
748
|
+
Prawn::Document.new do
|
749
|
+
text "Hello"
|
750
|
+
table([[ (1..80).map{ |i| "Line #{i}" }.join("\n"), "Column 2" ]])
|
751
|
+
end.page_count
|
752
|
+
).to eq 2
|
753
|
+
end
|
754
|
+
|
755
|
+
it "should_not start a new page to gain height when at the top of " +
|
756
|
+
"a bounding box, even if stretchy" do
|
757
|
+
expect(
|
758
|
+
Prawn::Document.new do
|
759
|
+
bounding_box([bounds.left, bounds.top - 20], :width => 400) do
|
760
|
+
table([[ (1..80).map{ |i| "Line #{i}" }.join("\n"), "Column 2" ]])
|
761
|
+
end
|
762
|
+
end.page_count
|
763
|
+
).to eq 1
|
764
|
+
end
|
765
|
+
|
766
|
+
it "should still break to the next page if in a stretchy bounding box " +
|
767
|
+
"but not at the top" do
|
768
|
+
expect(
|
769
|
+
Prawn::Document.new do
|
770
|
+
bounding_box([bounds.left, bounds.top - 20], :width => 400) do
|
771
|
+
text "Hello"
|
772
|
+
table([[ (1..80).map{ |i| "Line #{i}" }.join("\n"), "Column 2" ]])
|
773
|
+
end
|
774
|
+
end.page_count
|
775
|
+
).to eq 2
|
776
|
+
end
|
777
|
+
|
778
|
+
it "should only draw first-page header if the first body row fits" do
|
779
|
+
pdf = Prawn::Document.new
|
780
|
+
|
781
|
+
pdf.y = 60 # not enough room for a table row
|
782
|
+
pdf.table [["Header"], ["Body"]], :header => true
|
783
|
+
|
784
|
+
output = PDF::Inspector::Page.analyze(pdf.render)
|
785
|
+
# Ensure we only drew the header once, on the second page
|
786
|
+
expect(output.pages[0][:strings]).to be_empty
|
787
|
+
expect(output.pages[1][:strings]).to eq ["Header", "Body"]
|
788
|
+
end
|
789
|
+
|
790
|
+
it 'should only draw first-page header if the first multi-row fits',
|
791
|
+
:issue => 707 do
|
792
|
+
pdf = Prawn::Document.new
|
793
|
+
|
794
|
+
pdf.y = 100 # not enough room for the header and multirow cell
|
795
|
+
pdf.table [
|
796
|
+
[{content: 'Header', colspan: 2}],
|
797
|
+
[{content: 'Multirow cell', rowspan: 3}, 'Line 1'],
|
798
|
+
] + (2..3).map { |i| ["Line #{i}"] }, :header => true
|
799
|
+
|
800
|
+
output = PDF::Inspector::Page.analyze(pdf.render)
|
801
|
+
# Ensure we only drew the header once, on the second page
|
802
|
+
expect(output.pages[0][:strings]).to eq []
|
803
|
+
expect(output.pages[1][:strings]).to eq ['Header', 'Multirow cell', 'Line 1',
|
804
|
+
'Line 2', 'Line 3']
|
805
|
+
end
|
806
|
+
|
807
|
+
context 'when the last row of first page of a table has a rowspan > 1' do
|
808
|
+
it 'should move the cells below that rowspan cell to the next page' do
|
809
|
+
pdf = Prawn::Document.new
|
810
|
+
|
811
|
+
pdf.y = 100 # not enough room for the rowspan cell
|
812
|
+
pdf.table [
|
813
|
+
['R0C0', 'R0C1', 'R0C2'],
|
814
|
+
['R1C0', {content: 'R1C1', rowspan: 2}, 'R1C2'],
|
815
|
+
['R2C0', 'R2C2'],
|
816
|
+
]
|
817
|
+
|
818
|
+
output = PDF::Inspector::Page.analyze(pdf.render)
|
819
|
+
# Ensure we output the cells of row 2 on the new page only
|
820
|
+
expect(output.pages[0][:strings]).to eq ['R0C0', 'R0C1', 'R0C2']
|
821
|
+
expect(output.pages[1][:strings]).to eq ['R1C0', 'R1C1', 'R1C2', 'R2C0', 'R2C2']
|
822
|
+
end
|
823
|
+
end
|
824
|
+
|
825
|
+
it "should draw background before borders, but only within pages" do
|
826
|
+
@pdf = Prawn::Document.new
|
827
|
+
|
828
|
+
# give enough room for only the first row
|
829
|
+
@pdf.y = @pdf.bounds.absolute_bottom + 30
|
830
|
+
t = @pdf.make_table([["A", "B"],
|
831
|
+
["C", "D"]],
|
832
|
+
:cell_style => {:background_color => 'ff0000'})
|
833
|
+
|
834
|
+
ca = t.cells[0, 0]
|
835
|
+
cb = t.cells[0, 1]
|
836
|
+
cc = t.cells[1, 0]
|
837
|
+
cd = t.cells[1, 1]
|
838
|
+
|
839
|
+
# All backgrounds should draw before any borders on page 1...
|
840
|
+
expect(ca).to receive(:draw_background).ordered
|
841
|
+
expect(cb).to receive(:draw_background).ordered
|
842
|
+
expect(ca).to receive(:draw_borders).ordered
|
843
|
+
expect(cb).to receive(:draw_borders).ordered
|
844
|
+
# ...and page 2
|
845
|
+
expect(@pdf).to receive(:start_new_page).ordered
|
846
|
+
expect(cc).to receive(:draw_background).ordered
|
847
|
+
expect(cd).to receive(:draw_background).ordered
|
848
|
+
expect(cc).to receive(:draw_borders).ordered
|
849
|
+
expect(cd).to receive(:draw_borders).ordered
|
850
|
+
|
851
|
+
t.draw
|
852
|
+
end
|
853
|
+
|
854
|
+
describe "before_rendering_page callback" do
|
855
|
+
before(:each) { @pdf = Prawn::Document.new }
|
856
|
+
|
857
|
+
it "is passed all cells to be rendered on that page" do
|
858
|
+
kicked = 0
|
859
|
+
|
860
|
+
@pdf.table([["foo"]] * 100) do |t|
|
861
|
+
t.before_rendering_page do |page|
|
862
|
+
expect(page.row_count).to eq ((kicked < 3) ? 30 : 10)
|
863
|
+
expect(page.column_count).to eq 1
|
864
|
+
expect(page.row(0).first.content).to eq "foo"
|
865
|
+
expect(page.row(-1).first.content).to eq "foo"
|
866
|
+
kicked += 1
|
867
|
+
end
|
868
|
+
end
|
869
|
+
|
870
|
+
expect(kicked).to eq 4
|
871
|
+
end
|
872
|
+
|
873
|
+
it "numbers cells relative to their position on page" do
|
874
|
+
@pdf.table([["foo"]] * 100) do |t|
|
875
|
+
t.before_rendering_page do |page|
|
876
|
+
expect(page[0, 0].content).to eq "foo"
|
877
|
+
end
|
878
|
+
end
|
879
|
+
end
|
880
|
+
|
881
|
+
it "changing cells in the callback affects their rendering" do
|
882
|
+
t = @pdf.make_table([["foo"]] * 40) do |table|
|
883
|
+
table.before_rendering_page do |page|
|
884
|
+
page[0, 0].background_color = "ff0000"
|
885
|
+
end
|
886
|
+
end
|
887
|
+
|
888
|
+
expect(t.cells[30, 0]).to receive(:draw_background)
|
889
|
+
.and_wrap_original do |original_method, *args, &block|
|
890
|
+
expect(t.cells[30, 0].background_color).to eq 'ff0000'
|
891
|
+
original_method.call(*args, &block)
|
892
|
+
end
|
893
|
+
|
894
|
+
expect(t.cells[31, 0]).to receive(:draw_background)
|
895
|
+
.and_wrap_original do |original_method, *args, &block|
|
896
|
+
expect(t.cells[31, 0].background_color).to eq nil
|
897
|
+
original_method.call(*args, &block)
|
898
|
+
end
|
899
|
+
|
900
|
+
t.draw
|
901
|
+
end
|
902
|
+
|
903
|
+
it "passes headers on page 2+" do
|
904
|
+
@pdf.table([["header"]] + [["foo"]] * 100, :header => true) do |t|
|
905
|
+
t.before_rendering_page do |page|
|
906
|
+
expect(page[0, 0].content).to eq "header"
|
907
|
+
end
|
908
|
+
end
|
909
|
+
end
|
910
|
+
|
911
|
+
it "updates dummy cell header rows" do
|
912
|
+
header = [[{:content => "header", :colspan => 2}]]
|
913
|
+
data = [["foo", "bar"]] * 31
|
914
|
+
@pdf.table(header + data, :header => true) do |t|
|
915
|
+
t.before_rendering_page do |page|
|
916
|
+
cell = page[0, 0]
|
917
|
+
cell.dummy_cells.each {|dc| expect(dc.row).to eq cell.row }
|
918
|
+
end
|
919
|
+
end
|
920
|
+
end
|
921
|
+
|
922
|
+
it "allows headers to be changed" do
|
923
|
+
expect(@pdf).to receive(:draw_text!).with("hdr1", anything).ordered
|
924
|
+
expect(@pdf).to receive(:draw_text!).with("foo", anything).exactly(29).times.ordered
|
925
|
+
# Verify that the changed cell doesn't mutate subsequent pages
|
926
|
+
expect(@pdf).to receive(:draw_text!).with("header", anything).ordered
|
927
|
+
expect(@pdf).to receive(:draw_text!).with("foo", anything).exactly(11).times.ordered
|
928
|
+
|
929
|
+
set_first_page_headers = false
|
930
|
+
@pdf.table([["header"]] + [["foo"]] * 40, :header => true) do |t|
|
931
|
+
t.before_rendering_page do |page|
|
932
|
+
# only change first page header
|
933
|
+
page[0, 0].content = "hdr1" unless set_first_page_headers
|
934
|
+
set_first_page_headers = true
|
935
|
+
end
|
936
|
+
end
|
937
|
+
end
|
938
|
+
end
|
939
|
+
end
|
940
|
+
|
941
|
+
describe "#style" do
|
942
|
+
it "should send #style to its first argument, passing the style hash and" +
|
943
|
+
" block" do
|
944
|
+
|
945
|
+
stylable = double
|
946
|
+
expect(stylable).to receive(:style).with({:foo => :bar}).once.and_yield
|
947
|
+
|
948
|
+
block = double
|
949
|
+
expect(block).to receive(:kick).once
|
950
|
+
|
951
|
+
Prawn::Document.new do
|
952
|
+
table([["x"]]) do
|
953
|
+
style(stylable, {:foo => :bar}) { block.kick }
|
954
|
+
end
|
955
|
+
end
|
956
|
+
end
|
957
|
+
|
958
|
+
it "should default to {} for the hash argument" do
|
959
|
+
stylable = double
|
960
|
+
expect(stylable).to receive(:style).with({}).once
|
961
|
+
|
962
|
+
Prawn::Document.new do
|
963
|
+
table([["x"]]) { style(stylable) }
|
964
|
+
end
|
965
|
+
end
|
966
|
+
|
967
|
+
it "ignores unknown values on a cell-by-cell basis" do
|
968
|
+
Prawn::Document.new do
|
969
|
+
table([["x", [["y"]]]], :cell_style => {:overflow => :shrink_to_fit})
|
970
|
+
end
|
971
|
+
end
|
972
|
+
end
|
973
|
+
|
974
|
+
describe "row_colors" do
|
975
|
+
it "should allow array syntax for :row_colors" do
|
976
|
+
data = [["foo"], ["bar"], ["baz"]]
|
977
|
+
pdf = Prawn::Document.new
|
978
|
+
t = pdf.table(data, :row_colors => ['cccccc', 'ffffff'])
|
979
|
+
expect(t.cells.map{|x| x.background_color}).to eq %w[cccccc ffffff cccccc]
|
980
|
+
end
|
981
|
+
|
982
|
+
it "should ignore headers" do
|
983
|
+
data = [["header"], ["foo"], ["bar"], ["baz"]]
|
984
|
+
pdf = Prawn::Document.new
|
985
|
+
t = pdf.table(data,
|
986
|
+
{ :header => true,
|
987
|
+
:row_colors => ['cccccc', 'ffffff']}) do
|
988
|
+
row(0).background_color = '333333'
|
989
|
+
end
|
990
|
+
|
991
|
+
expect(t.cells.map{|x| x.background_color}).to eq %w[333333 cccccc ffffff cccccc]
|
992
|
+
end
|
993
|
+
|
994
|
+
it "stripes rows consistently from page to page, skipping header rows" do
|
995
|
+
data = [["header"]] + [["foo"]] * 70
|
996
|
+
pdf = Prawn::Document.new
|
997
|
+
t = pdf.make_table(data,
|
998
|
+
{ :header => true,
|
999
|
+
:row_colors => ['cccccc', 'ffffff']}) do
|
1000
|
+
cells.padding = 0
|
1001
|
+
cells.size = 9
|
1002
|
+
row(0).size = 11
|
1003
|
+
end
|
1004
|
+
|
1005
|
+
# page 1: header + 67 cells (odd number -- verifies that the next
|
1006
|
+
# page disrupts the even/odd coloring, since both the last data cell
|
1007
|
+
# on this page and the first one on the next are colored cccccc)
|
1008
|
+
expect(Prawn::Table::Cell).to receive(:draw_cells)
|
1009
|
+
.and_wrap_original do |original_method, *args, &block|
|
1010
|
+
cells = args.first
|
1011
|
+
expect(cells.map { |c, _| c.background_color }).to eq [nil] + (%w[cccccc ffffff] * 33) + %w[cccccc]
|
1012
|
+
original_method.call(*args, &block)
|
1013
|
+
end
|
1014
|
+
# page 2: header and 3 data cells
|
1015
|
+
expect(Prawn::Table::Cell).to receive(:draw_cells)
|
1016
|
+
.and_wrap_original do |original_method, *args, &block|
|
1017
|
+
cells = args.first
|
1018
|
+
expect(cells.map { |c, _| c.background_color }).to eq [nil] + %w[cccccc ffffff cccccc]
|
1019
|
+
original_method.call(*args, &block)
|
1020
|
+
end
|
1021
|
+
|
1022
|
+
t.draw
|
1023
|
+
end
|
1024
|
+
|
1025
|
+
it "should_not override an explicit background_color" do
|
1026
|
+
data = [["foo"], ["bar"], ["baz"]]
|
1027
|
+
pdf = Prawn::Document.new
|
1028
|
+
table = pdf.table(data, :row_colors => ['cccccc', 'ffffff']) { |t|
|
1029
|
+
t.cells[0, 0].background_color = 'dddddd'
|
1030
|
+
}
|
1031
|
+
expect(table.cells.map{|x| x.background_color}).to eq %w[dddddd ffffff cccccc]
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
describe "inking" do
|
1036
|
+
before(:each) do
|
1037
|
+
@pdf = Prawn::Document.new
|
1038
|
+
end
|
1039
|
+
|
1040
|
+
it "should set the x-position of each cell based on widths" do
|
1041
|
+
@table = @pdf.table([["foo", "bar", "baz"]])
|
1042
|
+
|
1043
|
+
x = 0
|
1044
|
+
(0..2).each do |col|
|
1045
|
+
cell = @table.cells[0, col]
|
1046
|
+
expect(cell.x).to eq x
|
1047
|
+
x += cell.width
|
1048
|
+
end
|
1049
|
+
end
|
1050
|
+
|
1051
|
+
it "should set the y-position of each cell based on heights" do
|
1052
|
+
y = 0
|
1053
|
+
@table = @pdf.make_table([["foo"], ["bar"], ["baz"]])
|
1054
|
+
|
1055
|
+
(0..2).each do |row|
|
1056
|
+
cell = @table.cells[row, 0]
|
1057
|
+
expect(cell.y).to be_within(0.01).of(y)
|
1058
|
+
y -= cell.height
|
1059
|
+
end
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
it "should output content cell by cell, row by row" do
|
1063
|
+
data = [["foo","bar"],["baz","bang"]]
|
1064
|
+
@pdf = Prawn::Document.new
|
1065
|
+
@pdf.table(data)
|
1066
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
1067
|
+
expect(output.strings).to eq data.flatten
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
it "should_not cause an error if rendering the very first row causes a " +
|
1071
|
+
"page break" do
|
1072
|
+
Prawn::Document.new do |pdf|
|
1073
|
+
arr = Array(1..5).collect{|i| ["cell #{i}"] }
|
1074
|
+
|
1075
|
+
pdf.move_down( pdf.y - (pdf.bounds.absolute_bottom + 3) )
|
1076
|
+
|
1077
|
+
expect {
|
1078
|
+
pdf.table(arr)
|
1079
|
+
}.to_not raise_error
|
1080
|
+
end
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
it "should draw all backgrounds before any borders" do
|
1084
|
+
# lest backgrounds overlap borders:
|
1085
|
+
# https://github.com/sandal/prawn/pull/226
|
1086
|
+
|
1087
|
+
t = @pdf.make_table([["A", "B"]],
|
1088
|
+
:cell_style => {:background_color => 'ff0000'})
|
1089
|
+
ca = t.cells[0, 0]
|
1090
|
+
cb = t.cells[0, 1]
|
1091
|
+
|
1092
|
+
# XXX Not a perfectly general test, because it would still be acceptable
|
1093
|
+
# if we drew B then A
|
1094
|
+
expect(ca).to receive(:draw_background).ordered
|
1095
|
+
expect(cb).to receive(:draw_background).ordered
|
1096
|
+
expect(ca).to receive(:draw_borders).ordered
|
1097
|
+
expect(cb).to receive(:draw_borders).ordered
|
1098
|
+
|
1099
|
+
t.draw
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
it "should allow multiple inkings of the same table" do
|
1103
|
+
pdf = Prawn::Document.new
|
1104
|
+
t = Prawn::Table.new([["foo"]], pdf)
|
1105
|
+
|
1106
|
+
expect(pdf).to receive(:bounding_box).with([anything, 495], kind_of(Hash)).and_yield
|
1107
|
+
expect(pdf).to receive(:bounding_box).with([anything, 395], kind_of(Hash)).and_yield
|
1108
|
+
expect(pdf).to receive(:draw_text!).with("foo", anything).twice
|
1109
|
+
|
1110
|
+
pdf.move_cursor_to(500)
|
1111
|
+
t.draw
|
1112
|
+
|
1113
|
+
pdf.move_cursor_to(400)
|
1114
|
+
t.draw
|
1115
|
+
end
|
1116
|
+
|
1117
|
+
describe "in stretchy bounding boxes" do
|
1118
|
+
it "should draw all cells on a row at the same y-position" do
|
1119
|
+
pdf = Prawn::Document.new
|
1120
|
+
|
1121
|
+
text_y = pdf.y.to_i - 5 # text starts 5pt below current y pos (padding)
|
1122
|
+
|
1123
|
+
pdf.bounding_box([0, pdf.cursor], :width => pdf.bounds.width) do
|
1124
|
+
expect(pdf).to receive(:draw_text!).exactly(3).times
|
1125
|
+
.and_wrap_original do |original_method, *args, &block|
|
1126
|
+
expect(pdf.bounds.absolute_top).to eq text_y
|
1127
|
+
original_method.call(*args, &block)
|
1128
|
+
end
|
1129
|
+
|
1130
|
+
pdf.table([%w[a b c]])
|
1131
|
+
end
|
1132
|
+
end
|
1133
|
+
end
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
describe "headers" do
|
1137
|
+
context "single row header" do
|
1138
|
+
it "should add headers to output when specified" do
|
1139
|
+
data = [["a", "b"], ["foo","bar"],["baz","bang"]]
|
1140
|
+
@pdf = Prawn::Document.new
|
1141
|
+
@pdf.table(data, :header => true)
|
1142
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
1143
|
+
expect(output.strings).to eq data.flatten
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
it "should repeat headers across pages" do
|
1147
|
+
data = [["foo","bar"]] * 30
|
1148
|
+
headers = ["baz","foobar"]
|
1149
|
+
@pdf = Prawn::Document.new
|
1150
|
+
@pdf.table([headers] + data, :header => true)
|
1151
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
1152
|
+
expect(output.strings).to eq headers + data.flatten[0..-3] + headers +
|
1153
|
+
data.flatten[-2..-1]
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
it "draws headers at the correct position" do
|
1157
|
+
data = [["header"]] + [["foo"]] * 40
|
1158
|
+
|
1159
|
+
expect(Prawn::Table::Cell).to receive(:draw_cells).twice
|
1160
|
+
.and_wrap_original do |original_method, *args, &block|
|
1161
|
+
cells = args.first
|
1162
|
+
cells.each do |cell, pt|
|
1163
|
+
if cell.content == "header"
|
1164
|
+
# Assert that header text is drawn at the same location on each page
|
1165
|
+
if @header_location
|
1166
|
+
expect(pt).to eq @header_location
|
1167
|
+
else
|
1168
|
+
@header_location = pt
|
1169
|
+
end
|
1170
|
+
end
|
1171
|
+
end
|
1172
|
+
original_method.call(*args, &block)
|
1173
|
+
end
|
1174
|
+
@pdf = Prawn::Document.new
|
1175
|
+
@pdf.table(data, :header => true)
|
1176
|
+
end
|
1177
|
+
|
1178
|
+
it "draws headers at the correct position with column box" do
|
1179
|
+
data = [["header"]] + [["foo"]] * 40
|
1180
|
+
|
1181
|
+
expect(Prawn::Table::Cell).to receive(:draw_cells).twice
|
1182
|
+
.and_wrap_original do |original_method, *args, &block|
|
1183
|
+
cells = args.first
|
1184
|
+
cells.each do |cell, pt|
|
1185
|
+
if cell.content == "header"
|
1186
|
+
expect(pt[0]).to eq @pdf.bounds.left
|
1187
|
+
end
|
1188
|
+
end
|
1189
|
+
original_method.call(*args, &block)
|
1190
|
+
end
|
1191
|
+
@pdf = Prawn::Document.new
|
1192
|
+
@pdf.column_box [0, @pdf.cursor], :width => @pdf.bounds.width, :columns => 2 do
|
1193
|
+
@pdf.table(data, :header => true)
|
1194
|
+
end
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
it "should_not draw header twice when starting new page" do
|
1198
|
+
@pdf = Prawn::Document.new
|
1199
|
+
@pdf.y = 0
|
1200
|
+
@pdf.table([["Header"], ["Body"]], :header => true)
|
1201
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
1202
|
+
expect(output.strings).to eq ["Header", "Body"]
|
1203
|
+
end
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
context "multiple row header" do
|
1207
|
+
it "should add headers to output when specified" do
|
1208
|
+
data = [["a", "b"], ["c", "d"], ["foo","bar"],["baz","bang"]]
|
1209
|
+
@pdf = Prawn::Document.new
|
1210
|
+
@pdf.table(data, :header => 2)
|
1211
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
1212
|
+
expect(output.strings).to eq data.flatten
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
it "should repeat headers across pages" do
|
1216
|
+
data = [["foo","bar"]] * 30
|
1217
|
+
headers = ["baz","foobar"] + ["bas", "foobaz"]
|
1218
|
+
@pdf = Prawn::Document.new
|
1219
|
+
@pdf.table([headers] + data, :header => 2)
|
1220
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
1221
|
+
expect(output.strings).to eq headers + data.flatten[0..-3] + headers +
|
1222
|
+
data.flatten[-4..-1]
|
1223
|
+
end
|
1224
|
+
|
1225
|
+
it "draws headers at the correct position" do
|
1226
|
+
data = [["header"]] + [["header2"]] + [["foo"]] * 40
|
1227
|
+
|
1228
|
+
expect(Prawn::Table::Cell).to receive(:draw_cells).twice
|
1229
|
+
.and_wrap_original do |original_method, *args, &block|
|
1230
|
+
cells = args.first
|
1231
|
+
cells.each do |cell, pt|
|
1232
|
+
if cell.content == "header"
|
1233
|
+
# Assert that header text is drawn at the same location on each page
|
1234
|
+
if @header_location
|
1235
|
+
expect(pt).to eq @header_location
|
1236
|
+
else
|
1237
|
+
@header_location = pt
|
1238
|
+
end
|
1239
|
+
end
|
1240
|
+
|
1241
|
+
if cell.content == "header2"
|
1242
|
+
# Assert that header text is drawn at the same location on each page
|
1243
|
+
if @header2_location
|
1244
|
+
expect(pt).to eq @header2_location
|
1245
|
+
else
|
1246
|
+
@header2_location = pt
|
1247
|
+
end
|
1248
|
+
end
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
original_method.call(*args, &block)
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
@pdf = Prawn::Document.new
|
1255
|
+
@pdf.table(data, :header => 2)
|
1256
|
+
end
|
1257
|
+
|
1258
|
+
it "should_not draw header twice when starting new page" do
|
1259
|
+
@pdf = Prawn::Document.new
|
1260
|
+
@pdf.y = 0
|
1261
|
+
@pdf.table([["Header"], ["Header2"], ["Body"]], :header => 2)
|
1262
|
+
output = PDF::Inspector::Text.analyze(@pdf.render)
|
1263
|
+
expect(output.strings).to eq ["Header", "Header2", "Body"]
|
1264
|
+
end
|
1265
|
+
end
|
1266
|
+
end
|
1267
|
+
|
1268
|
+
describe "nested tables" do
|
1269
|
+
before(:each) do
|
1270
|
+
@pdf = Prawn::Document.new
|
1271
|
+
@subtable = Prawn::Table.new([["foo"]], @pdf)
|
1272
|
+
@table = @pdf.table([[@subtable, "bar"], ['', { content: @subtable, padding: 10 }]])
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
it "can be created from an Array" do
|
1276
|
+
cell = Prawn::Table::Cell.make(@pdf, [["foo"]])
|
1277
|
+
expect(cell).to be_a_kind_of(Prawn::Table::Cell::Subtable)
|
1278
|
+
expect(cell.subtable).to be_a_kind_of(Prawn::Table)
|
1279
|
+
end
|
1280
|
+
|
1281
|
+
it "defaults its padding to zero" do
|
1282
|
+
expect(@table.cells[0, 0].padding).to eq [0, 0, 0, 0]
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
it "has a subtable accessor" do
|
1286
|
+
expect(@table.cells[0, 0].subtable).to eq @subtable
|
1287
|
+
end
|
1288
|
+
|
1289
|
+
it "determines its dimensions from the subtable" do
|
1290
|
+
expect(@table.cells[0, 0].width).to eq @subtable.width
|
1291
|
+
expect(@table.cells[0, 0].height).to eq @subtable.height
|
1292
|
+
end
|
1293
|
+
|
1294
|
+
it "pads the holding cell with padding options" do
|
1295
|
+
expect(@table.cells[1, 1].padding).to eq [10, 10, 10, 10]
|
1296
|
+
end
|
1297
|
+
end
|
1298
|
+
|
1299
|
+
it "Prints table on one page when using subtable with colspan > 1", :unresolved, issue: 10 do
|
1300
|
+
pdf = Prawn::Document.new(margin: [ 30, 71, 55, 71])
|
1301
|
+
|
1302
|
+
lines = "one\ntwo\nthree\nfour"
|
1303
|
+
|
1304
|
+
sub_table_lines = lines.split("\n").map do |line|
|
1305
|
+
if line == "one"
|
1306
|
+
[ { content: "#{line}", colspan: 2, size: 11} ]
|
1307
|
+
else
|
1308
|
+
[ { content: "\u2022"}, { content: "#{line}"} ]
|
1309
|
+
end
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
sub_table = pdf.make_table(sub_table_lines,
|
1313
|
+
cell_style: { border_color: '00ff00'})
|
1314
|
+
|
1315
|
+
#outer table
|
1316
|
+
pdf.table [[
|
1317
|
+
{ content: "Placeholder text", width: 200 },
|
1318
|
+
{ content: sub_table }
|
1319
|
+
]], width: 515, cell_style: { border_width: 1, border_color: 'ff0000' }
|
1320
|
+
|
1321
|
+
pdf.render
|
1322
|
+
expect(pdf.page_count).to eq 1
|
1323
|
+
end
|
1324
|
+
|
1325
|
+
describe "An invalid table" do
|
1326
|
+
|
1327
|
+
before(:each) do
|
1328
|
+
@pdf = Prawn::Document.new
|
1329
|
+
@bad_data = ["Single Nested Array"]
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
it "should raise_error error when invalid table data is given" do
|
1333
|
+
expect {
|
1334
|
+
@pdf.table(@bad_data)
|
1335
|
+
}.to raise_error(Prawn::Errors::InvalidTableData)
|
1336
|
+
end
|
1337
|
+
|
1338
|
+
it "should raise_error an EmptyTableError with empty table data" do
|
1339
|
+
expect {
|
1340
|
+
data = []
|
1341
|
+
@pdf = Prawn::Document.new
|
1342
|
+
@pdf.table(data)
|
1343
|
+
}.to raise_error( Prawn::Errors::EmptyTable )
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
it "should raise_error an EmptyTableError with nil table data" do
|
1347
|
+
expect {
|
1348
|
+
data = nil
|
1349
|
+
@pdf = Prawn::Document.new
|
1350
|
+
@pdf.table(data)
|
1351
|
+
}.to raise_error( Prawn::Errors::EmptyTable )
|
1352
|
+
end
|
1353
|
+
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
end
|
1357
|
+
|
1358
|
+
describe "colspan / rowspan" do
|
1359
|
+
before(:each) { create_pdf }
|
1360
|
+
|
1361
|
+
it "doesn't raise an error" do
|
1362
|
+
expect {
|
1363
|
+
@pdf.table([[{:content => "foo", :colspan => 2, :rowspan => 2}]])
|
1364
|
+
}.to_not raise_error
|
1365
|
+
end
|
1366
|
+
|
1367
|
+
it "colspan is properly counted" do
|
1368
|
+
t = @pdf.make_table([[{:content => "foo", :colspan => 2}]])
|
1369
|
+
expect(t.column_length).to eq 2
|
1370
|
+
end
|
1371
|
+
|
1372
|
+
it "rowspan is properly counted" do
|
1373
|
+
t = @pdf.make_table([[{:content => "foo", :rowspan => 2}]])
|
1374
|
+
expect(t.row_length).to eq 2
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
it "raises if colspan or rowspan are called after layout" do
|
1378
|
+
expect {
|
1379
|
+
@pdf.table([["foo"]]) { cells[0, 0].colspan = 2 }
|
1380
|
+
}.to raise_error(Prawn::Errors::InvalidTableSpan)
|
1381
|
+
|
1382
|
+
expect {
|
1383
|
+
@pdf.table([["foo"]]) { cells[0, 0].rowspan = 2 }
|
1384
|
+
}.to raise_error(Prawn::Errors::InvalidTableSpan)
|
1385
|
+
end
|
1386
|
+
|
1387
|
+
it "raises when spans overlap" do
|
1388
|
+
expect {
|
1389
|
+
@pdf.table([["foo", {:content => "bar", :rowspan => 2}],
|
1390
|
+
[{:content => "baz", :colspan => 2}]])
|
1391
|
+
}.to raise_error(Prawn::Errors::InvalidTableSpan)
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
it "table and cell width account for colspan" do
|
1395
|
+
t = @pdf.table([["a", {:content => "b", :colspan => 2}]],
|
1396
|
+
:column_widths => [100, 100, 100])
|
1397
|
+
spanned = t.cells[0, 1]
|
1398
|
+
expect(spanned.colspan).to eq 2
|
1399
|
+
expect(t.width).to eq 300
|
1400
|
+
expect(t.cells.min_width).to eq 300
|
1401
|
+
expect(t.cells.max_width).to eq 300
|
1402
|
+
expect(spanned.width).to eq 200
|
1403
|
+
end
|
1404
|
+
|
1405
|
+
it "table and cell height account for rowspan" do
|
1406
|
+
t = @pdf.table([["a"], [{:content => "b", :rowspan => 2}]]) do
|
1407
|
+
row(0..2).height = 100
|
1408
|
+
end
|
1409
|
+
spanned = t.cells[1, 0]
|
1410
|
+
expect(spanned.rowspan).to eq 2
|
1411
|
+
expect(t.height).to eq 300
|
1412
|
+
expect(spanned.height).to eq 200
|
1413
|
+
end
|
1414
|
+
|
1415
|
+
it "provides the full content_width as drawing space" do
|
1416
|
+
w = @pdf.make_table([["foo"]]).cells[0, 0].content_width
|
1417
|
+
|
1418
|
+
t = @pdf.make_table([[{:content => "foo", :colspan => 2}]])
|
1419
|
+
expect(t.cells[0, 0].spanned_content_width).to eq w
|
1420
|
+
end
|
1421
|
+
|
1422
|
+
it "dummy cells are not drawn" do
|
1423
|
+
# make a fake master cell for the dummy cell to slave to
|
1424
|
+
t = @pdf.make_table([[{:content => "foo", :colspan => 2}]])
|
1425
|
+
|
1426
|
+
# drawing just a dummy cell should_not ink
|
1427
|
+
expect(@pdf).to_not receive(:stroke_line)
|
1428
|
+
expect(@pdf).to_not receive(:draw_text!)
|
1429
|
+
Prawn::Table::Cell.draw_cells([t.cells[0, 1]])
|
1430
|
+
end
|
1431
|
+
|
1432
|
+
it "dummy cells do not add any height or width" do
|
1433
|
+
t1 = @pdf.table([["foo"]])
|
1434
|
+
|
1435
|
+
t2 = @pdf.table([[{:content => "foo", :colspan => 2}]])
|
1436
|
+
expect(t2.width).to eq t1.width
|
1437
|
+
|
1438
|
+
t3 = @pdf.table([[{:content => "foo", :rowspan => 2}]])
|
1439
|
+
expect(t3.height).to eq t1.height
|
1440
|
+
end
|
1441
|
+
|
1442
|
+
it "dummy cells ignored by #style" do
|
1443
|
+
t = @pdf.table([[{:content => "blah", :colspan => 2}]],
|
1444
|
+
:cell_style => { :size => 9 })
|
1445
|
+
expect(t.cells[0, 0].size).to eq 9
|
1446
|
+
end
|
1447
|
+
|
1448
|
+
context "inheriting master cell styles from dummy cell" do
|
1449
|
+
# Relatively full coverage for all these attributes that should be
|
1450
|
+
# inherited.
|
1451
|
+
[["border_X_width", 20],
|
1452
|
+
["border_X_color", "123456"],
|
1453
|
+
["padding_X", 20]].each do |attribute, val|
|
1454
|
+
attribute_right = attribute.sub("X", "right")
|
1455
|
+
attribute_left = attribute.sub("X", "left")
|
1456
|
+
attribute_bottom = attribute.sub("X", "bottom")
|
1457
|
+
attribute_top = attribute.sub("X", "top")
|
1458
|
+
|
1459
|
+
specify "#{attribute_right} of right column is inherited" do
|
1460
|
+
t = @pdf.table([[{:content => "blah", :colspan => 2}]]) do |table|
|
1461
|
+
table.column(1).send("#{attribute_right}=", val)
|
1462
|
+
end
|
1463
|
+
|
1464
|
+
expect(t.cells[0, 0].send(attribute_right)).to eq val
|
1465
|
+
end
|
1466
|
+
|
1467
|
+
specify "#{attribute_bottom} of bottom row is inherited" do
|
1468
|
+
t = @pdf.table([[{:content => "blah", :rowspan => 2}]]) do |table|
|
1469
|
+
table.row(1).send("#{attribute_bottom}=", val)
|
1470
|
+
end
|
1471
|
+
|
1472
|
+
expect(t.cells[0, 0].send(attribute_bottom)).to eq val
|
1473
|
+
end
|
1474
|
+
|
1475
|
+
specify "#{attribute_left} of right column is not inherited" do
|
1476
|
+
t = @pdf.table([[{:content => "blah", :colspan => 2}]]) do |table|
|
1477
|
+
table.column(1).send("#{attribute_left}=", val)
|
1478
|
+
end
|
1479
|
+
|
1480
|
+
expect(t.cells[0, 0].send(attribute_left)).to_not eq val
|
1481
|
+
end
|
1482
|
+
|
1483
|
+
specify "#{attribute_right} of interior column is not inherited" do
|
1484
|
+
t = @pdf.table([[{:content => "blah", :colspan => 3}]]) do |table|
|
1485
|
+
table.column(1).send("#{attribute_right}=", val)
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
expect(t.cells[0, 0].send(attribute_right)).to_not eq val
|
1489
|
+
end
|
1490
|
+
|
1491
|
+
specify "#{attribute_bottom} of interior row is not inherited" do
|
1492
|
+
t = @pdf.table([[{:content => "blah", :rowspan => 3}]]) do |table|
|
1493
|
+
table.row(1).send("#{attribute_bottom}=", val)
|
1494
|
+
end
|
1495
|
+
|
1496
|
+
expect(t.cells[0, 0].send(attribute_bottom)).to_not eq val
|
1497
|
+
end
|
1498
|
+
|
1499
|
+
specify "#{attribute_top} of bottom row is not inherited" do
|
1500
|
+
t = @pdf.table([[{:content => "blah", :rowspan => 2}]]) do |table|
|
1501
|
+
table.row(1).send("#{attribute_top}=", val)
|
1502
|
+
end
|
1503
|
+
|
1504
|
+
expect(t.cells[0, 0].send(attribute_top)).to_not eq val
|
1505
|
+
end
|
1506
|
+
end
|
1507
|
+
end
|
1508
|
+
|
1509
|
+
it "splits natural width between cols in the group" do
|
1510
|
+
t = @pdf.table([[{:content => "foo", :colspan => 2}]])
|
1511
|
+
widths = t.column_widths
|
1512
|
+
expect(widths[0]).to eq widths[1]
|
1513
|
+
end
|
1514
|
+
|
1515
|
+
it "splits natural width between cols when width is increased" do
|
1516
|
+
t = @pdf.table([[{:content => "foo", :colspan => 2}]],
|
1517
|
+
:width => @pdf.bounds.width)
|
1518
|
+
widths = t.column_widths
|
1519
|
+
expect(widths[0]).to eq widths[1]
|
1520
|
+
end
|
1521
|
+
|
1522
|
+
it "splits min-width between cols in the group" do
|
1523
|
+
# Since column_widths, when reducing column widths, reduces proportional to
|
1524
|
+
# the remaining width after each column's min width, we must ensure that the
|
1525
|
+
# min-width is split proportionally in order to ensure the width is still
|
1526
|
+
# split evenly when the width is reduced. (See "splits natural width between
|
1527
|
+
# cols when width is reduced".)
|
1528
|
+
t = @pdf.table([[{:content => "foo", :colspan => 2}]],
|
1529
|
+
:width => 20)
|
1530
|
+
expect(t.column(0).min_width).to eq t.column(1).min_width
|
1531
|
+
end
|
1532
|
+
|
1533
|
+
it "splits natural width between cols when width is reduced" do
|
1534
|
+
t = @pdf.table([[{:content => "foo", :colspan => 2}]],
|
1535
|
+
:width => 20)
|
1536
|
+
widths = t.column_widths
|
1537
|
+
expect(widths[0]).to eq widths[1]
|
1538
|
+
end
|
1539
|
+
|
1540
|
+
it "honors a large, explicitly set table width" do
|
1541
|
+
t = @pdf.table([[{:content => "AAAAAAAAAA", :colspan => 3}],
|
1542
|
+
["A", "B", "C"]],
|
1543
|
+
:width => 400)
|
1544
|
+
|
1545
|
+
expect(t.column_widths.inject(0) { |sum, w| sum + w }).to be_within(0.01).of(400)
|
1546
|
+
end
|
1547
|
+
|
1548
|
+
it "honors a small, explicitly set table width" do
|
1549
|
+
t = @pdf.table([[{:content => "Lorem ipsum dolor sit amet " * 20,
|
1550
|
+
:colspan => 3}],
|
1551
|
+
["A", "B", "C"]],
|
1552
|
+
:width => 200)
|
1553
|
+
expect(t.column_widths.inject(0) { |sum, w| sum + w }).to be_within(0.01).of(200)
|
1554
|
+
end
|
1555
|
+
|
1556
|
+
it "splits natural_content_height between rows in the group" do
|
1557
|
+
t = @pdf.table([[{:content => "foo", :rowspan => 2}]])
|
1558
|
+
heights = t.row_heights
|
1559
|
+
expect(heights[0]).to eq heights[1]
|
1560
|
+
end
|
1561
|
+
|
1562
|
+
it "skips column numbers that have been col-spanned" do
|
1563
|
+
t = @pdf.table([["a", "b", {:content => "c", :colspan => 3}, "d"]])
|
1564
|
+
expect(t.cells[0, 0].content).to eq "a"
|
1565
|
+
expect(t.cells[0, 1].content).to eq "b"
|
1566
|
+
expect(t.cells[0, 2].content).to eq "c"
|
1567
|
+
expect(t.cells[0, 3]).to be_a_kind_of(Prawn::Table::Cell::SpanDummy)
|
1568
|
+
expect(t.cells[0, 4]).to be_a_kind_of(Prawn::Table::Cell::SpanDummy)
|
1569
|
+
expect(t.cells[0, 5].content).to eq "d"
|
1570
|
+
end
|
1571
|
+
|
1572
|
+
it "skips row/col positions that have been row-spanned" do
|
1573
|
+
t = @pdf.table([["a", {:content => "b", :colspan => 2, :rowspan => 2}, "c"],
|
1574
|
+
["d", "e"],
|
1575
|
+
["f", "g", "h", "i"]])
|
1576
|
+
expect(t.cells[0, 0].content).to eq "a"
|
1577
|
+
expect(t.cells[0, 1].content).to eq "b"
|
1578
|
+
expect(t.cells[0, 2]).to be_a_kind_of(Prawn::Table::Cell::SpanDummy)
|
1579
|
+
expect(t.cells[0, 3].content).to eq "c"
|
1580
|
+
|
1581
|
+
expect(t.cells[1, 0].content).to eq "d"
|
1582
|
+
expect(t.cells[1, 1]).to be_a_kind_of(Prawn::Table::Cell::SpanDummy)
|
1583
|
+
expect(t.cells[1, 2]).to be_a_kind_of(Prawn::Table::Cell::SpanDummy)
|
1584
|
+
expect(t.cells[1, 3].content).to eq "e"
|
1585
|
+
|
1586
|
+
expect(t.cells[2, 0].content).to eq "f"
|
1587
|
+
expect(t.cells[2, 1].content).to eq "g"
|
1588
|
+
expect(t.cells[2, 2].content).to eq "h"
|
1589
|
+
expect(t.cells[2, 3].content).to eq "i"
|
1590
|
+
end
|
1591
|
+
|
1592
|
+
it 'illustrates issue #20', issue: 20 do
|
1593
|
+
pdf = Prawn::Document.new
|
1594
|
+
description = "one\ntwo\nthree"
|
1595
|
+
bullets = description.split("\n")
|
1596
|
+
bullets.each_with_index do |bullet, ndx|
|
1597
|
+
rows = [[]]
|
1598
|
+
|
1599
|
+
if ndx < 1
|
1600
|
+
rows << [ { content: "blah blah blah", colspan: 2, font_style: :bold, size: 12, padding_bottom: 1 }]
|
1601
|
+
else
|
1602
|
+
rows << [ { content: bullet, width: 440, padding_top: 0, align: :justify } ]
|
1603
|
+
end
|
1604
|
+
pdf.table(rows, header: true, cell_style: { border_width: 0, inline_format: true })
|
1605
|
+
end
|
1606
|
+
pdf.render
|
1607
|
+
end
|
1608
|
+
|
1609
|
+
it 'illustrates issue #20 (2) and #22', issue: 22 do
|
1610
|
+
pdf = Prawn::Document.new
|
1611
|
+
pdf.table [['one', 'two']], position: :center
|
1612
|
+
pdf.table [['three', 'four']], position: :center
|
1613
|
+
pdf.render
|
1614
|
+
expect(pdf.page_count).to eq 1
|
1615
|
+
end
|
1616
|
+
|
1617
|
+
it 'illustrates issue #56 cell style should not be overwritten by table style', issue: 56 do
|
1618
|
+
t = @pdf.table([['col1', 'col2'],
|
1619
|
+
['val1', { content: 'val2', align: :left }]],
|
1620
|
+
cell_style: { align: :center })
|
1621
|
+
expect(t.cells[0, 0].align).to eq :center
|
1622
|
+
expect(t.cells[0, 1].align).to eq :center
|
1623
|
+
expect(t.cells[1, 0].align).to eq :center
|
1624
|
+
expect(t.cells[1, 1].align).to eq :left
|
1625
|
+
end
|
1626
|
+
end
|