prawn 1.0.0.rc1 → 1.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. data/Gemfile +18 -0
  2. data/README.md +5 -3
  3. data/Rakefile +8 -14
  4. data/data/pdfs/nested_pages.pdf +13 -13
  5. data/lib/prawn.rb +3 -1
  6. data/lib/prawn/compatibility.rb +46 -10
  7. data/lib/prawn/core.rb +3 -1
  8. data/lib/prawn/core/document_state.rb +2 -1
  9. data/lib/prawn/core/object_store.rb +61 -5
  10. data/lib/prawn/core/page.rb +3 -6
  11. data/lib/prawn/core/pdf_object.rb +21 -4
  12. data/lib/prawn/core/reference.rb +6 -2
  13. data/lib/prawn/core/text.rb +4 -4
  14. data/lib/prawn/core/text/formatted/line_wrap.rb +23 -8
  15. data/lib/prawn/document.rb +21 -15
  16. data/lib/prawn/document/bounding_box.rb +3 -3
  17. data/lib/prawn/document/column_box.rb +22 -4
  18. data/lib/prawn/document/snapshot.rb +1 -1
  19. data/lib/prawn/encoding.rb +1 -1
  20. data/lib/prawn/errors.rb +4 -0
  21. data/lib/prawn/font.rb +1 -1
  22. data/lib/prawn/font/afm.rb +30 -72
  23. data/lib/prawn/font/ttf.rb +6 -33
  24. data/lib/prawn/graphics.rb +148 -23
  25. data/lib/prawn/graphics/color.rb +8 -1
  26. data/lib/prawn/graphics/patterns.rb +137 -0
  27. data/lib/prawn/images.rb +25 -19
  28. data/lib/prawn/images/jpg.rb +4 -4
  29. data/lib/prawn/images/png.rb +18 -12
  30. data/lib/prawn/security.rb +6 -4
  31. data/lib/prawn/soft_mask.rb +94 -0
  32. data/lib/prawn/table.rb +136 -31
  33. data/lib/prawn/table/cell.rb +260 -29
  34. data/lib/prawn/table/cell/span_dummy.rb +88 -0
  35. data/lib/prawn/table/cell/text.rb +36 -14
  36. data/lib/prawn/table/cells.rb +91 -41
  37. data/lib/prawn/text.rb +3 -2
  38. data/lib/prawn/text/formatted/box.rb +14 -5
  39. data/lib/prawn/text/formatted/fragment.rb +33 -22
  40. data/lib/prawn/text/formatted/parser.rb +5 -2
  41. data/lib/prawn/utilities.rb +44 -0
  42. data/manual/basic_concepts/adding_pages.rb +27 -0
  43. data/manual/basic_concepts/basic_concepts.rb +34 -0
  44. data/manual/basic_concepts/creation.rb +39 -0
  45. data/manual/basic_concepts/cursor.rb +33 -0
  46. data/manual/basic_concepts/measurement.rb +25 -0
  47. data/manual/basic_concepts/origin.rb +38 -0
  48. data/manual/basic_concepts/other_cursor_helpers.rb +40 -0
  49. data/manual/bounding_box/bounding_box.rb +39 -0
  50. data/manual/bounding_box/bounds.rb +49 -0
  51. data/manual/bounding_box/canvas.rb +24 -0
  52. data/manual/bounding_box/creation.rb +23 -0
  53. data/manual/bounding_box/indentation.rb +46 -0
  54. data/manual/bounding_box/nesting.rb +45 -0
  55. data/manual/bounding_box/russian_boxes.rb +40 -0
  56. data/manual/bounding_box/stretchy.rb +31 -0
  57. data/manual/document_and_page_options/background.rb +27 -0
  58. data/manual/document_and_page_options/document_and_page_options.rb +31 -0
  59. data/manual/document_and_page_options/metadata.rb +23 -0
  60. data/manual/document_and_page_options/page_margins.rb +38 -0
  61. data/manual/document_and_page_options/page_size.rb +34 -0
  62. data/manual/example_file.rb +116 -0
  63. data/manual/example_helper.rb +430 -0
  64. data/manual/example_package.rb +53 -0
  65. data/manual/example_section.rb +46 -0
  66. data/manual/graphics/circle_and_ellipse.rb +22 -0
  67. data/manual/graphics/color.rb +24 -0
  68. data/manual/graphics/common_lines.rb +28 -0
  69. data/manual/graphics/fill_and_stroke.rb +42 -0
  70. data/manual/graphics/fill_rules.rb +37 -0
  71. data/manual/graphics/gradients.rb +37 -0
  72. data/manual/graphics/graphics.rb +58 -0
  73. data/manual/graphics/helper.rb +17 -0
  74. data/manual/graphics/line_width.rb +35 -0
  75. data/manual/graphics/lines_and_curves.rb +41 -0
  76. data/manual/graphics/polygon.rb +29 -0
  77. data/manual/graphics/rectangle.rb +21 -0
  78. data/manual/graphics/rotate.rb +28 -0
  79. data/manual/graphics/scale.rb +41 -0
  80. data/manual/graphics/soft_masks.rb +46 -0
  81. data/manual/graphics/stroke_cap.rb +31 -0
  82. data/manual/graphics/stroke_dash.rb +43 -0
  83. data/manual/graphics/stroke_join.rb +30 -0
  84. data/manual/graphics/translate.rb +29 -0
  85. data/manual/graphics/transparency.rb +35 -0
  86. data/manual/images/absolute_position.rb +23 -0
  87. data/manual/images/fit.rb +21 -0
  88. data/manual/images/horizontal.rb +25 -0
  89. data/manual/images/images.rb +40 -0
  90. data/manual/images/plain_image.rb +18 -0
  91. data/manual/images/scale.rb +22 -0
  92. data/manual/images/vertical.rb +28 -0
  93. data/manual/images/width_and_height.rb +25 -0
  94. data/manual/layout/boxes.rb +27 -0
  95. data/manual/layout/content.rb +25 -0
  96. data/manual/layout/layout.rb +28 -0
  97. data/manual/layout/simple_grid.rb +23 -0
  98. data/manual/manual/cover.rb +26 -0
  99. data/manual/manual/foreword.rb +13 -0
  100. data/manual/manual/how_to_read_this_manual.rb +41 -0
  101. data/manual/manual/manual.rb +36 -0
  102. data/manual/outline/add_subsection_to.rb +61 -0
  103. data/manual/outline/insert_section_after.rb +47 -0
  104. data/manual/outline/outline.rb +32 -0
  105. data/manual/outline/sections_and_pages.rb +67 -0
  106. data/manual/repeatable_content/page_numbering.rb +54 -0
  107. data/manual/repeatable_content/repeatable_content.rb +31 -0
  108. data/manual/repeatable_content/repeater.rb +55 -0
  109. data/manual/repeatable_content/stamp.rb +41 -0
  110. data/manual/security/encryption.rb +31 -0
  111. data/manual/security/permissions.rb +38 -0
  112. data/manual/security/security.rb +28 -0
  113. data/manual/syntax_highlight.rb +52 -0
  114. data/manual/table/basic_block.rb +53 -0
  115. data/manual/table/before_rendering_page.rb +26 -0
  116. data/manual/table/cell_border_lines.rb +24 -0
  117. data/manual/table/cell_borders_and_bg.rb +31 -0
  118. data/manual/table/cell_dimensions.rb +30 -0
  119. data/manual/table/cell_text.rb +38 -0
  120. data/manual/table/column_widths.rb +30 -0
  121. data/manual/table/content_and_subtables.rb +39 -0
  122. data/manual/table/creation.rb +27 -0
  123. data/manual/table/filtering.rb +36 -0
  124. data/manual/table/flow_and_header.rb +17 -0
  125. data/manual/table/image_cells.rb +33 -0
  126. data/manual/table/position.rb +29 -0
  127. data/manual/table/row_colors.rb +20 -0
  128. data/manual/table/span.rb +30 -0
  129. data/manual/table/style.rb +22 -0
  130. data/manual/table/table.rb +52 -0
  131. data/manual/table/width.rb +27 -0
  132. data/manual/templates/full_template.rb +23 -0
  133. data/manual/templates/page_template.rb +47 -0
  134. data/manual/templates/templates.rb +26 -0
  135. data/manual/text/alignment.rb +44 -0
  136. data/manual/text/color.rb +24 -0
  137. data/manual/text/column_box.rb +32 -0
  138. data/manual/text/fallback_fonts.rb +37 -0
  139. data/manual/text/font.rb +41 -0
  140. data/manual/text/font_size.rb +45 -0
  141. data/manual/text/font_style.rb +23 -0
  142. data/manual/text/formatted_callbacks.rb +60 -0
  143. data/manual/text/formatted_text.rb +50 -0
  144. data/manual/text/free_flowing_text.rb +51 -0
  145. data/manual/text/group.rb +29 -0
  146. data/manual/text/inline.rb +43 -0
  147. data/manual/text/kerning_and_character_spacing.rb +39 -0
  148. data/manual/text/leading.rb +25 -0
  149. data/manual/text/line_wrapping.rb +41 -0
  150. data/manual/text/paragraph_indentation.rb +26 -0
  151. data/manual/text/positioned_text.rb +38 -0
  152. data/manual/text/registering_families.rb +48 -0
  153. data/manual/text/rendering_and_color.rb +37 -0
  154. data/manual/text/right_to_left_text.rb +43 -0
  155. data/manual/text/rotation.rb +43 -0
  156. data/manual/text/single_usage.rb +37 -0
  157. data/manual/text/text.rb +75 -0
  158. data/manual/text/text_box_excess.rb +32 -0
  159. data/manual/text/text_box_extensions.rb +45 -0
  160. data/manual/text/text_box_overflow.rb +44 -0
  161. data/manual/text/utf8.rb +28 -0
  162. data/manual/text/win_ansi_charset.rb +59 -0
  163. data/prawn.gemspec +10 -7
  164. data/spec/bounding_box_spec.rb +107 -17
  165. data/spec/cell_spec.rb +66 -40
  166. data/spec/column_box_spec.rb +33 -0
  167. data/spec/document_spec.rb +45 -24
  168. data/spec/extensions/encoding_helpers.rb +6 -0
  169. data/spec/extensions/mocha.rb +1 -0
  170. data/spec/font_spec.rb +71 -53
  171. data/spec/formatted_text_arranger_spec.rb +19 -19
  172. data/spec/formatted_text_box_spec.rb +16 -16
  173. data/spec/formatted_text_fragment_spec.rb +6 -6
  174. data/spec/graphics_spec.rb +96 -31
  175. data/spec/grid_spec.rb +2 -2
  176. data/spec/images_spec.rb +18 -10
  177. data/spec/jpg_spec.rb +1 -1
  178. data/spec/line_wrap_spec.rb +14 -14
  179. data/spec/measurement_units_spec.rb +2 -2
  180. data/spec/name_tree_spec.rb +6 -6
  181. data/spec/object_store_spec.rb +17 -17
  182. data/spec/outline_spec.rb +35 -17
  183. data/spec/pdf_object_spec.rb +3 -1
  184. data/spec/png_spec.rb +22 -19
  185. data/spec/reference_spec.rb +24 -1
  186. data/spec/repeater_spec.rb +9 -9
  187. data/spec/security_spec.rb +3 -3
  188. data/spec/snapshot_spec.rb +3 -3
  189. data/spec/soft_mask_spec.rb +117 -0
  190. data/spec/span_spec.rb +4 -4
  191. data/spec/spec_helper.rb +12 -6
  192. data/spec/stamp_spec.rb +12 -12
  193. data/spec/stroke_styles_spec.rb +5 -5
  194. data/spec/table_spec.rb +458 -88
  195. data/spec/template_spec.rb +108 -54
  196. data/spec/text_at_spec.rb +17 -17
  197. data/spec/text_box_spec.rb +76 -45
  198. data/spec/text_rendering_mode_spec.rb +5 -5
  199. data/spec/text_spacing_spec.rb +4 -4
  200. data/spec/text_spec.rb +44 -40
  201. metadata +419 -250
  202. data/lib/prawn/graphics/gradient.rb +0 -84
  203. data/lib/prawn/security/arcfour.rb +0 -51
@@ -9,6 +9,13 @@ describe "Document built from a template" do
9
9
  page_counter.pages.size.should == 1
10
10
  end
11
11
 
12
+ it "should not set the template page's parent to the document pages catalog (especially with nested pages)" do
13
+ filename = "#{Prawn::DATADIR}/pdfs/nested_pages.pdf"
14
+ @pdf = Prawn::Document.new(:template => filename, :skip_page_creation => true)
15
+ @pdf.state.page.dictionary.data[:Parent].should_not == @pdf.state.store.pages
16
+ end
17
+
18
+
12
19
  it "should have start with the Y cursor at the top of the document" do
13
20
  filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
14
21
 
@@ -20,27 +27,27 @@ describe "Document built from a template" do
20
27
  filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
21
28
 
22
29
  @pdf = Prawn::Document.new(:template => filename, :margin => 0)
23
- assert_equal @pdf.page.margins, { :left => 0,
24
- :right => 0,
25
- :top => 0,
26
- :bottom => 0 }
30
+ @pdf.page.margins.should == { :left => 0,
31
+ :right => 0,
32
+ :top => 0,
33
+ :bottom => 0 }
27
34
 
28
35
  @pdf = Prawn::Document.new(:template => filename, :left_margin => 0)
29
36
 
30
- assert_equal @pdf.page.margins, { :left => 0,
31
- :right => 36,
32
- :top => 36,
33
- :bottom => 36 }
37
+ @pdf.page.margins.should == { :left => 0,
38
+ :right => 36,
39
+ :top => 36,
40
+ :bottom => 36 }
34
41
 
35
42
  @pdf.start_new_page(:right_margin => 0)
36
43
 
37
- assert_equal @pdf.page.margins, { :left => 0,
38
- :right => 0,
39
- :top => 36,
40
- :bottom => 36 }
44
+ @pdf.page.margins.should == { :left => 0,
45
+ :right => 0,
46
+ :top => 36,
47
+ :bottom => 36 }
48
+
41
49
 
42
50
 
43
-
44
51
  end
45
52
 
46
53
  it "should not add an extra restore_graphics_state operator to the end of any content stream" do
@@ -57,9 +64,9 @@ describe "Document built from a template" do
57
64
  data.include?("QQ").should == false
58
65
  end
59
66
  end
60
-
67
+
61
68
  it "should have a single page object if importing a single page template" do
62
- filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
69
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
63
70
 
64
71
  @pdf = Prawn::Document.new(:template => filename)
65
72
  output = StringIO.new(@pdf.render)
@@ -71,7 +78,7 @@ describe "Document built from a template" do
71
78
  end
72
79
 
73
80
  it "should have two content streams if importing a single page template" do
74
- filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
81
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
75
82
 
76
83
  @pdf = Prawn::Document.new(:template => filename)
77
84
  output = StringIO.new(@pdf.render)
@@ -83,16 +90,16 @@ describe "Document built from a template" do
83
90
  end
84
91
 
85
92
  it "should not die if using this PDF as a template" do
86
- filename = "#{Prawn::BASEDIR}/data/pdfs/complex_template.pdf"
93
+ filename = "#{Prawn::DATADIR}/pdfs/complex_template.pdf"
87
94
 
88
- assert_nothing_raised do
95
+ lambda {
89
96
  @pdf = Prawn::Document.new(:template => filename)
90
- end
97
+ }.should_not raise_error
91
98
  end
92
99
 
93
100
 
94
101
  it "should have balance q/Q operators on all content streams" do
95
- filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
102
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
96
103
 
97
104
  @pdf = Prawn::Document.new(:template => filename)
98
105
  output = StringIO.new(@pdf.render)
@@ -108,7 +115,7 @@ describe "Document built from a template" do
108
115
  end
109
116
 
110
117
  it "should allow text to be added to a single page template" do
111
- filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
118
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
112
119
 
113
120
  @pdf = Prawn::Document.new(:template => filename)
114
121
 
@@ -119,7 +126,7 @@ describe "Document built from a template" do
119
126
  end
120
127
 
121
128
  it "should allow PDFs with page resources behind an indirect object to be used as templates" do
122
- filename = "#{Prawn::BASEDIR}/data/pdfs/resources_as_indirect_object.pdf"
129
+ filename = "#{Prawn::DATADIR}/pdfs/resources_as_indirect_object.pdf"
123
130
 
124
131
  @pdf = Prawn::Document.new(:template => filename)
125
132
 
@@ -131,7 +138,7 @@ describe "Document built from a template" do
131
138
  end
132
139
 
133
140
  it "should copy the PDF version from the template file" do
134
- filename = "#{Prawn::BASEDIR}/data/pdfs/version_1_6.pdf"
141
+ filename = "#{Prawn::DATADIR}/pdfs/version_1_6.pdf"
135
142
 
136
143
  @pdf = Prawn::Document.new(:template => filename)
137
144
  str = @pdf.render
@@ -139,9 +146,9 @@ describe "Document built from a template" do
139
146
  end
140
147
 
141
148
  it "should correctly add a TTF font to a template that has existing fonts" do
142
- filename = "#{Prawn::BASEDIR}/data/pdfs/contains_ttf_font.pdf"
149
+ filename = "#{Prawn::DATADIR}/pdfs/contains_ttf_font.pdf"
143
150
  @pdf = Prawn::Document.new(:template => filename)
144
- @pdf.font "#{Prawn::BASEDIR}/data/fonts/Chalkboard.ttf"
151
+ @pdf.font "#{Prawn::DATADIR}/fonts/Chalkboard.ttf"
145
152
  @pdf.move_down(40)
146
153
  @pdf.text "Hi There"
147
154
 
@@ -155,51 +162,74 @@ describe "Document built from a template" do
155
162
  end
156
163
 
157
164
  it "should correctly import a template file that is missing a MediaBox entry" do
158
- filename = "#{Prawn::BASEDIR}/data/pdfs/page_without_mediabox.pdf"
165
+ filename = "#{Prawn::DATADIR}/pdfs/page_without_mediabox.pdf"
159
166
 
160
167
  @pdf = Prawn::Document.new(:template => filename)
161
168
  str = @pdf.render
162
169
  str[0,4].should == "%PDF"
163
170
  end
164
171
 
172
+ context "with the template as a stream" do
173
+ it "should correctly import a template file from a stream" do
174
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
175
+ io = StringIO.new(File.binread(filename))
176
+ @pdf = Prawn::Document.new(:template => io)
177
+ str = @pdf.render
178
+ str[0,4].should == "%PDF"
179
+ end
180
+ end
181
+
182
+ it "merges metadata info" do
183
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
184
+ info = { :Title => "Sample METADATA",
185
+ :Author => "Me",
186
+ :Subject => "Not Working",
187
+ :CreationDate => Time.now }
188
+
189
+ @pdf = Prawn::Document.new(:template => filename, :info => info)
190
+ output = StringIO.new(@pdf.render)
191
+ hash = PDF::Reader::ObjectHash.new(output)
192
+ info.keys.each { |k| hash[hash.trailer[:Info]].keys.include?(k).should == true }
193
+ end
194
+
165
195
  end
166
196
 
167
197
  describe "Document#start_new_page with :template option" do
168
198
  filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
169
-
199
+
170
200
  it "should set the imported page's parent to the document pages catalog" do
171
201
  @pdf = Prawn::Document.new()
172
202
  @pdf.start_new_page(:template => filename)
173
203
  @pdf.state.page.dictionary.data[:Parent].should == @pdf.state.store.pages
174
204
  end
175
-
205
+
176
206
  it "should set start the Y cursor at the top of the page" do
177
207
  @pdf = Prawn::Document.new()
178
208
  @pdf.start_new_page(:template => filename)
179
209
  (@pdf.y == nil).should == false
180
210
  end
181
-
211
+
182
212
  it "should respect margins set by Prawn" do
183
213
  @pdf = Prawn::Document.new(:margin => 0)
184
214
  @pdf.start_new_page(:template => filename)
185
- assert_equal @pdf.page.margins, { :left => 0,
186
- :right => 0,
187
- :top => 0,
188
- :bottom => 0 }
215
+ @pdf.page.margins.should == { :left => 0,
216
+ :right => 0,
217
+ :top => 0,
218
+ :bottom => 0 }
189
219
 
190
220
  @pdf = Prawn::Document.new(:left_margin => 0)
191
221
  @pdf.start_new_page(:template => filename)
192
- assert_equal @pdf.page.margins, { :left => 0,
193
- :right => 36,
194
- :top => 36,
195
- :bottom => 36 }
222
+ @pdf.page.margins.should == { :left => 0,
223
+ :right => 36,
224
+ :top => 36,
225
+ :bottom => 36 }
196
226
  @pdf.start_new_page(:template => filename, :right_margin => 0)
197
- assert_equal @pdf.page.margins, { :left => 0,
198
- :right => 0,
199
- :top => 36,
200
- :bottom => 36 }
227
+ @pdf.page.margins.should == { :left => 0,
228
+ :right => 0,
229
+ :top => 36,
230
+ :bottom => 36 }
201
231
  end
202
-
232
+
203
233
  it "should not add an extra restore_graphics_state operator to the end of any content stream" do
204
234
  @pdf = Prawn::Document.new
205
235
  @pdf.start_new_page(:template => filename)
@@ -213,9 +243,9 @@ describe "Document#start_new_page with :template option" do
213
243
  data.include?("QQ").should == false
214
244
  end
215
245
  end
216
-
246
+
217
247
  it "should have two content streams if importing a single page template" do
218
- filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
248
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
219
249
  @pdf = Prawn::Document.new()
220
250
  @pdf.start_new_page(:template => filename)
221
251
  output = StringIO.new(@pdf.render)
@@ -224,9 +254,9 @@ describe "Document#start_new_page with :template option" do
224
254
  template_page = hash[pages[1]]
225
255
  template_page[:Contents].size.should == 2
226
256
  end
227
-
257
+
228
258
  it "should have balance q/Q operators on all content streams" do
229
- filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
259
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
230
260
 
231
261
  @pdf = Prawn::Document.new()
232
262
  @pdf.start_new_page(:template => filename)
@@ -241,7 +271,7 @@ describe "Document#start_new_page with :template option" do
241
271
  data.scan("Q").size.should == 1
242
272
  end
243
273
  end
244
-
274
+
245
275
  it "should allow text to be added to a single page template" do
246
276
 
247
277
  @pdf = Prawn::Document.new()
@@ -252,9 +282,9 @@ describe "Document#start_new_page with :template option" do
252
282
  text = PDF::Inspector::Text.analyze(@pdf.render)
253
283
  text.strings.first.should == "Adding some text"
254
284
  end
255
-
285
+
256
286
  it "should allow PDFs with page resources behind an indirect object to be used as templates" do
257
- filename = "#{Prawn::BASEDIR}/data/pdfs/resources_as_indirect_object.pdf"
287
+ filename = "#{Prawn::DATADIR}/pdfs/resources_as_indirect_object.pdf"
258
288
 
259
289
  @pdf = Prawn::Document.new()
260
290
  @pdf.start_new_page(:template => filename)
@@ -265,12 +295,12 @@ describe "Document#start_new_page with :template option" do
265
295
  all_text = text.strings.join
266
296
  all_text.include?("Adding some text").should == true
267
297
  end
268
-
298
+
269
299
  it "should correctly add a TTF font to a template that has existing fonts" do
270
- filename = "#{Prawn::BASEDIR}/data/pdfs/contains_ttf_font.pdf"
300
+ filename = "#{Prawn::DATADIR}/pdfs/contains_ttf_font.pdf"
271
301
  @pdf = Prawn::Document.new()
272
302
  @pdf.start_new_page(:template => filename)
273
- @pdf.font "#{Prawn::BASEDIR}/data/fonts/Chalkboard.ttf"
303
+ @pdf.font "#{Prawn::DATADIR}/fonts/Chalkboard.ttf"
274
304
  @pdf.move_down(40)
275
305
  @pdf.text "Hi There"
276
306
 
@@ -283,10 +313,34 @@ describe "Document#start_new_page with :template option" do
283
313
  fonts = resources[:Font]
284
314
  fonts.size.should == 2
285
315
  end
286
-
316
+
317
+ it "indexes template pages when used multiple times" do
318
+ filename = "#{Prawn::DATADIR}/pdfs/multipage_template.pdf"
319
+ @repeated_pdf = Prawn::Document.new()
320
+ 3.times { @repeated_pdf.start_new_page(:template => filename) }
321
+ repeated_hash = PDF::Reader::ObjectHash.new(StringIO.new(@repeated_pdf.render))
322
+ @sequential_pdf = Prawn::Document.new()
323
+ (1..3).each { |p| @sequential_pdf.start_new_page(:template => filename, :template_page => p ) }
324
+ sequential_hash = PDF::Reader::ObjectHash.new(StringIO.new(@sequential_pdf.render))
325
+ (repeated_hash.size < sequential_hash.size).should == true
326
+ end
327
+
328
+ context "with the template as a stream" do
329
+ it "should correctly import a template file from a stream" do
330
+ filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
331
+ io = StringIO.new(File.binread(filename))
332
+
333
+ @pdf = Prawn::Document.new()
334
+ @pdf.start_new_page(:template => io)
335
+
336
+ str = @pdf.render
337
+ str[0,4].should == "%PDF"
338
+ end
339
+ end
340
+
287
341
  context "using template_page option" do
288
342
  it "uses the specified page option" do
289
- filename = "#{Prawn::BASEDIR}/data/pdfs/multipage_template.pdf"
343
+ filename = "#{Prawn::DATADIR}/pdfs/multipage_template.pdf"
290
344
  @pdf = Prawn::Document.new()
291
345
  @pdf.start_new_page(:template => filename, :template_page => 2)
292
346
  text = PDF::Inspector::Text.analyze(@pdf.render)
@@ -5,12 +5,12 @@ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
5
5
  describe "#draw_text" do
6
6
  before(:each) { create_pdf }
7
7
 
8
- it "should raise ArgumentError if :at option omitted" do
9
- lambda { @pdf.draw_text("hai", { }) }.should.raise(ArgumentError)
8
+ it "should raise_error ArgumentError if :at option omitted" do
9
+ lambda { @pdf.draw_text("hai", { }) }.should raise_error(ArgumentError)
10
10
  end
11
11
 
12
- it "should raise ArgumentError if :align option included" do
13
- lambda { @pdf.draw_text("hai", :at => [0, 0], :align => :center) }.should.raise(ArgumentError)
12
+ it "should raise_error ArgumentError if :align option included" do
13
+ lambda { @pdf.draw_text("hai", :at => [0, 0], :align => :center) }.should raise_error(ArgumentError)
14
14
  end
15
15
 
16
16
  it "should allow drawing empty strings to the page" do
@@ -85,8 +85,8 @@ describe "#draw_text" do
85
85
  text.font_settings[1][:name].should == :Courier
86
86
  end
87
87
 
88
- it "should raise an exception when an unknown font is used" do
89
- lambda { @pdf.font "Pao bu" }.should.raise(Prawn::Errors::UnknownFont)
88
+ it "should raise_error an exception when an unknown font is used" do
89
+ lambda { @pdf.font "Pao bu" }.should raise_error(Prawn::Errors::UnknownFont)
90
90
  end
91
91
 
92
92
  it "should correctly render a utf-8 string when using a built-in font" do
@@ -100,29 +100,29 @@ describe "#draw_text" do
100
100
 
101
101
  if "spec".respond_to?(:encode!)
102
102
  # Handle non utf-8 string encodings in a sane way on M17N aware VMs
103
- it "should raise an exception when a utf-8 incompatible string is rendered" do
103
+ it "should raise_error an exception when a utf-8 incompatible string is rendered" do
104
104
  str = "Blah \xDD"
105
105
  str.force_encoding("ASCII-8BIT")
106
- lambda { @pdf.draw_text(str, :at => [0, 0]) }.should.raise(
106
+ lambda { @pdf.draw_text(str, :at => [0, 0]) }.should raise_error(
107
107
  Prawn::Errors::IncompatibleStringEncoding)
108
108
  end
109
- it "should not raise an exception when a shift-jis string is rendered" do
110
- datafile = "#{Prawn::BASEDIR}/data/shift_jis_text.txt"
109
+ it "should_not raise_error an exception when a shift-jis string is rendered" do
110
+ datafile = "#{Prawn::DATADIR}/shift_jis_text.txt"
111
111
  sjis_str = File.open(datafile, "r:shift_jis") { |f| f.gets }
112
- @pdf.font("#{Prawn::BASEDIR}/data/fonts/gkai00mp.ttf")
113
- lambda { @pdf.draw_text(sjis_str, :at => [0, 0]) }.should.not.raise(
112
+ @pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf")
113
+ lambda { @pdf.draw_text(sjis_str, :at => [0, 0]) }.should_not raise_error(
114
114
  Prawn::Errors::IncompatibleStringEncoding)
115
115
  end
116
116
  else
117
117
  # Handle non utf-8 string encodings in a sane way on non-M17N aware VMs
118
- it "should raise an exception when a corrupt utf-8 string is rendered" do
118
+ it "should raise_error an exception when a corrupt utf-8 string is rendered" do
119
119
  str = "Blah \xDD"
120
- lambda { @pdf.draw_text(str, :at => [0, 0]) }.should.raise(
120
+ lambda { @pdf.draw_text(str, :at => [0, 0]) }.should raise_error(
121
121
  Prawn::Errors::IncompatibleStringEncoding)
122
122
  end
123
- it "should raise an exception when a shift-jis string is rendered" do
124
- sjis_str = File.read("#{Prawn::BASEDIR}/data/shift_jis_text.txt")
125
- lambda { @pdf.draw_text(sjis_str, :at => [0, 0]) }.should.raise(
123
+ it "should raise_error an exception when a shift-jis string is rendered" do
124
+ sjis_str = File.read("#{Prawn::DATADIR}/shift_jis_text.txt")
125
+ lambda { @pdf.draw_text(sjis_str, :at => [0, 0]) }.should raise_error(
126
126
  Prawn::Errors::IncompatibleStringEncoding)
127
127
  end
128
128
  end
@@ -3,55 +3,55 @@
3
3
  require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
4
 
5
5
  describe "Text::Box#nothing_printed?" do
6
- it "should be true when nothing printed" do
6
+ it "should be_true when nothing printed" do
7
7
  create_pdf
8
8
  string = "Hello world, how are you?\nI'm fine, thank you."
9
9
  text_box = Prawn::Text::Box.new(string,
10
10
  :height => 2,
11
11
  :document => @pdf)
12
12
  text_box.render
13
- text_box.nothing_printed?.should.be true
13
+ text_box.nothing_printed?.should be_true
14
14
  end
15
- it "should be false when something printed" do
15
+ it "should be_false when something printed" do
16
16
  create_pdf
17
17
  string = "Hello world, how are you?\nI'm fine, thank you."
18
18
  text_box = Prawn::Text::Box.new(string,
19
19
  :height => 14,
20
20
  :document => @pdf)
21
21
  text_box.render
22
- text_box.nothing_printed?.should.be false
22
+ text_box.nothing_printed?.should be_false
23
23
  end
24
24
  end
25
25
 
26
26
  describe "Text::Box#everything_printed?" do
27
- it "should be false when not everything printed" do
27
+ it "should be_false when not everything printed" do
28
28
  create_pdf
29
29
  string = "Hello world, how are you?\nI'm fine, thank you."
30
30
  text_box = Prawn::Text::Box.new(string,
31
31
  :height => 14,
32
32
  :document => @pdf)
33
33
  text_box.render
34
- text_box.everything_printed?.should.be false
34
+ text_box.everything_printed?.should be_false
35
35
  end
36
- it "should be true when everything printed" do
36
+ it "should be_true when everything printed" do
37
37
  create_pdf
38
38
  string = "Hello world, how are you?\nI'm fine, thank you."
39
39
  text_box = Prawn::Text::Box.new(string,
40
40
  :document => @pdf)
41
41
  text_box.render
42
- text_box.everything_printed?.should.be true
42
+ text_box.everything_printed?.should be_true
43
43
  end
44
44
  end
45
45
 
46
46
  describe "Text::Box#line_gap" do
47
- it "should equal the line gap of the font when using a single " +
47
+ it "should == the line gap of the font when using a single " +
48
48
  "font and font size" do
49
49
  create_pdf
50
50
  string = "Hello world, how are you?\nI'm fine, thank you."
51
51
  text_box = Prawn::Text::Box.new(string,
52
52
  :document => @pdf)
53
53
  text_box.render
54
- text_box.line_gap.should.be.close(@pdf.font.line_gap, 0.0001)
54
+ text_box.line_gap.should be_within(0.0001).of(@pdf.font.line_gap)
55
55
  end
56
56
  end
57
57
 
@@ -74,7 +74,7 @@ describe "Text::Box" do
74
74
  @pdf.text_direction(:rtl)
75
75
  @pdf.text_direction = :rtl
76
76
  @pdf.text_direction = :rtl
77
- @pdf.font("#{Prawn::BASEDIR}/data/fonts/gkai00mp.ttf", :size => 16) do
77
+ @pdf.font("#{Prawn::DATADIR}/fonts/gkai00mp.ttf", :size => 16) do
78
78
  @pdf.text "写个小"
79
79
  end
80
80
  text = PDF::Inspector::Text.analyze(@pdf.render)
@@ -128,7 +128,7 @@ describe "Text::Box#render with :align => :justify" do
128
128
  text_box = Prawn::Text::Box.new(string, options)
129
129
  text_box.render
130
130
  contents = PDF::Inspector::Text.analyze(@pdf.render)
131
- contents.word_spacing[0].should.be > 0
131
+ contents.word_spacing[0].should be > 0
132
132
  end
133
133
  it "should not justify the last line of a paragraph" do
134
134
  create_pdf
@@ -137,7 +137,7 @@ describe "Text::Box#render with :align => :justify" do
137
137
  text_box = Prawn::Text::Box.new(string, options)
138
138
  text_box.render
139
139
  contents = PDF::Inspector::Text.analyze(@pdf.render)
140
- contents.word_spacing.should.be.empty
140
+ contents.word_spacing.should be_empty
141
141
  end
142
142
  end
143
143
 
@@ -160,19 +160,19 @@ describe "Text::Box" do
160
160
  end
161
161
 
162
162
  describe "Text::Box#height without leading" do
163
- it "should equal the sum of the height of each line, " +
163
+ it "should == the sum of the height of each line, " +
164
164
  "not including the space below the last line" do
165
165
  create_pdf
166
166
  text = "Oh hai text rect.\nOh hai text rect."
167
167
  options = { :document => @pdf }
168
168
  text_box = Prawn::Text::Box.new(text, options)
169
169
  text_box.render
170
- text_box.height.should.be.close(@pdf.font.height * 2 - @pdf.font.line_gap, 0.001)
170
+ text_box.height.should be_within(0.001).of(@pdf.font.height * 2 - @pdf.font.line_gap)
171
171
  end
172
172
  end
173
173
 
174
174
  describe "Text::Box#height with leading" do
175
- it "should equal the sum of the height of each line plus leading, " +
175
+ it "should == the sum of the height of each line plus leading, " +
176
176
  "but not including the space below the last line" do
177
177
  create_pdf
178
178
  text = "Oh hai text rect.\nOh hai text rect."
@@ -180,7 +180,38 @@ describe "Text::Box#height with leading" do
180
180
  options = { :document => @pdf, :leading => leading }
181
181
  text_box = Prawn::Text::Box.new(text, options)
182
182
  text_box.render
183
- text_box.height.should.be.close((@pdf.font.height + leading) * 2 - @pdf.font.line_gap - leading, 0.001)
183
+ text_box.height.should be_within(0.001).of((@pdf.font.height + leading) * 2 - @pdf.font.line_gap - leading)
184
+ end
185
+ end
186
+
187
+ describe "Text::Box with :draw_text_callback" do
188
+ before(:each) { create_pdf }
189
+
190
+ it "hits the callback whenever text is drawn" do
191
+ draw_block = stub()
192
+ draw_block.expects(:kick).with("this text is long enough to")
193
+ draw_block.expects(:kick).with("span two lines")
194
+
195
+ @pdf.text_box "this text is long enough to span two lines",
196
+ :width => 150,
197
+ :draw_text_callback => lambda { |text, _| draw_block.kick(text) }
198
+ end
199
+
200
+ it "hits the callback once per fragment for :inline_format" do
201
+ draw_block = stub()
202
+ draw_block.expects(:kick).with("this text has ")
203
+ draw_block.expects(:kick).with("fancy")
204
+ draw_block.expects(:kick).with(" formatting")
205
+
206
+ @pdf.text_box "this text has <b>fancy</b> formatting",
207
+ :inline_format => true, :width => 500,
208
+ :draw_text_callback => lambda { |text, _| draw_block.kick(text) }
209
+ end
210
+
211
+ it "does not call #draw_text!" do
212
+ @pdf.expects(:draw_text!).never
213
+ @pdf.text_box "some text", :width => 500,
214
+ :draw_text_callback => lambda { |_, _| }
184
215
  end
185
216
  end
186
217
 
@@ -188,7 +219,7 @@ describe "Text::Box#valid_options" do
188
219
  it "should return an array" do
189
220
  create_pdf
190
221
  text_box = Prawn::Text::Box.new("", :document => @pdf)
191
- text_box.valid_options.should.be.kind_of(Array)
222
+ text_box.valid_options.should be_a_kind_of(Array)
192
223
  end
193
224
  end
194
225
 
@@ -211,7 +242,7 @@ describe "Text::Box#render" do
211
242
  text_box = Prawn::Text::Box.new(@text, @options)
212
243
  text_box.render
213
244
  text = PDF::Inspector::Text.analyze(@pdf.render)
214
- text.strings.should.not.be.empty
245
+ text.strings.should_not be_empty
215
246
  end
216
247
  it "should not draw a transformation matrix" do
217
248
  create_pdf
@@ -245,15 +276,15 @@ describe "Text::Box#render(:dry_run => true)" do
245
276
  text_box = Prawn::Text::Box.new(@text, @options)
246
277
  text_box.render(:dry_run => true)
247
278
  text = PDF::Inspector::Text.analyze(@pdf.render)
248
- text.strings.should.be.empty
279
+ text.strings.should be_empty
249
280
  end
250
- it "subsequent calls to render should not raise an ArgumentError exception" do
281
+ it "subsequent calls to render should_not raise_error an ArgumentError exception" do
251
282
  create_pdf
252
283
  @text = "™©"
253
284
  @options = { :document => @pdf }
254
285
  text_box = Prawn::Text::Box.new(@text, @options)
255
286
  text_box.render(:dry_run => true)
256
- lambda { text_box.render }.should.not.raise(
287
+ lambda { text_box.render }.should_not raise_error(
257
288
  Prawn::Errors::IncompatibleStringEncoding)
258
289
  end
259
290
  end
@@ -329,7 +360,7 @@ describe "Text::Box#render with :rotate option of 30)" do
329
360
  reduce_precision(@cos), 0, 0]
330
361
 
331
362
  text = PDF::Inspector::Text.analyze(@pdf.render)
332
- text.strings.should.not.be.empty
363
+ text.strings.should_not be_empty
333
364
  end
334
365
  end
335
366
  context ":rotate_around option of :upper_left" do
@@ -352,7 +383,7 @@ describe "Text::Box#render with :rotate option of 30)" do
352
383
  reduce_precision(@cos), 0, 0]
353
384
 
354
385
  text = PDF::Inspector::Text.analyze(@pdf.render)
355
- text.strings.should.not.be.empty
386
+ text.strings.should_not be_empty
356
387
  end
357
388
  end
358
389
  context "default :rotate_around" do
@@ -374,7 +405,7 @@ describe "Text::Box#render with :rotate option of 30)" do
374
405
  reduce_precision(@cos), 0, 0]
375
406
 
376
407
  text = PDF::Inspector::Text.analyze(@pdf.render)
377
- text.strings.should.not.be.empty
408
+ text.strings.should_not be_empty
378
409
  end
379
410
  end
380
411
  context ":rotate_around option of :upper_right" do
@@ -397,7 +428,7 @@ describe "Text::Box#render with :rotate option of 30)" do
397
428
  reduce_precision(@cos), 0, 0]
398
429
 
399
430
  text = PDF::Inspector::Text.analyze(@pdf.render)
400
- text.strings.should.not.be.empty
431
+ text.strings.should_not be_empty
401
432
  end
402
433
  end
403
434
  context ":rotate_around option of :lower_right" do
@@ -420,7 +451,7 @@ describe "Text::Box#render with :rotate option of 30)" do
420
451
  reduce_precision(@cos), 0, 0]
421
452
 
422
453
  text = PDF::Inspector::Text.analyze(@pdf.render)
423
- text.strings.should.not.be.empty
454
+ text.strings.should_not be_empty
424
455
  end
425
456
  end
426
457
  context ":rotate_around option of :lower_left" do
@@ -443,7 +474,7 @@ describe "Text::Box#render with :rotate option of 30)" do
443
474
  reduce_precision(@cos), 0, 0]
444
475
 
445
476
  text = PDF::Inspector::Text.analyze(@pdf.render)
446
- text.strings.should.not.be.empty
477
+ text.strings.should_not be_empty
447
478
  end
448
479
  end
449
480
  end
@@ -456,7 +487,7 @@ describe "Text::Box default height" do
456
487
  @text = "Oh hai\n" * 60
457
488
  text_box = Prawn::Text::Box.new(@text, :document => @pdf)
458
489
  text_box.render
459
- text_box.height.should.be.close(target_height, @pdf.font.height)
490
+ text_box.height.should be_within(@pdf.font.height).of(target_height)
460
491
  end
461
492
 
462
493
  it "should use the margin-box bottom if only in a stretchy bbox" do
@@ -465,7 +496,7 @@ describe "Text::Box default height" do
465
496
  @text = "Oh hai\n" * 60
466
497
  text_box = Prawn::Text::Box.new(@text, :document => @pdf)
467
498
  text_box.render
468
- text_box.height.should.be.close(target_height, @pdf.font.height)
499
+ text_box.height.should be_within(@pdf.font.height).of(target_height)
469
500
  end
470
501
  end
471
502
 
@@ -477,7 +508,7 @@ describe "Text::Box default height" do
477
508
  text_box = Prawn::Text::Box.new(@text, :document => @pdf,
478
509
  :height => 100, :overflow => :expand)
479
510
  text_box.render
480
- text_box.height.should.be.close(target_height, @pdf.font.height)
511
+ text_box.height.should be_within(@pdf.font.height).of(target_height)
481
512
  end
482
513
  end
483
514
 
@@ -488,7 +519,7 @@ describe "Text::Box default height" do
488
519
  @text = "Oh hai\n" * 60
489
520
  text_box = Prawn::Text::Box.new(@text, :document => @pdf)
490
521
  text_box.render
491
- text_box.height.should.be.close(200, @pdf.font.height)
522
+ text_box.height.should be_within(@pdf.font.height).of(200)
492
523
  end
493
524
  end
494
525
  end
@@ -535,7 +566,7 @@ describe "Text::Box with text than can fit in the box" do
535
566
  @options[:leading] = 40
536
567
  text_box = Prawn::Text::Box.new(@text, @options)
537
568
  text_box.render
538
- text_box.text.gsub("\n", " ").should.not == @text.strip
569
+ text_box.text.gsub("\n", " ").should_not == @text.strip
539
570
  end
540
571
  end
541
572
 
@@ -556,7 +587,7 @@ describe "Text::Box with text that fits exactly in the box" do
556
587
  expected_height = @options.delete(:height)
557
588
  text_box = Prawn::Text::Box.new(@text, @options)
558
589
  text_box.render
559
- text_box.height.should.be.close(expected_height, 0.0001)
590
+ text_box.height.should be_within(0.0001).of(expected_height)
560
591
  end
561
592
 
562
593
  it "should print everything" do
@@ -581,7 +612,7 @@ describe "Text::Box with text that fits exactly in the box" do
581
612
  @options[:height] += @options[:leading] * @interlines - 1
582
613
  text_box = Prawn::Text::Box.new(@text, @options)
583
614
  text_box.render
584
- text_box.text.should.not == @text
615
+ text_box.text.should_not == @text
585
616
  end
586
617
  end
587
618
 
@@ -601,7 +632,7 @@ describe "Text::Box with text that fits exactly in the box" do
601
632
  @options[:height] += @options[:leading] * @interlines - 1
602
633
  text_box = Prawn::Text::Box.new(@text, @options)
603
634
  text_box.render
604
- text_box.text.should.not == @text
635
+ text_box.text.should_not == @text
605
636
  end
606
637
  end
607
638
  end
@@ -617,7 +648,7 @@ describe "Text::Box printing UTF-8 string with higher bit characters" do
617
648
  :height => bounding_height,
618
649
  :document => @pdf
619
650
  }
620
- file = "#{Prawn::BASEDIR}/data/fonts/Action Man.dfont"
651
+ file = "#{Prawn::DATADIR}/fonts/Action Man.dfont"
621
652
  @pdf.font_families["Action Man"] = {
622
653
  :normal => { :file => file, :font => "ActionMan" },
623
654
  :italic => { :file => file, :font => "ActionMan-Italic" },
@@ -638,7 +669,7 @@ describe "Text::Box printing UTF-8 string with higher bit characters" do
638
669
  remaining_text = @text_box.render
639
670
  lambda {
640
671
  @pdf.text_box(remaining_text, :document => @pdf)
641
- }.should.not.raise(Prawn::Errors::IncompatibleStringEncoding)
672
+ }.should_not raise_error(Prawn::Errors::IncompatibleStringEncoding)
642
673
  end
643
674
  end
644
675
 
@@ -652,11 +683,11 @@ describe "Text::Box printing UTF-8 string with higher bit characters" do
652
683
  remaining_text = @text_box.render
653
684
  lambda {
654
685
  @pdf.text_box(remaining_text, :document => @pdf)
655
- }.should.raise(Prawn::Errors::IncompatibleStringEncoding)
686
+ }.should raise_error(Prawn::Errors::IncompatibleStringEncoding)
656
687
  lambda {
657
688
  @pdf.text_box(remaining_text, :skip_encoding => true,
658
689
  :document => @pdf)
659
- }.should.not.raise(Prawn::Errors::IncompatibleStringEncoding)
690
+ }.should_not raise_error(Prawn::Errors::IncompatibleStringEncoding)
660
691
  end
661
692
  end
662
693
  end
@@ -680,18 +711,18 @@ describe "Text::Box with more text than can fit in the box" do
680
711
  end
681
712
  it "should be truncated" do
682
713
  @text_box.render
683
- @text_box.text.gsub("\n", " ").should.not == @text.strip
714
+ @text_box.text.gsub("\n", " ").should_not == @text.strip
684
715
  end
685
716
  it "render should not return an empty string because some text remains unprinted" do
686
- @text_box.render.should.not.be.empty
717
+ @text_box.render.should_not be_empty
687
718
  end
688
719
  it "#height should be no taller than the specified height" do
689
720
  @text_box.render
690
- @text_box.height.should.be <= @bounding_height
721
+ @text_box.height.should be <= @bounding_height
691
722
  end
692
723
  it "#height should be within one font height of the specified height" do
693
724
  @text_box.render
694
- @bounding_height.should.be.close(@text_box.height, @pdf.font.height)
725
+ @bounding_height.should be_within(@pdf.font.height).of(@text_box.height)
695
726
  end
696
727
  context "with :rotate option" do
697
728
  it "unrendered text should be the same as when not rotated" do
@@ -800,7 +831,7 @@ describe "Text::Box with a solid block of Chinese characters" do
800
831
  :height => 162.0,
801
832
  :document => @pdf
802
833
  }
803
- @pdf.font "#{Prawn::BASEDIR}/data/fonts/gkai00mp.ttf"
834
+ @pdf.font "#{Prawn::DATADIR}/fonts/gkai00mp.ttf"
804
835
  @options[:overflow] = :truncate
805
836
  text_box = Prawn::Text::Box.new(@text, @options)
806
837
  text_box.render