prawn 2.1.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 (280) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/GPLv2 +20 -21
  5. data/Gemfile +3 -9
  6. data/Rakefile +9 -41
  7. data/lib/prawn.rb +37 -49
  8. data/lib/prawn/document.rb +193 -141
  9. data/lib/prawn/document/bounding_box.rb +50 -30
  10. data/lib/prawn/document/column_box.rb +7 -7
  11. data/lib/prawn/document/internals.rb +8 -6
  12. data/lib/prawn/document/span.rb +22 -16
  13. data/lib/prawn/encoding.rb +69 -68
  14. data/lib/prawn/errors.rb +12 -7
  15. data/lib/prawn/font.rb +104 -69
  16. data/lib/prawn/font_metric_cache.rb +20 -13
  17. data/lib/prawn/{font → fonts}/afm.rb +108 -72
  18. data/lib/prawn/{font → fonts}/dfont.rb +5 -11
  19. data/lib/prawn/fonts/otf.rb +11 -0
  20. data/lib/prawn/fonts/ttc.rb +36 -0
  21. data/lib/prawn/{font → fonts}/ttf.rb +126 -81
  22. data/lib/prawn/graphics.rb +119 -81
  23. data/lib/prawn/graphics/blend_mode.rb +9 -8
  24. data/lib/prawn/graphics/cap_style.rb +3 -3
  25. data/lib/prawn/graphics/color.rb +43 -39
  26. data/lib/prawn/graphics/dash.rb +23 -11
  27. data/lib/prawn/graphics/join_style.rb +9 -3
  28. data/lib/prawn/graphics/patterns.rb +204 -102
  29. data/lib/prawn/graphics/transformation.rb +15 -9
  30. data/lib/prawn/graphics/transparency.rb +17 -13
  31. data/lib/prawn/grid.rb +84 -48
  32. data/lib/prawn/image_handler.rb +5 -5
  33. data/lib/prawn/images.rb +60 -49
  34. data/lib/prawn/images/image.rb +2 -1
  35. data/lib/prawn/images/jpg.rb +31 -22
  36. data/lib/prawn/images/png.rb +67 -63
  37. data/lib/prawn/measurement_extensions.rb +10 -9
  38. data/lib/prawn/measurements.rb +19 -15
  39. data/lib/prawn/outline.rb +98 -77
  40. data/lib/prawn/repeater.rb +15 -11
  41. data/lib/prawn/security.rb +93 -70
  42. data/lib/prawn/security/arcfour.rb +2 -2
  43. data/lib/prawn/soft_mask.rb +26 -26
  44. data/lib/prawn/stamp.rb +20 -13
  45. data/lib/prawn/text.rb +76 -60
  46. data/lib/prawn/text/box.rb +18 -14
  47. data/lib/prawn/text/formatted.rb +5 -5
  48. data/lib/prawn/text/formatted/arranger.rb +80 -40
  49. data/lib/prawn/text/formatted/box.rb +140 -101
  50. data/lib/prawn/text/formatted/fragment.rb +11 -14
  51. data/lib/prawn/text/formatted/line_wrap.rb +128 -67
  52. data/lib/prawn/text/formatted/parser.rb +147 -123
  53. data/lib/prawn/text/formatted/wrap.rb +48 -32
  54. data/lib/prawn/transformation_stack.rb +7 -5
  55. data/lib/prawn/utilities.rb +7 -22
  56. data/lib/prawn/version.rb +2 -2
  57. data/lib/prawn/view.rb +17 -7
  58. data/manual/basic_concepts/adding_pages.rb +6 -7
  59. data/manual/basic_concepts/basic_concepts.rb +31 -22
  60. data/manual/basic_concepts/creation.rb +10 -11
  61. data/manual/basic_concepts/cursor.rb +4 -5
  62. data/manual/basic_concepts/measurement.rb +7 -8
  63. data/manual/basic_concepts/origin.rb +5 -6
  64. data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
  65. data/manual/basic_concepts/view.rb +22 -16
  66. data/manual/bounding_box/bounding_box.rb +29 -24
  67. data/manual/bounding_box/bounds.rb +11 -12
  68. data/manual/bounding_box/canvas.rb +7 -8
  69. data/manual/bounding_box/creation.rb +6 -7
  70. data/manual/bounding_box/indentation.rb +14 -15
  71. data/manual/bounding_box/nesting.rb +25 -18
  72. data/manual/bounding_box/russian_boxes.rb +14 -13
  73. data/manual/bounding_box/stretchy.rb +12 -13
  74. data/manual/contents.rb +28 -22
  75. data/manual/cover.rb +33 -28
  76. data/manual/document_and_page_options/background.rb +15 -13
  77. data/manual/document_and_page_options/document_and_page_options.rb +25 -20
  78. data/manual/document_and_page_options/metadata.rb +18 -16
  79. data/manual/document_and_page_options/page_margins.rb +18 -20
  80. data/manual/document_and_page_options/page_size.rb +13 -12
  81. data/manual/document_and_page_options/print_scaling.rb +18 -15
  82. data/manual/example_helper.rb +5 -4
  83. data/manual/graphics/blend_mode.rb +12 -9
  84. data/manual/graphics/circle_and_ellipse.rb +4 -5
  85. data/manual/graphics/color.rb +7 -9
  86. data/manual/graphics/common_lines.rb +7 -8
  87. data/manual/graphics/fill_and_stroke.rb +5 -6
  88. data/manual/graphics/fill_rules.rb +10 -10
  89. data/manual/graphics/gradients.rb +27 -21
  90. data/manual/graphics/graphics.rb +48 -40
  91. data/manual/graphics/helper.rb +19 -9
  92. data/manual/graphics/line_width.rb +8 -7
  93. data/manual/graphics/lines_and_curves.rb +7 -8
  94. data/manual/graphics/polygon.rb +6 -8
  95. data/manual/graphics/rectangle.rb +4 -5
  96. data/manual/graphics/rotate.rb +6 -7
  97. data/manual/graphics/scale.rb +14 -15
  98. data/manual/graphics/soft_masks.rb +3 -4
  99. data/manual/graphics/stroke_cap.rb +6 -7
  100. data/manual/graphics/stroke_dash.rb +15 -16
  101. data/manual/graphics/stroke_join.rb +5 -6
  102. data/manual/graphics/translate.rb +10 -10
  103. data/manual/graphics/transparency.rb +7 -8
  104. data/manual/how_to_read_this_manual.rb +6 -6
  105. data/manual/images/absolute_position.rb +6 -7
  106. data/manual/images/fit.rb +7 -8
  107. data/manual/images/horizontal.rb +10 -11
  108. data/manual/images/images.rb +28 -24
  109. data/manual/images/plain_image.rb +5 -6
  110. data/manual/images/scale.rb +9 -10
  111. data/manual/images/vertical.rb +16 -14
  112. data/manual/images/width_and_height.rb +10 -11
  113. data/manual/layout/boxes.rb +5 -6
  114. data/manual/layout/content.rb +7 -8
  115. data/manual/layout/layout.rb +18 -16
  116. data/manual/layout/simple_grid.rb +6 -7
  117. data/manual/outline/add_subsection_to.rb +20 -21
  118. data/manual/outline/insert_section_after.rb +15 -16
  119. data/manual/outline/outline.rb +21 -17
  120. data/manual/outline/sections_and_pages.rb +17 -18
  121. data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
  122. data/manual/repeatable_content/page_numbering.rb +17 -16
  123. data/manual/repeatable_content/repeatable_content.rb +25 -19
  124. data/manual/repeatable_content/repeater.rb +14 -15
  125. data/manual/repeatable_content/stamp.rb +14 -15
  126. data/manual/security/encryption.rb +9 -10
  127. data/manual/security/permissions.rb +21 -14
  128. data/manual/security/security.rb +19 -16
  129. data/manual/table.rb +3 -3
  130. data/manual/text/alignment.rb +16 -17
  131. data/manual/text/color.rb +12 -11
  132. data/manual/text/column_box.rb +9 -10
  133. data/manual/text/fallback_fonts.rb +25 -21
  134. data/manual/text/font.rb +11 -12
  135. data/manual/text/font_size.rb +13 -14
  136. data/manual/text/font_style.rb +10 -8
  137. data/manual/text/formatted_callbacks.rb +33 -24
  138. data/manual/text/formatted_text.rb +36 -25
  139. data/manual/text/free_flowing_text.rb +22 -23
  140. data/manual/text/inline.rb +18 -19
  141. data/manual/text/kerning_and_character_spacing.rb +14 -15
  142. data/manual/text/leading.rb +7 -8
  143. data/manual/text/line_wrapping.rb +37 -18
  144. data/manual/text/paragraph_indentation.rb +12 -14
  145. data/manual/text/positioned_text.rb +15 -16
  146. data/manual/text/registering_families.rb +20 -21
  147. data/manual/text/rendering_and_color.rb +9 -10
  148. data/manual/text/right_to_left_text.rb +26 -19
  149. data/manual/text/rotation.rb +33 -23
  150. data/manual/text/single_usage.rb +8 -9
  151. data/manual/text/text.rb +57 -52
  152. data/manual/text/text_box_excess.rb +20 -17
  153. data/manual/text/text_box_extensions.rb +18 -15
  154. data/manual/text/text_box_overflow.rb +20 -19
  155. data/manual/text/utf8.rb +11 -12
  156. data/manual/text/win_ansi_charset.rb +27 -25
  157. data/prawn.gemspec +41 -34
  158. data/spec/extensions/encoding_helpers.rb +3 -3
  159. data/spec/prawn/document/bounding_box_spec.rb +550 -0
  160. data/spec/prawn/document/column_box_spec.rb +75 -0
  161. data/spec/prawn/document/security_spec.rb +176 -0
  162. data/spec/prawn/document_annotations_spec.rb +76 -0
  163. data/spec/prawn/document_destinations_spec.rb +15 -0
  164. data/spec/prawn/document_grid_spec.rb +99 -0
  165. data/spec/prawn/document_reference_spec.rb +27 -0
  166. data/spec/prawn/document_span_spec.rb +44 -0
  167. data/spec/prawn/document_spec.rb +805 -0
  168. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  169. data/spec/prawn/font_spec.rb +544 -0
  170. data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
  171. data/spec/prawn/graphics/transparency_spec.rb +81 -0
  172. data/spec/prawn/graphics_spec.rb +872 -0
  173. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  174. data/spec/{image_handler_spec.rb → prawn/image_handler_spec.rb} +14 -14
  175. data/spec/prawn/images/jpg_spec.rb +20 -0
  176. data/spec/prawn/images/png_spec.rb +283 -0
  177. data/spec/prawn/images_spec.rb +229 -0
  178. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  179. data/spec/prawn/outline_spec.rb +512 -0
  180. data/spec/prawn/repeater_spec.rb +166 -0
  181. data/spec/prawn/soft_mask_spec.rb +74 -0
  182. data/spec/prawn/stamp_spec.rb +173 -0
  183. data/spec/prawn/text/box_spec.rb +1110 -0
  184. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  185. data/spec/prawn/text/formatted/box_spec.rb +849 -0
  186. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  187. data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
  188. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  189. data/spec/prawn/text_draw_text_spec.rb +150 -0
  190. data/spec/prawn/text_rendering_mode_spec.rb +48 -0
  191. data/spec/prawn/text_spacing_spec.rb +95 -0
  192. data/spec/prawn/text_spec.rb +603 -0
  193. data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
  194. data/spec/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +22 -19
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +18 -19
  198. metadata +102 -222
  199. metadata.gz.sig +0 -0
  200. data/data/images/16bit.alpha +0 -0
  201. data/data/images/16bit.color +0 -0
  202. data/data/images/16bit.png +0 -0
  203. data/data/images/arrow.png +0 -0
  204. data/data/images/arrow2.png +0 -0
  205. data/data/images/blend_modes_bottom_layer.jpg +0 -0
  206. data/data/images/blend_modes_top_layer.jpg +0 -0
  207. data/data/images/dice.alpha +0 -0
  208. data/data/images/dice.color +0 -0
  209. data/data/images/dice.png +0 -0
  210. data/data/images/dice_interlaced.png +0 -0
  211. data/data/images/fractal.jpg +0 -0
  212. data/data/images/indexed_color.dat +0 -0
  213. data/data/images/indexed_color.png +0 -0
  214. data/data/images/indexed_transparency.png +0 -0
  215. data/data/images/indexed_transparency_alpha.dat +0 -0
  216. data/data/images/indexed_transparency_color.dat +0 -0
  217. data/data/images/letterhead.jpg +0 -0
  218. data/data/images/license.md +0 -8
  219. data/data/images/page_white_text.alpha +0 -0
  220. data/data/images/page_white_text.color +0 -0
  221. data/data/images/page_white_text.png +0 -0
  222. data/data/images/pigs.jpg +0 -0
  223. data/data/images/prawn.png +0 -0
  224. data/data/images/ruport.png +0 -0
  225. data/data/images/ruport_data.dat +0 -0
  226. data/data/images/ruport_transparent.png +0 -0
  227. data/data/images/ruport_type0.png +0 -0
  228. data/data/images/stef.jpg +0 -0
  229. data/data/images/tru256.bmp +0 -0
  230. data/data/images/web-links.dat +0 -1
  231. data/data/images/web-links.png +0 -0
  232. data/data/pdfs/complex_template.pdf +0 -0
  233. data/data/pdfs/contains_ttf_font.pdf +0 -0
  234. data/data/pdfs/encrypted.pdf +0 -0
  235. data/data/pdfs/form.pdf +1 -819
  236. data/data/pdfs/hexagon.pdf +0 -61
  237. data/data/pdfs/indirect_reference.pdf +0 -86
  238. data/data/pdfs/multipage_template.pdf +0 -127
  239. data/data/pdfs/nested_pages.pdf +0 -118
  240. data/data/pdfs/page_without_mediabox.pdf +0 -193
  241. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  242. data/data/pdfs/two_hexagons.pdf +0 -90
  243. data/data/pdfs/version_1_6.pdf +0 -61
  244. data/data/shift_jis_text.txt +0 -1
  245. data/spec/acceptance/png_spec.rb +0 -35
  246. data/spec/annotations_spec.rb +0 -67
  247. data/spec/blend_mode_spec.rb +0 -71
  248. data/spec/bounding_box_spec.rb +0 -501
  249. data/spec/column_box_spec.rb +0 -59
  250. data/spec/destinations_spec.rb +0 -13
  251. data/spec/document_spec.rb +0 -738
  252. data/spec/font_metric_cache_spec.rb +0 -52
  253. data/spec/font_spec.rb +0 -475
  254. data/spec/formatted_text_arranger_spec.rb +0 -452
  255. data/spec/formatted_text_box_spec.rb +0 -716
  256. data/spec/formatted_text_fragment_spec.rb +0 -299
  257. data/spec/graphics_spec.rb +0 -705
  258. data/spec/grid_spec.rb +0 -95
  259. data/spec/images_spec.rb +0 -167
  260. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  261. data/spec/jpg_spec.rb +0 -23
  262. data/spec/line_wrap_spec.rb +0 -366
  263. data/spec/measurement_units_spec.rb +0 -22
  264. data/spec/outline_spec.rb +0 -409
  265. data/spec/png_spec.rb +0 -257
  266. data/spec/reference_spec.rb +0 -25
  267. data/spec/repeater_spec.rb +0 -154
  268. data/spec/security_spec.rb +0 -151
  269. data/spec/soft_mask_spec.rb +0 -78
  270. data/spec/span_spec.rb +0 -43
  271. data/spec/stamp_spec.rb +0 -179
  272. data/spec/stroke_styles_spec.rb +0 -208
  273. data/spec/text_at_spec.rb +0 -142
  274. data/spec/text_box_spec.rb +0 -1042
  275. data/spec/text_rendering_mode_spec.rb +0 -45
  276. data/spec/text_spacing_spec.rb +0 -93
  277. data/spec/text_spec.rb +0 -543
  278. data/spec/text_with_inline_formatting_spec.rb +0 -35
  279. data/spec/transparency_spec.rb +0 -91
  280. data/spec/view_spec.rb +0 -42
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # We've already seen one way of using text boxes with the <code>text_box</code>
4
4
  # method. Turns out this method is just a convenience for using the
5
5
  # <code>Prawn::Text::Box</code> class as it creates a new object and call
@@ -9,9 +9,8 @@
9
9
  # effect when we use the <code>text_box</code> method. To add an extension all
10
10
  # we need to do is append the <code>Prawn::Text::Box.extensions</code> array
11
11
  # with a module.
12
- #
13
- require File.expand_path(File.join(File.dirname(__FILE__),
14
- %w[.. example_helper]))
12
+
13
+ require '../example_helper'
15
14
 
16
15
  filename = File.basename(__FILE__).gsub('.rb', '.pdf')
17
16
  Prawn::ManualBuilder::Example.generate(filename) do
@@ -22,22 +21,26 @@ Prawn::ManualBuilder::Example.generate(filename) do
22
21
  end
23
22
 
24
23
  y_position = cursor - 10
25
- width = 100
26
- height = 100
24
+ width = 100
25
+ height = 100
27
26
 
28
27
  Prawn::Text::Box.extensions << TriangleBox
29
28
  stroke_rectangle([0, y_position], width, height)
30
- text_box("A" * 100,
31
- :at => [0, y_position],
32
- :width => width,
33
- :height => height)
29
+ text_box(
30
+ 'A' * 100,
31
+ at: [0, y_position],
32
+ width: width,
33
+ height: height
34
+ )
34
35
 
35
36
  Prawn::Text::Formatted::Box.extensions << TriangleBox
36
37
  stroke_rectangle([200, y_position], width, height)
37
- formatted_text_box([:text => "A" * 100, :color => "009900"],
38
- :at => [200, y_position],
39
- :width => width,
40
- :height => height)
38
+ formatted_text_box(
39
+ [{ text: 'A' * 100, color: '009900' }],
40
+ at: [200, y_position],
41
+ width: width,
42
+ height: height
43
+ )
41
44
 
42
45
  # Here we clear the extensions array
43
46
  Prawn::Text::Box.extensions.clear
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # The <code>text_box</code> method accepts both <code>:width</code> and
4
4
  # <code>:height</code> options. So what happens if the text doesn't fit the box?
5
5
  #
@@ -15,36 +15,37 @@
15
15
  # If the <code>:disable_wrap_by_char</code> is set to <code>true</code>
16
16
  # then any text wrapping done while using the <code>:shrink_to_fit</code>
17
17
  # mode will not break up the middle of words.
18
- #
19
- require File.expand_path(File.join(File.dirname(__FILE__),
20
- %w[.. example_helper]))
18
+
19
+ require_relative '../example_helper'
21
20
 
22
21
  filename = File.basename(__FILE__).gsub('.rb', '.pdf')
23
22
  Prawn::ManualBuilder::Example.generate(filename) do
24
- string = "This is the sample text used for the text boxes. See how it " +
25
- "behave with the various overflow options used."
23
+ string = 'This is the sample text used for the text boxes. See how it ' \
24
+ 'behave with the various overflow options used.'
26
25
 
27
26
  text string
28
27
 
29
28
  y_position = cursor - 20
30
- [:truncate, :expand, :shrink_to_fit].each_with_index do |mode, i|
31
- text_box string, :at => [i * 150, y_position],
32
- :width => 100,
33
- :height => 50,
34
- :overflow => mode
29
+ %i[truncate expand shrink_to_fit].each_with_index do |mode, i|
30
+ text_box string,
31
+ at: [i * 150, y_position],
32
+ width: 100,
33
+ height: 50,
34
+ overflow: mode
35
35
  end
36
36
 
37
- string = "If the box is too small for the text, :shrink_to_fit " +
38
- "can render the text in a really small font size."
37
+ string = 'If the box is too small for the text, :shrink_to_fit ' \
38
+ 'can render the text in a really small font size.'
39
39
 
40
40
  move_down 120
41
41
  text string
42
42
  y_position = cursor - 20
43
43
  [nil, 8, 10, 12].each_with_index do |value, index|
44
- text_box string, :at => [index * 150, y_position],
45
- :width => 50,
46
- :height => 50,
47
- :overflow => :shrink_to_fit,
48
- :min_font_size => value
44
+ text_box string,
45
+ at: [index * 150, y_position],
46
+ width: 50,
47
+ height: 50,
48
+ overflow: :shrink_to_fit,
49
+ min_font_size: value
49
50
  end
50
51
  end
@@ -1,28 +1,27 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # Multilingualization isn't much of a problem on Prawn as its default encoding
4
4
  # is UTF-8. The only thing you need to worry about is if the font support the
5
5
  # glyphs of your language.
6
- #
7
- require File.expand_path(File.join(File.dirname(__FILE__),
8
- %w[.. example_helper]))
6
+
7
+ require_relative '../example_helper'
9
8
 
10
9
  filename = File.basename(__FILE__).gsub('.rb', '.pdf')
11
10
  Prawn::ManualBuilder::Example.generate(filename) do
12
- text "Take this example, a simple Euro sign:"
13
- text "", :size => 32
11
+ text 'Take this example, a simple Euro sign:'
12
+ text '', size: 32
14
13
  move_down 20
15
14
 
16
- text "This works, because € is one of the few " +
17
- "non-ASCII glyphs supported in PDF built-in fonts."
15
+ text 'This works, because € is one of the few ' \
16
+ 'non-ASCII glyphs supported in PDF built-in fonts.'
18
17
 
19
18
  move_down 20
20
19
 
21
- text "For full internationalized text support, we need to use TTF fonts:"
20
+ text 'For full internationalized text support, we need to use external fonts:'
22
21
  move_down 20
23
22
 
24
23
  font("#{Prawn::DATADIR}/fonts/DejaVuSans.ttf") do
25
- text "ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει."
26
- text "There you go."
24
+ text 'ὕαλον ϕαγεῖν δύναμαι· τοῦτο οὔ με βλάπτει.'
25
+ text 'There you go.'
27
26
  end
28
27
  end
@@ -1,57 +1,59 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # Prints a list of all of the glyphs that can be rendered by Adobe's built
4
4
  # in fonts, along with their character widths and WinAnsi codes. Be sure
5
5
  # to pass these glyphs as UTF-8, and Prawn will transcode them for you.
6
- #
7
- require File.expand_path(File.join(File.dirname(__FILE__),
8
- %w[.. example_helper]))
6
+
7
+ require_relative '../example_helper'
9
8
 
10
9
  filename = File.basename(__FILE__).gsub('.rb', '.pdf')
11
10
  Prawn::ManualBuilder::Example.generate(filename) do
12
- FONT_SIZE = 9.5
11
+ font_size = 9.5
13
12
 
14
13
  x = 0
15
14
  y = bounds.top
16
15
 
17
- fields = [[20, :right], [8, :left], [12, :center], [30, :right], [8, :left],
18
- [0, :left]]
16
+ fields = [
17
+ [20, :right], [8, :left], [12, :center], [30, :right], [8, :left],
18
+ [0, :left]
19
+ ]
19
20
 
20
- font "Helvetica", :size => FONT_SIZE
21
+ font 'Helvetica', size: font_size
21
22
 
22
- move_down 30
23
- text "(See next page for WinAnsi table)", :align => :center
24
23
  start_new_page
25
24
 
26
25
  Prawn::Encoding::WinAnsi::CHARACTERS.each_with_index do |name, index|
27
- next if name == ".notdef"
28
- y -= FONT_SIZE
26
+ next if name == '.notdef'
27
+
28
+ y -= font_size
29
29
 
30
- if y < FONT_SIZE
31
- y = bounds.top - FONT_SIZE
30
+ if y < font_size
31
+ y = bounds.top - font_size
32
32
  x += 170
33
33
  end
34
34
 
35
- code = "%d." % index
36
- char = index.chr
35
+ code = format('%<index>d.', index: index)
36
+ char = index.chr.force_encoding(::Encoding::Windows_1252)
37
37
 
38
- width = 1000 * width_of(char, :size => FONT_SIZE) / FONT_SIZE
39
- size = "%d" % width
38
+ width = 1000 * width_of(char, size: font_size) / font_size
39
+ size = format('%<width>d', width: width)
40
40
 
41
41
  data = [code, nil, char, size, nil, name]
42
- dx = x
42
+ dx = x
43
43
  fields.zip(data).each do |(total_width, align), field|
44
44
  if field
45
- width = width_of(field, :size => FONT_SIZE)
45
+ width = width_of(field, size: font_size)
46
46
 
47
47
  case align
48
- when :left then offset = 0
49
- when :right then offset = total_width - width
48
+ when :left then offset = 0
49
+ when :right then offset = total_width - width
50
50
  when :center then offset = (total_width - width) / 2
51
51
  end
52
52
 
53
- text_box(field.force_encoding("windows-1252").encode("UTF-8"),
54
- :at => [dx + offset, y])
53
+ text_box(
54
+ field.dup.force_encoding('windows-1252').encode('UTF-8'),
55
+ at: [dx + offset, y]
56
+ )
55
57
  end
56
58
 
57
59
  dx += total_width
@@ -1,43 +1,50 @@
1
- basedir = File.expand_path(File.dirname(__FILE__))
1
+ # frozen_string_literal: true
2
+
3
+ basedir = __dir__
2
4
 
3
5
  require "#{basedir}/lib/prawn/version"
4
6
 
5
7
  Gem::Specification.new do |spec|
6
- spec.name = "prawn"
8
+ spec.name = 'prawn'
7
9
  spec.version = Prawn::VERSION
8
10
  spec.platform = Gem::Platform::RUBY
9
- spec.summary = "A fast and nimble PDF generator for Ruby"
10
- spec.files = Dir.glob("{examples,lib,spec,manual}/**/**/*") +
11
- Dir.glob("data/{encodings,images,pdfs}/*") +
12
- Dir.glob("data/fonts/{MustRead.html,*.afm}") +
13
- ["data/shift_jis_text.txt"] +
14
- ["Rakefile", "prawn.gemspec", "Gemfile",
15
- "COPYING", "LICENSE", "GPLv2", "GPLv3",
16
- ".yardopts"]
17
- spec.require_path = "lib"
18
- spec.required_ruby_version = '>= 2.0.0'
19
- spec.required_rubygems_version = ">= 1.3.6"
20
-
21
- spec.test_files = Dir[ "spec/*_spec.rb" ]
22
- spec.authors = ["Gregory Brown", "Brad Ediger", "Daniel Nelson", "Jonathan Greenberg", "James Healy"]
23
- spec.email = ["gregory.t.brown@gmail.com", "brad@bradediger.com", "dnelson@bluejade.com", "greenberg@entryway.net", "jimmy@deefa.com"]
24
- spec.rubyforge_project = "prawn"
25
- spec.licenses = %w(PRAWN GPL-2.0 GPL-3.0)
26
-
27
- spec.add_dependency('ttfunk', '~> 1.4.0')
28
- spec.add_dependency('pdf-core', "~> 0.6.1")
29
-
30
- spec.add_development_dependency('pdf-inspector', '~> 1.2.1')
31
- spec.add_development_dependency('yard')
32
- spec.add_development_dependency('rspec', '~> 3.0')
33
- spec.add_development_dependency('rake')
34
- spec.add_development_dependency('simplecov')
35
- spec.add_development_dependency('prawn-manual_builder', ">= 0.2.0")
36
- spec.add_development_dependency('pdf-reader', '~>1.2')
37
- spec.add_development_dependency('rubocop', '0.30.1')
38
- spec.add_development_dependency('code_statistics', '0.2.13')
39
-
40
- spec.homepage = "http://prawn.majesticseacreature.com"
11
+ spec.summary = 'A fast and nimble PDF generator for Ruby'
12
+
13
+ spec.cert_chain = ['certs/pointlessone.pem']
14
+ if $PROGRAM_NAME.end_with? 'gem'
15
+ spec.signing_key = File.expand_path('~/.gem/gem-private_key.pem')
16
+ end
17
+
18
+ spec.files = Dir.glob('{examples,lib,spec,manual}/**/**/*') +
19
+ Dir.glob('data/fonts/{MustRead.html,*.afm}') +
20
+ [
21
+ 'Rakefile', 'prawn.gemspec', 'Gemfile',
22
+ 'COPYING', 'LICENSE', 'GPLv2', 'GPLv3',
23
+ '.yardopts'
24
+ ]
25
+ spec.require_path = 'lib'
26
+ spec.required_ruby_version = '>= 2.5'
27
+ spec.required_rubygems_version = '>= 1.3.6'
28
+
29
+ spec.authors = [
30
+ 'Gregory Brown', 'Brad Ediger', 'Daniel Nelson', 'Jonathan Greenberg',
31
+ 'James Healy'
32
+ ]
33
+ spec.email = [
34
+ 'gregory.t.brown@gmail.com', 'brad@bradediger.com', 'dnelson@bluejade.com',
35
+ 'greenberg@entryway.net', 'jimmy@deefa.com'
36
+ ]
37
+ spec.licenses = %w[PRAWN GPL-2.0 GPL-3.0]
38
+
39
+ spec.add_dependency('pdf-core', '~> 0.9.0')
40
+ spec.add_dependency('ttfunk', '~> 1.7')
41
+
42
+ spec.add_development_dependency('pdf-inspector', '>= 1.2.1', '< 2.0.a')
43
+ spec.add_development_dependency('pdf-reader', ['~> 1.4', '>= 1.4.1'])
44
+ spec.add_development_dependency('prawn-dev', '~> 0.1.0')
45
+ spec.add_development_dependency('prawn-manual_builder', '>= 0.3.0')
46
+
47
+ spec.homepage = 'http://prawnpdf.org'
41
48
  spec.description = <<END_DESC
42
49
  Prawn is a fast, tiny, and nimble PDF generator for Ruby
43
50
  END_DESC
@@ -1,11 +1,11 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
3
  module EncodingHelpers
4
4
  def win1252_string(str)
5
- str.force_encoding(Encoding::Windows_1252)
5
+ str.dup.force_encoding(Encoding::Windows_1252)
6
6
  end
7
7
 
8
8
  def bin_string(str)
9
- str.force_encoding(Encoding::ASCII_8BIT)
9
+ str.dup.force_encoding(Encoding::ASCII_8BIT)
10
10
  end
11
11
  end
@@ -0,0 +1,550 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Document::BoundingBox do
6
+ let(:pdf) { create_pdf }
7
+
8
+ describe 'attributes' do
9
+ let(:box) do
10
+ described_class.new(
11
+ nil,
12
+ nil,
13
+ [100, 125],
14
+ width: 50,
15
+ height: 75
16
+ )
17
+ end
18
+
19
+ it 'has an anchor at (x, y - height)' do
20
+ expect(box.anchor).to eq([100, 50])
21
+ end
22
+
23
+ it 'has a left boundary of 0' do
24
+ expect(box.left).to eq(0)
25
+ end
26
+
27
+ it 'has a right boundary equal to the width' do
28
+ expect(box.right).to eq(50)
29
+ end
30
+
31
+ it 'has a top boundary of height' do
32
+ expect(box.top).to eq(75)
33
+ end
34
+
35
+ it 'has a bottom boundary of 0' do
36
+ expect(box.bottom).to eq(0)
37
+ end
38
+
39
+ it 'has a top-left of [0, height]' do
40
+ expect(box.top_left).to eq([0, 75])
41
+ end
42
+
43
+ it 'has a top-right of [width, height]' do
44
+ expect(box.top_right).to eq([50, 75])
45
+ end
46
+
47
+ it 'has a bottom-left of [0, 0]' do
48
+ expect(box.bottom_left).to eq([0, 0])
49
+ end
50
+
51
+ it 'has a bottom-right of [width ,0]' do
52
+ expect(box.bottom_right).to eq([50, 0])
53
+ end
54
+
55
+ it 'has an absolute left boundary of x' do
56
+ expect(box.absolute_left).to eq(100)
57
+ end
58
+
59
+ it 'has an absolute right boundary of x + width' do
60
+ expect(box.absolute_right).to eq(150)
61
+ end
62
+
63
+ it 'has an absolute top boundary of y' do
64
+ expect(box.absolute_top).to eq(125)
65
+ end
66
+
67
+ it 'has an absolute bottom boundary of y - height' do
68
+ expect(box.absolute_bottom).to eq(50)
69
+ end
70
+
71
+ it 'has an absolute bottom-left of [x, y - height]' do
72
+ expect(box.absolute_bottom_left).to eq([100, 50])
73
+ end
74
+
75
+ it 'has an absolute bottom-right of [x + width, y - height]' do
76
+ expect(box.absolute_bottom_right).to eq([150, 50])
77
+ end
78
+
79
+ it 'has an absolute top-left of [x, y]' do
80
+ expect(box.absolute_top_left).to eq([100, 125])
81
+ end
82
+
83
+ it 'has an absolute top-right of [x + width, y]' do
84
+ expect(box.absolute_top_right).to eq([150, 125])
85
+ end
86
+ end
87
+
88
+ describe 'validations' do
89
+ it 'requires width to be set' do
90
+ expect do
91
+ described_class.new(nil, nil, [100, 100])
92
+ end.to raise_error(ArgumentError)
93
+ end
94
+
95
+ it 'raise_errors an ArgumentError if a block is not passed' do
96
+ pdf = Prawn::Document.new
97
+ expect do
98
+ pdf.bounding_box([0, 0], width: 200)
99
+ end.to raise_error(ArgumentError)
100
+ end
101
+ end
102
+
103
+ describe 'drawing' do
104
+ it 'does not stomp on the arguments to bounding_box' do
105
+ pdf = Prawn::Document.new
106
+ x = [100, 500]
107
+ pdf.bounding_box x, width: 100 do
108
+ pdf.text 'bork-bork-bork'
109
+ end
110
+ expect(x).to eq([100, 500])
111
+ end
112
+
113
+ it 'restores Document#bounds to the correct margin box on exit' do
114
+ pdf = Prawn::Document.new(margin: 200)
115
+
116
+ # add a multi-page bounding box
117
+ pdf.bounding_box([100, pdf.bounds.top], width: 400) do
118
+ pdf.text "The rain in spain falls mainly in the plains.\n" * 30
119
+ end
120
+
121
+ pdf.start_new_page(margin: 0)
122
+
123
+ x_min, y_min, x_max, y_max = pdf.page.dimensions
124
+
125
+ expect(pdf.bounds.absolute_top_left).to eq([x_min, y_max])
126
+ expect(pdf.bounds.absolute_bottom_right).to eq([x_max, y_min])
127
+ end
128
+
129
+ it 'restores the parent bounding box when calls are nested' do
130
+ pdf.bounding_box [100, 500], width: 300, height: 300 do
131
+ expect(pdf.bounds.absolute_top)
132
+ .to eq(500 + pdf.margin_box.absolute_bottom)
133
+ expect(pdf.bounds.absolute_left)
134
+ .to eq(100 + pdf.margin_box.absolute_left)
135
+
136
+ parent_box = pdf.bounds
137
+
138
+ pdf.bounding_box [50, 200], width: 100, height: 100 do
139
+ expect(pdf.bounds.absolute_top)
140
+ .to eq(200 + parent_box.absolute_bottom)
141
+ expect(pdf.bounds.absolute_left).to eq(50 + parent_box.absolute_left)
142
+ end
143
+
144
+ expect(pdf.bounds.absolute_top)
145
+ .to eq(500 + pdf.margin_box.absolute_bottom)
146
+ expect(pdf.bounds.absolute_left)
147
+ .to eq(100 + pdf.margin_box.absolute_left)
148
+ end
149
+ end
150
+
151
+ it 'calculates a height if none is specified' do
152
+ pdf.bounding_box([100, 500], width: 100) do
153
+ pdf.text 'The rain in Spain falls mainly on the plains.'
154
+ end
155
+
156
+ expect(pdf.y).to be_within(0.001).of(458.384)
157
+ end
158
+
159
+ it 'keeps track of the max height the box was stretched to' do
160
+ box =
161
+ pdf.bounding_box(pdf.bounds.top_left, width: 100) do
162
+ pdf.move_down 100
163
+ pdf.move_up 15
164
+ end
165
+
166
+ expect(box.height).to eq(100)
167
+ end
168
+
169
+ it 'advances the y-position by bbox.height by default' do
170
+ orig_y = pdf.y
171
+ pdf.bounding_box [0, pdf.cursor], width: pdf.bounds.width, height: 30 do
172
+ pdf.text 'hello'
173
+ end
174
+ expect(pdf.y).to be_within(0.001).of(orig_y - 30)
175
+ end
176
+
177
+ it 'does not advance y-position if passed :hold_position => true' do
178
+ orig_y = pdf.y
179
+ pdf.bounding_box(
180
+ [0, pdf.cursor],
181
+ width: pdf.bounds.width,
182
+ hold_position: true
183
+ ) do
184
+ pdf.text 'hello'
185
+ end
186
+ # y only advances by height of one line ("hello")
187
+ expect(pdf.y).to be_within(0.001).of(orig_y - pdf.height_of('hello'))
188
+ end
189
+
190
+ it 'does not advance y-position of a stretchy bbox if it would stretch '\
191
+ 'the bbox further' do
192
+ bottom = pdf.y = pdf.margin_box.absolute_bottom
193
+ pdf.bounding_box [0, pdf.margin_box.top], width: pdf.bounds.width do
194
+ pdf.y = bottom
195
+ pdf.text 'hello' # starts a new page
196
+ end
197
+ expect(pdf.page_count).to eq(2)
198
+
199
+ # Restoring the position (to the absolute bottom) would stretch the bbox
200
+ # to the bottom of the page, which we don't want. This should be
201
+ # equivalent to a bbox with :hold_position => true, where we only advance
202
+ # by the amount that was actually drawn.
203
+ expect(pdf.y).to be_within(0.001).of(
204
+ pdf.margin_box.absolute_top - pdf.height_of('hello')
205
+ )
206
+ end
207
+ end
208
+
209
+ describe 'Indentation' do
210
+ it 'temporarilies shift the x coordinate and width' do
211
+ pdf.bounding_box([100, 100], width: 200) do
212
+ pdf.indent(20) do
213
+ expect(pdf.bounds.absolute_left).to eq(120)
214
+ expect(pdf.bounds.width).to eq(180)
215
+ end
216
+ end
217
+ end
218
+
219
+ it 'restores the x coordinate and width after block exits' do
220
+ pdf.bounding_box([100, 100], width: 200) do
221
+ pdf.indent(20) do
222
+ # no-op
223
+ end
224
+ expect(pdf.bounds.absolute_left).to eq(100)
225
+ expect(pdf.bounds.width).to eq(200)
226
+ end
227
+ end
228
+
229
+ it 'restores the x coordinate and width on error' do
230
+ pdf.bounding_box([100, 100], width: 200) do
231
+ pdf.indent(20) { raise }
232
+ rescue StandardError
233
+ expect(pdf.bounds.absolute_left).to eq(100)
234
+ expect(pdf.bounds.width).to eq(200)
235
+ end
236
+ end
237
+
238
+ it 'maintains left indentation across a page break' do
239
+ original_left = pdf.bounds.absolute_left
240
+
241
+ pdf.indent(20) do
242
+ expect(pdf.bounds.absolute_left).to eq(original_left + 20)
243
+ pdf.start_new_page
244
+ expect(pdf.bounds.absolute_left).to eq(original_left + 20)
245
+ end
246
+
247
+ expect(pdf.bounds.absolute_left).to eq(original_left)
248
+ end
249
+
250
+ it 'maintains right indentation across a page break' do
251
+ original_width = pdf.bounds.width
252
+
253
+ pdf.indent(0, 20) do
254
+ expect(pdf.bounds.width).to eq(original_width - 20)
255
+ pdf.start_new_page
256
+ expect(pdf.bounds.width).to eq(original_width - 20)
257
+ end
258
+
259
+ expect(pdf.bounds.width).to eq(original_width)
260
+ end
261
+
262
+ it 'optionally allows adjustment of the right bound as well' do
263
+ pdf.bounding_box([100, 100], width: 200) do
264
+ pdf.indent(20, 30) do
265
+ expect(pdf.bounds.absolute_left).to eq(120)
266
+ expect(pdf.bounds.width).to eq(150)
267
+ end
268
+ expect(pdf.bounds.absolute_left).to eq(100)
269
+ expect(pdf.bounds.width).to eq(200)
270
+ end
271
+ end
272
+
273
+ describe 'in a ColumnBox' do
274
+ it 'subtracts the given indentation from the available width' do
275
+ pdf.column_box(
276
+ [0, pdf.cursor],
277
+ width: pdf.bounds.width,
278
+ height: 200,
279
+ columns: 2,
280
+ spacer: 20
281
+ ) do
282
+ width = pdf.bounds.width
283
+ pdf.indent(20) do
284
+ expect(pdf.bounds.width).to be_within(0.01).of(width - 20)
285
+ end
286
+ end
287
+ end
288
+
289
+ it 'subtracts right padding from the available width' do
290
+ pdf.column_box(
291
+ [0, pdf.cursor],
292
+ width: pdf.bounds.width,
293
+ height: 200,
294
+ columns: 2,
295
+ spacer: 20
296
+ ) do
297
+ width = pdf.bounds.width
298
+ pdf.indent(20, 30) do
299
+ expect(pdf.bounds.width).to be_within(0.01).of(width - 50)
300
+ end
301
+ end
302
+ end
303
+
304
+ it 'maintains the same left indentation across column breaks' do
305
+ pdf.column_box(
306
+ [0, pdf.cursor],
307
+ width: pdf.bounds.width,
308
+ columns: 3,
309
+ spacer: 15
310
+ ) do
311
+ 3.times do |_column|
312
+ x = pdf.bounds.left_side
313
+ pdf.indent(20) do
314
+ expect(pdf.bounds.left_side).to eq(x + 20)
315
+ end
316
+ pdf.bounds.move_past_bottom
317
+ end
318
+ end
319
+ end
320
+
321
+ it 'does not change the right margin if only left indentation is '\
322
+ 'requested' do
323
+ pdf.column_box(
324
+ [0, pdf.cursor],
325
+ width: pdf.bounds.width,
326
+ columns: 3,
327
+ spacer: 15
328
+ ) do
329
+ 3.times do |_column|
330
+ x = pdf.bounds.right_side
331
+ pdf.indent(20) do
332
+ expect(pdf.bounds.right_side).to eq(x)
333
+ end
334
+ pdf.bounds.move_past_bottom
335
+ end
336
+ end
337
+ end
338
+
339
+ it 'maintains the same right indentation across columns' do
340
+ pdf.column_box(
341
+ [0, pdf.cursor],
342
+ width: pdf.bounds.width,
343
+ columns: 3,
344
+ spacer: 15
345
+ ) do
346
+ 3.times do |_column|
347
+ x = pdf.bounds.right_side
348
+ pdf.indent(20, 10) do
349
+ expect(pdf.bounds.right_side).to eq(x - 10)
350
+ end
351
+ pdf.bounds.move_past_bottom
352
+ end
353
+ end
354
+ end
355
+
356
+ it 'keeps the right indentation after nesting indents' do
357
+ pdf.column_box(
358
+ [0, pdf.cursor],
359
+ width: pdf.bounds.width,
360
+ columns: 3,
361
+ spacer: 15
362
+ ) do
363
+ 3.times do |_column|
364
+ # I am giving a right indent of 10...
365
+ pdf.indent(20, 10) do
366
+ x = pdf.bounds.right_side
367
+ # ...and no right indent here...
368
+ pdf.indent(20) do
369
+ # right indent is inherited from the parent!
370
+ expect(pdf.bounds.right_side).to eq(x)
371
+ end
372
+ end
373
+ pdf.bounds.move_past_bottom
374
+ end
375
+ end
376
+ end
377
+
378
+ it 'reverts the right indentation if negative indent is given in '\
379
+ 'nested indent' do
380
+ pdf.column_box(
381
+ [0, pdf.cursor],
382
+ width: pdf.bounds.width,
383
+ columns: 3,
384
+ spacer: 15
385
+ ) do
386
+ 3.times do |_column|
387
+ x = pdf.bounds.right_side
388
+ pdf.indent(20, 10) do
389
+ # requesting a negative right-indent of equivalent size...
390
+ pdf.indent(20, -10) do
391
+ # ...resets the right margin to that of the column!
392
+ expect(pdf.bounds.right_side).to eq(x)
393
+ end
394
+ end
395
+ pdf.bounds.move_past_bottom
396
+ end
397
+ end
398
+ end
399
+
400
+ it 'reduces the available column width by the sum of ' \
401
+ 'all nested indents' do
402
+ pdf.column_box(
403
+ [0, pdf.cursor],
404
+ width: pdf.bounds.width,
405
+ columns: 3,
406
+ spacer: 15
407
+ ) do
408
+ 3.times do |_column|
409
+ w = pdf.bounds.width
410
+ pdf.indent(20, 10) do
411
+ pdf.indent(20, 10) do
412
+ expect(pdf.bounds.width).to eq(w - 60)
413
+ end
414
+ end
415
+ pdf.bounds.move_past_bottom
416
+ end
417
+ end
418
+ end
419
+ end
420
+ end
421
+
422
+ describe 'A canvas' do
423
+ it 'uses whatever the last set y position is' do
424
+ pdf.canvas do
425
+ pdf.bounding_box([100, 500], width: 200) { pdf.move_down 50 }
426
+ end
427
+ expect(pdf.y).to eq(450)
428
+ end
429
+
430
+ it 'restores the original ypos after execution', issue: 523 do
431
+ doc = Prawn::Document.new(skip_page_creation: true)
432
+ doc.start_new_page
433
+
434
+ original_ypos = doc.y
435
+
436
+ doc.canvas do
437
+ # draw
438
+ end
439
+
440
+ expect(doc.y).to eq(original_ypos)
441
+ end
442
+ end
443
+
444
+ describe 'Deep-copying' do
445
+ it 'creates a new object that does not copy @document' do
446
+ Prawn::Document.new do |pdf|
447
+ orig = pdf.bounds
448
+ copy = orig.deep_copy
449
+
450
+ expect(copy).to_not eq(pdf.bounds)
451
+ expect(copy.document).to be_nil
452
+ end
453
+ end
454
+
455
+ it 'deep-copies parent bounds' do
456
+ Prawn::Document.new do |pdf|
457
+ outside = pdf.bounds
458
+ pdf.bounding_box [100, 100], width: 100 do
459
+ copy = pdf.bounds.deep_copy
460
+
461
+ # the parent bounds should have the same parameters
462
+ expect(copy.parent.width).to eq(outside.width)
463
+ expect(copy.parent.height).to eq(outside.height)
464
+
465
+ # but should not be the same object
466
+ expect(copy.parent).to_not eq(outside)
467
+ end
468
+ end
469
+ end
470
+ end
471
+
472
+ describe 'Prawn::Document#reference_bounds' do
473
+ it 'returns self for non-stretchy bounds' do
474
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
475
+ expect(pdf.reference_bounds).to eq(pdf.bounds)
476
+ end
477
+ end
478
+
479
+ it 'returns the parent bounds if in a stretchy box' do
480
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
481
+ correct_bounds = pdf.bounds
482
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
483
+ expect(pdf.reference_bounds).to eq(correct_bounds)
484
+ end
485
+ end
486
+ end
487
+
488
+ it 'finds the non-stretchy box through 2 levels' do
489
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
490
+ correct_bounds = pdf.bounds
491
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
492
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
493
+ expect(pdf.reference_bounds).to eq(correct_bounds)
494
+ end
495
+ end
496
+ end
497
+ end
498
+
499
+ it "returns the margin box if there's no explicit bbox" do
500
+ expect(pdf.reference_bounds).to eq(pdf.margin_box)
501
+
502
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
503
+ expect(pdf.reference_bounds).to eq(pdf.margin_box)
504
+ end
505
+ end
506
+
507
+ it "returns the canvas box if we're in a canvas" do
508
+ pdf.canvas do
509
+ canvas_box = pdf.bounds
510
+
511
+ expect(pdf.reference_bounds).to eq(canvas_box)
512
+
513
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
514
+ expect(pdf.reference_bounds).to eq(canvas_box)
515
+ end
516
+ end
517
+ end
518
+ end
519
+
520
+ describe '#move_past_bottom' do
521
+ it 'ordinarilies start a new page' do
522
+ pdf.bounds.move_past_bottom
523
+ pdf.text 'Foo'
524
+
525
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
526
+ expect(pages.size).to eq(2)
527
+ expect(pages[0][:strings]).to eq([])
528
+ expect(pages[1][:strings]).to eq(['Foo'])
529
+ end
530
+
531
+ it 'moves to the top of the next page if it exists already' do
532
+ # save away the y-position at the top of a page
533
+ top_y = pdf.y
534
+
535
+ # create a blank page but go to the page before it
536
+ pdf.start_new_page
537
+ pdf.go_to_page 1
538
+ pdf.text 'Foo'
539
+
540
+ pdf.bounds.move_past_bottom
541
+ expect(pdf.y).to be_within(0.001).of(top_y)
542
+ pdf.text 'Bar'
543
+
544
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
545
+ expect(pages.size).to eq(2)
546
+ expect(pages[0][:strings]).to eq(['Foo'])
547
+ expect(pages[1][:strings]).to eq(['Bar'])
548
+ end
549
+ end
550
+ end