prawn 0.13.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (348) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +10 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -16
  6. data/Rakefile +17 -39
  7. data/lib/prawn/document/bounding_box.rb +85 -42
  8. data/lib/prawn/document/column_box.rb +21 -11
  9. data/lib/prawn/document/internals.rb +40 -147
  10. data/lib/prawn/document/span.rb +25 -17
  11. data/lib/prawn/document.rb +286 -245
  12. data/lib/prawn/encoding.rb +68 -101
  13. data/lib/prawn/errors.rb +47 -43
  14. data/lib/prawn/font.rb +204 -155
  15. data/lib/prawn/font_metric_cache.rb +25 -21
  16. data/lib/prawn/fonts/afm.rb +292 -0
  17. data/lib/prawn/{font → fonts}/dfont.rb +7 -13
  18. data/lib/prawn/fonts/otf.rb +11 -0
  19. data/lib/prawn/fonts/ttc.rb +36 -0
  20. data/lib/prawn/{font → fonts}/ttf.rb +142 -80
  21. data/lib/prawn/graphics/blend_mode.rb +65 -0
  22. data/lib/prawn/graphics/cap_style.rb +6 -5
  23. data/lib/prawn/graphics/color.rb +47 -44
  24. data/lib/prawn/graphics/dash.rb +30 -13
  25. data/lib/prawn/graphics/join_style.rb +13 -6
  26. data/lib/prawn/graphics/patterns.rb +221 -90
  27. data/lib/prawn/graphics/transformation.rb +21 -12
  28. data/lib/prawn/graphics/transparency.rb +21 -17
  29. data/lib/prawn/graphics.rb +155 -128
  30. data/lib/prawn/{layout/grid.rb → grid.rb} +110 -47
  31. data/lib/prawn/image_handler.rb +16 -2
  32. data/lib/prawn/images/image.rb +4 -2
  33. data/lib/prawn/images/jpg.rb +39 -30
  34. data/lib/prawn/images/png.rb +132 -169
  35. data/lib/prawn/images.rb +70 -62
  36. data/lib/prawn/measurement_extensions.rb +15 -10
  37. data/lib/prawn/measurements.rb +22 -23
  38. data/lib/prawn/outline.rb +301 -13
  39. data/lib/prawn/repeater.rb +19 -17
  40. data/lib/prawn/security/arcfour.rb +54 -0
  41. data/lib/prawn/security.rb +108 -86
  42. data/lib/prawn/soft_mask.rb +40 -41
  43. data/lib/prawn/stamp.rb +29 -12
  44. data/lib/prawn/text/box.rb +27 -29
  45. data/lib/prawn/text/formatted/arranger.rb +110 -67
  46. data/lib/prawn/text/formatted/box.rb +233 -165
  47. data/lib/prawn/text/formatted/fragment.rb +27 -27
  48. data/lib/prawn/text/formatted/line_wrap.rb +137 -97
  49. data/lib/prawn/text/formatted/parser.rb +149 -127
  50. data/lib/prawn/text/formatted/wrap.rb +57 -37
  51. data/lib/prawn/text/formatted.rb +6 -4
  52. data/lib/prawn/text.rb +105 -73
  53. data/lib/prawn/transformation_stack.rb +44 -0
  54. data/lib/prawn/utilities.rb +11 -21
  55. data/lib/prawn/version.rb +5 -0
  56. data/lib/prawn/view.rb +101 -0
  57. data/lib/prawn.rb +42 -68
  58. data/{data/images/fractal.jpg → manual/absolute_position.pdf} +0 -0
  59. data/manual/basic_concepts/adding_pages.rb +9 -10
  60. data/manual/basic_concepts/basic_concepts.rb +33 -24
  61. data/manual/basic_concepts/creation.rb +10 -11
  62. data/manual/basic_concepts/cursor.rb +9 -10
  63. data/manual/basic_concepts/measurement.rb +10 -11
  64. data/manual/basic_concepts/origin.rb +8 -9
  65. data/manual/basic_concepts/other_cursor_helpers.rb +17 -18
  66. data/manual/basic_concepts/view.rb +48 -0
  67. data/manual/bounding_box/bounding_box.rb +31 -29
  68. data/manual/bounding_box/bounds.rb +17 -18
  69. data/manual/bounding_box/canvas.rb +8 -9
  70. data/manual/bounding_box/creation.rb +8 -9
  71. data/manual/bounding_box/indentation.rb +22 -23
  72. data/manual/bounding_box/nesting.rb +32 -25
  73. data/manual/bounding_box/russian_boxes.rb +19 -19
  74. data/manual/bounding_box/stretchy.rb +18 -20
  75. data/manual/contents.rb +35 -0
  76. data/manual/cover.rb +43 -0
  77. data/manual/document_and_page_options/background.rb +16 -14
  78. data/manual/document_and_page_options/document_and_page_options.rb +26 -23
  79. data/manual/document_and_page_options/metadata.rb +21 -19
  80. data/manual/document_and_page_options/page_margins.rb +20 -22
  81. data/manual/document_and_page_options/page_size.rb +15 -15
  82. data/manual/document_and_page_options/print_scaling.rb +23 -0
  83. data/manual/example_helper.rb +5 -408
  84. data/manual/graphics/blend_mode.rb +52 -0
  85. data/manual/graphics/circle_and_ellipse.rb +8 -9
  86. data/manual/graphics/color.rb +11 -13
  87. data/manual/graphics/common_lines.rb +13 -12
  88. data/manual/graphics/fill_and_stroke.rb +10 -11
  89. data/manual/graphics/fill_rules.rb +13 -12
  90. data/manual/graphics/gradients.rb +28 -22
  91. data/manual/graphics/graphics.rb +52 -46
  92. data/manual/graphics/helper.rb +20 -10
  93. data/manual/graphics/line_width.rb +13 -12
  94. data/manual/graphics/lines_and_curves.rb +13 -14
  95. data/manual/graphics/polygon.rb +10 -12
  96. data/manual/graphics/rectangle.rb +7 -8
  97. data/manual/graphics/rotate.rb +9 -12
  98. data/manual/graphics/scale.rb +19 -18
  99. data/manual/graphics/soft_masks.rb +5 -7
  100. data/manual/graphics/stroke_cap.rb +10 -11
  101. data/manual/graphics/stroke_dash.rb +16 -17
  102. data/manual/graphics/stroke_join.rb +10 -11
  103. data/manual/graphics/translate.rb +13 -13
  104. data/manual/graphics/transparency.rb +11 -13
  105. data/manual/{manual/how_to_read_this_manual.rb → how_to_read_this_manual.rb} +23 -25
  106. data/manual/images/absolute_position.rb +9 -10
  107. data/manual/images/fit.rb +9 -10
  108. data/manual/images/horizontal.rb +13 -14
  109. data/manual/images/images.rb +31 -30
  110. data/manual/images/plain_image.rb +6 -7
  111. data/manual/images/scale.rb +12 -13
  112. data/manual/images/vertical.rb +19 -17
  113. data/manual/images/width_and_height.rb +13 -14
  114. data/manual/layout/boxes.rb +14 -15
  115. data/manual/layout/content.rb +12 -13
  116. data/manual/layout/layout.rb +19 -20
  117. data/manual/layout/simple_grid.rb +8 -9
  118. data/manual/outline/add_subsection_to.rb +26 -27
  119. data/manual/outline/insert_section_after.rb +19 -20
  120. data/manual/outline/outline.rb +23 -22
  121. data/manual/outline/sections_and_pages.rb +24 -25
  122. data/manual/repeatable_content/alternate_page_numbering.rb +36 -0
  123. data/manual/repeatable_content/page_numbering.rb +20 -19
  124. data/manual/repeatable_content/repeatable_content.rb +26 -22
  125. data/manual/repeatable_content/repeater.rb +18 -19
  126. data/manual/repeatable_content/stamp.rb +18 -19
  127. data/manual/security/encryption.rb +8 -11
  128. data/manual/security/permissions.rb +20 -15
  129. data/manual/security/security.rb +20 -20
  130. data/manual/table.rb +16 -0
  131. data/manual/text/alignment.rb +17 -18
  132. data/manual/text/color.rb +13 -13
  133. data/manual/text/column_box.rb +10 -12
  134. data/manual/text/fallback_fonts.rb +29 -25
  135. data/manual/text/font.rb +17 -18
  136. data/manual/text/font_size.rb +21 -22
  137. data/manual/text/font_style.rb +12 -10
  138. data/manual/text/formatted_callbacks.rb +36 -26
  139. data/manual/text/formatted_text.rb +41 -34
  140. data/manual/text/free_flowing_text.rb +28 -29
  141. data/manual/text/inline.rb +23 -26
  142. data/manual/text/kerning_and_character_spacing.rb +20 -21
  143. data/manual/text/leading.rb +10 -11
  144. data/manual/text/line_wrapping.rb +40 -21
  145. data/manual/text/paragraph_indentation.rb +17 -12
  146. data/manual/text/positioned_text.rb +19 -20
  147. data/manual/text/registering_families.rb +33 -30
  148. data/manual/text/rendering_and_color.rb +11 -12
  149. data/manual/text/right_to_left_text.rb +31 -20
  150. data/manual/text/rotation.rb +36 -27
  151. data/manual/text/single_usage.rb +13 -14
  152. data/manual/text/text.rb +62 -62
  153. data/manual/text/text_box_excess.rb +22 -19
  154. data/manual/text/text_box_extensions.rb +21 -18
  155. data/manual/text/text_box_overflow.rb +28 -21
  156. data/manual/text/utf8.rb +16 -17
  157. data/manual/text/win_ansi_charset.rb +29 -26
  158. data/prawn.gemspec +45 -43
  159. data/spec/extensions/encoding_helpers.rb +4 -3
  160. data/spec/prawn/document/bounding_box_spec.rb +550 -0
  161. data/spec/prawn/document/column_box_spec.rb +75 -0
  162. data/spec/prawn/document/security_spec.rb +176 -0
  163. data/spec/prawn/document_annotations_spec.rb +76 -0
  164. data/spec/prawn/document_destinations_spec.rb +15 -0
  165. data/spec/prawn/document_grid_spec.rb +99 -0
  166. data/spec/prawn/document_reference_spec.rb +27 -0
  167. data/spec/prawn/document_span_spec.rb +44 -0
  168. data/spec/prawn/document_spec.rb +805 -0
  169. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  170. data/spec/prawn/font_spec.rb +544 -0
  171. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  172. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  173. data/spec/prawn/graphics_spec.rb +872 -0
  174. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  175. data/spec/prawn/image_handler_spec.rb +53 -0
  176. data/spec/prawn/images/jpg_spec.rb +20 -0
  177. data/spec/prawn/images/png_spec.rb +283 -0
  178. data/spec/prawn/images_spec.rb +229 -0
  179. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  180. data/spec/prawn/outline_spec.rb +512 -0
  181. data/spec/prawn/repeater_spec.rb +166 -0
  182. data/spec/prawn/soft_mask_spec.rb +74 -0
  183. data/spec/prawn/stamp_spec.rb +173 -0
  184. data/spec/prawn/text/box_spec.rb +1110 -0
  185. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  186. data/spec/prawn/text/formatted/box_spec.rb +849 -0
  187. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  188. data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
  189. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  190. data/spec/prawn/text_draw_text_spec.rb +150 -0
  191. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  192. data/spec/prawn/text_spacing_spec.rb +95 -0
  193. data/spec/prawn/text_spec.rb +603 -0
  194. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  195. data/spec/prawn/transformation_stack_spec.rb +66 -0
  196. data/spec/prawn/view_spec.rb +63 -0
  197. data/spec/prawn_manual_spec.rb +35 -0
  198. data/spec/spec_helper.rb +22 -21
  199. data.tar.gz.sig +0 -0
  200. metadata +168 -307
  201. metadata.gz.sig +0 -0
  202. data/README.md +0 -109
  203. data/data/encodings/win_ansi.txt +0 -29
  204. data/data/images/16bit.alpha +0 -0
  205. data/data/images/16bit.dat +0 -0
  206. data/data/images/16bit.png +0 -0
  207. data/data/images/arrow.png +0 -0
  208. data/data/images/arrow2.png +0 -0
  209. data/data/images/barcode_issue.png +0 -0
  210. data/data/images/dice.alpha +0 -0
  211. data/data/images/dice.dat +0 -0
  212. data/data/images/dice.png +0 -0
  213. data/data/images/dice_interlaced.png +0 -0
  214. data/data/images/indexed_color.dat +0 -0
  215. data/data/images/indexed_color.png +0 -0
  216. data/data/images/letterhead.jpg +0 -0
  217. data/data/images/page_white_text.alpha +0 -0
  218. data/data/images/page_white_text.dat +0 -0
  219. data/data/images/page_white_text.png +0 -0
  220. data/data/images/pigs.jpg +0 -0
  221. data/data/images/prawn.png +0 -0
  222. data/data/images/ruport.png +0 -0
  223. data/data/images/ruport_data.dat +0 -0
  224. data/data/images/ruport_transparent.png +0 -0
  225. data/data/images/ruport_type0.png +0 -0
  226. data/data/images/stef.jpg +0 -0
  227. data/data/images/tru256.bmp +0 -0
  228. data/data/images/web-links.dat +0 -1
  229. data/data/images/web-links.png +0 -0
  230. data/data/pdfs/complex_template.pdf +0 -0
  231. data/data/pdfs/contains_ttf_font.pdf +0 -0
  232. data/data/pdfs/encrypted.pdf +0 -0
  233. data/data/pdfs/form.pdf +1 -819
  234. data/data/pdfs/hexagon.pdf +0 -61
  235. data/data/pdfs/indirect_reference.pdf +0 -86
  236. data/data/pdfs/multipage_template.pdf +0 -127
  237. data/data/pdfs/nested_pages.pdf +0 -118
  238. data/data/pdfs/page_without_mediabox.pdf +0 -193
  239. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  240. data/data/pdfs/two_hexagons.pdf +0 -90
  241. data/data/pdfs/version_1_6.pdf +0 -61
  242. data/data/shift_jis_text.txt +0 -1
  243. data/lib/pdf/core/annotations.rb +0 -60
  244. data/lib/pdf/core/byte_string.rb +0 -9
  245. data/lib/pdf/core/destinations.rb +0 -90
  246. data/lib/pdf/core/document_state.rb +0 -78
  247. data/lib/pdf/core/filter_list.rb +0 -51
  248. data/lib/pdf/core/filters.rb +0 -36
  249. data/lib/pdf/core/graphics_state.rb +0 -68
  250. data/lib/pdf/core/literal_string.rb +0 -16
  251. data/lib/pdf/core/name_tree.rb +0 -177
  252. data/lib/pdf/core/object_store.rb +0 -320
  253. data/lib/pdf/core/outline.rb +0 -315
  254. data/lib/pdf/core/page.rb +0 -212
  255. data/lib/pdf/core/page_geometry.rb +0 -126
  256. data/lib/pdf/core/pdf_object.rb +0 -124
  257. data/lib/pdf/core/reference.rb +0 -103
  258. data/lib/pdf/core/stream.rb +0 -98
  259. data/lib/pdf/core/text.rb +0 -275
  260. data/lib/pdf/core.rb +0 -35
  261. data/lib/prawn/compatibility.rb +0 -91
  262. data/lib/prawn/document/graphics_state.rb +0 -73
  263. data/lib/prawn/document/snapshot.rb +0 -89
  264. data/lib/prawn/font/afm.rb +0 -203
  265. data/lib/prawn/layout.rb +0 -20
  266. data/lib/prawn/table/cell/image.rb +0 -70
  267. data/lib/prawn/table/cell/in_table.rb +0 -27
  268. data/lib/prawn/table/cell/span_dummy.rb +0 -92
  269. data/lib/prawn/table/cell/subtable.rb +0 -65
  270. data/lib/prawn/table/cell/text.rb +0 -153
  271. data/lib/prawn/table/cell.rb +0 -770
  272. data/lib/prawn/table/cells.rb +0 -295
  273. data/lib/prawn/table.rb +0 -643
  274. data/manual/example_file.rb +0 -116
  275. data/manual/example_package.rb +0 -53
  276. data/manual/example_section.rb +0 -46
  277. data/manual/manual/cover.rb +0 -35
  278. data/manual/manual/foreword.rb +0 -85
  279. data/manual/manual/manual.rb +0 -35
  280. data/manual/syntax_highlight.rb +0 -52
  281. data/manual/table/basic_block.rb +0 -53
  282. data/manual/table/before_rendering_page.rb +0 -26
  283. data/manual/table/cell_border_lines.rb +0 -24
  284. data/manual/table/cell_borders_and_bg.rb +0 -31
  285. data/manual/table/cell_dimensions.rb +0 -30
  286. data/manual/table/cell_text.rb +0 -38
  287. data/manual/table/column_widths.rb +0 -30
  288. data/manual/table/content_and_subtables.rb +0 -39
  289. data/manual/table/creation.rb +0 -27
  290. data/manual/table/filtering.rb +0 -36
  291. data/manual/table/flow_and_header.rb +0 -17
  292. data/manual/table/image_cells.rb +0 -33
  293. data/manual/table/position.rb +0 -29
  294. data/manual/table/row_colors.rb +0 -20
  295. data/manual/table/span.rb +0 -30
  296. data/manual/table/style.rb +0 -22
  297. data/manual/table/table.rb +0 -52
  298. data/manual/table/width.rb +0 -27
  299. data/manual/templates/full_template.rb +0 -25
  300. data/manual/templates/page_template.rb +0 -48
  301. data/manual/templates/templates.rb +0 -27
  302. data/manual/text/group.rb +0 -29
  303. data/spec/acceptance/png.rb +0 -23
  304. data/spec/annotations_spec.rb +0 -74
  305. data/spec/bounding_box_spec.rb +0 -493
  306. data/spec/cell_spec.rb +0 -628
  307. data/spec/column_box_spec.rb +0 -33
  308. data/spec/destinations_spec.rb +0 -15
  309. data/spec/document_spec.rb +0 -761
  310. data/spec/extensions/mocha.rb +0 -44
  311. data/spec/filters_spec.rb +0 -34
  312. data/spec/font_metric_cache_spec.rb +0 -52
  313. data/spec/font_spec.rb +0 -464
  314. data/spec/formatted_text_arranger_spec.rb +0 -421
  315. data/spec/formatted_text_box_spec.rb +0 -650
  316. data/spec/formatted_text_fragment_spec.rb +0 -298
  317. data/spec/graphics_spec.rb +0 -651
  318. data/spec/grid_spec.rb +0 -85
  319. data/spec/image_handler_spec.rb +0 -42
  320. data/spec/images_spec.rb +0 -157
  321. data/spec/inline_formatted_text_parser_spec.rb +0 -564
  322. data/spec/jpg_spec.rb +0 -25
  323. data/spec/line_wrap_spec.rb +0 -333
  324. data/spec/measurement_units_spec.rb +0 -23
  325. data/spec/name_tree_spec.rb +0 -112
  326. data/spec/object_store_spec.rb +0 -170
  327. data/spec/outline_spec.rb +0 -448
  328. data/spec/pdf_object_spec.rb +0 -172
  329. data/spec/png_spec.rb +0 -240
  330. data/spec/reference_spec.rb +0 -82
  331. data/spec/repeater_spec.rb +0 -158
  332. data/spec/security_spec.rb +0 -158
  333. data/spec/snapshot_spec.rb +0 -186
  334. data/spec/soft_mask_spec.rb +0 -117
  335. data/spec/span_spec.rb +0 -44
  336. data/spec/stamp_spec.rb +0 -158
  337. data/spec/stream_spec.rb +0 -58
  338. data/spec/stroke_styles_spec.rb +0 -211
  339. data/spec/table/span_dummy_spec.rb +0 -17
  340. data/spec/table_spec.rb +0 -1355
  341. data/spec/template_spec.rb +0 -351
  342. data/spec/text_at_spec.rb +0 -130
  343. data/spec/text_box_spec.rb +0 -1030
  344. data/spec/text_rendering_mode_spec.rb +0 -45
  345. data/spec/text_spacing_spec.rb +0 -93
  346. data/spec/text_spec.rb +0 -425
  347. data/spec/text_with_inline_formatting_spec.rb +0 -35
  348. data/spec/transparency_spec.rb +0 -89
data/spec/table_spec.rb DELETED
@@ -1,1355 +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" do
7
-
8
- describe "converting data to Cell objects" do
9
- before(:each) do
10
- @pdf = Prawn::Document.new
11
- @table = @pdf.table([%w[R0C0 R0C1], %w[R1C0 R1C1]])
12
- end
13
-
14
- it "should return a Prawn::Table" do
15
- @table.should be_a_kind_of Prawn::Table
16
- end
17
-
18
- it "should flatten the data into the @cells array in row-major order" do
19
- @table.cells.map { |c| c.content }.should == %w[R0C0 R0C1 R1C0 R1C1]
20
- end
21
-
22
- it "should add row and column numbers to each cell" do
23
- c = @table.cells.to_a.first
24
- c.row.should == 0
25
- c.column.should == 0
26
- end
27
-
28
- it "should allow empty fields" do
29
- lambda {
30
- data = [["foo","bar"],["baz",""]]
31
- @pdf.table(data)
32
- }.should_not raise_error
33
- end
34
-
35
- it "should allow a table with a header but no body" do
36
- lambda { @pdf.table([["Header"]], :header => true) }.should_not raise_error
37
- end
38
-
39
- it "should accurately count columns from data" do
40
- # First data row may contain colspan which would hide true column count
41
- data = [["Name:", {:content => "Some very long name", :colspan => 5}]]
42
- pdf = Prawn::Document.new
43
- table = Prawn::Table.new data, pdf
44
- table.column_widths.length.should == 6
45
- end
46
- end
47
-
48
- describe "You can explicitly set the column widths and use a colspan > 1" do
49
- it "should work with a colspan > 1 with given column_widths (issue #407)" do
50
- #normal entries in line 1
51
- data = [
52
- [ '','',''],
53
- [ { :content => "", :colspan => 3 } ],
54
- [ "", "", "" ],
55
- ]
56
- pdf = Prawn::Document.new
57
- table = Prawn::Table.new data, pdf, :column_widths => [100 , 200, 240]
58
-
59
- #colspan entry in line 1
60
- data = [
61
- [ { :content => "", :colspan => 3 } ],
62
- [ "", "", "" ],
63
- ]
64
- pdf = Prawn::Document.new
65
- table = Prawn::Table.new data, pdf, :column_widths => [100 , 200, 240]
66
-
67
- #mixed entries in line 1
68
- data = [
69
- [ { :content => "", :colspan =>2 }, "" ],
70
- [ "", "", "" ],
71
- ]
72
- pdf = Prawn::Document.new
73
- table = Prawn::Table.new data, pdf, :column_widths => [100 , 200, 240]
74
-
75
- data = [['', '', {:content => '', :colspan => 2}, '',''],
76
- ['',{:content => '', :colspan => 5}]
77
- ]
78
- pdf = Prawn::Document.new
79
- table = Prawn::Table.new data, pdf, :column_widths => [50 , 100, 50, 50, 50, 50]
80
-
81
- end
82
-
83
- it "illustrate issue #533" do
84
- data = [['', '', '', '', '',''],
85
- ['',{:content => '', :colspan => 5}]]
86
- pdf = Prawn::Document.new
87
- table = Prawn::Table.new data, pdf, :column_widths => [50, 200, 40, 40, 50, 50]
88
- end
89
-
90
- it "illustrates issue #502" do
91
- pdf = Prawn::Document.new
92
- first = {:content=>"Foooo fo foooooo",:width=>50,:align=>:center}
93
- second = {:content=>"Foooo",:colspan=>2,:width=>70,:align=>:center}
94
- third = {:content=>"fooooooooooo, fooooooooooooo, fooo, foooooo fooooo",:width=>55,:align=>:center}
95
- fourth = {:content=>"Bar",:width=>15,:align=>:center}
96
- table_content = [[
97
- first,
98
- [[second],[third,fourth]]
99
- ]]
100
- pdf.move_down(20)
101
- pdf.table(table_content)
102
- end
103
- end
104
-
105
- describe "#initialize" do
106
- before(:each) do
107
- @pdf = Prawn::Document.new
108
- end
109
-
110
- it "should instance_eval a 0-arg block" do
111
- initializer = mock()
112
- initializer.expects(:kick).once
113
-
114
- @pdf.table([["a"]]){
115
- initializer.kick
116
- }
117
- end
118
-
119
- it "should call a 1-arg block with the document as the argument" do
120
- initializer = mock()
121
- initializer.expects(:kick).once
122
-
123
- @pdf.table([["a"]]){ |doc|
124
- doc.should be_a_kind_of(Prawn::Table); initializer.kick }
125
- end
126
-
127
- it "should proxy cell methods to #cells" do
128
- table = @pdf.table([["a"]], :cell_style => { :padding => 11 })
129
- table.cells[0, 0].padding.should == [11, 11, 11, 11]
130
- end
131
-
132
- it "should set row and column length" do
133
- table = @pdf.table([["a", "b", "c"], ["d", "e", "f"]])
134
- table.row_length.should == 2
135
- table.column_length.should == 3
136
- end
137
-
138
- it "should generate a text cell based on a String" do
139
- t = @pdf.table([["foo"]])
140
- t.cells[0,0].should be_a_kind_of(Prawn::Table::Cell::Text)
141
- end
142
-
143
- it "should pass through a text cell" do
144
- c = Prawn::Table::Cell::Text.new(@pdf, [0,0], :content => "foo")
145
- t = @pdf.table([[c]])
146
- t.cells[0,0].should == c
147
- end
148
- end
149
-
150
- describe "cell accessors" do
151
- before(:each) do
152
- @pdf = Prawn::Document.new
153
- @table = @pdf.table([%w[R0C0 R0C1], %w[R1C0 R1C1]])
154
- end
155
-
156
- it "should select rows by number or range" do
157
- Set.new(@table.row(0).map { |c| c.content }).should ==
158
- Set.new(%w[R0C0 R0C1])
159
- Set.new(@table.rows(0..1).map { |c| c.content }).should ==
160
- Set.new(%w[R0C0 R0C1 R1C0 R1C1])
161
- end
162
-
163
- it "should select rows by array" do
164
- Set.new(@table.rows([0, 1]).map { |c| c.content }).should ==
165
- Set.new(%w[R0C0 R0C1 R1C0 R1C1])
166
- end
167
-
168
- it "should allow negative row selectors" do
169
- Set.new(@table.row(-1).map { |c| c.content }).should ==
170
- Set.new(%w[R1C0 R1C1])
171
- Set.new(@table.rows(-2..-1).map { |c| c.content }).should ==
172
- Set.new(%w[R0C0 R0C1 R1C0 R1C1])
173
- Set.new(@table.rows(0..-1).map { |c| c.content }).should ==
174
- Set.new(%w[R0C0 R0C1 R1C0 R1C1])
175
- end
176
-
177
- it "should select columns by number or range" do
178
- Set.new(@table.column(0).map { |c| c.content }).should ==
179
- Set.new(%w[R0C0 R1C0])
180
- Set.new(@table.columns(0..1).map { |c| c.content }).should ==
181
- Set.new(%w[R0C0 R0C1 R1C0 R1C1])
182
- end
183
-
184
- it "should select columns by array" do
185
- Set.new(@table.columns([0, 1]).map { |c| c.content }).should ==
186
- Set.new(%w[R0C0 R0C1 R1C0 R1C1])
187
- end
188
-
189
- it "should allow negative column selectors" do
190
- Set.new(@table.column(-1).map { |c| c.content }).should ==
191
- Set.new(%w[R0C1 R1C1])
192
- Set.new(@table.columns(-2..-1).map { |c| c.content }).should ==
193
- Set.new(%w[R0C0 R0C1 R1C0 R1C1])
194
- Set.new(@table.columns(0..-1).map { |c| c.content }).should ==
195
- Set.new(%w[R0C0 R0C1 R1C0 R1C1])
196
- end
197
-
198
- it "should allow rows and columns to be combined" do
199
- @table.row(0).column(1).map { |c| c.content }.should == ["R0C1"]
200
- end
201
-
202
- it "should accept a filter block, returning a cell proxy" do
203
- @table.cells.filter { |c| c.content =~ /R0/ }.column(1).map{ |c|
204
- c.content }.should == ["R0C1"]
205
- end
206
-
207
- it "should accept the [] method, returning a Cell or nil" do
208
- @table.cells[0, 0].content.should == "R0C0"
209
- @table.cells[12, 12].should be_nil
210
- end
211
-
212
- it "should proxy unknown methods to the cells" do
213
- @table.cells.height = 200
214
- @table.row(1).height = 100
215
-
216
- @table.cells[0, 0].height.should == 200
217
- @table.cells[1, 0].height.should == 100
218
- end
219
-
220
- it "should ignore non-setter methods" do
221
- lambda {
222
- @table.cells.content_width
223
- }.should raise_error(NoMethodError)
224
- end
225
-
226
- it "skips cells that don't respond to the given method" do
227
- table = @pdf.make_table([[{:content => "R0", :colspan => 2}],
228
- %w[R1C0 R1C1]])
229
- lambda {
230
- table.row(0).font_style = :bold
231
- }.should_not raise_error
232
- end
233
-
234
- it "should accept the style method, proxying its calls to the cells" do
235
- @table.cells.style(:height => 200, :width => 200)
236
- @table.column(0).style(:width => 100)
237
-
238
- @table.cells[0, 1].width.should == 200
239
- @table.cells[1, 0].height.should == 200
240
- @table.cells[1, 0].width.should == 100
241
- end
242
-
243
- it "style method should accept a block, passing each cell to be styled" do
244
- @table.cells.style { |c| c.height = 200 }
245
- @table.cells[0, 1].height.should == 200
246
- end
247
-
248
- it "should return the width of selected columns for #width" do
249
- c0_width = @table.column(0).map{ |c| c.width }.max
250
- c1_width = @table.column(1).map{ |c| c.width }.max
251
-
252
- @table.column(0).width.should == c0_width
253
- @table.column(1).width.should == c1_width
254
-
255
- @table.columns(0..1).width.should == c0_width + c1_width
256
- @table.cells.width.should == c0_width + c1_width
257
- end
258
-
259
- it "should return the height of selected rows for #height" do
260
- r0_height = @table.row(0).map{ |c| c.height }.max
261
- r1_height = @table.row(1).map{ |c| c.height }.max
262
-
263
- @table.row(0).height.should == r0_height
264
- @table.row(1).height.should == r1_height
265
-
266
- @table.rows(0..1).height.should == r0_height + r1_height
267
- @table.cells.height.should == r0_height + r1_height
268
- end
269
- end
270
-
271
- describe "layout" do
272
- before(:each) do
273
- @pdf = Prawn::Document.new
274
- @long_text = "The quick brown fox jumped over the lazy dogs. " * 5
275
- end
276
-
277
- describe "width" do
278
- it "should raise_error an error if the given width is outside of range" do
279
- lambda do
280
- @pdf.table([["foo"]], :width => 1)
281
- end.should raise_error(Prawn::Errors::CannotFit)
282
-
283
- lambda do
284
- @pdf.table([[@long_text]], :width => @pdf.bounds.width + 100)
285
- end.should raise_error(Prawn::Errors::CannotFit)
286
- end
287
-
288
- it "should accept the natural width for small tables" do
289
- pad = 10 # default padding
290
- @table = @pdf.table([["a"]])
291
- @table.width.should == @table.cells[0, 0].natural_content_width + pad
292
- end
293
-
294
- it "width should == sum(column_widths)" do
295
- table = Prawn::Table.new([%w[ a b c ], %w[d e f]], @pdf) do
296
- column(0).width = 50
297
- column(1).width = 100
298
- column(2).width = 150
299
- end
300
- table.width.should == 300
301
- end
302
-
303
- it "should accept Numeric for column_widths" do
304
- table = Prawn::Table.new([%w[ a b c ], %w[d e f]], @pdf) do |t|
305
- t.column_widths = 50
306
- end
307
- table.width.should == 150
308
- end
309
-
310
- it "should calculate unspecified column widths as "+
311
- "(max(string_width) + 2*horizontal_padding)" do
312
- hpad, fs = 3, 12
313
- columns = 2
314
- table = Prawn::Table.new( [%w[ foo b ], %w[d foobar]], @pdf,
315
- :cell_style => { :padding => hpad, :size => fs } )
316
-
317
- col0_width = @pdf.width_of("foo", :size => fs)
318
- col1_width = @pdf.width_of("foobar", :size => fs)
319
-
320
- table.width.should == col0_width + col1_width + 2*columns*hpad
321
- end
322
-
323
- it "should allow mixing autocalculated and preset"+
324
- "column widths within a single table" do
325
- hpad, fs = 10, 6
326
- stretchy_columns = 2
327
-
328
- col0_width = 50
329
- col1_width = @pdf.width_of("foo", :size => fs)
330
- col2_width = @pdf.width_of("foobar", :size => fs)
331
- col3_width = 150
332
-
333
- table = Prawn::Table.new( [%w[snake foo b apple],
334
- %w[kitten d foobar banana]], @pdf,
335
- :cell_style => { :padding => hpad, :size => fs }) do
336
-
337
- column(0).width = col0_width
338
- column(3).width = col3_width
339
- end
340
-
341
- table.width.should == col1_width + col2_width +
342
- 2*stretchy_columns*hpad +
343
- col0_width + col3_width
344
- end
345
-
346
- it "should preserve all manually requested column widths" do
347
- col0_width = 50
348
- col1_width = 20
349
- col3_width = 60
350
-
351
- table = Prawn::Table.new( [["snake", "foo", "b",
352
- "some long, long text that will wrap"],
353
- %w[kitten d foobar banana]], @pdf,
354
- :width => 150) do
355
-
356
- column(0).width = col0_width
357
- column(1).width = col1_width
358
- column(3).width = col3_width
359
- end
360
-
361
- table.draw
362
-
363
- table.column(0).width.should == col0_width
364
- table.column(1).width.should == col1_width
365
- table.column(3).width.should == col3_width
366
- end
367
-
368
- it "should_not exceed the maximum width of the margin_box" do
369
- expected_width = @pdf.margin_box.width
370
- data = [
371
- ['This is a column with a lot of text that should comfortably exceed '+
372
- 'the width of a normal document margin_box width', 'Some more text',
373
- 'and then some more', 'Just a bit more to be extra sure']
374
- ]
375
- table = Prawn::Table.new(data, @pdf)
376
-
377
- table.width.should == expected_width
378
- end
379
-
380
- it "should_not exceed the maximum width of the margin_box even with" +
381
- "manual widths specified" do
382
- expected_width = @pdf.margin_box.width
383
- data = [
384
- ['This is a column with a lot of text that should comfortably exceed '+
385
- 'the width of a normal document margin_box width', 'Some more text',
386
- 'and then some more', 'Just a bit more to be extra sure']
387
- ]
388
- table = Prawn::Table.new(data, @pdf) { column(1).width = 100 }
389
-
390
- table.width.should == expected_width
391
- end
392
-
393
- it "scales down only the non-preset column widths when the natural width" +
394
- "exceeds the maximum width of the margin_box" do
395
- expected_width = @pdf.margin_box.width
396
- data = [
397
- ['This is a column with a lot of text that should comfortably exceed '+
398
- 'the width of a normal document margin_box width', 'Some more text',
399
- 'and then some more', 'Just a bit more to be extra sure']
400
- ]
401
- table = Prawn::Table.new(data, @pdf) { column(1).width = 100; column(3).width = 50 }
402
-
403
- table.width.should == expected_width
404
- table.column_widths[1].should == 100
405
- table.column_widths[3].should == 50
406
- end
407
-
408
- it "should allow width to be reset even after it has been calculated" do
409
- @table = @pdf.table([[@long_text]])
410
- @table.width
411
- @table.width = 100
412
- @table.width.should == 100
413
- end
414
-
415
- it "should shrink columns evenly when two equal columns compete" do
416
- @table = @pdf.table([["foo", @long_text], [@long_text, "foo"]])
417
- @table.cells[0, 0].width.should == @table.cells[0, 1].width
418
- end
419
-
420
- it "should grow columns evenly when equal deficient columns compete" do
421
- @table = @pdf.table([["foo", "foobar"], ["foobar", "foo"]], :width => 500)
422
- @table.cells[0, 0].width.should == @table.cells[0, 1].width
423
- end
424
-
425
- it "should respect manual widths" do
426
- @table = @pdf.table([%w[foo bar baz], %w[baz bar foo]], :width => 500) do
427
- column(1).width = 60
428
- end
429
- @table.column(1).width.should == 60
430
- @table.column(0).width.should == @table.column(2).width
431
- end
432
-
433
- it "should allow table cells to be resized in block" do
434
- # if anything goes wrong, a CannotFit error will be raised
435
-
436
- @pdf.table([%w[1 2 3 4 5]]) do |t|
437
- t.width = 40
438
- t.cells.size = 8
439
- t.cells.padding = 0
440
- end
441
- end
442
-
443
- it "should be the width of the :width parameter" do
444
- expected_width = 300
445
- table = Prawn::Table.new( [%w[snake foo b apple],
446
- %w[kitten d foobar banana]], @pdf,
447
- :width => expected_width)
448
-
449
- table.width.should == expected_width
450
- end
451
-
452
- it "should_not exceed the :width option" do
453
- expected_width = 400
454
- data = [
455
- ['This is a column with a lot of text that should comfortably exceed '+
456
- 'the width of a normal document margin_box width', 'Some more text',
457
- 'and then some more', 'Just a bit more to be extra sure']
458
- ]
459
- table = Prawn::Table.new(data, @pdf, :width => expected_width)
460
-
461
- table.width.should == expected_width
462
- end
463
-
464
- it "should_not exceed the :width option even with manual widths specified" do
465
- expected_width = 400
466
- data = [
467
- ['This is a column with a lot of text that should comfortably exceed '+
468
- 'the width of a normal document margin_box width', 'Some more text',
469
- 'and then some more', 'Just a bit more to be extra sure']
470
- ]
471
- table = Prawn::Table.new(data, @pdf, :width => expected_width) do
472
- column(1).width = 100
473
- end
474
-
475
- table.width.should == expected_width
476
- end
477
-
478
- it "should calculate unspecified column widths even " +
479
- "with colspan cells declared" do
480
- pdf = Prawn::Document.new
481
- hpad, fs = 3, 5
482
- columns = 3
483
-
484
- data = [ [ { :content => 'foo', :colspan => 2 }, "foobar" ],
485
- [ "foo", "foo", "foo" ] ]
486
- table = Prawn::Table.new( data, pdf,
487
- :cell_style => {
488
- :padding_left => hpad, :padding_right => hpad,
489
- :size => fs
490
- })
491
-
492
- col0_width = pdf.width_of("foo", :size => fs) # cell 1, 0
493
- col1_width = pdf.width_of("foo", :size => fs) # cell 1, 1
494
- col2_width = pdf.width_of("foobar", :size => fs) # cell 0, 1 (at col 2)
495
-
496
- table.width.should == col0_width + col1_width +
497
- col2_width + 2*columns*hpad
498
- end
499
- end
500
-
501
- describe "height" do
502
- it "should set all cells in a row to the same height" do
503
- @table = @pdf.table([["foo", @long_text]])
504
- @table.cells[0, 0].height.should == @table.cells[0, 1].height
505
- end
506
-
507
- it "should move y-position to the bottom of the table after drawing" do
508
- old_y = @pdf.y
509
- table = @pdf.table([["foo"]])
510
- @pdf.y.should == old_y - table.height
511
- end
512
-
513
- it "should_not wrap unnecessarily" do
514
- # Test for FP errors and glitches
515
- t = @pdf.table([["Bender Bending Rodriguez"]])
516
- h = @pdf.height_of("one line")
517
- (t.height - 10).should be < h*1.5
518
- end
519
-
520
- it "should have a height of n rows" do
521
- data = [["foo"],["bar"],["baaaz"]]
522
-
523
- vpad = 4
524
- origin = @pdf.y
525
- @pdf.table data, :cell_style => { :padding => vpad }
526
-
527
- table_height = origin - @pdf.y
528
- font_height = @pdf.font.height
529
- line_gap = @pdf.font.line_gap
530
-
531
- num_rows = data.length
532
- table_height.should be_within(0.001).of(
533
- num_rows * font_height + 2*vpad*num_rows )
534
- end
535
-
536
- end
537
-
538
- describe "position" do
539
- it "should center tables with :position => :center" do
540
- @pdf.expects(:bounding_box).with do |(x, y), opts|
541
- expected = (@pdf.bounds.width - 500) / 2.0
542
- (x - expected).abs < 0.001
543
- end
544
-
545
- @pdf.table([["foo"]], :column_widths => 500, :position => :center)
546
- end
547
-
548
- it "should right-align tables with :position => :right" do
549
- @pdf.expects(:bounding_box).with do |(x, y), opts|
550
- expected = @pdf.bounds.width - 500
551
- (x - expected).abs < 0.001
552
- end
553
-
554
- @pdf.table([["foo"]], :column_widths => 500, :position => :right)
555
- end
556
-
557
- it "should accept a Numeric" do
558
- @pdf.expects(:bounding_box).with do |(x, y), opts|
559
- expected = 123
560
- (x - expected).abs < 0.001
561
- end
562
-
563
- @pdf.table([["foo"]], :column_widths => 500, :position => 123)
564
- end
565
-
566
- it "should raise_error an ArgumentError on unknown :position" do
567
- lambda do
568
- @pdf.table([["foo"]], :position => :bratwurst)
569
- end.should raise_error(ArgumentError)
570
- end
571
- end
572
-
573
- end
574
-
575
- describe "Multi-page tables" do
576
- it "should flow to the next page when hitting the bottom of the bounds" do
577
- Prawn::Document.new { table([["foo"]] * 30) }.page_count.should == 1
578
- Prawn::Document.new { table([["foo"]] * 31) }.page_count.should == 2
579
- Prawn::Document.new { table([["foo"]] * 31); table([["foo"]] * 35) }.
580
- page_count.should == 3
581
- end
582
-
583
- it "should respect the containing bounds" do
584
- Prawn::Document.new do
585
- bounding_box([0, cursor], :width => bounds.width, :height => 72) do
586
- table([["foo"]] * 4)
587
- end
588
- end.page_count.should == 2
589
- end
590
-
591
- it "should_not start a new page before finishing out a row" do
592
- Prawn::Document.new do
593
- table([[ (1..80).map{ |i| "Line #{i}" }.join("\n"), "Column 2" ]])
594
- end.page_count.should == 1
595
- end
596
-
597
- it "should only start new page on long cells if it would gain us height" do
598
- Prawn::Document.new do
599
- text "Hello"
600
- table([[ (1..80).map{ |i| "Line #{i}" }.join("\n"), "Column 2" ]])
601
- end.page_count.should == 2
602
- end
603
-
604
- it "should_not start a new page to gain height when at the top of " +
605
- "a bounding box, even if stretchy" do
606
- Prawn::Document.new do
607
- bounding_box([bounds.left, bounds.top - 20], :width => 400) do
608
- table([[ (1..80).map{ |i| "Line #{i}" }.join("\n"), "Column 2" ]])
609
- end
610
- end.page_count.should == 1
611
- end
612
-
613
- it "should still break to the next page if in a stretchy bounding box " +
614
- "but not at the top" do
615
- Prawn::Document.new do
616
- bounding_box([bounds.left, bounds.top - 20], :width => 400) do
617
- text "Hello"
618
- table([[ (1..80).map{ |i| "Line #{i}" }.join("\n"), "Column 2" ]])
619
- end
620
- end.page_count.should == 2
621
- end
622
-
623
- it "should only draw first-page header if the first body row fits" do
624
- pdf = Prawn::Document.new
625
-
626
- pdf.y = 60 # not enough room for a table row
627
- pdf.table [["Header"], ["Body"]], :header => true
628
-
629
- output = PDF::Inspector::Page.analyze(pdf.render)
630
- # Ensure we only drew the header once, on the second page
631
- output.pages[0][:strings].should be_empty
632
- output.pages[1][:strings].should == ["Header", "Body"]
633
- end
634
-
635
- it "should draw background before borders, but only within pages" do
636
- seq = sequence("drawing_order")
637
-
638
- @pdf = Prawn::Document.new
639
-
640
- # give enough room for only the first row
641
- @pdf.y = @pdf.bounds.absolute_bottom + 30
642
- t = @pdf.make_table([["A", "B"],
643
- ["C", "D"]],
644
- :cell_style => {:background_color => 'ff0000'})
645
-
646
- ca = t.cells[0, 0]
647
- cb = t.cells[0, 1]
648
- cc = t.cells[1, 0]
649
- cd = t.cells[1, 1]
650
-
651
- # All backgrounds should draw before any borders on page 1...
652
- ca.expects(:draw_background).in_sequence(seq)
653
- cb.expects(:draw_background).in_sequence(seq)
654
- ca.expects(:draw_borders).in_sequence(seq)
655
- cb.expects(:draw_borders).in_sequence(seq)
656
- # ...and page 2
657
- @pdf.expects(:start_new_page).in_sequence(seq)
658
- cc.expects(:draw_background).in_sequence(seq)
659
- cd.expects(:draw_background).in_sequence(seq)
660
- cc.expects(:draw_borders).in_sequence(seq)
661
- cd.expects(:draw_borders).in_sequence(seq)
662
-
663
- t.draw
664
- end
665
-
666
- describe "before_rendering_page callback" do
667
- before(:each) { @pdf = Prawn::Document.new }
668
-
669
- it "is passed all cells to be rendered on that page" do
670
- kicked = 0
671
-
672
- @pdf.table([["foo"]] * 100) do |t|
673
- t.before_rendering_page do |page|
674
- page.row_count.should == ((kicked < 3) ? 30 : 10)
675
- page.column_count.should == 1
676
- page.row(0).first.content.should == "foo"
677
- page.row(-1).first.content.should == "foo"
678
- kicked += 1
679
- end
680
- end
681
-
682
- kicked.should == 4
683
- end
684
-
685
- it "numbers cells relative to their position on page" do
686
- @pdf.table([["foo"]] * 100) do |t|
687
- t.before_rendering_page do |page|
688
- page[0, 0].content.should == "foo"
689
- end
690
- end
691
- end
692
-
693
- it "changing cells in the callback affects their rendering" do
694
- seq = sequence("render order")
695
-
696
- t = @pdf.make_table([["foo"]] * 40) do |table|
697
- table.before_rendering_page do |page|
698
- page[0, 0].background_color = "ff0000"
699
- end
700
- end
701
-
702
- t.cells[30, 0].stubs(:draw_background).checking do |xy|
703
- t.cells[30, 0].background_color.should == 'ff0000'
704
- end
705
- t.cells[31, 0].stubs(:draw_background).checking do |xy|
706
- t.cells[31, 0].background_color.should == nil
707
- end
708
-
709
- t.draw
710
- end
711
-
712
- it "passes headers on page 2+" do
713
- @pdf.table([["header"]] + [["foo"]] * 100, :header => true) do |t|
714
- t.before_rendering_page do |page|
715
- page[0, 0].content.should == "header"
716
- end
717
- end
718
- end
719
-
720
- it "updates dummy cell header rows" do
721
- header = [[{:content => "header", :colspan => 2}]]
722
- data = [["foo", "bar"]] * 31
723
- @pdf.table(header + data, :header => true) do |t|
724
- t.before_rendering_page do |page|
725
- cell = page[0, 0]
726
- cell.dummy_cells.each {|dc| dc.row.should == cell.row }
727
- end
728
- end
729
- end
730
-
731
- it "allows headers to be changed" do
732
- seq = sequence("render order")
733
- @pdf.expects(:draw_text!).with { |t, _| t == "hdr1"}.in_sequence(seq)
734
- @pdf.expects(:draw_text!).with { |t, _| t == "foo"}.times(29).in_sequence(seq)
735
- # Verify that the changed cell doesn't mutate subsequent pages
736
- @pdf.expects(:draw_text!).with { |t, _| t == "header"}.in_sequence(seq)
737
- @pdf.expects(:draw_text!).with { |t, _| t == "foo"}.times(11).in_sequence(seq)
738
-
739
- set_first_page_headers = false
740
- @pdf.table([["header"]] + [["foo"]] * 40, :header => true) do |t|
741
- t.before_rendering_page do |page|
742
- # only change first page header
743
- page[0, 0].content = "hdr1" unless set_first_page_headers
744
- set_first_page_headers = true
745
- end
746
- end
747
- end
748
- end
749
- end
750
-
751
- describe "#style" do
752
- it "should send #style to its first argument, passing the style hash and" +
753
- " block" do
754
-
755
- stylable = stub()
756
- stylable.expects(:style).with(:foo => :bar).once.yields
757
-
758
- block = stub()
759
- block.expects(:kick).once
760
-
761
- Prawn::Document.new do
762
- table([["x"]]) { style(stylable, :foo => :bar) { block.kick } }
763
- end
764
- end
765
-
766
- it "should default to {} for the hash argument" do
767
- stylable = stub()
768
- stylable.expects(:style).with({}).once
769
-
770
- Prawn::Document.new do
771
- table([["x"]]) { style(stylable) }
772
- end
773
- end
774
-
775
- it "ignores unknown values on a cell-by-cell basis" do
776
- Prawn::Document.new do
777
- table([["x", [["y"]]]], :cell_style => {:overflow => :shrink_to_fit})
778
- end
779
- end
780
- end
781
-
782
- describe "row_colors" do
783
- it "should allow array syntax for :row_colors" do
784
- data = [["foo"], ["bar"], ["baz"]]
785
- pdf = Prawn::Document.new
786
- t = pdf.table(data, :row_colors => ['cccccc', 'ffffff'])
787
- t.cells.map{|x| x.background_color}.should == %w[cccccc ffffff cccccc]
788
- end
789
-
790
- it "should ignore headers" do
791
- data = [["header"], ["foo"], ["bar"], ["baz"]]
792
- pdf = Prawn::Document.new
793
- t = pdf.table(data, :header => true,
794
- :row_colors => ['cccccc', 'ffffff']) do
795
- row(0).background_color = '333333'
796
- end
797
-
798
- t.cells.map{|x| x.background_color}.should ==
799
- %w[333333 cccccc ffffff cccccc]
800
- end
801
-
802
- it "stripes rows consistently from page to page, skipping header rows" do
803
- data = [["header"]] + [["foo"]] * 70
804
- pdf = Prawn::Document.new
805
- t = pdf.make_table(data, :header => true,
806
- :row_colors => ['cccccc', 'ffffff']) do
807
- cells.padding = 0
808
- cells.size = 9
809
- row(0).size = 11
810
- end
811
-
812
- # page 1: header + 67 cells (odd number -- verifies that the next
813
- # page disrupts the even/odd coloring, since both the last data cell
814
- # on this page and the first one on the next are colored cccccc)
815
- Prawn::Table::Cell.expects(:draw_cells).with do |cells|
816
- cells.map { |c, (x, y)| c.background_color } ==
817
- [nil] + (%w[cccccc ffffff] * 33) + %w[cccccc]
818
- end
819
- # page 2: header and 3 data cells
820
- Prawn::Table::Cell.expects(:draw_cells).with do |cells|
821
- cells.map { |c, (x, y)| c.background_color } ==
822
- [nil] + %w[cccccc ffffff cccccc]
823
- end
824
- t.draw
825
- end
826
-
827
- it "should_not override an explicit background_color" do
828
- data = [["foo"], ["bar"], ["baz"]]
829
- pdf = Prawn::Document.new
830
- table = pdf.table(data, :row_colors => ['cccccc', 'ffffff']) { |t|
831
- t.cells[0, 0].background_color = 'dddddd'
832
- }
833
- table.cells.map{|x| x.background_color}.should == %w[dddddd ffffff cccccc]
834
- end
835
- end
836
-
837
- describe "inking" do
838
- before(:each) do
839
- @pdf = Prawn::Document.new
840
- end
841
-
842
- it "should set the x-position of each cell based on widths" do
843
- @table = @pdf.table([["foo", "bar", "baz"]])
844
-
845
- x = 0
846
- (0..2).each do |col|
847
- cell = @table.cells[0, col]
848
- cell.x.should == x
849
- x += cell.width
850
- end
851
- end
852
-
853
- it "should set the y-position of each cell based on heights" do
854
- y = 0
855
- @table = @pdf.make_table([["foo"], ["bar"], ["baz"]])
856
-
857
- (0..2).each do |row|
858
- cell = @table.cells[row, 0]
859
- cell.y.should be_within(0.01).of(y)
860
- y -= cell.height
861
- end
862
- end
863
-
864
- it "should output content cell by cell, row by row" do
865
- data = [["foo","bar"],["baz","bang"]]
866
- @pdf = Prawn::Document.new
867
- @pdf.table(data)
868
- output = PDF::Inspector::Text.analyze(@pdf.render)
869
- output.strings.should == data.flatten
870
- end
871
-
872
- it "should_not cause an error if rendering the very first row causes a " +
873
- "page break" do
874
- Prawn::Document.new do |pdf|
875
- arr = Array(1..5).collect{|i| ["cell #{i}"] }
876
-
877
- pdf.move_down( pdf.y - (pdf.bounds.absolute_bottom + 3) )
878
-
879
- lambda {
880
- pdf.table(arr)
881
- }.should_not raise_error
882
- end
883
- end
884
-
885
- it "should draw all backgrounds before any borders" do
886
- # lest backgrounds overlap borders:
887
- # https://github.com/sandal/prawn/pull/226
888
-
889
- seq = sequence("drawing_order")
890
-
891
- t = @pdf.make_table([["A", "B"]],
892
- :cell_style => {:background_color => 'ff0000'})
893
- ca = t.cells[0, 0]
894
- cb = t.cells[0, 1]
895
-
896
- # XXX Not a perfectly general test, because it would still be acceptable
897
- # if we drew B then A
898
- ca.expects(:draw_background).in_sequence(seq)
899
- cb.expects(:draw_background).in_sequence(seq)
900
- ca.expects(:draw_borders).in_sequence(seq)
901
- cb.expects(:draw_borders).in_sequence(seq)
902
-
903
- t.draw
904
- end
905
-
906
- it "should allow multiple inkings of the same table" do
907
- pdf = Prawn::Document.new
908
- t = Prawn::Table.new([["foo"]], pdf)
909
-
910
- pdf.expects(:bounding_box).with{|(x, y), options| y.to_i == 495}.yields
911
- pdf.expects(:bounding_box).with{|(x, y), options| y.to_i == 395}.yields
912
- pdf.expects(:draw_text!).with{ |text, options| text == 'foo' }.twice
913
-
914
- pdf.move_cursor_to(500)
915
- t.draw
916
-
917
- pdf.move_cursor_to(400)
918
- t.draw
919
- end
920
-
921
- describe "in stretchy bounding boxes" do
922
- it "should draw all cells on a row at the same y-position" do
923
- pdf = Prawn::Document.new
924
-
925
- text_y = pdf.y.to_i - 5 # text starts 5pt below current y pos (padding)
926
-
927
- pdf.bounding_box([0, pdf.cursor], :width => pdf.bounds.width) do
928
- pdf.expects(:draw_text!).checking { |text, options|
929
- pdf.bounds.absolute_top.should == text_y
930
- }.times(3)
931
-
932
- pdf.table([%w[a b c]])
933
- end
934
- end
935
- end
936
- end
937
-
938
- describe "headers" do
939
- context "single row header" do
940
- it "should add headers to output when specified" do
941
- data = [["a", "b"], ["foo","bar"],["baz","bang"]]
942
- @pdf = Prawn::Document.new
943
- @pdf.table(data, :header => true)
944
- output = PDF::Inspector::Text.analyze(@pdf.render)
945
- output.strings.should == data.flatten
946
- end
947
-
948
- it "should repeat headers across pages" do
949
- data = [["foo","bar"]] * 30
950
- headers = ["baz","foobar"]
951
- @pdf = Prawn::Document.new
952
- @pdf.table([headers] + data, :header => true)
953
- output = PDF::Inspector::Text.analyze(@pdf.render)
954
- output.strings.should == headers + data.flatten[0..-3] + headers +
955
- data.flatten[-2..-1]
956
- end
957
-
958
- it "draws headers at the correct position" do
959
- data = [["header"]] + [["foo"]] * 40
960
-
961
- Prawn::Table::Cell.expects(:draw_cells).times(2).checking do |cells|
962
- cells.each do |cell, pt|
963
- if cell.content == "header"
964
- # Assert that header text is drawn at the same location on each page
965
- if @header_location
966
- pt.should == @header_location
967
- else
968
- @header_location = pt
969
- end
970
- end
971
- end
972
- end
973
- @pdf = Prawn::Document.new
974
- @pdf.table(data, :header => true)
975
- end
976
-
977
- it "draws headers at the correct position with column box" do
978
- data = [["header"]] + [["foo"]] * 40
979
-
980
- Prawn::Table::Cell.expects(:draw_cells).times(2).checking do |cells|
981
- cells.each do |cell, pt|
982
- if cell.content == "header"
983
- pt[0].should == @pdf.bounds.left
984
- end
985
- end
986
- end
987
- @pdf = Prawn::Document.new
988
- @pdf.column_box [0, @pdf.cursor], :width => @pdf.bounds.width, :columns => 2 do
989
- @pdf.table(data, :header => true)
990
- end
991
- end
992
-
993
- it "should_not draw header twice when starting new page" do
994
- @pdf = Prawn::Document.new
995
- @pdf.y = 0
996
- @pdf.table([["Header"], ["Body"]], :header => true)
997
- output = PDF::Inspector::Text.analyze(@pdf.render)
998
- output.strings.should == ["Header", "Body"]
999
- end
1000
- end
1001
-
1002
- context "multiple row header" do
1003
- it "should add headers to output when specified" do
1004
- data = [["a", "b"], ["c", "d"], ["foo","bar"],["baz","bang"]]
1005
- @pdf = Prawn::Document.new
1006
- @pdf.table(data, :header => 2)
1007
- output = PDF::Inspector::Text.analyze(@pdf.render)
1008
- output.strings.should == data.flatten
1009
- end
1010
-
1011
- it "should repeat headers across pages" do
1012
- data = [["foo","bar"]] * 30
1013
- headers = ["baz","foobar"] + ["bas", "foobaz"]
1014
- @pdf = Prawn::Document.new
1015
- @pdf.table([headers] + data, :header => 2)
1016
- output = PDF::Inspector::Text.analyze(@pdf.render)
1017
- output.strings.should == headers + data.flatten[0..-3] + headers +
1018
- data.flatten[-4..-1]
1019
- end
1020
-
1021
- it "draws headers at the correct position" do
1022
- data = [["header"]] + [["header2"]] + [["foo"]] * 40
1023
-
1024
- Prawn::Table::Cell.expects(:draw_cells).times(2).checking do |cells|
1025
- cells.each do |cell, pt|
1026
- if cell.content == "header"
1027
- # Assert that header text is drawn at the same location on each page
1028
- if @header_location
1029
- pt.should == @header_location
1030
- else
1031
- @header_location = pt
1032
- end
1033
- end
1034
-
1035
- if cell.content == "header2"
1036
- # Assert that header text is drawn at the same location on each page
1037
- if @header2_location
1038
- pt.should == @header2_location
1039
- else
1040
- @header2_location = pt
1041
- end
1042
- end
1043
- end
1044
- end
1045
- @pdf = Prawn::Document.new
1046
- @pdf.table(data, :header => 2)
1047
- end
1048
-
1049
- it "should_not draw header twice when starting new page" do
1050
- @pdf = Prawn::Document.new
1051
- @pdf.y = 0
1052
- @pdf.table([["Header"], ["Header2"], ["Body"]], :header => 2)
1053
- output = PDF::Inspector::Text.analyze(@pdf.render)
1054
- output.strings.should == ["Header", "Header2", "Body"]
1055
- end
1056
- end
1057
- end
1058
-
1059
- describe "nested tables" do
1060
- before(:each) do
1061
- @pdf = Prawn::Document.new
1062
- @subtable = Prawn::Table.new([["foo"]], @pdf)
1063
- @table = @pdf.table([[@subtable, "bar"]])
1064
- end
1065
-
1066
- it "can be created from an Array" do
1067
- cell = Prawn::Table::Cell.make(@pdf, [["foo"]])
1068
- cell.should be_a_kind_of(Prawn::Table::Cell::Subtable)
1069
- cell.subtable.should be_a_kind_of(Prawn::Table)
1070
- end
1071
-
1072
- it "defaults its padding to zero" do
1073
- @table.cells[0, 0].padding.should == [0, 0, 0, 0]
1074
- end
1075
-
1076
- it "has a subtable accessor" do
1077
- @table.cells[0, 0].subtable.should == @subtable
1078
- end
1079
-
1080
- it "determines its dimensions from the subtable" do
1081
- @table.cells[0, 0].width.should == @subtable.width
1082
- @table.cells[0, 0].height.should == @subtable.height
1083
- end
1084
-
1085
- end
1086
-
1087
- describe "An invalid table" do
1088
-
1089
- before(:each) do
1090
- @pdf = Prawn::Document.new
1091
- @bad_data = ["Single Nested Array"]
1092
- end
1093
-
1094
- it "should raise_error error when invalid table data is given" do
1095
- lambda {
1096
- @pdf.table(@bad_data)
1097
- }.should raise_error(Prawn::Errors::InvalidTableData)
1098
- end
1099
-
1100
- it "should raise_error an EmptyTableError with empty table data" do
1101
- lambda {
1102
- data = []
1103
- @pdf = Prawn::Document.new
1104
- @pdf.table(data)
1105
- }.should raise_error( Prawn::Errors::EmptyTable )
1106
- end
1107
-
1108
- it "should raise_error an EmptyTableError with nil table data" do
1109
- lambda {
1110
- data = nil
1111
- @pdf = Prawn::Document.new
1112
- @pdf.table(data)
1113
- }.should raise_error( Prawn::Errors::EmptyTable )
1114
- end
1115
-
1116
- end
1117
-
1118
- end
1119
-
1120
- describe "colspan / rowspan" do
1121
- before(:each) { create_pdf }
1122
-
1123
- it "doesn't raise an error" do
1124
- lambda {
1125
- @pdf.table([[{:content => "foo", :colspan => 2, :rowspan => 2}]])
1126
- }.should_not raise_error
1127
- end
1128
-
1129
- it "colspan is properly counted" do
1130
- t = @pdf.make_table([[{:content => "foo", :colspan => 2}]])
1131
- t.column_length.should == 2
1132
- end
1133
-
1134
- it "rowspan is properly counted" do
1135
- t = @pdf.make_table([[{:content => "foo", :rowspan => 2}]])
1136
- t.row_length.should == 2
1137
- end
1138
-
1139
- it "raises if colspan or rowspan are called after layout" do
1140
- lambda {
1141
- @pdf.table([["foo"]]) { cells[0, 0].colspan = 2 }
1142
- }.should raise_error(Prawn::Errors::InvalidTableSpan)
1143
-
1144
- lambda {
1145
- @pdf.table([["foo"]]) { cells[0, 0].rowspan = 2 }
1146
- }.should raise_error(Prawn::Errors::InvalidTableSpan)
1147
- end
1148
-
1149
- it "raises when spans overlap" do
1150
- lambda {
1151
- @pdf.table([["foo", {:content => "bar", :rowspan => 2}],
1152
- [{:content => "baz", :colspan => 2}]])
1153
- }.should raise_error(Prawn::Errors::InvalidTableSpan)
1154
- end
1155
-
1156
- it "table and cell width account for colspan" do
1157
- t = @pdf.table([["a", {:content => "b", :colspan => 2}]],
1158
- :column_widths => [100, 100, 100])
1159
- spanned = t.cells[0, 1]
1160
- spanned.colspan.should == 2
1161
- t.width.should == 300
1162
- t.cells.min_width.should == 300
1163
- t.cells.max_width.should == 300
1164
- spanned.width.should == 200
1165
- end
1166
-
1167
- it "table and cell height account for rowspan" do
1168
- t = @pdf.table([["a"], [{:content => "b", :rowspan => 2}]]) do
1169
- row(0..2).height = 100
1170
- end
1171
- spanned = t.cells[1, 0]
1172
- spanned.rowspan.should == 2
1173
- t.height.should == 300
1174
- spanned.height.should == 200
1175
- end
1176
-
1177
- it "provides the full content_width as drawing space" do
1178
- w = @pdf.make_table([["foo"]]).cells[0, 0].content_width
1179
-
1180
- t = @pdf.make_table([[{:content => "foo", :colspan => 2}]])
1181
- t.cells[0, 0].spanned_content_width.should == w
1182
- end
1183
-
1184
- it "dummy cells are not drawn" do
1185
- # make a fake master cell for the dummy cell to slave to
1186
- t = @pdf.make_table([[{:content => "foo", :colspan => 2}]])
1187
-
1188
- # drawing just a dummy cell should_not ink
1189
- @pdf.expects(:stroke_line).never
1190
- @pdf.expects(:draw_text!).never
1191
- Prawn::Table::Cell.draw_cells([t.cells[0, 1]])
1192
- end
1193
-
1194
- it "dummy cells do not add any height or width" do
1195
- t1 = @pdf.table([["foo"]])
1196
-
1197
- t2 = @pdf.table([[{:content => "foo", :colspan => 2}]])
1198
- t2.width.should == t1.width
1199
-
1200
- t3 = @pdf.table([[{:content => "foo", :rowspan => 2}]])
1201
- t3.height.should == t1.height
1202
- end
1203
-
1204
- it "dummy cells ignored by #style" do
1205
- t = @pdf.table([[{:content => "blah", :colspan => 2}]],
1206
- :cell_style => { :size => 9 })
1207
- t.cells[0, 0].size.should == 9
1208
- end
1209
-
1210
- context "inheriting master cell styles from dummy cell" do
1211
- # Relatively full coverage for all these attributes that should be
1212
- # inherited.
1213
- [["border_X_width", 20],
1214
- ["border_X_color", "123456"],
1215
- ["padding_X", 20]].each do |attribute, val|
1216
- attribute_right = attribute.sub("X", "right")
1217
- attribute_left = attribute.sub("X", "left")
1218
- attribute_bottom = attribute.sub("X", "bottom")
1219
- attribute_top = attribute.sub("X", "top")
1220
-
1221
- specify "#{attribute_right} of right column is inherited" do
1222
- t = @pdf.table([[{:content => "blah", :colspan => 2}]]) do |table|
1223
- table.column(1).send("#{attribute_right}=", val)
1224
- end
1225
-
1226
- t.cells[0, 0].send(attribute_right).should == val
1227
- end
1228
-
1229
- specify "#{attribute_bottom} of bottom row is inherited" do
1230
- t = @pdf.table([[{:content => "blah", :rowspan => 2}]]) do |table|
1231
- table.row(1).send("#{attribute_bottom}=", val)
1232
- end
1233
-
1234
- t.cells[0, 0].send(attribute_bottom).should == val
1235
- end
1236
-
1237
- specify "#{attribute_left} of right column is not inherited" do
1238
- t = @pdf.table([[{:content => "blah", :colspan => 2}]]) do |table|
1239
- table.column(1).send("#{attribute_left}=", val)
1240
- end
1241
-
1242
- t.cells[0, 0].send(attribute_left).should_not == val
1243
- end
1244
-
1245
- specify "#{attribute_right} of interior column is not inherited" do
1246
- t = @pdf.table([[{:content => "blah", :colspan => 3}]]) do |table|
1247
- table.column(1).send("#{attribute_right}=", val)
1248
- end
1249
-
1250
- t.cells[0, 0].send(attribute_right).should_not == val
1251
- end
1252
-
1253
- specify "#{attribute_bottom} of interior row is not inherited" do
1254
- t = @pdf.table([[{:content => "blah", :rowspan => 3}]]) do |table|
1255
- table.row(1).send("#{attribute_bottom}=", val)
1256
- end
1257
-
1258
- t.cells[0, 0].send(attribute_bottom).should_not == val
1259
- end
1260
-
1261
- specify "#{attribute_top} of bottom row is not inherited" do
1262
- t = @pdf.table([[{:content => "blah", :rowspan => 2}]]) do |table|
1263
- table.row(1).send("#{attribute_top}=", val)
1264
- end
1265
-
1266
- t.cells[0, 0].send(attribute_top).should_not == val
1267
- end
1268
- end
1269
- end
1270
-
1271
- it "splits natural width between cols in the group" do
1272
- t = @pdf.table([[{:content => "foo", :colspan => 2}]])
1273
- widths = t.column_widths
1274
- widths[0].should == widths[1]
1275
- end
1276
-
1277
- it "splits natural width between cols when width is increased" do
1278
- t = @pdf.table([[{:content => "foo", :colspan => 2}]],
1279
- :width => @pdf.bounds.width)
1280
- widths = t.column_widths
1281
- widths[0].should == widths[1]
1282
- end
1283
-
1284
- it "splits min-width between cols in the group" do
1285
- # Since column_widths, when reducing column widths, reduces proportional to
1286
- # the remaining width after each column's min width, we must ensure that the
1287
- # min-width is split proportionally in order to ensure the width is still
1288
- # split evenly when the width is reduced. (See "splits natural width between
1289
- # cols when width is reduced".)
1290
- t = @pdf.table([[{:content => "foo", :colspan => 2}]],
1291
- :width => 20)
1292
- t.column(0).min_width.should == t.column(1).min_width
1293
- end
1294
-
1295
- it "splits natural width between cols when width is reduced" do
1296
- t = @pdf.table([[{:content => "foo", :colspan => 2}]],
1297
- :width => 20)
1298
- widths = t.column_widths
1299
- widths[0].should == widths[1]
1300
- end
1301
-
1302
- it "honors a large, explicitly set table width" do
1303
- t = @pdf.table([[{:content => "AAAAAAAAAA", :colspan => 3}],
1304
- ["A", "B", "C"]],
1305
- :width => 400)
1306
-
1307
- t.column_widths.inject(0) { |sum, w| sum + w }.
1308
- should be_within(0.01).of(400)
1309
- end
1310
-
1311
- it "honors a small, explicitly set table width" do
1312
- t = @pdf.table([[{:content => "Lorem ipsum dolor sit amet " * 20,
1313
- :colspan => 3}],
1314
- ["A", "B", "C"]],
1315
- :width => 200)
1316
- t.column_widths.inject(0) { |sum, w| sum + w }.
1317
- should be_within(0.01).of(200)
1318
- end
1319
-
1320
- it "splits natural_content_height between rows in the group" do
1321
- t = @pdf.table([[{:content => "foo", :rowspan => 2}]])
1322
- heights = t.row_heights
1323
- heights[0].should == heights[1]
1324
- end
1325
-
1326
- it "skips column numbers that have been col-spanned" do
1327
- t = @pdf.table([["a", "b", {:content => "c", :colspan => 3}, "d"]])
1328
- t.cells[0, 0].content.should == "a"
1329
- t.cells[0, 1].content.should == "b"
1330
- t.cells[0, 2].content.should == "c"
1331
- t.cells[0, 3].should be_a_kind_of(Prawn::Table::Cell::SpanDummy)
1332
- t.cells[0, 4].should be_a_kind_of(Prawn::Table::Cell::SpanDummy)
1333
- t.cells[0, 5].content.should == "d"
1334
- end
1335
-
1336
- it "skips row/col positions that have been row-spanned" do
1337
- t = @pdf.table([["a", {:content => "b", :colspan => 2, :rowspan => 2}, "c"],
1338
- ["d", "e"],
1339
- ["f", "g", "h", "i"]])
1340
- t.cells[0, 0].content.should == "a"
1341
- t.cells[0, 1].content.should == "b"
1342
- t.cells[0, 2].should be_a_kind_of(Prawn::Table::Cell::SpanDummy)
1343
- t.cells[0, 3].content.should == "c"
1344
-
1345
- t.cells[1, 0].content.should == "d"
1346
- t.cells[1, 1].should be_a_kind_of(Prawn::Table::Cell::SpanDummy)
1347
- t.cells[1, 2].should be_a_kind_of(Prawn::Table::Cell::SpanDummy)
1348
- t.cells[1, 3].content.should == "e"
1349
-
1350
- t.cells[2, 0].content.should == "f"
1351
- t.cells[2, 1].content.should == "g"
1352
- t.cells[2, 2].content.should == "h"
1353
- t.cells[2, 3].content.should == "i"
1354
- end
1355
- end