prawn 2.0.2 → 2.3.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 (277) 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 +20 -23
  7. data/lib/prawn.rb +37 -49
  8. data/lib/prawn/document.rb +181 -133
  9. data/lib/prawn/document/bounding_box.rb +41 -29
  10. data/lib/prawn/document/column_box.rb +7 -7
  11. data/lib/prawn/document/internals.rb +18 -8
  12. data/lib/prawn/document/span.rb +21 -16
  13. data/lib/prawn/encoding.rb +69 -68
  14. data/lib/prawn/errors.rb +12 -7
  15. data/lib/prawn/font.rb +115 -69
  16. data/lib/prawn/font_metric_cache.rb +14 -8
  17. data/lib/prawn/{font → fonts}/afm.rb +102 -68
  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 +87 -68
  22. data/lib/prawn/graphics.rb +120 -80
  23. data/lib/prawn/graphics/blend_mode.rb +65 -0
  24. data/lib/prawn/graphics/cap_style.rb +3 -3
  25. data/lib/prawn/graphics/color.rb +27 -25
  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 +197 -67
  29. data/lib/prawn/graphics/transformation.rb +17 -8
  30. data/lib/prawn/graphics/transparency.rb +17 -13
  31. data/lib/prawn/grid.rb +48 -47
  32. data/lib/prawn/image_handler.rb +5 -5
  33. data/lib/prawn/images.rb +39 -30
  34. data/lib/prawn/images/image.rb +2 -1
  35. data/lib/prawn/images/jpg.rb +28 -22
  36. data/lib/prawn/images/png.rb +107 -66
  37. data/lib/prawn/measurement_extensions.rb +10 -9
  38. data/lib/prawn/measurements.rb +19 -15
  39. data/lib/prawn/outline.rb +97 -77
  40. data/lib/prawn/repeater.rb +14 -10
  41. data/lib/prawn/security.rb +81 -61
  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 +68 -52
  46. data/lib/prawn/text/box.rb +11 -8
  47. data/lib/prawn/text/formatted.rb +5 -5
  48. data/lib/prawn/text/formatted/arranger.rb +78 -49
  49. data/lib/prawn/text/formatted/box.rb +134 -100
  50. data/lib/prawn/text/formatted/fragment.rb +11 -14
  51. data/lib/prawn/text/formatted/line_wrap.rb +121 -63
  52. data/lib/prawn/text/formatted/parser.rb +139 -117
  53. data/lib/prawn/text/formatted/wrap.rb +43 -31
  54. data/lib/prawn/transformation_stack.rb +44 -0
  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 +6 -7
  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 +4 -5
  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 +24 -17
  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 +11 -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 +17 -15
  82. data/manual/example_helper.rb +5 -4
  83. data/manual/graphics/blend_mode.rb +52 -0
  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 +4 -5
  88. data/manual/graphics/fill_rules.rb +9 -10
  89. data/manual/graphics/gradients.rb +27 -21
  90. data/manual/graphics/graphics.rb +48 -39
  91. data/manual/graphics/helper.rb +12 -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 +4 -5
  99. data/manual/graphics/stroke_cap.rb +6 -7
  100. data/manual/graphics/stroke_dash.rb +11 -12
  101. data/manual/graphics/stroke_join.rb +5 -6
  102. data/manual/graphics/translate.rb +9 -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 +9 -10
  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 +13 -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 +19 -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 +7 -8
  137. data/manual/text/formatted_callbacks.rb +25 -21
  138. data/manual/text/formatted_text.rb +33 -25
  139. data/manual/text/free_flowing_text.rb +20 -21
  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 +13 -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 +28 -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 +18 -19
  155. data/manual/text/utf8.rb +11 -12
  156. data/manual/text/win_ansi_charset.rb +21 -19
  157. data/prawn.gemspec +45 -33
  158. data/spec/extensions/encoding_helpers.rb +3 -3
  159. data/spec/prawn/document/bounding_box_spec.rb +546 -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 +36 -0
  167. data/spec/prawn/document_spec.rb +802 -0
  168. data/spec/prawn/font_metric_cache_spec.rb +54 -0
  169. data/spec/prawn/font_spec.rb +542 -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 +837 -0
  173. data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
  174. data/spec/prawn/image_handler_spec.rb +53 -0
  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 +224 -0
  178. data/spec/prawn/measurements_extensions_spec.rb +24 -0
  179. data/spec/prawn/outline_spec.rb +412 -0
  180. data/spec/prawn/repeater_spec.rb +165 -0
  181. data/spec/prawn/soft_mask_spec.rb +74 -0
  182. data/spec/prawn/stamp_spec.rb +172 -0
  183. data/spec/prawn/text/box_spec.rb +1112 -0
  184. data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
  185. data/spec/prawn/text/formatted/box_spec.rb +846 -0
  186. data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
  187. data/spec/prawn/text/formatted/line_wrap_spec.rb +494 -0
  188. data/spec/prawn/text/formatted/parser_spec.rb +697 -0
  189. data/spec/prawn/text_draw_text_spec.rb +149 -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/prawn/transformation_stack_spec.rb +66 -0
  195. data/spec/prawn/view_spec.rb +63 -0
  196. data/spec/prawn_manual_spec.rb +35 -0
  197. data/spec/spec_helper.rb +19 -23
  198. metadata +145 -185
  199. metadata.gz.sig +4 -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/dice.alpha +0 -0
  206. data/data/images/dice.color +0 -0
  207. data/data/images/dice.png +0 -0
  208. data/data/images/dice_interlaced.png +0 -0
  209. data/data/images/fractal.jpg +0 -0
  210. data/data/images/indexed_color.dat +0 -0
  211. data/data/images/indexed_color.png +0 -0
  212. data/data/images/letterhead.jpg +0 -0
  213. data/data/images/license.md +0 -8
  214. data/data/images/page_white_text.alpha +0 -0
  215. data/data/images/page_white_text.color +0 -0
  216. data/data/images/page_white_text.png +0 -0
  217. data/data/images/pal_bk.png +0 -0
  218. data/data/images/pigs.jpg +0 -0
  219. data/data/images/prawn.png +0 -0
  220. data/data/images/ruport.png +0 -0
  221. data/data/images/ruport_data.dat +0 -0
  222. data/data/images/ruport_transparent.png +0 -0
  223. data/data/images/ruport_type0.png +0 -0
  224. data/data/images/stef.jpg +0 -0
  225. data/data/images/tru256.bmp +0 -0
  226. data/data/images/web-links.dat +0 -1
  227. data/data/images/web-links.png +0 -0
  228. data/data/pdfs/complex_template.pdf +0 -0
  229. data/data/pdfs/contains_ttf_font.pdf +0 -0
  230. data/data/pdfs/encrypted.pdf +0 -0
  231. data/data/pdfs/form.pdf +1 -819
  232. data/data/pdfs/hexagon.pdf +0 -61
  233. data/data/pdfs/indirect_reference.pdf +0 -86
  234. data/data/pdfs/multipage_template.pdf +0 -127
  235. data/data/pdfs/nested_pages.pdf +0 -118
  236. data/data/pdfs/page_without_mediabox.pdf +0 -193
  237. data/data/pdfs/resources_as_indirect_object.pdf +0 -83
  238. data/data/pdfs/two_hexagons.pdf +0 -90
  239. data/data/pdfs/version_1_6.pdf +0 -61
  240. data/data/shift_jis_text.txt +0 -1
  241. data/spec/acceptance/png.rb +0 -24
  242. data/spec/annotations_spec.rb +0 -67
  243. data/spec/bounding_box_spec.rb +0 -501
  244. data/spec/column_box_spec.rb +0 -59
  245. data/spec/destinations_spec.rb +0 -13
  246. data/spec/document_spec.rb +0 -742
  247. data/spec/extensions/mocha.rb +0 -45
  248. data/spec/font_metric_cache_spec.rb +0 -52
  249. data/spec/font_spec.rb +0 -475
  250. data/spec/formatted_text_arranger_spec.rb +0 -423
  251. data/spec/formatted_text_box_spec.rb +0 -716
  252. data/spec/formatted_text_fragment_spec.rb +0 -299
  253. data/spec/graphics_spec.rb +0 -666
  254. data/spec/grid_spec.rb +0 -95
  255. data/spec/image_handler_spec.rb +0 -53
  256. data/spec/images_spec.rb +0 -167
  257. data/spec/inline_formatted_text_parser_spec.rb +0 -568
  258. data/spec/jpg_spec.rb +0 -23
  259. data/spec/line_wrap_spec.rb +0 -366
  260. data/spec/measurement_units_spec.rb +0 -22
  261. data/spec/outline_spec.rb +0 -409
  262. data/spec/png_spec.rb +0 -235
  263. data/spec/reference_spec.rb +0 -25
  264. data/spec/repeater_spec.rb +0 -154
  265. data/spec/security_spec.rb +0 -151
  266. data/spec/soft_mask_spec.rb +0 -78
  267. data/spec/span_spec.rb +0 -43
  268. data/spec/stamp_spec.rb +0 -179
  269. data/spec/stroke_styles_spec.rb +0 -208
  270. data/spec/text_at_spec.rb +0 -142
  271. data/spec/text_box_spec.rb +0 -1038
  272. data/spec/text_rendering_mode_spec.rb +0 -45
  273. data/spec/text_spacing_spec.rb +0 -93
  274. data/spec/text_spec.rb +0 -549
  275. data/spec/text_with_inline_formatting_spec.rb +0 -35
  276. data/spec/transparency_spec.rb +0 -91
  277. data/spec/view_spec.rb +0 -42
@@ -1,5 +1,5 @@
1
- # encoding: utf-8
2
- #
1
+ # frozen_string_literal: true
2
+
3
3
  # Whenever the <code>text_box</code> method truncates text, this truncated bit
4
4
  # is not lost, it is the method return value and we can take advantage of that.
5
5
  #
@@ -8,25 +8,28 @@
8
8
  # This example renders as much of the text as will fit in a larger font inside
9
9
  # one text_box and then proceeds to render the remaining text in the default
10
10
  # size in a second text_box.
11
- #
12
- require File.expand_path(File.join(File.dirname(__FILE__),
13
- %w[.. example_helper]))
11
+
12
+ require '../example_helper'
14
13
 
15
14
  filename = File.basename(__FILE__).gsub('.rb', '.pdf')
16
15
  Prawn::ManualBuilder::Example.generate(filename) do
17
- string = "This is the beginning of the text. It will be cut somewhere and " +
18
- "the rest of the text will procede to be rendered this time by " +
19
- "calling another method." + " . " * 50
16
+ string = 'This is the beginning of the text. It will be cut somewhere and ' \
17
+ 'the rest of the text will procede to be rendered this time by ' \
18
+ 'calling another method.' + ' . ' * 50
20
19
 
21
20
  y_position = cursor - 20
22
- excess_text = text_box string,
23
- :width => 300,
24
- :height => 50,
25
- :overflow => :truncate,
26
- :at => [100, y_position],
27
- :size => 18
21
+ excess_text = text_box(
22
+ string,
23
+ width: 300,
24
+ height: 50,
25
+ overflow: :truncate,
26
+ at: [100, y_position],
27
+ size: 18
28
+ )
28
29
 
29
- text_box excess_text,
30
- :width => 300,
31
- :at => [100, y_position - 100]
30
+ text_box(
31
+ excess_text,
32
+ width: 300,
33
+ at: [100, y_position - 100]
34
+ )
32
35
  end
@@ -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,35 @@
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, at: [i * 150, y_position],
31
+ width: 100,
32
+ height: 50,
33
+ overflow: mode
35
34
  end
36
35
 
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."
36
+ string = 'If the box is too small for the text, :shrink_to_fit ' \
37
+ 'can render the text in a really small font size.'
39
38
 
40
39
  move_down 120
41
40
  text string
42
41
  y_position = cursor - 20
43
42
  [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
43
+ text_box string, at: [index * 150, y_position],
44
+ width: 50,
45
+ height: 50,
46
+ overflow: :shrink_to_fit,
47
+ min_font_size: value
49
48
  end
50
49
  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,11 +1,10 @@
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
@@ -14,17 +13,18 @@ Prawn::ManualBuilder::Example.generate(filename) do
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"
26
+ next if name == '.notdef'
27
+
28
28
  y -= FONT_SIZE
29
29
 
30
30
  if y < FONT_SIZE
@@ -32,17 +32,17 @@ Prawn::ManualBuilder::Example.generate(filename) do
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
48
  when :left then offset = 0
@@ -50,8 +50,10 @@ Prawn::ManualBuilder::Example.generate(filename) do
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,44 +1,56 @@
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 = ['RUBY', 'GPL-2', 'GPL-3']
26
-
27
- spec.add_dependency('ttfunk', '~> 1.4.0')
28
- spec.add_dependency('pdf-core', "~> 0.6.0")
29
-
30
- spec.add_development_dependency('pdf-inspector', '~> 1.2.0')
31
- spec.add_development_dependency('yard')
32
- spec.add_development_dependency('rspec', '2.14.1')
33
- spec.add_development_dependency('mocha')
34
- spec.add_development_dependency('rake')
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.8.1')
40
+ spec.add_dependency('ttfunk', '~> 1.6')
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-manual_builder', '>= 0.3.0')
45
+ spec.add_development_dependency('rake', '~> 12.0')
46
+ spec.add_development_dependency('rspec', '~> 3.0')
47
+ spec.add_development_dependency('rubocop', '~> 0.84.0')
48
+ spec.add_development_dependency('rubocop-performance', '~> 1.1')
49
+ spec.add_development_dependency('rubocop-rspec', '~> 1.32')
35
50
  spec.add_development_dependency('simplecov')
36
- spec.add_development_dependency('prawn-manual_builder', ">= 0.2.0")
37
- spec.add_development_dependency('pdf-reader', '~>1.2')
38
- spec.add_development_dependency('rubocop', '0.30.1')
39
- spec.add_development_dependency('code_statistics', '0.2.13')
51
+ spec.add_development_dependency('yard')
40
52
 
41
- spec.homepage = "http://prawn.majesticseacreature.com"
53
+ spec.homepage = 'http://prawnpdf.org'
42
54
  spec.description = <<END_DESC
43
55
  Prawn is a fast, tiny, and nimble PDF generator for Ruby
44
56
  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,546 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Prawn::Document::BoundingBox do
6
+ let(:pdf) { create_pdf }
7
+ let(:x) { 100 }
8
+ let(:y) { 125 }
9
+ let(:width) { 50 }
10
+ let(:height) { 75 }
11
+ let(:box) do
12
+ described_class.new(
13
+ nil,
14
+ nil,
15
+ [x, y],
16
+ width: width,
17
+ height: height
18
+ )
19
+ end
20
+
21
+ it 'has an anchor at (x, y - height)' do
22
+ expect(box.anchor).to eq([x, y - height])
23
+ end
24
+
25
+ it 'has a left boundary of 0' do
26
+ expect(box.left).to eq(0)
27
+ end
28
+
29
+ it 'has a right boundary equal to the width' do
30
+ expect(box.right).to eq(width)
31
+ end
32
+
33
+ it 'has a top boundary of height' do
34
+ expect(box.top).to eq(height)
35
+ end
36
+
37
+ it 'has a bottom boundary of 0' do
38
+ expect(box.bottom).to eq(0)
39
+ end
40
+
41
+ it 'has a top-left of [0,height]' do
42
+ expect(box.top_left).to eq([0, height])
43
+ end
44
+
45
+ it 'has a top-right of [width,height]' do
46
+ expect(box.top_right).to eq([width, height])
47
+ end
48
+
49
+ it 'has a bottom-left of [0,0]' do
50
+ expect(box.bottom_left).to eq([0, 0])
51
+ end
52
+
53
+ it 'has a bottom-right of [width,0]' do
54
+ expect(box.bottom_right).to eq([width, 0])
55
+ end
56
+
57
+ it 'has an absolute left boundary of x' do
58
+ expect(box.absolute_left).to eq(x)
59
+ end
60
+
61
+ it 'has an absolute right boundary of x + width' do
62
+ expect(box.absolute_right).to eq(x + width)
63
+ end
64
+
65
+ it 'has an absolute top boundary of y' do
66
+ expect(box.absolute_top).to eq(y)
67
+ end
68
+
69
+ it 'has an absolute bottom boundary of y - height' do
70
+ expect(box.absolute_bottom).to eq(y - height)
71
+ end
72
+
73
+ it 'has an absolute bottom-left of [x,y-height]' do
74
+ expect(box.absolute_bottom_left).to eq([x, y - height])
75
+ end
76
+
77
+ it 'has an absolute bottom-right of [x+width,y-height]' do
78
+ expect(box.absolute_bottom_right).to eq([x + width, y - height])
79
+ end
80
+
81
+ it 'has an absolute top-left of [x,y]' do
82
+ expect(box.absolute_top_left).to eq([x, y])
83
+ end
84
+
85
+ it 'has an absolute top-right of [x+width,y]' do
86
+ expect(box.absolute_top_right).to eq([x + width, y])
87
+ end
88
+
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
+
102
+ describe 'drawing' do
103
+ it 'does not stomp on the arguments to bounding_box' do
104
+ pdf = Prawn::Document.new
105
+ x = [100, 500]
106
+ pdf.bounding_box x, width: 100 do
107
+ pdf.text 'bork-bork-bork'
108
+ end
109
+ expect(x).to eq([100, 500])
110
+ end
111
+
112
+ it 'restores Document#bounds to the correct margin box on exit' do
113
+ pdf = Prawn::Document.new(margin: 200)
114
+
115
+ # add a multi-page bounding box
116
+ pdf.bounding_box([100, pdf.bounds.top], width: 400) do
117
+ pdf.text "The rain in spain falls mainly in the plains.\n" * 30
118
+ end
119
+
120
+ pdf.start_new_page(margin: 0)
121
+
122
+ x_min, y_min, x_max, y_max = pdf.page.dimensions
123
+
124
+ expect(pdf.bounds.absolute_top_left).to eq([x_min, y_max])
125
+ expect(pdf.bounds.absolute_bottom_right).to eq([x_max, y_min])
126
+ end
127
+
128
+ it 'restores the parent bounding box when calls are nested' do
129
+ pdf.bounding_box [100, 500], width: 300, height: 300 do
130
+ expect(pdf.bounds.absolute_top)
131
+ .to eq(500 + pdf.margin_box.absolute_bottom)
132
+ expect(pdf.bounds.absolute_left)
133
+ .to eq(100 + pdf.margin_box.absolute_left)
134
+
135
+ parent_box = pdf.bounds
136
+
137
+ pdf.bounding_box [50, 200], width: 100, height: 100 do
138
+ expect(pdf.bounds.absolute_top)
139
+ .to eq(200 + parent_box.absolute_bottom)
140
+ expect(pdf.bounds.absolute_left).to eq(50 + parent_box.absolute_left)
141
+ end
142
+
143
+ expect(pdf.bounds.absolute_top)
144
+ .to eq(500 + pdf.margin_box.absolute_bottom)
145
+ expect(pdf.bounds.absolute_left)
146
+ .to eq(100 + pdf.margin_box.absolute_left)
147
+ end
148
+ end
149
+
150
+ it 'calculates a height if none is specified' do
151
+ pdf.bounding_box([100, 500], width: 100) do
152
+ pdf.text 'The rain in Spain falls mainly on the plains.'
153
+ end
154
+
155
+ expect(pdf.y).to be_within(0.001).of(458.384)
156
+ end
157
+
158
+ it 'keeps track of the max height the box was stretched to' do
159
+ box = pdf.bounding_box(pdf.bounds.top_left, width: 100) do
160
+ pdf.move_down 100
161
+ pdf.move_up 15
162
+ end
163
+
164
+ expect(box.height).to eq(100)
165
+ end
166
+
167
+ it 'advances the y-position by bbox.height by default' do
168
+ orig_y = pdf.y
169
+ pdf.bounding_box [0, pdf.cursor], width: pdf.bounds.width, height: 30 do
170
+ pdf.text 'hello'
171
+ end
172
+ expect(pdf.y).to be_within(0.001).of(orig_y - 30)
173
+ end
174
+
175
+ it 'does not advance y-position if passed :hold_position => true' do
176
+ orig_y = pdf.y
177
+ pdf.bounding_box(
178
+ [0, pdf.cursor],
179
+ width: pdf.bounds.width,
180
+ hold_position: true
181
+ ) do
182
+ pdf.text 'hello'
183
+ end
184
+ # y only advances by height of one line ("hello")
185
+ expect(pdf.y).to be_within(0.001).of(orig_y - pdf.height_of('hello'))
186
+ end
187
+
188
+ it 'does not advance y-position of a stretchy bbox if it would stretch '\
189
+ 'the bbox further' do
190
+ bottom = pdf.y = pdf.margin_box.absolute_bottom
191
+ pdf.bounding_box [0, pdf.margin_box.top], width: pdf.bounds.width do
192
+ pdf.y = bottom
193
+ pdf.text 'hello' # starts a new page
194
+ end
195
+ expect(pdf.page_count).to eq(2)
196
+
197
+ # Restoring the position (to the absolute bottom) would stretch the bbox
198
+ # to the bottom of the page, which we don't want. This should be
199
+ # equivalent to a bbox with :hold_position => true, where we only advance
200
+ # by the amount that was actually drawn.
201
+ expect(pdf.y).to be_within(0.001).of(
202
+ pdf.margin_box.absolute_top - pdf.height_of('hello')
203
+ )
204
+ end
205
+ end
206
+
207
+ describe 'Indentation' do
208
+ it 'temporarilies shift the x coordinate and width' do
209
+ pdf.bounding_box([100, 100], width: 200) do
210
+ pdf.indent(20) do
211
+ expect(pdf.bounds.absolute_left).to eq(120)
212
+ expect(pdf.bounds.width).to eq(180)
213
+ end
214
+ end
215
+ end
216
+
217
+ it 'restores the x coordinate and width after block exits' do
218
+ pdf.bounding_box([100, 100], width: 200) do
219
+ pdf.indent(20) do
220
+ # no-op
221
+ end
222
+ expect(pdf.bounds.absolute_left).to eq(100)
223
+ expect(pdf.bounds.width).to eq(200)
224
+ end
225
+ end
226
+
227
+ it 'restores the x coordinate and width on error' do
228
+ pdf.bounding_box([100, 100], width: 200) do
229
+ pdf.indent(20) { raise }
230
+ rescue StandardError
231
+ expect(pdf.bounds.absolute_left).to eq(100)
232
+ expect(pdf.bounds.width).to eq(200)
233
+ end
234
+ end
235
+
236
+ it 'maintains left indentation across a page break' do
237
+ original_left = pdf.bounds.absolute_left
238
+
239
+ pdf.indent(20) do
240
+ expect(pdf.bounds.absolute_left).to eq(original_left + 20)
241
+ pdf.start_new_page
242
+ expect(pdf.bounds.absolute_left).to eq(original_left + 20)
243
+ end
244
+
245
+ expect(pdf.bounds.absolute_left).to eq(original_left)
246
+ end
247
+
248
+ it 'maintains right indentation across a page break' do
249
+ original_width = pdf.bounds.width
250
+
251
+ pdf.indent(0, 20) do
252
+ expect(pdf.bounds.width).to eq(original_width - 20)
253
+ pdf.start_new_page
254
+ expect(pdf.bounds.width).to eq(original_width - 20)
255
+ end
256
+
257
+ expect(pdf.bounds.width).to eq(original_width)
258
+ end
259
+
260
+ it 'optionally allows adjustment of the right bound as well' do
261
+ pdf.bounding_box([100, 100], width: 200) do
262
+ pdf.indent(20, 30) do
263
+ expect(pdf.bounds.absolute_left).to eq(120)
264
+ expect(pdf.bounds.width).to eq(150)
265
+ end
266
+ expect(pdf.bounds.absolute_left).to eq(100)
267
+ expect(pdf.bounds.width).to eq(200)
268
+ end
269
+ end
270
+
271
+ describe 'in a ColumnBox' do
272
+ it 'subtracts the given indentation from the available width' do
273
+ pdf.column_box(
274
+ [0, pdf.cursor],
275
+ width: pdf.bounds.width,
276
+ height: 200,
277
+ columns: 2,
278
+ spacer: 20
279
+ ) do
280
+ width = pdf.bounds.width
281
+ pdf.indent(20) do
282
+ expect(pdf.bounds.width).to be_within(0.01).of(width - 20)
283
+ end
284
+ end
285
+ end
286
+
287
+ it 'subtracts right padding from the available width' do
288
+ pdf.column_box(
289
+ [0, pdf.cursor],
290
+ width: pdf.bounds.width,
291
+ height: 200,
292
+ columns: 2,
293
+ spacer: 20
294
+ ) do
295
+ width = pdf.bounds.width
296
+ pdf.indent(20, 30) do
297
+ expect(pdf.bounds.width).to be_within(0.01).of(width - 50)
298
+ end
299
+ end
300
+ end
301
+
302
+ it 'maintains the same left indentation across column breaks' do
303
+ pdf.column_box(
304
+ [0, pdf.cursor],
305
+ width: pdf.bounds.width,
306
+ columns: 3,
307
+ spacer: 15
308
+ ) do
309
+ 3.times do |_column|
310
+ x = pdf.bounds.left_side
311
+ pdf.indent(20) do
312
+ expect(pdf.bounds.left_side).to eq(x + 20)
313
+ end
314
+ pdf.bounds.move_past_bottom
315
+ end
316
+ end
317
+ end
318
+
319
+ it 'does not change the right margin if only left indentation is '\
320
+ 'requested' do
321
+ pdf.column_box(
322
+ [0, pdf.cursor],
323
+ width: pdf.bounds.width,
324
+ columns: 3,
325
+ spacer: 15
326
+ ) do
327
+ 3.times do |_column|
328
+ x = pdf.bounds.right_side
329
+ pdf.indent(20) do
330
+ expect(pdf.bounds.right_side).to eq(x)
331
+ end
332
+ pdf.bounds.move_past_bottom
333
+ end
334
+ end
335
+ end
336
+
337
+ it 'maintains the same right indentation across columns' do
338
+ pdf.column_box(
339
+ [0, pdf.cursor],
340
+ width: pdf.bounds.width,
341
+ columns: 3,
342
+ spacer: 15
343
+ ) do
344
+ 3.times do |_column|
345
+ x = pdf.bounds.right_side
346
+ pdf.indent(20, 10) do
347
+ expect(pdf.bounds.right_side).to eq(x - 10)
348
+ end
349
+ pdf.bounds.move_past_bottom
350
+ end
351
+ end
352
+ end
353
+
354
+ it 'keeps the right indentation after nesting indents' do
355
+ pdf.column_box(
356
+ [0, pdf.cursor],
357
+ width: pdf.bounds.width,
358
+ columns: 3,
359
+ spacer: 15
360
+ ) do
361
+ 3.times do |_column|
362
+ # I am giving a right indent of 10...
363
+ pdf.indent(20, 10) do
364
+ x = pdf.bounds.right_side
365
+ # ...and no right indent here...
366
+ pdf.indent(20) do
367
+ # right indent is inherited from the parent!
368
+ expect(pdf.bounds.right_side).to eq(x)
369
+ end
370
+ end
371
+ pdf.bounds.move_past_bottom
372
+ end
373
+ end
374
+ end
375
+
376
+ it 'reverts the right indentation if negative indent is given in '\
377
+ 'nested indent' do
378
+ pdf.column_box(
379
+ [0, pdf.cursor],
380
+ width: pdf.bounds.width,
381
+ columns: 3,
382
+ spacer: 15
383
+ ) do
384
+ 3.times do |_column|
385
+ x = pdf.bounds.right_side
386
+ pdf.indent(20, 10) do
387
+ # requesting a negative right-indent of equivalent size...
388
+ pdf.indent(20, -10) do
389
+ # ...resets the right margin to that of the column!
390
+ expect(pdf.bounds.right_side).to eq(x)
391
+ end
392
+ end
393
+ pdf.bounds.move_past_bottom
394
+ end
395
+ end
396
+ end
397
+
398
+ it 'reduces the available column width by the sum of ' \
399
+ 'all nested indents' do
400
+ pdf.column_box(
401
+ [0, pdf.cursor],
402
+ width: pdf.bounds.width,
403
+ columns: 3,
404
+ spacer: 15
405
+ ) do
406
+ 3.times do |_column|
407
+ w = pdf.bounds.width
408
+ pdf.indent(20, 10) do
409
+ pdf.indent(20, 10) do
410
+ expect(pdf.bounds.width).to eq(w - 60)
411
+ end
412
+ end
413
+ pdf.bounds.move_past_bottom
414
+ end
415
+ end
416
+ end
417
+ end
418
+ end
419
+
420
+ describe 'A canvas' do
421
+ it 'uses whatever the last set y position is' do
422
+ pdf.canvas do
423
+ pdf.bounding_box([100, 500], width: 200) { pdf.move_down 50 }
424
+ end
425
+ expect(pdf.y).to eq(450)
426
+ end
427
+
428
+ it 'restores the original ypos after execution', issue: 523 do
429
+ doc = Prawn::Document.new(skip_page_creation: true)
430
+ doc.start_new_page
431
+
432
+ original_ypos = doc.y
433
+
434
+ doc.canvas {}
435
+
436
+ expect(doc.y).to eq(original_ypos)
437
+ end
438
+ end
439
+
440
+ describe 'Deep-copying' do
441
+ it 'creates a new object that does not copy @document' do
442
+ Prawn::Document.new do |pdf|
443
+ orig = pdf.bounds
444
+ copy = orig.deep_copy
445
+
446
+ expect(copy).to_not eq(pdf.bounds)
447
+ expect(copy.document).to be_nil
448
+ end
449
+ end
450
+
451
+ it 'deep-copies parent bounds' do
452
+ Prawn::Document.new do |pdf|
453
+ outside = pdf.bounds
454
+ pdf.bounding_box [100, 100], width: 100 do
455
+ copy = pdf.bounds.deep_copy
456
+
457
+ # the parent bounds should have the same parameters
458
+ expect(copy.parent.width).to eq(outside.width)
459
+ expect(copy.parent.height).to eq(outside.height)
460
+
461
+ # but should not be the same object
462
+ expect(copy.parent).to_not eq(outside)
463
+ end
464
+ end
465
+ end
466
+ end
467
+
468
+ describe 'Prawn::Document#reference_bounds' do
469
+ it 'returns self for non-stretchy bounds' do
470
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
471
+ expect(pdf.reference_bounds).to eq(pdf.bounds)
472
+ end
473
+ end
474
+
475
+ it 'returns the parent bounds if in a stretchy box' do
476
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
477
+ correct_bounds = pdf.bounds
478
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
479
+ expect(pdf.reference_bounds).to eq(correct_bounds)
480
+ end
481
+ end
482
+ end
483
+
484
+ it 'finds the non-stretchy box through 2 levels' do
485
+ pdf.bounding_box([0, pdf.cursor], width: 100, height: 100) do
486
+ correct_bounds = pdf.bounds
487
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
488
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
489
+ expect(pdf.reference_bounds).to eq(correct_bounds)
490
+ end
491
+ end
492
+ end
493
+ end
494
+
495
+ it "returns the margin box if there's no explicit bbox" do
496
+ expect(pdf.reference_bounds).to eq(pdf.margin_box)
497
+
498
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
499
+ expect(pdf.reference_bounds).to eq(pdf.margin_box)
500
+ end
501
+ end
502
+
503
+ it "returns the canvas box if we're in a canvas" do
504
+ pdf.canvas do
505
+ canvas_box = pdf.bounds
506
+
507
+ expect(pdf.reference_bounds).to eq(canvas_box)
508
+
509
+ pdf.bounding_box([0, pdf.cursor], width: 100) do
510
+ expect(pdf.reference_bounds).to eq(canvas_box)
511
+ end
512
+ end
513
+ end
514
+ end
515
+
516
+ describe '#move_past_bottom' do
517
+ it 'ordinarilies start a new page' do
518
+ pdf.bounds.move_past_bottom
519
+ pdf.text 'Foo'
520
+
521
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
522
+ expect(pages.size).to eq(2)
523
+ expect(pages[0][:strings]).to eq([])
524
+ expect(pages[1][:strings]).to eq(['Foo'])
525
+ end
526
+
527
+ it 'moves to the top of the next page if it exists already' do
528
+ # save away the y-position at the top of a page
529
+ top_y = pdf.y
530
+
531
+ # create a blank page but go to the page before it
532
+ pdf.start_new_page
533
+ pdf.go_to_page 1
534
+ pdf.text 'Foo'
535
+
536
+ pdf.bounds.move_past_bottom
537
+ expect(pdf.y).to be_within(0.001).of(top_y)
538
+ pdf.text 'Bar'
539
+
540
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
541
+ expect(pages.size).to eq(2)
542
+ expect(pages[0][:strings]).to eq(['Foo'])
543
+ expect(pages[1][:strings]).to eq(['Bar'])
544
+ end
545
+ end
546
+ end