pdf_tempura 0.0.2
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.
- checksums.yaml +15 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +342 -0
- data/Rakefile +1 -0
- data/example/my_pdf.rb +37 -0
- data/lib/pdf_tempura.rb +8 -0
- data/lib/pdf_tempura/document.rb +121 -0
- data/lib/pdf_tempura/document/boxed_characters.rb +70 -0
- data/lib/pdf_tempura/document/boxed_characters/groups.rb +53 -0
- data/lib/pdf_tempura/document/character_field.rb +37 -0
- data/lib/pdf_tempura/document/checkbox_field.rb +15 -0
- data/lib/pdf_tempura/document/default_commands.rb +40 -0
- data/lib/pdf_tempura/document/field/base.rb +55 -0
- data/lib/pdf_tempura/document/field_set.rb +51 -0
- data/lib/pdf_tempura/document/page.rb +33 -0
- data/lib/pdf_tempura/document/table.rb +95 -0
- data/lib/pdf_tempura/document/table/boxed_character_column.rb +20 -0
- data/lib/pdf_tempura/document/table/checkbox_column.rb +9 -0
- data/lib/pdf_tempura/document/table/column.rb +18 -0
- data/lib/pdf_tempura/document/table/spacer.rb +13 -0
- data/lib/pdf_tempura/document/table/text_column.rb +9 -0
- data/lib/pdf_tempura/document/text_field.rb +18 -0
- data/lib/pdf_tempura/document/validation.rb +79 -0
- data/lib/pdf_tempura/extensions/hash/stringify_keys.rb +35 -0
- data/lib/pdf_tempura/render.rb +18 -0
- data/lib/pdf_tempura/render/boxed_characters.rb +42 -0
- data/lib/pdf_tempura/render/character_field.rb +49 -0
- data/lib/pdf_tempura/render/checkbox_field.rb +35 -0
- data/lib/pdf_tempura/render/debug.rb +16 -0
- data/lib/pdf_tempura/render/debug/annotation/base.rb +83 -0
- data/lib/pdf_tempura/render/debug/character_field_annotation.rb +13 -0
- data/lib/pdf_tempura/render/debug/checkbox_field_annotation.rb +24 -0
- data/lib/pdf_tempura/render/debug/field_set_annotation.rb +23 -0
- data/lib/pdf_tempura/render/debug/grid.rb +59 -0
- data/lib/pdf_tempura/render/debug/outside_annotation.rb +42 -0
- data/lib/pdf_tempura/render/debug/table_annotation.rb +19 -0
- data/lib/pdf_tempura/render/debug/text_field_annotation.rb +42 -0
- data/lib/pdf_tempura/render/field.rb +40 -0
- data/lib/pdf_tempura/render/field_bounds.rb +26 -0
- data/lib/pdf_tempura/render/field_data_mapper.rb +15 -0
- data/lib/pdf_tempura/render/field_set.rb +31 -0
- data/lib/pdf_tempura/render/option_access.rb +21 -0
- data/lib/pdf_tempura/render/page.rb +23 -0
- data/lib/pdf_tempura/render/table.rb +35 -0
- data/lib/pdf_tempura/render/text_field.rb +13 -0
- data/lib/pdf_tempura/renderer.rb +39 -0
- data/lib/pdf_tempura/version.rb +3 -0
- data/pdf_tempura.gemspec +27 -0
- data/spec/assets/sample_pdf_form.odg +0 -0
- data/spec/assets/sample_pdf_form.pdf +0 -0
- data/spec/integration_spec.rb +88 -0
- data/spec/lib/pdf_tempura/document/boxed_characters_spec.rb +125 -0
- data/spec/lib/pdf_tempura/document/checkbox_field_spec.rb +54 -0
- data/spec/lib/pdf_tempura/document/field_common.rb +12 -0
- data/spec/lib/pdf_tempura/document/field_set_spec.rb +38 -0
- data/spec/lib/pdf_tempura/document/page_spec.rb +57 -0
- data/spec/lib/pdf_tempura/document/table_spec.rb +161 -0
- data/spec/lib/pdf_tempura/document/text_field_spec.rb +195 -0
- data/spec/lib/pdf_tempura/document_spec.rb +131 -0
- data/spec/lib/pdf_tempura/extensions/hash/stringify_keys_spec.rb +42 -0
- data/spec/lib/pdf_tempura/render/boxed_characters_spec.rb +68 -0
- data/spec/lib/pdf_tempura/render/checkbox_field_spec.rb +39 -0
- data/spec/lib/pdf_tempura/render/debug/annotation_renderer/base_spec.rb +45 -0
- data/spec/lib/pdf_tempura/render/debug/checkbox_field_annotation_spec.rb +45 -0
- data/spec/lib/pdf_tempura/render/debug/grid_spec.rb +15 -0
- data/spec/lib/pdf_tempura/render/debug/text_field_annotation_spec.rb +46 -0
- data/spec/lib/pdf_tempura/render/field_data_mapper_spec.rb +31 -0
- data/spec/lib/pdf_tempura/render/field_set_spec.rb +41 -0
- data/spec/lib/pdf_tempura/render/field_spec.rb +37 -0
- data/spec/lib/pdf_tempura/render/page_spec.rb +77 -0
- data/spec/lib/pdf_tempura/render/table_spec.rb +44 -0
- data/spec/lib/pdf_tempura/render/text_field_spec.rb +39 -0
- data/spec/lib/pdf_tempura/renderer_spec.rb +79 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/shared_examples/field_examples.rb +265 -0
- metadata +219 -0
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfTempura::Document do
|
4
|
+
|
5
|
+
let(:dummy_class) do
|
6
|
+
Class.new(described_class)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#new" do
|
10
|
+
let(:data) do
|
11
|
+
{
|
12
|
+
1 => {
|
13
|
+
first_name: "Stan",
|
14
|
+
surname: "Smith",
|
15
|
+
company: "CIA",
|
16
|
+
address: "The Pentagon, Washington, DC"
|
17
|
+
},
|
18
|
+
2 => {
|
19
|
+
emergency_contact: "Francine Smith",
|
20
|
+
phone_number: "123-456-7890"
|
21
|
+
},
|
22
|
+
"3" => {
|
23
|
+
pin: "123456"
|
24
|
+
}
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
before :each do
|
29
|
+
dummy_class.page(1){}
|
30
|
+
dummy_class.page(2){}
|
31
|
+
dummy_class.page(3){}
|
32
|
+
end
|
33
|
+
|
34
|
+
it "loads the data into each correct page" do
|
35
|
+
document = dummy_class.new(data)
|
36
|
+
|
37
|
+
document.pages.first.data.should == {
|
38
|
+
"first_name" => "Stan",
|
39
|
+
"surname" => "Smith",
|
40
|
+
"company" => "CIA",
|
41
|
+
"address" => "The Pentagon, Washington, DC"
|
42
|
+
}
|
43
|
+
|
44
|
+
document.pages[1].data.should == {
|
45
|
+
"emergency_contact" => "Francine Smith",
|
46
|
+
"phone_number" => "123-456-7890"
|
47
|
+
}
|
48
|
+
|
49
|
+
document.pages[2].data.should == {
|
50
|
+
"pin" => "123456"
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
it "doesn't modify the class level pages" do
|
55
|
+
dummy_class.new(data)
|
56
|
+
dummy_class.pages.first.data.should == {}
|
57
|
+
dummy_class.pages.last.data.should == {}
|
58
|
+
end
|
59
|
+
|
60
|
+
context "too many pages" do
|
61
|
+
let(:data) do
|
62
|
+
{
|
63
|
+
1 => {},
|
64
|
+
2 => {},
|
65
|
+
3 => {},
|
66
|
+
4 => {}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
it "complains" do
|
70
|
+
expect { dummy_class.new(data)}.to raise_exception("There are more pages in the data than pages defined. Use 'repeatable' to repeat template pages in the document class.")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe ".template" do
|
76
|
+
it "sets the template file path" do
|
77
|
+
dummy_class.template "/some/path/to/template.pdf"
|
78
|
+
dummy_class.template_file_path.should == "/some/path/to/template.pdf"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "raises an argument error if you send it something that's not a string" do
|
82
|
+
expect{
|
83
|
+
dummy_class.template [123]
|
84
|
+
}.to raise_error ArgumentError, "Template path must be a string."
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe ".page" do
|
89
|
+
let(:page){ PdfTempura::Document::Page.new(200) }
|
90
|
+
|
91
|
+
it "yield a page object" do
|
92
|
+
expect{ |block|
|
93
|
+
dummy_class.page(200, &block)
|
94
|
+
}.to yield_with_args(page)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "passed method calls on to the new page object" do
|
98
|
+
PdfTempura::Document::Page.any_instance.should_receive(:fields)
|
99
|
+
|
100
|
+
dummy_class.page(200) do
|
101
|
+
fields
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "adds the page object to the pages list" do
|
106
|
+
expect{
|
107
|
+
dummy_class.page(200){}
|
108
|
+
}.to change(dummy_class.pages, :count).by(1)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe ".pages" do
|
113
|
+
it "returns an array" do
|
114
|
+
dummy_class.pages.should be_a(Array)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe ".debug" do
|
119
|
+
it "stores the debug options" do
|
120
|
+
dummy_class.debug :grid, :outlines
|
121
|
+
dummy_class.debug_options.should == [:grid, :outlines]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
describe ".debug_options" do
|
126
|
+
it "returns an array" do
|
127
|
+
dummy_class.pages.should be_a(Array)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfTempura::Extensions::Hash::StringifyKeys do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
{
|
7
|
+
foo: true,
|
8
|
+
bar: {
|
9
|
+
blah: "abc"
|
10
|
+
},
|
11
|
+
woo: [
|
12
|
+
1,
|
13
|
+
{
|
14
|
+
blorgh: false
|
15
|
+
}
|
16
|
+
]
|
17
|
+
}.extend(described_class)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#stringify_keys" do
|
21
|
+
example do
|
22
|
+
result = subject.stringify_keys
|
23
|
+
result["foo"].should be_true
|
24
|
+
result["bar"].should == { "blah" => "abc" }
|
25
|
+
result["woo"].should == [1, { "blorgh" => false }]
|
26
|
+
|
27
|
+
subject["foo"].should be_nil
|
28
|
+
subject["bar"].should be_nil
|
29
|
+
subject["woo"].should be_nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#stringify_keys!" do
|
34
|
+
example do
|
35
|
+
subject.stringify_keys!
|
36
|
+
subject["foo"].should be_true
|
37
|
+
subject["bar"].should == { "blah" => "abc" }
|
38
|
+
subject["woo"].should == [1, { "blorgh" => false }]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfTempura::Render::BoxedCharacters do
|
4
|
+
|
5
|
+
let(:field_options) {{box_width: 10, box_spacing: 2}}
|
6
|
+
let(:field) {
|
7
|
+
PdfTempura::Document::BoxedCharacters.new(:pin,[0,0],20,field_options) do
|
8
|
+
characters 2
|
9
|
+
space 2
|
10
|
+
characters 8
|
11
|
+
space 2
|
12
|
+
characters 2
|
13
|
+
end
|
14
|
+
}
|
15
|
+
let(:data) { "228888888822" }
|
16
|
+
let(:pdf) { Prawn::Document.new }
|
17
|
+
let(:options) { {} }
|
18
|
+
|
19
|
+
describe "init" do
|
20
|
+
example do
|
21
|
+
|
22
|
+
expect {
|
23
|
+
described_class.new(field, data, options)
|
24
|
+
}.not_to raise_exception
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "render" do
|
29
|
+
|
30
|
+
context "with appropriate data" do
|
31
|
+
it "renders each field with the appropriate data" do
|
32
|
+
expect {
|
33
|
+
described_class.new(field,data,options).render(pdf)
|
34
|
+
}.not_to raise_exception
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "with nil data" do
|
39
|
+
let(:data) {nil}
|
40
|
+
it "assumes an empty string and still renders without error" do
|
41
|
+
expect {
|
42
|
+
described_class.new(field,data,options).render(pdf)
|
43
|
+
}.not_to raise_exception
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "with inappropriate data" do
|
48
|
+
let(:data) {"123456789101112"}
|
49
|
+
it "throws an argument error if truncate not specified" do
|
50
|
+
expect {
|
51
|
+
described_class.new(field,data,options).render(pdf)
|
52
|
+
}.to raise_error ArgumentError, "Data for pin must be exactly 12 characters or use the truncate option."
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when truncate is specified" do
|
56
|
+
let(:field_options) {{box_width: 10, box_spacing: 2, truncate: true}}
|
57
|
+
it "renders without error" do
|
58
|
+
expect {
|
59
|
+
described_class.new(field,data,options).render(pdf)
|
60
|
+
}.not_to raise_exception
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfTempura::Render::CheckboxField do
|
4
|
+
|
5
|
+
let(:field) { PdfTempura::Document::CheckboxField.new("foo", [0,0], [100,100]) }
|
6
|
+
let(:options) { {} }
|
7
|
+
let(:pdf) { Prawn::Document.new }
|
8
|
+
|
9
|
+
describe "initialize" do
|
10
|
+
example do
|
11
|
+
expect {
|
12
|
+
described_class.new(field, "foo", options)
|
13
|
+
}.not_to raise_exception
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#render" do
|
18
|
+
|
19
|
+
subject { described_class.new(field, "foo", options) }
|
20
|
+
|
21
|
+
describe "calling the annotation drawing code when enabled" do
|
22
|
+
let(:options) do
|
23
|
+
{
|
24
|
+
:debug => [:outlines]
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:annotation_renderer) { double(:annotation_renderer) }
|
29
|
+
|
30
|
+
example do
|
31
|
+
PdfTempura::Render::Debug::CheckboxFieldAnnotation.should_receive(:new).with(field).and_return(annotation_renderer)
|
32
|
+
annotation_renderer.should_receive(:render).with(pdf)
|
33
|
+
subject.render(pdf)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfTempura::Render::Debug::Annotation::Base do
|
4
|
+
|
5
|
+
let(:pdf) { Prawn::Document.new }
|
6
|
+
let(:field) { PdfTempura::Document::TextField.new("foo", [0,0], [100,100]) }
|
7
|
+
|
8
|
+
subject { described_class.new(field) }
|
9
|
+
|
10
|
+
describe "#render" do
|
11
|
+
context "if field_options is not defined" do
|
12
|
+
example do
|
13
|
+
expect{
|
14
|
+
subject.render(pdf)
|
15
|
+
}.to raise_error NotImplementedError, "Implement field_options in your subclass."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "if label_options is not defined" do
|
20
|
+
before :each do
|
21
|
+
subject.stub(:field_options){ {} }
|
22
|
+
end
|
23
|
+
|
24
|
+
example do
|
25
|
+
expect{
|
26
|
+
subject.render(pdf)
|
27
|
+
}.to raise_error NotImplementedError, "Implement label_options in your subclass."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "if both are defined" do
|
32
|
+
before :each do
|
33
|
+
subject.stub(:field_options){ {} }
|
34
|
+
subject.stub(:label_options){ {} }
|
35
|
+
end
|
36
|
+
|
37
|
+
example do
|
38
|
+
expect{
|
39
|
+
subject.render(pdf)
|
40
|
+
}.to_not raise_error
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfTempura::Render::Debug::CheckboxFieldAnnotation do
|
4
|
+
|
5
|
+
let(:pdf) { Prawn::Document.new }
|
6
|
+
let(:field) { PdfTempura::Document::CheckboxField.new("foo", [0,0], [100,100]) }
|
7
|
+
|
8
|
+
let(:field_options) do
|
9
|
+
{
|
10
|
+
at: [1, 116],
|
11
|
+
width: 400,
|
12
|
+
height: 98,
|
13
|
+
valign: :top
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:label_options) do
|
18
|
+
{
|
19
|
+
at: [1, 91],
|
20
|
+
width: 98,
|
21
|
+
height: 98,
|
22
|
+
valign: :bottom,
|
23
|
+
align: :left,
|
24
|
+
single_line: true
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
subject { described_class.new(field) }
|
29
|
+
|
30
|
+
describe "#render" do
|
31
|
+
example do
|
32
|
+
expect{
|
33
|
+
subject.render(pdf)
|
34
|
+
}.to_not raise_error
|
35
|
+
end
|
36
|
+
|
37
|
+
example do
|
38
|
+
pdf.should_receive(:text_box).once.with("x: 0 y: 0 w: 100 h: 100", field_options)
|
39
|
+
pdf.should_receive(:text_box).once.with("foo", label_options)
|
40
|
+
subject.render(pdf)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfTempura::Render::Debug::TextFieldAnnotation do
|
4
|
+
|
5
|
+
let(:pdf) { Prawn::Document.new }
|
6
|
+
let(:field) { PdfTempura::Document::TextField.new("foo", [0,0], [100,100]) }
|
7
|
+
|
8
|
+
let(:field_options) do
|
9
|
+
{
|
10
|
+
at: [1, 99],
|
11
|
+
width: 98,
|
12
|
+
height: 98,
|
13
|
+
valign: :top,
|
14
|
+
single_line: true
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:label_options) do
|
19
|
+
{
|
20
|
+
at: [1, 99],
|
21
|
+
width: 98,
|
22
|
+
height: 98,
|
23
|
+
valign: :bottom,
|
24
|
+
align: :right,
|
25
|
+
single_line: true
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
subject { described_class.new(field) }
|
30
|
+
|
31
|
+
describe "#render" do
|
32
|
+
example do
|
33
|
+
expect{
|
34
|
+
subject.render(pdf)
|
35
|
+
}.to_not raise_error
|
36
|
+
end
|
37
|
+
|
38
|
+
example do
|
39
|
+
pdf.should_receive(:text_box).once.with("x: 0 y: 0 w: 100 h: 100", field_options)
|
40
|
+
pdf.should_receive(:text_box).once.with("foo", label_options)
|
41
|
+
subject.render(pdf)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfTempura::Render::FieldDataMapper do
|
4
|
+
|
5
|
+
let(:fields) do
|
6
|
+
[
|
7
|
+
PdfTempura::Document::TextField.new("one", [0,0], [0,0]),
|
8
|
+
PdfTempura::Document::TextField.new("bar", [0,0], [0,0]),
|
9
|
+
PdfTempura::Document::TextField.new("baz", [0,0], [0,0]),
|
10
|
+
]
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:data) do
|
14
|
+
{
|
15
|
+
"one" => "a1",
|
16
|
+
"bar" => "a2",
|
17
|
+
"bla" => "a4",
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".map" do
|
22
|
+
example do
|
23
|
+
described_class.map(fields, data).should == {
|
24
|
+
fields[0] => "a1",
|
25
|
+
fields[1] => "a2",
|
26
|
+
fields[2] => nil,
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|