alphasights-prawn 0.10.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 (244) hide show
  1. data/COPYING +340 -0
  2. data/HACKING +50 -0
  3. data/LICENSE +56 -0
  4. data/README +141 -0
  5. data/Rakefile +52 -0
  6. data/data/encodings/win_ansi.txt +29 -0
  7. data/data/fonts/Action Man.dfont +0 -0
  8. data/data/fonts/Activa.ttf +0 -0
  9. data/data/fonts/Chalkboard.ttf +0 -0
  10. data/data/fonts/Courier-Bold.afm +342 -0
  11. data/data/fonts/Courier-BoldOblique.afm +342 -0
  12. data/data/fonts/Courier-Oblique.afm +342 -0
  13. data/data/fonts/Courier.afm +342 -0
  14. data/data/fonts/DejaVuSans.ttf +0 -0
  15. data/data/fonts/Dustismo_Roman.ttf +0 -0
  16. data/data/fonts/Helvetica-Bold.afm +2827 -0
  17. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  18. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  19. data/data/fonts/Helvetica.afm +3051 -0
  20. data/data/fonts/MustRead.html +19 -0
  21. data/data/fonts/Symbol.afm +213 -0
  22. data/data/fonts/Times-Bold.afm +2588 -0
  23. data/data/fonts/Times-BoldItalic.afm +2384 -0
  24. data/data/fonts/Times-Italic.afm +2667 -0
  25. data/data/fonts/Times-Roman.afm +2419 -0
  26. data/data/fonts/ZapfDingbats.afm +225 -0
  27. data/data/fonts/comicsans.ttf +0 -0
  28. data/data/fonts/gkai00mp.ttf +0 -0
  29. data/data/images/16bit.alpha +0 -0
  30. data/data/images/16bit.dat +0 -0
  31. data/data/images/16bit.png +0 -0
  32. data/data/images/arrow.png +0 -0
  33. data/data/images/arrow2.png +0 -0
  34. data/data/images/barcode_issue.png +0 -0
  35. data/data/images/dice.alpha +0 -0
  36. data/data/images/dice.dat +0 -0
  37. data/data/images/dice.png +0 -0
  38. data/data/images/dice_interlaced.png +0 -0
  39. data/data/images/fractal.jpg +0 -0
  40. data/data/images/letterhead.jpg +0 -0
  41. data/data/images/page_white_text.alpha +0 -0
  42. data/data/images/page_white_text.dat +0 -0
  43. data/data/images/page_white_text.png +0 -0
  44. data/data/images/pigs.jpg +0 -0
  45. data/data/images/rails.dat +0 -0
  46. data/data/images/rails.png +0 -0
  47. data/data/images/ruport.png +0 -0
  48. data/data/images/ruport_data.dat +0 -0
  49. data/data/images/ruport_transparent.png +0 -0
  50. data/data/images/ruport_type0.png +0 -0
  51. data/data/images/stef.jpg +0 -0
  52. data/data/images/tru256.bmp +0 -0
  53. data/data/images/web-links.dat +1 -0
  54. data/data/images/web-links.png +0 -0
  55. data/data/pdfs/complex_template.pdf +0 -0
  56. data/data/pdfs/contains_ttf_font.pdf +0 -0
  57. data/data/pdfs/encrypted.pdf +0 -0
  58. data/data/pdfs/hexagon.pdf +61 -0
  59. data/data/pdfs/indirect_reference.pdf +86 -0
  60. data/data/pdfs/nested_pages.pdf +118 -0
  61. data/data/pdfs/resources_as_indirect_object.pdf +83 -0
  62. data/data/pdfs/two_hexagons.pdf +90 -0
  63. data/data/pdfs/version_1_6.pdf +61 -0
  64. data/data/shift_jis_text.txt +1 -0
  65. data/examples/bounding_box/bounding_boxes.rb +43 -0
  66. data/examples/bounding_box/indentation.rb +34 -0
  67. data/examples/bounding_box/russian_boxes.rb +36 -0
  68. data/examples/bounding_box/stretched_nesting.rb +67 -0
  69. data/examples/builder/simple.rb +28 -0
  70. data/examples/example_helper.rb +4 -0
  71. data/examples/general/background.rb +23 -0
  72. data/examples/general/canvas.rb +15 -0
  73. data/examples/general/context_sensitive_headers.rb +37 -0
  74. data/examples/general/float.rb +11 -0
  75. data/examples/general/margin.rb +36 -0
  76. data/examples/general/measurement_units.rb +51 -0
  77. data/examples/general/metadata-info.rb +16 -0
  78. data/examples/general/multi_page_layout.rb +18 -0
  79. data/examples/general/outlines.rb +50 -0
  80. data/examples/general/page_geometry.rb +31 -0
  81. data/examples/general/page_numbering.rb +15 -0
  82. data/examples/general/repeaters.rb +47 -0
  83. data/examples/general/stamp.rb +41 -0
  84. data/examples/general/templates.rb +13 -0
  85. data/examples/graphics/basic_images.rb +23 -0
  86. data/examples/graphics/chunkable.rb +38 -0
  87. data/examples/graphics/cmyk.rb +12 -0
  88. data/examples/graphics/curves.rb +11 -0
  89. data/examples/graphics/hexagon.rb +13 -0
  90. data/examples/graphics/image_fit.rb +15 -0
  91. data/examples/graphics/image_flow.rb +37 -0
  92. data/examples/graphics/image_position.rb +17 -0
  93. data/examples/graphics/line.rb +32 -0
  94. data/examples/graphics/png_types.rb +22 -0
  95. data/examples/graphics/polygons.rb +16 -0
  96. data/examples/graphics/remote_images.rb +12 -0
  97. data/examples/graphics/rounded_polygons.rb +19 -0
  98. data/examples/graphics/rounded_rectangle.rb +20 -0
  99. data/examples/graphics/ruport_style_helpers.rb +19 -0
  100. data/examples/graphics/stroke_bounds.rb +20 -0
  101. data/examples/graphics/stroke_cap_and_join.rb +45 -0
  102. data/examples/graphics/stroke_dash.rb +42 -0
  103. data/examples/graphics/transformations.rb +52 -0
  104. data/examples/graphics/transparency.rb +26 -0
  105. data/examples/m17n/chinese_text_wrapping.rb +17 -0
  106. data/examples/m17n/euro.rb +15 -0
  107. data/examples/m17n/sjis.rb +28 -0
  108. data/examples/m17n/utf8.rb +13 -0
  109. data/examples/m17n/win_ansi_charset.rb +54 -0
  110. data/examples/security/hello_foo.rb +8 -0
  111. data/examples/table/bill.rb +53 -0
  112. data/examples/table/cell.rb +12 -0
  113. data/examples/table/checkerboard.rb +22 -0
  114. data/examples/table/header.rb +14 -0
  115. data/examples/table/inline_format_table.rb +12 -0
  116. data/examples/table/multi_page_table.rb +9 -0
  117. data/examples/table/simple_table.rb +24 -0
  118. data/examples/table/subtable.rb +12 -0
  119. data/examples/table/widths.rb +20 -0
  120. data/examples/text/alignment.rb +18 -0
  121. data/examples/text/character_spacing.rb +12 -0
  122. data/examples/text/dfont.rb +48 -0
  123. data/examples/text/family_based_styling.rb +24 -0
  124. data/examples/text/font_calculations.rb +91 -0
  125. data/examples/text/font_size.rb +33 -0
  126. data/examples/text/hyphenation.rb +45 -0
  127. data/examples/text/indent_paragraphs.rb +22 -0
  128. data/examples/text/inline_format.rb +103 -0
  129. data/examples/text/kerning.rb +30 -0
  130. data/examples/text/rotated.rb +98 -0
  131. data/examples/text/shaped_text_box.rb +31 -0
  132. data/examples/text/simple_text.rb +17 -0
  133. data/examples/text/simple_text_ttf.rb +17 -0
  134. data/examples/text/text_box.rb +88 -0
  135. data/examples/text/text_box_returning_excess.rb +51 -0
  136. data/examples/text/text_flow.rb +67 -0
  137. data/lib/prawn.rb +27 -0
  138. data/lib/prawn/canvas.rb +119 -0
  139. data/lib/prawn/chunkable.rb +37 -0
  140. data/lib/prawn/compatibility.rb +51 -0
  141. data/lib/prawn/core.rb +85 -0
  142. data/lib/prawn/core/annotations.rb +61 -0
  143. data/lib/prawn/core/byte_string.rb +9 -0
  144. data/lib/prawn/core/chunk.rb +36 -0
  145. data/lib/prawn/core/destinations.rb +90 -0
  146. data/lib/prawn/core/document_state.rb +78 -0
  147. data/lib/prawn/core/literal_string.rb +16 -0
  148. data/lib/prawn/core/name_tree.rb +165 -0
  149. data/lib/prawn/core/object_store.rb +236 -0
  150. data/lib/prawn/core/page.rb +179 -0
  151. data/lib/prawn/core/pdf_object.rb +108 -0
  152. data/lib/prawn/core/reference.rb +112 -0
  153. data/lib/prawn/core/text.rb +140 -0
  154. data/lib/prawn/core/text/formatted/arranger.rb +266 -0
  155. data/lib/prawn/core/text/formatted/line_wrap.rb +127 -0
  156. data/lib/prawn/core/text/formatted/wrap.rb +112 -0
  157. data/lib/prawn/core/text/line_wrap.rb +209 -0
  158. data/lib/prawn/core/text/wrap.rb +80 -0
  159. data/lib/prawn/document.rb +573 -0
  160. data/lib/prawn/document/bounding_box.rb +425 -0
  161. data/lib/prawn/document/graphics_state.rb +48 -0
  162. data/lib/prawn/document/internals.rb +170 -0
  163. data/lib/prawn/document/page_geometry.rb +136 -0
  164. data/lib/prawn/document/snapshot.rb +87 -0
  165. data/lib/prawn/document_builder.rb +51 -0
  166. data/lib/prawn/document_builder/command.rb +38 -0
  167. data/lib/prawn/document_builder/constructs.rb +2 -0
  168. data/lib/prawn/document_builder/constructs/flowing_text_construct.rb +18 -0
  169. data/lib/prawn/document_builder/constructs/path_construct.rb +9 -0
  170. data/lib/prawn/document_builder/layout.rb +25 -0
  171. data/lib/prawn/document_builder/modifications.rb +2 -0
  172. data/lib/prawn/document_builder/modifications/layout_modification.rb +9 -0
  173. data/lib/prawn/document_builder/modifications/path_modification.rb +9 -0
  174. data/lib/prawn/encoding.rb +121 -0
  175. data/lib/prawn/errors.rb +94 -0
  176. data/lib/prawn/font.rb +341 -0
  177. data/lib/prawn/font/afm.rb +225 -0
  178. data/lib/prawn/font/dfont.rb +42 -0
  179. data/lib/prawn/font/ttf.rb +350 -0
  180. data/lib/prawn/graphics.rb +325 -0
  181. data/lib/prawn/graphics/cap_style.rb +38 -0
  182. data/lib/prawn/graphics/color.rb +205 -0
  183. data/lib/prawn/graphics/dash.rb +71 -0
  184. data/lib/prawn/graphics/join_style.rb +38 -0
  185. data/lib/prawn/graphics/transformation.rb +156 -0
  186. data/lib/prawn/graphics/transparency.rb +99 -0
  187. data/lib/prawn/images.rb +348 -0
  188. data/lib/prawn/images/jpg.rb +46 -0
  189. data/lib/prawn/images/png.rb +226 -0
  190. data/lib/prawn/measurement_extensions.rb +46 -0
  191. data/lib/prawn/measurements.rb +71 -0
  192. data/lib/prawn/outline.rb +278 -0
  193. data/lib/prawn/repeater.rb +129 -0
  194. data/lib/prawn/security.rb +262 -0
  195. data/lib/prawn/security/arcfour.rb +51 -0
  196. data/lib/prawn/stamp.rb +126 -0
  197. data/lib/prawn/table.rb +421 -0
  198. data/lib/prawn/table/accessors.rb +180 -0
  199. data/lib/prawn/table/cell.rb +350 -0
  200. data/lib/prawn/table/cell/in_table.rb +27 -0
  201. data/lib/prawn/table/cell/subtable.rb +65 -0
  202. data/lib/prawn/table/cell/text.rb +125 -0
  203. data/lib/prawn/text.rb +449 -0
  204. data/lib/prawn/text/box.rb +392 -0
  205. data/lib/prawn/text/formatted.rb +4 -0
  206. data/lib/prawn/text/formatted/box.rb +228 -0
  207. data/lib/prawn/text/formatted/fragment.rb +181 -0
  208. data/lib/prawn/text/formatted/parser.rb +213 -0
  209. data/spec/annotations_spec.rb +90 -0
  210. data/spec/bounding_box_spec.rb +190 -0
  211. data/spec/cell_spec.rb +348 -0
  212. data/spec/destinations_spec.rb +15 -0
  213. data/spec/document_spec.rb +473 -0
  214. data/spec/font_spec.rb +324 -0
  215. data/spec/formatted_text_arranger_spec.rb +426 -0
  216. data/spec/formatted_text_box_spec.rb +756 -0
  217. data/spec/formatted_text_fragment_spec.rb +211 -0
  218. data/spec/graphics_spec.rb +446 -0
  219. data/spec/images_spec.rb +96 -0
  220. data/spec/inline_formatted_text_parser_spec.rb +502 -0
  221. data/spec/jpg_spec.rb +25 -0
  222. data/spec/line_wrap_spec.rb +341 -0
  223. data/spec/measurement_units_spec.rb +23 -0
  224. data/spec/name_tree_spec.rb +112 -0
  225. data/spec/object_store_spec.rb +160 -0
  226. data/spec/outline_spec.rb +269 -0
  227. data/spec/pdf_object_spec.rb +170 -0
  228. data/spec/png_spec.rb +237 -0
  229. data/spec/reference_spec.rb +82 -0
  230. data/spec/repeater_spec.rb +96 -0
  231. data/spec/security_spec.rb +120 -0
  232. data/spec/snapshot_spec.rb +138 -0
  233. data/spec/spec_helper.rb +26 -0
  234. data/spec/stamp_spec.rb +108 -0
  235. data/spec/stroke_styles_spec.rb +163 -0
  236. data/spec/table_spec.rb +598 -0
  237. data/spec/template_spec.rb +158 -0
  238. data/spec/text_at_spec.rb +119 -0
  239. data/spec/text_box_spec.rb +742 -0
  240. data/spec/text_spacing_spec.rb +75 -0
  241. data/spec/text_spec.rb +333 -0
  242. data/spec/text_with_inline_formatting_spec.rb +193 -0
  243. data/spec/transparency_spec.rb +89 -0
  244. metadata +331 -0
@@ -0,0 +1,138 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "Prawn::Document#transaction" do
6
+
7
+ it "should properly commit if no error is raised" do
8
+ pdf = Prawn::Document.new do
9
+ transaction do
10
+ text "This is shown"
11
+ end
12
+ end
13
+ text = PDF::Inspector::Text.analyze(pdf.render)
14
+ text.strings.should == ["This is shown"]
15
+ end
16
+
17
+ it "should not display text if transaction is rolled back" do
18
+ pdf = Prawn::Document.new do
19
+ transaction do
20
+ text "This is not shown"
21
+ rollback
22
+ end
23
+ end
24
+ text = PDF::Inspector::Text.analyze(pdf.render)
25
+ text.strings.should == []
26
+ end
27
+
28
+ it "should return true/false value indicating success of the transaction" do
29
+ Prawn::Document.new do
30
+ success = transaction { }
31
+ success.should == true
32
+
33
+ success = transaction { rollback }
34
+ success.should == false
35
+ end
36
+ end
37
+
38
+ it "should support nested transactions" do
39
+ pdf = Prawn::Document.new do
40
+ transaction do
41
+ text "This is shown"
42
+ transaction do
43
+ text "and this is not"
44
+ rollback
45
+ end
46
+ text "and this is"
47
+ end
48
+ end
49
+ text = PDF::Inspector::Text.analyze(pdf.render)
50
+ text.strings.should == ["This is shown", "and this is"]
51
+ end
52
+
53
+ it "should allow rollback of multiple pages" do
54
+ pdf = Prawn::Document.new do
55
+ transaction do
56
+ 5.times { start_new_page }
57
+ text "way out there and will never be shown"
58
+ rollback
59
+ end
60
+ text "This is the real text, only one page"
61
+ end
62
+
63
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
64
+ pages.size.should == 1
65
+ end
66
+
67
+ # Because the Pages object, when restored, points to the snapshotted pages
68
+ # by identifier, we have to restore the snapshot into the same page objects,
69
+ # or else old pages will appear in the post-rollback document.
70
+ it "should restore the pages into the same objects" do
71
+ Prawn::Document.new do
72
+ old_page_object_id = state.page.dictionary.identifier
73
+ old_page_content_id = state.page.content.identifier
74
+
75
+ transaction do
76
+ start_new_page
77
+ rollback
78
+ end
79
+
80
+ state.page.dictionary.identifier.should == old_page_object_id
81
+ state.page.content.identifier.should == old_page_content_id
82
+ end
83
+
84
+ end
85
+
86
+ it "page object should refer to the page_content object after restore" do
87
+
88
+ Prawn::Document.new do
89
+ transaction do
90
+ start_new_page
91
+ rollback
92
+ end
93
+
94
+ # should be the exact same object, not a clone
95
+ state.page.dictionary.data[:Contents].should == state.page.content
96
+ end
97
+
98
+ end
99
+
100
+ describe "with a stamp dictionary present" do
101
+
102
+ it "should properly commit if no error is raised" do
103
+ pdf = Prawn::Document.new do
104
+ create_stamp("test_stamp") { draw_text "This is shown", :at => [0,0] }
105
+ transaction do
106
+ stamp("test_stamp")
107
+ end
108
+ end
109
+ pdf.render.should =~ /\/Stamp1 Do/
110
+ end
111
+
112
+ it "should properly rollback when #rollback is called" do
113
+ pdf = Prawn::Document.new do
114
+ create_stamp("test_stamp") { draw_text "This is not shown", :at => [0,0] }
115
+
116
+ transaction do
117
+ stamp("test_stamp")
118
+ rollback
119
+ end
120
+ end
121
+ pdf.render.should.not =~ /\/Stamp1 Do/
122
+ end
123
+
124
+ end
125
+
126
+ it "should restore page_number on rollback" do
127
+ Prawn::Document.new do
128
+ transaction do
129
+ 5.times { start_new_page }
130
+ rollback
131
+ end
132
+
133
+ page_number.should == 1
134
+ end
135
+ end
136
+
137
+ end
138
+
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ puts "Prawn specs: Running on Ruby Version: #{RUBY_VERSION}"
4
+
5
+ require "rubygems"
6
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
7
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'vendor',
8
+ 'pdf-inspector','lib')
9
+ require "prawn"
10
+
11
+ Prawn.debug = true
12
+
13
+ ruby_19 do
14
+ gem "test-unit", "=1.2.3"
15
+ end
16
+ require "test/spec"
17
+ require "mocha"
18
+
19
+ gem 'pdf-reader', ">=0.8"
20
+ require "pdf/reader"
21
+ require "pdf/inspector"
22
+
23
+ def create_pdf(klass=Prawn::Document)
24
+ @pdf = klass.new(:margin => 0)
25
+ end
26
+
@@ -0,0 +1,108 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
2
+
3
+ describe "create_stamp before any page is added" do
4
+ it "should work with the font class" do
5
+ @pdf = Prawn::Document.new(:skip_page_creation => true)
6
+ lambda {
7
+ @pdf.create_stamp("my_stamp") do
8
+ @pdf.font.height
9
+ end
10
+ }.should.not.raise(Prawn::Errors::NotOnPage)
11
+ end
12
+ it "should work with setting color" do
13
+ @pdf = Prawn::Document.new(:skip_page_creation => true)
14
+ lambda {
15
+ @pdf.create_stamp("my_stamp") do
16
+ @pdf.fill_color = 'ff0000'
17
+ end
18
+ }.should.not.raise(Prawn::Errors::NotOnPage)
19
+ end
20
+ end
21
+
22
+ describe "#stamp_at" do
23
+ it "should work" do
24
+ create_pdf
25
+ @pdf.create_stamp("MyStamp")
26
+ @pdf.stamp_at("MyStamp", [100, 200])
27
+ # I had modified PDF::Inspector::XObject to receive the
28
+ # invoke_xobject message and count the number of times it was
29
+ # called, but it was only called once, so I reverted checking the
30
+ # output with a regular expression
31
+ @pdf.render.should =~ /\/Stamp1 Do.*?/m
32
+ end
33
+ end
34
+
35
+ describe "Document with a stamp" do
36
+ it "should raise NameTaken error when attempt to create stamp "+
37
+ "with same name as an existing stamp" do
38
+ create_pdf
39
+ @pdf.create_stamp("MyStamp")
40
+ lambda {
41
+ @pdf.create_stamp("MyStamp")
42
+ }.should.raise(Prawn::Errors::NameTaken)
43
+ end
44
+
45
+ it "should raise InvalidName error when attempt to create "+
46
+ "stamp with a blank name" do
47
+ create_pdf
48
+ lambda {
49
+ @pdf.create_stamp("")
50
+ }.should.raise(Prawn::Errors::InvalidName)
51
+ end
52
+
53
+ it "a new XObject should be defined for each stamp created" do
54
+ create_pdf
55
+ @pdf.create_stamp("MyStamp")
56
+ @pdf.create_stamp("AnotherStamp")
57
+ @pdf.stamp("MyStamp")
58
+ @pdf.stamp("AnotherStamp")
59
+
60
+ inspector = PDF::Inspector::XObject.analyze(@pdf.render)
61
+ xobjects = inspector.page_xobjects.last
62
+ xobjects.length.should == 2
63
+ end
64
+
65
+ it "calling stamp with a name that does not match an existing stamp "+
66
+ "should raise UndefinedObjectName" do
67
+ create_pdf
68
+ @pdf.create_stamp("MyStamp")
69
+ lambda {
70
+ @pdf.stamp("OtherStamp")
71
+ }.should.raise(Prawn::Errors::UndefinedObjectName)
72
+ end
73
+
74
+ it "stamp should be drawn into the document each time stamp is called" do
75
+ create_pdf
76
+ @pdf.create_stamp("MyStamp")
77
+ @pdf.stamp("MyStamp")
78
+ @pdf.stamp("MyStamp")
79
+ @pdf.stamp("MyStamp")
80
+ # I had modified PDF::Inspector::XObject to receive the
81
+ # invoke_xobject message and count the number of times it was
82
+ # called, but it was only called once, so I reverted checking the
83
+ # output with a regular expression
84
+ @pdf.render.should =~ /(\/Stamp1 Do.*?){3}/m
85
+ end
86
+
87
+ it "resources added during stamp creation should be added to the "+
88
+ "stamp XObject, not the page" do
89
+ create_pdf
90
+ @pdf.create_stamp("MyStamp") do
91
+ @pdf.transparent(0.5) { @pdf.circle_at([100, 100], :radius => 10)}
92
+ end
93
+ @pdf.stamp("MyStamp")
94
+
95
+ # Inspector::XObject does not give information about resources, so
96
+ # resorting to string matching
97
+
98
+ output = @pdf.render
99
+ objects = output.split("endobj")
100
+ objects.each do |object|
101
+ if object =~ /\/Type \/Page$/
102
+ object.should.not =~ /\/ExtGState/
103
+ elsif object =~ /\/Type \/XObject$/
104
+ object.should =~ /\/ExtGState/
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,163 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
+
5
+ describe "When stroking with default settings" do
6
+ before(:each) { create_pdf }
7
+ it "cap_style should be :butt" do
8
+ @pdf.cap_style.should == :butt
9
+ end
10
+
11
+ it "join_style should be :miter" do
12
+ @pdf.join_style.should == :miter
13
+ end
14
+
15
+ it "dashed? should be false" do
16
+ @pdf.should.not.be.dashed
17
+ end
18
+ end
19
+
20
+ describe "Cap styles" do
21
+ before(:each) { create_pdf }
22
+
23
+ it "should be able to use assignment operator" do
24
+ @pdf.cap_style = :round
25
+ @pdf.cap_style.should == :round
26
+ end
27
+
28
+ describe "#cap_style(:butt)" do
29
+ it "rendered PDF should include butt style cap" do
30
+ @pdf.cap_style(:butt)
31
+ cap_style = PDF::Inspector::Graphics::CapStyle.analyze(@pdf.render).cap_style
32
+ cap_style.should == 0
33
+ end
34
+ end
35
+
36
+ describe "#cap_style(:round)" do
37
+ it "rendered PDF should include round style cap" do
38
+ @pdf.cap_style(:round)
39
+ cap_style = PDF::Inspector::Graphics::CapStyle.analyze(@pdf.render).cap_style
40
+ cap_style.should == 1
41
+ end
42
+ end
43
+
44
+ describe "#cap_style(:projecting_square)" do
45
+ it "rendered PDF should include projecting_square style cap" do
46
+ @pdf.cap_style(:projecting_square)
47
+ cap_style = PDF::Inspector::Graphics::CapStyle.analyze(@pdf.render).cap_style
48
+ cap_style.should == 2
49
+ end
50
+ end
51
+
52
+ it "should carry the current cap style settings over to new pages" do
53
+ @pdf.cap_style(:round)
54
+ @pdf.start_new_page
55
+ cap_styles = PDF::Inspector::Graphics::CapStyle.analyze(@pdf.render)
56
+ cap_styles.cap_style_count.should == 2
57
+ cap_styles.cap_style.should == 1
58
+ end
59
+ end
60
+
61
+ describe "Join styles" do
62
+ before(:each) { create_pdf }
63
+
64
+ it "should be able to use assignment operator" do
65
+ @pdf.join_style = :round
66
+ @pdf.join_style.should == :round
67
+ end
68
+
69
+ describe "#join_style(:miter)" do
70
+ it "rendered PDF should include miter style join" do
71
+ @pdf.join_style(:miter)
72
+ join_style = PDF::Inspector::Graphics::JoinStyle.analyze(@pdf.render).join_style
73
+ join_style.should == 0
74
+ end
75
+ end
76
+
77
+ describe "#join_style(:round)" do
78
+ it "rendered PDF should include round style join" do
79
+ @pdf.join_style(:round)
80
+ join_style = PDF::Inspector::Graphics::JoinStyle.analyze(@pdf.render).join_style
81
+ join_style.should == 1
82
+ end
83
+ end
84
+
85
+ describe "#join_style(:bevel)" do
86
+ it "rendered PDF should include bevel style join" do
87
+ @pdf.join_style(:bevel)
88
+ join_style = PDF::Inspector::Graphics::JoinStyle.analyze(@pdf.render).join_style
89
+ join_style.should == 2
90
+ end
91
+ end
92
+
93
+ it "should carry the current join style settings over to new pages" do
94
+ @pdf.join_style(:round)
95
+ @pdf.start_new_page
96
+ join_styles = PDF::Inspector::Graphics::JoinStyle.analyze(@pdf.render)
97
+ join_styles.join_style_count.should == 2
98
+ join_styles.join_style.should == 1
99
+ end
100
+ end
101
+
102
+ describe "Dashes" do
103
+ before(:each) { create_pdf }
104
+
105
+ it "should be able to use assignment operator" do
106
+ @pdf.dash = 2
107
+ @pdf.should.be.dashed
108
+ end
109
+
110
+ describe "setting a dash" do
111
+ it "dashed? should be true" do
112
+ @pdf.dash(2)
113
+ @pdf.should.be.dashed
114
+ end
115
+ it "rendered PDF should include a stroked dash" do
116
+ @pdf.dash(2)
117
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
118
+ dashes.stroke_dash.should == [[2, 2], 0]
119
+ end
120
+ end
121
+
122
+ describe "setting a dash by passing a single argument" do
123
+ it "space between dashes should be the same length as the dash in the rendered PDF" do
124
+ @pdf.dash(2)
125
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
126
+ dashes.stroke_dash.should == [[2, 2], 0]
127
+ end
128
+ end
129
+
130
+ describe "with a space option that differs from the first argument" do
131
+ it "space between dashes in the rendered PDF should be different length than the length of the dash" do
132
+ @pdf.dash(2, :space => 3)
133
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
134
+ dashes.stroke_dash.should == [[2, 3], 0]
135
+ end
136
+ end
137
+
138
+ describe "with a non-zero phase option" do
139
+ it "rendered PDF should include a non-zero phase" do
140
+ @pdf.dash(2, :phase => 1)
141
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
142
+ dashes.stroke_dash.should == [[2, 2], 1]
143
+ end
144
+ end
145
+
146
+ describe "clearing stroke dash" do
147
+ it "should restore solid line" do
148
+ @pdf.dash(2)
149
+ @pdf.undash
150
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
151
+ dashes.stroke_dash.should == [[], 0]
152
+ end
153
+ end
154
+
155
+ it "should carry the current dash settings over to new pages" do
156
+ @pdf.dash(2)
157
+ @pdf.start_new_page
158
+ dashes = PDF::Inspector::Graphics::Dash.analyze(@pdf.render)
159
+ dashes.stroke_dash_count.should == 2
160
+ dashes.stroke_dash.should == [[2, 2], 0]
161
+ end
162
+
163
+ end
@@ -0,0 +1,598 @@
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.an.instance_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
33
+ end
34
+
35
+ # TODO: pending colspan
36
+ xit "should accurately count columns from data" do
37
+ # First data row may contain colspan which would hide true column count
38
+ data = [["Name:",{:text => "Some very long name", :colspan => 5}]]
39
+ pdf = Prawn::Document.new
40
+ table = Prawn::Table.new data, pdf
41
+ table.column_widths.length.should == 6
42
+ end
43
+ end
44
+
45
+ describe "#initialize" do
46
+ before(:each) do
47
+ @pdf = Prawn::Document.new
48
+ end
49
+
50
+ it "should instance_eval a 0-arg block" do
51
+ initializer = mock()
52
+ initializer.expects(:kick).once
53
+
54
+ @pdf.table([["a"]]){
55
+ self.should.be.an.instance_of(Prawn::Table); initializer.kick }
56
+ end
57
+
58
+ it "should call a 1-arg block with the document as the argument" do
59
+ initializer = mock()
60
+ initializer.expects(:kick).once
61
+
62
+ @pdf.table([["a"]]){ |doc|
63
+ doc.should.be.an.instance_of(Prawn::Table); initializer.kick }
64
+ end
65
+
66
+ it "should proxy cell methods to #cells" do
67
+ table = @pdf.table([["a"]], :cell_style => { :padding => 11 })
68
+ table.cells[0, 0].padding.should == [11, 11, 11, 11]
69
+ end
70
+
71
+ it "should set row and column length" do
72
+ table = @pdf.table([["a", "b", "c"], ["d", "e", "f"]])
73
+ table.row_length.should == 2
74
+ table.column_length.should == 3
75
+ end
76
+
77
+ it "should generate a text cell based on a String" do
78
+ t = @pdf.table([["foo"]])
79
+ t.cells[0,0].should.be.a.kind_of(Prawn::Table::Cell::Text)
80
+ end
81
+
82
+ it "should pass through a text cell" do
83
+ c = Prawn::Table::Cell::Text.new(@pdf, [0,0], :content => "foo")
84
+ t = @pdf.table([[c]])
85
+ t.cells[0,0].should == c
86
+ end
87
+ end
88
+
89
+ describe "cell accessors" do
90
+ before(:each) do
91
+ @pdf = Prawn::Document.new
92
+ @table = @pdf.table([%w[R0C0 R0C1], %w[R1C0 R1C1]])
93
+ end
94
+
95
+ it "should select rows by number or range" do
96
+ Set.new(@table.row(0).map { |c| c.content }).should ==
97
+ Set.new(%w[R0C0 R0C1])
98
+ Set.new(@table.rows(0..1).map { |c| c.content }).should ==
99
+ Set.new(%w[R0C0 R0C1 R1C0 R1C1])
100
+ end
101
+
102
+ it "should select columns by number or range" do
103
+ Set.new(@table.column(0).map { |c| c.content }).should ==
104
+ Set.new(%w[R0C0 R1C0])
105
+ Set.new(@table.columns(0..1).map { |c| c.content }).should ==
106
+ Set.new(%w[R0C0 R0C1 R1C0 R1C1])
107
+ end
108
+
109
+ it "should allow rows and columns to be combined" do
110
+ @table.row(0).column(1).map { |c| c.content }.should == ["R0C1"]
111
+ end
112
+
113
+ it "should accept a select block, returning a cell proxy" do
114
+ @table.cells.select { |c| c.content =~ /R0/ }.column(1).map{ |c|
115
+ c.content }.should == ["R0C1"]
116
+ end
117
+
118
+ it "should accept the [] method, returning a Cell or nil" do
119
+ @table.cells[0, 0].content.should == "R0C0"
120
+ @table.cells[12, 12].should.be.nil
121
+ end
122
+
123
+ it "should proxy unknown methods to the cells" do
124
+ @table.cells.height = 200
125
+ @table.row(1).height = 100
126
+
127
+ @table.cells[0, 0].height.should == 200
128
+ @table.cells[1, 0].height.should == 100
129
+ end
130
+
131
+ it "should accept the style method, proxying its calls to the cells" do
132
+ @table.cells.style(:height => 200, :width => 200)
133
+ @table.column(0).style(:width => 100)
134
+
135
+ @table.cells[0, 1].width.should == 200
136
+ @table.cells[1, 0].height.should == 200
137
+ @table.cells[1, 0].width.should == 100
138
+ end
139
+
140
+ it "should return the width of selected columns for #width" do
141
+ c0_width = @table.column(0).map{ |c| c.width }.max
142
+ c1_width = @table.column(1).map{ |c| c.width }.max
143
+
144
+ @table.column(0).width.should == c0_width
145
+ @table.column(1).width.should == c1_width
146
+
147
+ @table.columns(0..1).width.should == c0_width + c1_width
148
+ @table.cells.width.should == c0_width + c1_width
149
+ end
150
+
151
+ it "should return the height of selected rows for #height" do
152
+ r0_height = @table.row(0).map{ |c| c.height }.max
153
+ r1_height = @table.row(1).map{ |c| c.height }.max
154
+
155
+ @table.row(0).height.should == r0_height
156
+ @table.row(1).height.should == r1_height
157
+
158
+ @table.rows(0..1).height.should == r0_height + r1_height
159
+ @table.cells.height.should == r0_height + r1_height
160
+ end
161
+ end
162
+
163
+ describe "layout" do
164
+ before(:each) do
165
+ @pdf = Prawn::Document.new
166
+ @long_text = "The quick brown fox jumped over the lazy dogs. " * 5
167
+ end
168
+
169
+ describe "width" do
170
+ it "should raise an error if the given width is outside of range" do
171
+ lambda do
172
+ @pdf.table([["foo"]], :width => 1)
173
+ end.should.raise(Prawn::Errors::CannotFit)
174
+
175
+ lambda do
176
+ @pdf.table([[@long_text]], :width => @pdf.bounds.width + 100)
177
+ end.should.raise(Prawn::Errors::CannotFit)
178
+ end
179
+
180
+ it "should accept the natural width for small tables" do
181
+ pad = 10 # default padding
182
+ @table = @pdf.table([["a"]])
183
+ @table.width.should == @table.cells[0, 0].natural_content_width + pad
184
+ end
185
+
186
+ it "width should equal sum(column_widths)" do
187
+ table = Prawn::Table.new([%w[ a b c ], %w[d e f]], @pdf) do
188
+ column(0).width = 50
189
+ column(1).width = 100
190
+ column(2).width = 150
191
+ end
192
+ table.width.should == 300
193
+ end
194
+
195
+ it "should calculate unspecified column widths as "+
196
+ "(max(string_width) + 2*horizontal_padding)" do
197
+ hpad, fs = 3, 12
198
+ columns = 2
199
+ table = Prawn::Table.new( [%w[ foo b ], %w[d foobar]], @pdf,
200
+ :cell_style => { :padding => hpad, :size => fs } )
201
+
202
+ col0_width = @pdf.width_of("foo", :size => fs)
203
+ col1_width = @pdf.width_of("foobar", :size => fs)
204
+
205
+ table.width.should == col0_width + col1_width + 2*columns*hpad
206
+ end
207
+
208
+ it "should allow mixing autocalculated and preset"+
209
+ "column widths within a single table" do
210
+ hpad, fs = 10, 6
211
+ stretchy_columns = 2
212
+
213
+ col0_width = 50
214
+ col1_width = @pdf.width_of("foo", :size => fs)
215
+ col2_width = @pdf.width_of("foobar", :size => fs)
216
+ col3_width = 150
217
+
218
+ table = Prawn::Table.new( [%w[snake foo b apple],
219
+ %w[kitten d foobar banana]], @pdf,
220
+ :cell_style => { :padding => hpad, :size => fs }) do
221
+
222
+ column(0).width = col0_width
223
+ column(3).width = col3_width
224
+ end
225
+
226
+ table.width.should == col1_width + col2_width +
227
+ 2*stretchy_columns*hpad +
228
+ col0_width + col3_width
229
+ end
230
+
231
+ it "should not exceed the maximum width of the margin_box" do
232
+ expected_width = @pdf.margin_box.width
233
+ data = [
234
+ ['This is a column with a lot of text that should comfortably exceed '+
235
+ 'the width of a normal document margin_box width', 'Some more text',
236
+ 'and then some more', 'Just a bit more to be extra sure']
237
+ ]
238
+ table = Prawn::Table.new(data, @pdf)
239
+
240
+ table.width.should == expected_width
241
+ end
242
+
243
+ it "should not exceed the maximum width of the margin_box even with" +
244
+ "manual widths specified" do
245
+ expected_width = @pdf.margin_box.width
246
+ data = [
247
+ ['This is a column with a lot of text that should comfortably exceed '+
248
+ 'the width of a normal document margin_box width', 'Some more text',
249
+ 'and then some more', 'Just a bit more to be extra sure']
250
+ ]
251
+ table = Prawn::Table.new(data, @pdf) { column(1).width = 100 }
252
+
253
+ table.width.should == expected_width
254
+ end
255
+
256
+ it "scales down only the non-preset column widths when the natural width" +
257
+ "exceeds the maximum width of the margin_box" do
258
+ expected_width = @pdf.margin_box.width
259
+ data = [
260
+ ['This is a column with a lot of text that should comfortably exceed '+
261
+ 'the width of a normal document margin_box width', 'Some more text',
262
+ 'and then some more', 'Just a bit more to be extra sure']
263
+ ]
264
+ table = Prawn::Table.new(data, @pdf) { column(1).width = 100; column(3).width = 50 }
265
+
266
+ table.width.should == expected_width
267
+ table.column_widths[1].should == 100
268
+ table.column_widths[3].should == 50
269
+ end
270
+
271
+ it "should allow width to be reset even after it has been calculated" do
272
+ @table = @pdf.table([[@long_text]])
273
+ @table.width
274
+ @table.width = 100
275
+ @table.width.should == 100
276
+ end
277
+
278
+ it "should shrink columns evenly when two equal columns compete" do
279
+ @table = @pdf.table([["foo", @long_text], [@long_text, "foo"]])
280
+ @table.cells[0, 0].width.should == @table.cells[0, 1].width
281
+ end
282
+
283
+ it "should grow columns evenly when equal deficient columns compete" do
284
+ @table = @pdf.table([["foo", "foobar"], ["foobar", "foo"]], :width => 500)
285
+ @table.cells[0, 0].width.should == @table.cells[0, 1].width
286
+ end
287
+
288
+ it "should respect manual widths" do
289
+ @table = @pdf.table([%w[foo bar baz], %w[baz bar foo]], :width => 500) do
290
+ column(1).width = 60
291
+ end
292
+ @table.column(1).width.should == 60
293
+ @table.column(0).width.should == @table.column(2).width
294
+ end
295
+
296
+ it "should be the width of the :width parameter" do
297
+ expected_width = 300
298
+ table = Prawn::Table.new( [%w[snake foo b apple],
299
+ %w[kitten d foobar banana]], @pdf,
300
+ :width => expected_width)
301
+
302
+ table.width.should == expected_width
303
+ end
304
+
305
+ it "should not exceed the :width option" do
306
+ expected_width = 400
307
+ data = [
308
+ ['This is a column with a lot of text that should comfortably exceed '+
309
+ 'the width of a normal document margin_box width', 'Some more text',
310
+ 'and then some more', 'Just a bit more to be extra sure']
311
+ ]
312
+ table = Prawn::Table.new(data, @pdf, :width => expected_width)
313
+
314
+ table.width.should == expected_width
315
+ end
316
+
317
+ it "should not exceed the :width option even with manual widths specified" do
318
+ expected_width = 400
319
+ data = [
320
+ ['This is a column with a lot of text that should comfortably exceed '+
321
+ 'the width of a normal document margin_box width', 'Some more text',
322
+ 'and then some more', 'Just a bit more to be extra sure']
323
+ ]
324
+ table = Prawn::Table.new(data, @pdf, :width => expected_width) do
325
+ column(1).width = 100
326
+ end
327
+
328
+ table.width.should == expected_width
329
+ end
330
+
331
+ # TODO: pending colspan
332
+ xit "should calculate unspecified column widths even " +
333
+ "with colspan cells declared" do
334
+ pdf = Prawn::Document.new
335
+ hpad, fs = 3, 5
336
+ columns = 3
337
+
338
+ data = [ [ { :text => 'foo', :colspan => 2 }, "foobar" ],
339
+ [ "foo", "foo", "foo" ] ]
340
+ table = Prawn::Table.new( data, pdf,
341
+ :horizontal_padding => hpad,
342
+ :font_size => fs )
343
+
344
+ col0_width = pdf.width_of("foo", :size => fs) # cell 1, 0
345
+ col1_width = pdf.width_of("foo", :size => fs) # cell 1, 1
346
+ col2_width = pdf.width_of("foobar", :size => fs) # cell 0, 1 (at col 2)
347
+
348
+ table.width.should == col0_width.ceil + col1_width.ceil +
349
+ col2_width.ceil + 2*columns*hpad
350
+ end
351
+ end
352
+
353
+ describe "height" do
354
+ it "should set all cells in a row to the same height" do
355
+ @table = @pdf.table([["foo", @long_text]])
356
+ @table.cells[0, 0].height.should == @table.cells[0, 1].height
357
+ end
358
+
359
+ it "should move y-position to the bottom of the table after drawing" do
360
+ old_y = @pdf.y
361
+ table = @pdf.table([["foo"]])
362
+ @pdf.y.should == old_y - table.height
363
+ end
364
+
365
+ it "should not wrap unnecessarily" do
366
+ # Test for FP errors and glitches
367
+ t = @pdf.table([["Bender Bending Rodriguez"]])
368
+ h = @pdf.height_of("one line")
369
+ (t.height - 10).should.be < h*1.5
370
+ end
371
+
372
+ it "should have a height of n rows" do
373
+ data = [["foo"],["bar"],["baaaz"]]
374
+
375
+ vpad = 4
376
+ origin = @pdf.y
377
+ @pdf.table data, :cell_style => { :padding => vpad }
378
+
379
+ table_height = origin - @pdf.y
380
+ font_height = @pdf.font.height
381
+
382
+ num_rows = data.length
383
+ table_height.should.be.close(
384
+ num_rows*font_height + 2*vpad*num_rows, 0.001 )
385
+ end
386
+
387
+ end
388
+
389
+ end
390
+
391
+ describe "Multi-page tables" do
392
+ it "should flow to the next page when hitting the bottom of the bounds" do
393
+ Prawn::Document.new { table([["foo"]] * 30) }.page_count.should == 1
394
+ Prawn::Document.new { table([["foo"]] * 31) }.page_count.should == 2
395
+ Prawn::Document.new { table([["foo"]] * 31); table([["foo"]] * 31) }.
396
+ page_count.should == 3
397
+ end
398
+
399
+ it "should respect the containing bounds" do
400
+ Prawn::Document.new do
401
+ bounding_box([0, cursor], :width => bounds.width, :height => 72) do
402
+ table([["foo"]] * 4)
403
+ end
404
+ end.page_count.should == 2
405
+ end
406
+ end
407
+
408
+ describe "#style" do
409
+ it "should send #style to its first argument, passing the style hash and" +
410
+ " block" do
411
+
412
+ stylable = stub()
413
+ stylable.expects(:style).with(:foo => :bar).once.yields
414
+
415
+ block = stub()
416
+ block.expects(:kick).once
417
+
418
+ Prawn::Document.new do
419
+ table([["x"]]) { style(stylable, :foo => :bar) { block.kick } }
420
+ end
421
+ end
422
+
423
+ it "should default to {} for the hash argument" do
424
+ stylable = stub()
425
+ stylable.expects(:style).with({}).once
426
+
427
+ Prawn::Document.new do
428
+ table([["x"]]) { style(stylable) }
429
+ end
430
+ end
431
+ end
432
+
433
+ describe "row_colors" do
434
+ it "should allow array syntax for :row_colors" do
435
+ data = [["foo"], ["bar"], ["baz"]]
436
+ pdf = Prawn::Document.new
437
+ t = pdf.table(data, :row_colors => ['cccccc', 'ffffff'])
438
+ t.cells.map{|x| x.background_color}.should == %w[cccccc ffffff cccccc]
439
+ end
440
+
441
+ it "should ignore headers" do
442
+ data = [["header"], ["foo"], ["bar"], ["baz"]]
443
+ pdf = Prawn::Document.new
444
+ t = pdf.table(data, :header => true,
445
+ :row_colors => ['cccccc', 'ffffff']) do
446
+ row(0).background_color = '333333'
447
+ end
448
+
449
+ t.cells.map{|x| x.background_color}.should ==
450
+ %w[333333 cccccc ffffff cccccc]
451
+ end
452
+ end
453
+
454
+ describe "inking" do
455
+ before(:each) do
456
+ @pdf = Prawn::Document.new
457
+ end
458
+
459
+ it "should set the x-position of each cell based on widths" do
460
+ @table = @pdf.table([["foo", "bar", "baz"]])
461
+
462
+ x = 0
463
+ (0..2).each do |col|
464
+ cell = @table.cells[0, col]
465
+ cell.x.should == x
466
+ x += cell.width
467
+ end
468
+ end
469
+
470
+ it "should set the y-position of each cell based on heights" do
471
+ y = 0
472
+ @table = @pdf.make_table([["foo"], ["bar"], ["baz"]])
473
+
474
+ (0..2).each do |row|
475
+ cell = @table.cells[row, 0]
476
+ cell.y.should.be.close(y, 0.01)
477
+ y -= cell.height
478
+ end
479
+ end
480
+
481
+ it "should output content cell by cell, row by row" do
482
+ data = [["foo","bar"],["baz","bang"]]
483
+ @pdf = Prawn::Document.new
484
+ @pdf.table(data)
485
+ output = PDF::Inspector::Text.analyze(@pdf.render)
486
+ output.strings.should == data.flatten
487
+ end
488
+
489
+ it "should not cause an error if rendering the very first row causes a " +
490
+ "page break" do
491
+ Prawn::Document.new do
492
+ arr = Array(1..5).collect{|i| ["cell #{i}"] }
493
+
494
+ move_down( y - (bounds.absolute_bottom + 3) )
495
+
496
+ lambda {
497
+ table(arr)
498
+ }.should.not.raise
499
+ end
500
+ end
501
+
502
+ it "should allow multiple inkings of the same table" do
503
+ pdf = Prawn::Document.new
504
+ t = Prawn::Table.new([["foo"]], pdf)
505
+
506
+ pdf.expects(:bounding_box).with{|(x, y), options| y.to_i == 495}.yields
507
+ pdf.expects(:bounding_box).with{|(x, y), options| y.to_i == 395}.yields
508
+ pdf.expects(:draw_text!).with{ |text, options| text == 'foo' }.twice
509
+
510
+ pdf.move_cursor_to(500)
511
+ t.draw
512
+
513
+ pdf.move_cursor_to(400)
514
+ t.draw
515
+ end
516
+ end
517
+
518
+ describe "headers" do
519
+ it "should add headers to output when specified" do
520
+ data = [["a", "b"], ["foo","bar"],["baz","bang"]]
521
+ @pdf = Prawn::Document.new
522
+ @pdf.table(data, :header => true)
523
+ output = PDF::Inspector::Text.analyze(@pdf.render)
524
+ output.strings.should == data.flatten
525
+ end
526
+
527
+ it "should repeat headers across pages" do
528
+ data = [["foo","bar"]]*30
529
+ headers = ["baz","foobar"]
530
+ @pdf = Prawn::Document.new
531
+ @pdf.table([headers] + data, :header => true)
532
+ output = PDF::Inspector::Text.analyze(@pdf.render)
533
+ output.strings.should == headers + data.flatten[0..-3] + headers +
534
+ data.flatten[-2..-1]
535
+ end
536
+ end
537
+
538
+ describe "nested tables" do
539
+ before(:each) do
540
+ @pdf = Prawn::Document.new
541
+ @subtable = Prawn::Table.new([["foo"]], @pdf)
542
+ @table = @pdf.table([[@subtable, "bar"]])
543
+ end
544
+
545
+ it "can be created from an Array" do
546
+ cell = Prawn::Table::Cell.make(@pdf, [["foo"]])
547
+ cell.should.be.an.instance_of(Prawn::Table::Cell::Subtable)
548
+ cell.subtable.should.be.an.instance_of(Prawn::Table)
549
+ end
550
+
551
+ it "defaults its padding to zero" do
552
+ @table.cells[0, 0].padding.should == [0, 0, 0, 0]
553
+ end
554
+
555
+ it "has a subtable accessor" do
556
+ @table.cells[0, 0].subtable.should == @subtable
557
+ end
558
+
559
+ it "determines its dimensions from the subtable" do
560
+ @table.cells[0, 0].width.should == @subtable.width
561
+ @table.cells[0, 0].height.should == @subtable.height
562
+ end
563
+
564
+ end
565
+
566
+ describe "An invalid table" do
567
+
568
+ before(:each) do
569
+ @pdf = Prawn::Document.new
570
+ @bad_data = ["Single Nested Array"]
571
+ end
572
+
573
+ it "should raise error when invalid table data is given" do
574
+ assert_raises(Prawn::Errors::InvalidTableData) do
575
+ @pdf.table(@bad_data)
576
+ end
577
+ end
578
+
579
+ it "should raise an EmptyTableError with empty table data" do
580
+ lambda {
581
+ data = []
582
+ @pdf = Prawn::Document.new
583
+ @pdf.table(data)
584
+ }.should.raise( Prawn::Errors::EmptyTable )
585
+ end
586
+
587
+ it "should raise an EmptyTableError with nil table data" do
588
+ lambda {
589
+ data = nil
590
+ @pdf = Prawn::Document.new
591
+ @pdf.table(data)
592
+ }.should.raise( Prawn::Errors::EmptyTable )
593
+ end
594
+
595
+ end
596
+
597
+ end
598
+