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