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
@@ -0,0 +1,805 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'tempfile'
5
+
6
+ describe Prawn::Document do
7
+ let(:pdf) { create_pdf }
8
+
9
+ describe '.new' do
10
+ it 'does not modify its argument' do
11
+ options = { page_layout: :landscape }
12
+ described_class.new(options)
13
+ expect(options).to eq(page_layout: :landscape)
14
+ end
15
+ end
16
+
17
+ describe 'The cursor' do
18
+ it 'equals pdf.y - bounds.absolute_bottom' do
19
+ pdf = described_class.new
20
+ expect(pdf.cursor).to eq(pdf.bounds.top)
21
+
22
+ pdf.y = 300
23
+ expect(pdf.cursor).to eq(pdf.y - pdf.bounds.absolute_bottom)
24
+ end
25
+
26
+ it 'is able to move relative to the bottom margin' do
27
+ pdf = described_class.new
28
+ pdf.move_cursor_to(10)
29
+
30
+ expect(pdf.cursor).to eq(10)
31
+ expect(pdf.y).to eq(pdf.cursor + pdf.bounds.absolute_bottom)
32
+ end
33
+ end
34
+
35
+ describe 'when generating a document with a custom text formatter' do
36
+ it 'uses the provided text formatter' do
37
+ text_formatter =
38
+ Class.new do
39
+ def self.format(string)
40
+ [
41
+ {
42
+ text: string.gsub('Dr. Who?', "Just 'The Doctor'."),
43
+ styles: [],
44
+ color: nil,
45
+ link: nil,
46
+ anchor: nil,
47
+ local: nil,
48
+ font: nil,
49
+ size: nil,
50
+ character_spacing: nil
51
+ }
52
+ ]
53
+ end
54
+ end
55
+ pdf = described_class.new text_formatter: text_formatter
56
+ pdf.text 'Dr. Who?', inline_format: true
57
+ text = PDF::Inspector::Text.analyze(pdf.render)
58
+ expect(text.strings.first).to eq("Just 'The Doctor'.")
59
+ end
60
+ end
61
+
62
+ describe 'when generating a document from a subclass' do
63
+ it 'is an instance of the subclass' do
64
+ custom_document = Class.new(described_class)
65
+ custom_document.generate(Tempfile.new('generate_test').path) do |e|
66
+ expect(e.class).to eq(custom_document)
67
+ expect(e).to be_a_kind_of(described_class)
68
+ end
69
+ end
70
+
71
+ it 'retains any extensions found on Prawn::Document' do
72
+ mod1 = Module.new { attr_reader :test_extensions1 }
73
+ mod2 = Module.new { attr_reader :test_extensions2 }
74
+
75
+ described_class.extensions << mod1 << mod2
76
+
77
+ custom_document = Class.new(described_class)
78
+ expect(custom_document.extensions).to eq([mod1, mod2])
79
+
80
+ # remove the extensions we added to prawn document
81
+ described_class.extensions.delete(mod1)
82
+ described_class.extensions.delete(mod2)
83
+
84
+ expect(described_class.new.respond_to?(:test_extensions1)).to eq false
85
+ expect(described_class.new.respond_to?(:test_extensions2)).to eq false
86
+
87
+ # verify these still exist on custom class
88
+ expect(custom_document.extensions).to eq([mod1, mod2])
89
+
90
+ expect(custom_document.new.respond_to?(:test_extensions1)).to eq true
91
+ expect(custom_document.new.respond_to?(:test_extensions2)).to eq true
92
+ end
93
+ end
94
+
95
+ describe 'When creating multi-page documents' do
96
+ it 'initializes with a single page' do
97
+ page_counter = PDF::Inspector::Page.analyze(pdf.render)
98
+
99
+ expect(page_counter.pages.size).to eq(1)
100
+ expect(pdf.page_count).to eq(1)
101
+ end
102
+
103
+ it 'provides an accurate page_count' do
104
+ 3.times { pdf.start_new_page }
105
+ page_counter = PDF::Inspector::Page.analyze(pdf.render)
106
+
107
+ expect(page_counter.pages.size).to eq(4)
108
+ expect(pdf.page_count).to eq(4)
109
+ end
110
+ end
111
+
112
+ describe 'When beginning each new page' do
113
+ describe 'Background image feature' do
114
+ let(:filename) { "#{Prawn::DATADIR}/images/pigs.jpg" }
115
+ let(:pdf) { described_class.new(background: filename) }
116
+
117
+ it 'places a background image if it is in options block' do
118
+ output = pdf.render
119
+ images = PDF::Inspector::XObject.analyze(output)
120
+ # there should be 2 images in the page resources
121
+ expect(images.page_xobjects.first.size).to eq(1)
122
+ end
123
+
124
+ it 'places a background image interntally if it is in options block' do
125
+ expect(pdf.instance_variable_defined?(:@background)).to eq(true)
126
+ expect(pdf.instance_variable_get(:@background)).to eq(filename)
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '#float' do
132
+ it 'restores the original y-position' do
133
+ orig_y = pdf.y
134
+ pdf.float { pdf.text 'Foo' }
135
+ expect(pdf.y).to eq(orig_y)
136
+ end
137
+
138
+ it 'teleports across pages if necessary' do
139
+ pdf.float do
140
+ pdf.text 'Foo'
141
+ pdf.start_new_page
142
+ pdf.text 'Bar'
143
+ end
144
+ pdf.text 'Baz'
145
+
146
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
147
+ expect(pages.size).to eq(2)
148
+ expect(pages[0][:strings]).to eq(%w[Foo Baz])
149
+ expect(pages[1][:strings]).to eq(['Bar'])
150
+ end
151
+ end
152
+
153
+ describe '#start_new_page' do
154
+ it "doesn't modify the options hash" do
155
+ expect do
156
+ described_class.new.start_new_page({ margin: 0 }.freeze)
157
+ end.to_not raise_error
158
+ end
159
+
160
+ it 'sets individual page margins' do
161
+ doc = described_class.new
162
+ doc.start_new_page(top_margin: 42)
163
+ expect(doc.page.margins[:top]).to eq(42)
164
+ end
165
+ end
166
+
167
+ describe '#delete_page(index)' do
168
+ before do
169
+ pdf.text 'Page one'
170
+ pdf.start_new_page
171
+ pdf.text 'Page two'
172
+ pdf.start_new_page
173
+ pdf.text 'Page three'
174
+ end
175
+
176
+ it 'destroy a specific page of the document' do
177
+ pdf.delete_page(1)
178
+ expect(pdf.page_number).to eq(2)
179
+ text_analysis = PDF::Inspector::Text.analyze(pdf.render)
180
+ expect(text_analysis.strings).to eq(['Page one', 'Page three'])
181
+ end
182
+
183
+ it 'destroy the last page of the document' do
184
+ pdf.delete_page(-1)
185
+ expect(pdf.page_number).to eq(2)
186
+ text_analysis = PDF::Inspector::Text.analyze(pdf.render)
187
+ expect(text_analysis.strings).to eq(['Page one', 'Page two'])
188
+ end
189
+
190
+ context 'with an invalid index' do
191
+ let(:expected_content) { ['Page one', 'Page two', 'Page three'] }
192
+
193
+ it 'does not destroy an invalid positve index' do
194
+ pdf.delete_page(42)
195
+ expect(pdf.page_number).to eq(3)
196
+ text_analysis = PDF::Inspector::Text.analyze(pdf.render)
197
+ expect(text_analysis.strings).to eq(expected_content)
198
+ end
199
+
200
+ it 'does not destroy an invalid negative index' do
201
+ pdf.delete_page(-42)
202
+ expect(pdf.page_number).to eq(3)
203
+ text_analysis = PDF::Inspector::Text.analyze(pdf.render)
204
+ expect(text_analysis.strings).to eq(expected_content)
205
+ end
206
+ end
207
+ end
208
+
209
+ describe '#page_number' do
210
+ it 'is 1 for a new document' do
211
+ pdf = described_class.new
212
+ expect(pdf.page_number).to eq(1)
213
+ end
214
+
215
+ it 'is 0 for documents with no pages' do
216
+ pdf = described_class.new(skip_page_creation: true)
217
+ expect(pdf.page_number).to eq(0)
218
+ end
219
+
220
+ it 'is changed by go_to_page' do
221
+ pdf = described_class.new
222
+ 10.times { pdf.start_new_page }
223
+ pdf.go_to_page 3
224
+ expect(pdf.page_number).to eq(3)
225
+ end
226
+ end
227
+
228
+ describe 'on_page_create callback' do
229
+ it 'is delegated from Document to renderer' do
230
+ expect(pdf.respond_to?(:on_page_create)).to eq true
231
+ end
232
+
233
+ it 'is invoked with document' do
234
+ called_with = nil
235
+
236
+ pdf.renderer.on_page_create { |*args| called_with = args }
237
+
238
+ pdf.start_new_page
239
+
240
+ expect(called_with).to eq([pdf])
241
+ end
242
+
243
+ it 'is invoked for each new page' do
244
+ trigger = instance_double('trigger')
245
+ allow(trigger).to receive(:fire)
246
+
247
+ pdf.renderer.on_page_create { trigger.fire }
248
+
249
+ 5.times { pdf.start_new_page }
250
+
251
+ expect(trigger).to have_received(:fire).exactly(5).times
252
+ end
253
+
254
+ it 'is replaceable' do
255
+ trigger1 = instance_double('trigger 1')
256
+ allow(trigger1).to receive(:fire)
257
+
258
+ trigger2 = instance_double('trigger 2')
259
+ allow(trigger2).to receive(:fire)
260
+
261
+ pdf.renderer.on_page_create { trigger1.fire }
262
+
263
+ pdf.start_new_page
264
+
265
+ pdf.renderer.on_page_create { trigger2.fire }
266
+
267
+ pdf.start_new_page
268
+
269
+ expect(trigger1).to have_received(:fire).once
270
+ expect(trigger2).to have_received(:fire).once
271
+ end
272
+
273
+ it 'is clearable by calling on_page_create without a block' do
274
+ trigger = instance_double('trigger')
275
+ allow(trigger).to receive(:fire)
276
+
277
+ pdf.renderer.on_page_create { trigger.fire }
278
+
279
+ pdf.start_new_page
280
+
281
+ pdf.renderer.on_page_create
282
+
283
+ pdf.start_new_page
284
+
285
+ expect(trigger).to have_received(:fire).once
286
+ end
287
+ end
288
+
289
+ describe 'compression' do
290
+ it 'does not compress the page content stream if compression is disabled' do
291
+ pdf = described_class.new(compress: false)
292
+ allow(pdf.page.content.stream).to receive(:compress!).and_return(true)
293
+
294
+ pdf.text 'Hi There' * 20
295
+ pdf.render
296
+
297
+ expect(pdf.page.content.stream).to_not have_received(:compress!)
298
+ end
299
+
300
+ it 'compresses the page content stream if compression is enabled' do
301
+ pdf = described_class.new(compress: true)
302
+ allow(pdf.page.content.stream).to receive(:compress!).and_return(true)
303
+
304
+ pdf.text 'Hi There' * 20
305
+ pdf.render
306
+
307
+ expect(pdf.page.content.stream).to have_received(:compress!).once
308
+ end
309
+
310
+ it 'results in a smaller file size when compressed' do
311
+ doc_uncompressed = described_class.new
312
+ doc_compressed = described_class.new(compress: true)
313
+ [doc_compressed, doc_uncompressed].each do |pdf|
314
+ pdf.font "#{Prawn::DATADIR}/fonts/gkai00mp.ttf"
315
+ pdf.text '更可怕的是,同质化竞争对手可以按照URL中后面这个ID来遍历' * 10
316
+ end
317
+
318
+ expect(doc_compressed.render.length).to be <
319
+ doc_uncompressed.render.length
320
+ end
321
+ end
322
+
323
+ describe 'Dometadata' do
324
+ it 'outputs strings as UTF-16 with a byte order mark' do
325
+ pdf = described_class.new(info: { Author: 'Lóránt' })
326
+ expect(pdf.state.store.info.object).to match(
327
+ # UTF-16: BOM L ó r á n t
328
+ %r{/Author\s*<feff004c00f3007200e1006e0074>}i
329
+ )
330
+ end
331
+ end
332
+
333
+ describe 'When reopening pages' do
334
+ it 'modifies the content stream size' do
335
+ pdf =
336
+ described_class.new do
337
+ text 'Page 1'
338
+ start_new_page
339
+ text 'Page 2'
340
+ go_to_page 1
341
+ text 'More for page 1'
342
+ end
343
+
344
+ # Indirectly verify that the actual length does not match dictionary
345
+ # length. If it isn't, a MalformedPDFError will be raised
346
+ PDF::Inspector::Page.analyze(pdf.render)
347
+ end
348
+
349
+ it 'inserts pages after the current page when calling start_new_page' do
350
+ pdf = described_class.new
351
+ 3.times do |i|
352
+ pdf.text "Old page #{i + 1}"
353
+ pdf.start_new_page
354
+ end
355
+
356
+ pdf.go_to_page 1
357
+ pdf.start_new_page
358
+ pdf.text 'New page 2'
359
+
360
+ expect(pdf.page_number).to eq(2)
361
+
362
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
363
+ expect(pages.size).to eq(5)
364
+ expect(pages[1][:strings]).to eq(['New page 2'])
365
+ expect(pages[2][:strings]).to eq(['Old page 2'])
366
+ end
367
+
368
+ it 'restores the layout of the page' do
369
+ doc =
370
+ described_class.new do
371
+ start_new_page layout: :landscape
372
+ end
373
+
374
+ lsize = [doc.bounds.width, doc.bounds.height]
375
+
376
+ expect([doc.bounds.width, doc.bounds.height]).to eq lsize
377
+ doc.go_to_page 1
378
+ expect([doc.bounds.width, doc.bounds.height]).to eq lsize.reverse
379
+ end
380
+
381
+ it 'restores the margin box of the page' do
382
+ doc = described_class.new(margin: [100, 100])
383
+ page1_bounds = doc.bounds
384
+
385
+ doc.start_new_page(margin: [200, 200])
386
+
387
+ expect([doc.bounds.width, doc.bounds.height]).to eq(
388
+ [page1_bounds.width - 200, page1_bounds.height - 200]
389
+ )
390
+
391
+ doc.go_to_page(1)
392
+
393
+ expect(doc.bounds.width).to eq page1_bounds.width
394
+ expect(doc.bounds.height).to eq page1_bounds.height
395
+ end
396
+ end
397
+
398
+ describe 'When setting page size' do
399
+ it 'defaults to LETTER' do
400
+ pdf = described_class.new
401
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
402
+ expect(pages.first[:size]).to eq(PDF::Core::PageGeometry::SIZES['LETTER'])
403
+ end
404
+
405
+ (PDF::Core::PageGeometry::SIZES.keys - ['LETTER']).each do |k|
406
+ it "provides #{k} geometry" do
407
+ pdf = described_class.new(page_size: k)
408
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
409
+ expect(pages.first[:size]).to eq(PDF::Core::PageGeometry::SIZES[k])
410
+ end
411
+ end
412
+
413
+ it 'allows custom page size' do
414
+ pdf = described_class.new(page_size: [1920, 1080])
415
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
416
+ expect(pages.first[:size]).to eq([1920, 1080])
417
+ end
418
+
419
+ it 'retains page size by default when starting a new page' do
420
+ pdf = described_class.new(page_size: 'LEGAL')
421
+ pdf.start_new_page
422
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
423
+ pages.each do |page|
424
+ expect(page[:size]).to eq(PDF::Core::PageGeometry::SIZES['LEGAL'])
425
+ end
426
+ end
427
+ end
428
+
429
+ describe 'When setting page layout' do
430
+ it 'reverses coordinates for landscape' do
431
+ pdf = described_class.new(page_size: 'A4', page_layout: :landscape)
432
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
433
+ expect(pages.first[:size]).to eq(
434
+ PDF::Core::PageGeometry::SIZES['A4'].reverse
435
+ )
436
+ end
437
+
438
+ it 'retains page layout by default when starting a new page' do
439
+ pdf = described_class.new(page_layout: :landscape)
440
+ pdf.start_new_page(trace: true)
441
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
442
+ pages.each do |page|
443
+ expect(page[:size]).to eq(
444
+ PDF::Core::PageGeometry::SIZES['LETTER'].reverse
445
+ )
446
+ end
447
+ end
448
+
449
+ it 'swaps the bounds when starting a new page with different layout' do
450
+ pdf = described_class.new
451
+ size = [pdf.bounds.width, pdf.bounds.height]
452
+ pdf.start_new_page(layout: :landscape)
453
+ expect([pdf.bounds.width, pdf.bounds.height]).to eq(size.reverse)
454
+ end
455
+ end
456
+
457
+ describe '#mask' do
458
+ it 'allows transactional restoration of attributes' do
459
+ pdf = described_class.new
460
+ y = pdf.y
461
+ line_width = pdf.line_width
462
+ pdf.mask(:y, :line_width) do
463
+ pdf.y = y + 1
464
+ pdf.line_width = line_width + 1
465
+ expect(pdf.y).to_not eq(y)
466
+ expect(pdf.line_width).to_not eq(line_width)
467
+ end
468
+ expect(pdf.y).to eq(y)
469
+ expect(pdf.line_width).to eq(line_width)
470
+ end
471
+ end
472
+
473
+ describe '#render' do
474
+ it 'returns a 8 bit encoded string on a m17n aware VM' do
475
+ pdf = described_class.new(page_size: 'A4', page_layout: :landscape)
476
+ pdf.line [100, 100], [200, 200]
477
+ str = pdf.render
478
+ expect(str.encoding.to_s).to eq('ASCII-8BIT')
479
+ end
480
+
481
+ it 'triggers before_render callbacks just before rendering' do
482
+ pdf = described_class.new
483
+
484
+ # Verify the order: finalize -> fire callbacks -> render body
485
+ allow(pdf.renderer).to receive(:finalize_all_page_contents)
486
+ .and_call_original
487
+
488
+ trigger = instance_double('trigger')
489
+ allow(trigger).to receive(:fire)
490
+
491
+ pdf.renderer.before_render { trigger.fire }
492
+
493
+ allow(pdf.renderer).to receive(:render_body).and_call_original
494
+
495
+ pdf.render(StringIO.new)
496
+
497
+ expect(pdf.renderer).to have_received(:finalize_all_page_contents)
498
+ .ordered
499
+ expect(trigger).to have_received(:fire).ordered
500
+ expect(pdf.renderer).to have_received(:render_body).ordered
501
+ end
502
+
503
+ it 'is idempotent' do
504
+ pdf = described_class.new
505
+
506
+ contents = pdf.render
507
+ contents2 = pdf.render
508
+ expect(contents2).to eq(contents)
509
+ end
510
+ end
511
+
512
+ describe 'PDF file versions' do
513
+ it 'defaults to 1.3' do
514
+ pdf = described_class.new
515
+ str = pdf.render
516
+ expect(str[0, 8]).to eq('%PDF-1.3')
517
+ end
518
+
519
+ it 'allows the default to be changed' do
520
+ pdf = described_class.new
521
+ pdf.renderer.min_version(1.4)
522
+ str = pdf.render
523
+ expect(str[0, 8]).to eq('%PDF-1.4')
524
+ end
525
+ end
526
+
527
+ describe '#go_to_page' do
528
+ it 'has 2 pages after calling start_new_page and go_to_page' do
529
+ pdf = described_class.new
530
+ pdf.text 'James'
531
+ pdf.start_new_page
532
+ pdf.text 'Anthony'
533
+ pdf.go_to_page(1)
534
+ pdf.text 'Healy'
535
+
536
+ page_counter = PDF::Inspector::Page.analyze(pdf.render)
537
+ expect(page_counter.pages.size).to eq(2)
538
+ end
539
+
540
+ it 'correctlies add text to pages' do
541
+ pdf = described_class.new
542
+ pdf.text 'James'
543
+ pdf.start_new_page
544
+ pdf.text 'Anthony'
545
+ pdf.go_to_page(1)
546
+ pdf.text 'Healy'
547
+
548
+ text = PDF::Inspector::Text.analyze(pdf.render)
549
+
550
+ expect(text.strings.size).to eq(3)
551
+ expect(text.strings.include?('James')).to eq(true)
552
+ expect(text.strings.include?('Anthony')).to eq(true)
553
+ expect(text.strings.include?('Healy')).to eq(true)
554
+ end
555
+ end
556
+
557
+ describe 'content stream characteristics' do
558
+ it 'has 1 single content stream for a single page PDF' do
559
+ pdf = described_class.new
560
+ pdf.text 'James'
561
+ output = StringIO.new(pdf.render)
562
+ hash = PDF::Reader::ObjectHash.new(output)
563
+
564
+ streams = hash.values.select { |obj| obj.is_a?(PDF::Reader::Stream) }
565
+
566
+ expect(streams.size).to eq(1)
567
+ end
568
+
569
+ it 'has 1 single content stream for a single page PDF, even if go_to_page '\
570
+ 'is used' do
571
+ pdf = described_class.new
572
+ pdf.text 'James'
573
+ pdf.go_to_page(1)
574
+ pdf.text 'Healy'
575
+ output = StringIO.new(pdf.render)
576
+ hash = PDF::Reader::ObjectHash.new(output)
577
+
578
+ streams = hash.values.select { |obj| obj.is_a?(PDF::Reader::Stream) }
579
+
580
+ expect(streams.size).to eq(1)
581
+ end
582
+ end
583
+
584
+ describe '#number_pages' do
585
+ let(:pdf) { described_class.new(skip_page_creation: true) }
586
+
587
+ it "replaces the '<page>' string with the proper page number" do
588
+ pdf.start_new_page
589
+ allow(pdf).to receive(:text_box)
590
+ pdf.number_pages '<page>, test', page_filter: :all
591
+ expect(pdf).to have_received(:text_box).with('1, test', height: 50)
592
+ end
593
+
594
+ it "replaces the '<total>' string with the total page count" do
595
+ pdf.start_new_page
596
+ allow(pdf).to receive(:text_box)
597
+ pdf.number_pages 'test, <total>', page_filter: :all
598
+ expect(pdf).to have_received(:text_box).with('test, 1', height: 50)
599
+ end
600
+
601
+ it 'must print each page if given the :all page_filter' do
602
+ 10.times { pdf.start_new_page }
603
+ allow(pdf).to receive(:text_box)
604
+ pdf.number_pages 'test', page_filter: :all
605
+ expect(pdf).to have_received(:text_box).exactly(10).times
606
+ end
607
+
608
+ it 'must print each page if no :page_filter is specified' do
609
+ 10.times { pdf.start_new_page }
610
+ allow(pdf).to receive(:text_box)
611
+ pdf.number_pages 'test'
612
+ expect(pdf).to have_received(:text_box).exactly(10).times
613
+ end
614
+
615
+ it 'must not print the page number if given a nil filter' do
616
+ 10.times { pdf.start_new_page }
617
+ allow(pdf).to receive(:text_box)
618
+ pdf.number_pages 'test', page_filter: nil
619
+ expect(pdf).to_not have_received(:text_box)
620
+ end
621
+
622
+ context 'with start_count_at option' do
623
+ [1, 2].each do |startat|
624
+ context "equal to #{startat}" do
625
+ it 'increments the pages' do
626
+ 2.times { pdf.start_new_page }
627
+ options = { page_filter: :all, start_count_at: startat }
628
+ allow(pdf).to receive(:text_box)
629
+ pdf.number_pages '<page> <total>', options
630
+
631
+ expect(pdf).to have_received(:text_box)
632
+ .with("#{startat} 2", height: 50)
633
+ expect(pdf).to have_received(:text_box)
634
+ .with("#{startat + 1} 2", height: 50)
635
+ end
636
+ end
637
+ end
638
+
639
+ [0, nil].each do |val|
640
+ context "equal to #{val}" do
641
+ it 'defaults to start at page 1' do
642
+ 3.times { pdf.start_new_page }
643
+ options = { page_filter: :all, start_count_at: val }
644
+ allow(pdf).to receive(:text_box)
645
+ pdf.number_pages '<page> <total>', options
646
+
647
+ expect(pdf).to have_received(:text_box).with('1 3', height: 50)
648
+ expect(pdf).to have_received(:text_box).with('2 3', height: 50)
649
+ expect(pdf).to have_received(:text_box).with('3 3', height: 50)
650
+ end
651
+ end
652
+ end
653
+ end
654
+
655
+ context 'with total_pages option' do
656
+ it 'allows the total pages count to be overridden' do
657
+ 2.times { pdf.start_new_page }
658
+ allow(pdf).to receive(:text_box)
659
+ pdf.number_pages '<page> <total>', page_filter: :all, total_pages: 10
660
+
661
+ expect(pdf).to have_received(:text_box).with('1 10', height: 50)
662
+ expect(pdf).to have_received(:text_box).with('2 10', height: 50)
663
+ end
664
+ end
665
+
666
+ context 'with special page filter' do
667
+ describe 'such as :odd' do
668
+ it 'increments the pages' do
669
+ 3.times { pdf.start_new_page }
670
+ allow(pdf).to receive(:text_box)
671
+ pdf.number_pages '<page> <total>', page_filter: :odd
672
+
673
+ expect(pdf).to have_received(:text_box).with('1 3', height: 50)
674
+ expect(pdf).to have_received(:text_box).with('3 3', height: 50)
675
+ expect(pdf).to_not have_received(:text_box).with('2 3', height: 50)
676
+ end
677
+ end
678
+
679
+ describe 'missing' do
680
+ it 'does not print any page numbers' do
681
+ 3.times { pdf.start_new_page }
682
+ allow(pdf).to receive(:text_box)
683
+ pdf.number_pages '<page> <total>', page_filter: nil
684
+
685
+ expect(pdf).to_not have_received(:text_box)
686
+ end
687
+ end
688
+ end
689
+
690
+ context 'with both a special page filter and a start_count_at parameter' do
691
+ describe 'such as :odd and 7' do
692
+ it 'increments the pages' do
693
+ 3.times { pdf.start_new_page }
694
+ allow(pdf).to receive(:text_box)
695
+ pdf.number_pages '<page> <total>',
696
+ page_filter: :odd,
697
+ start_count_at: 5
698
+
699
+ expect(pdf).to_not have_received(:text_box).with('1 3', height: 50)
700
+ # page 1
701
+ expect(pdf).to have_received(:text_box).with('5 3', height: 50)
702
+
703
+ # page 2
704
+ expect(pdf).to_not have_received(:text_box).with('6 3', height: 50)
705
+
706
+ # page 3
707
+ expect(pdf).to have_received(:text_box).with('7 3', height: 50)
708
+ end
709
+ end
710
+
711
+ context 'with some crazy proc and 2' do
712
+ it 'increments the pages' do
713
+ 6.times { pdf.start_new_page }
714
+ options = {
715
+ page_filter: ->(p) { p != 2 && p != 5 },
716
+ start_count_at: 4
717
+ }
718
+ allow(pdf).to receive(:text_box)
719
+ pdf.number_pages '<page> <total>', options
720
+
721
+ # page 1
722
+ expect(pdf).to have_received(:text_box).with('4 6', height: 50)
723
+
724
+ # page 2
725
+ expect(pdf).to_not have_received(:text_box).with('5 6', height: 50)
726
+
727
+ # page 3
728
+ expect(pdf).to have_received(:text_box).with('6 6', height: 50)
729
+
730
+ # page 4
731
+ expect(pdf).to have_received(:text_box).with('7 6', height: 50)
732
+
733
+ # page 5
734
+ expect(pdf).to_not have_received(:text_box).with('8 6', height: 50)
735
+
736
+ # page 6
737
+ expect(pdf).to have_received(:text_box).with('9 6', height: 50)
738
+ end
739
+ end
740
+ end
741
+
742
+ describe 'height option' do
743
+ before do
744
+ pdf.start_new_page
745
+ end
746
+
747
+ it 'with 10 height' do
748
+ allow(pdf).to receive(:text_box)
749
+ pdf.number_pages '<page> <total>', height: 10
750
+ expect(pdf).to have_received(:text_box).with('1 1', height: 10)
751
+ end
752
+
753
+ it 'with nil height' do
754
+ allow(pdf).to receive(:text_box)
755
+ pdf.number_pages '<page> <total>', height: nil
756
+ expect(pdf).to have_received(:text_box).with('1 1', height: nil)
757
+ end
758
+
759
+ it 'with no height' do
760
+ allow(pdf).to receive(:text_box)
761
+ pdf.number_pages '<page> <total>'
762
+ expect(pdf).to have_received(:text_box).with('1 1', height: 50)
763
+ end
764
+ end
765
+ end
766
+
767
+ describe '#page_match?' do
768
+ let(:pdf) do
769
+ described_class.new(skip_page_creation: true) do |pdf|
770
+ 10.times { pdf.start_new_page }
771
+ end
772
+ end
773
+
774
+ it 'returns nil given no filter' do
775
+ expect(pdf).to_not be_page_match(:nil, 1)
776
+ end
777
+
778
+ it 'must provide an :all filter' do
779
+ expect((1..pdf.page_count).all? { |i| pdf.page_match?(:all, i) })
780
+ .to eq true
781
+ end
782
+
783
+ it 'must provide an :odd filter' do
784
+ odd, even = (1..pdf.page_count).partition(&:odd?)
785
+ expect(odd.all? { |i| pdf.page_match?(:odd, i) }).to eq true
786
+ expect(even).to_not(be_any { |i| pdf.page_match?(:odd, i) })
787
+ end
788
+
789
+ it 'must be able to filter by an array of page numbers' do
790
+ fltr = [1, 2, 7]
791
+ expect((1..10).select { |i| pdf.page_match?(fltr, i) }).to eq([1, 2, 7])
792
+ end
793
+
794
+ it 'must be able to filter by a range of page numbers' do
795
+ fltr = 2..4
796
+ expect((1..10).select { |i| pdf.page_match?(fltr, i) }).to eq([2, 3, 4])
797
+ end
798
+
799
+ it 'must be able to filter by an arbitrary proc' do
800
+ fltr = ->(x) { x == 1 || (x % 3).zero? }
801
+ expect((1..10).select { |i| pdf.page_match?(fltr, i) })
802
+ .to eq([1, 3, 6, 9])
803
+ end
804
+ end
805
+ end