prawn 1.1.0 → 1.2.1

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