prawn 0.13.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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