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.
Files changed (80) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +18 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +5 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +342 -0
  8. data/Rakefile +1 -0
  9. data/example/my_pdf.rb +37 -0
  10. data/lib/pdf_tempura.rb +8 -0
  11. data/lib/pdf_tempura/document.rb +121 -0
  12. data/lib/pdf_tempura/document/boxed_characters.rb +70 -0
  13. data/lib/pdf_tempura/document/boxed_characters/groups.rb +53 -0
  14. data/lib/pdf_tempura/document/character_field.rb +37 -0
  15. data/lib/pdf_tempura/document/checkbox_field.rb +15 -0
  16. data/lib/pdf_tempura/document/default_commands.rb +40 -0
  17. data/lib/pdf_tempura/document/field/base.rb +55 -0
  18. data/lib/pdf_tempura/document/field_set.rb +51 -0
  19. data/lib/pdf_tempura/document/page.rb +33 -0
  20. data/lib/pdf_tempura/document/table.rb +95 -0
  21. data/lib/pdf_tempura/document/table/boxed_character_column.rb +20 -0
  22. data/lib/pdf_tempura/document/table/checkbox_column.rb +9 -0
  23. data/lib/pdf_tempura/document/table/column.rb +18 -0
  24. data/lib/pdf_tempura/document/table/spacer.rb +13 -0
  25. data/lib/pdf_tempura/document/table/text_column.rb +9 -0
  26. data/lib/pdf_tempura/document/text_field.rb +18 -0
  27. data/lib/pdf_tempura/document/validation.rb +79 -0
  28. data/lib/pdf_tempura/extensions/hash/stringify_keys.rb +35 -0
  29. data/lib/pdf_tempura/render.rb +18 -0
  30. data/lib/pdf_tempura/render/boxed_characters.rb +42 -0
  31. data/lib/pdf_tempura/render/character_field.rb +49 -0
  32. data/lib/pdf_tempura/render/checkbox_field.rb +35 -0
  33. data/lib/pdf_tempura/render/debug.rb +16 -0
  34. data/lib/pdf_tempura/render/debug/annotation/base.rb +83 -0
  35. data/lib/pdf_tempura/render/debug/character_field_annotation.rb +13 -0
  36. data/lib/pdf_tempura/render/debug/checkbox_field_annotation.rb +24 -0
  37. data/lib/pdf_tempura/render/debug/field_set_annotation.rb +23 -0
  38. data/lib/pdf_tempura/render/debug/grid.rb +59 -0
  39. data/lib/pdf_tempura/render/debug/outside_annotation.rb +42 -0
  40. data/lib/pdf_tempura/render/debug/table_annotation.rb +19 -0
  41. data/lib/pdf_tempura/render/debug/text_field_annotation.rb +42 -0
  42. data/lib/pdf_tempura/render/field.rb +40 -0
  43. data/lib/pdf_tempura/render/field_bounds.rb +26 -0
  44. data/lib/pdf_tempura/render/field_data_mapper.rb +15 -0
  45. data/lib/pdf_tempura/render/field_set.rb +31 -0
  46. data/lib/pdf_tempura/render/option_access.rb +21 -0
  47. data/lib/pdf_tempura/render/page.rb +23 -0
  48. data/lib/pdf_tempura/render/table.rb +35 -0
  49. data/lib/pdf_tempura/render/text_field.rb +13 -0
  50. data/lib/pdf_tempura/renderer.rb +39 -0
  51. data/lib/pdf_tempura/version.rb +3 -0
  52. data/pdf_tempura.gemspec +27 -0
  53. data/spec/assets/sample_pdf_form.odg +0 -0
  54. data/spec/assets/sample_pdf_form.pdf +0 -0
  55. data/spec/integration_spec.rb +88 -0
  56. data/spec/lib/pdf_tempura/document/boxed_characters_spec.rb +125 -0
  57. data/spec/lib/pdf_tempura/document/checkbox_field_spec.rb +54 -0
  58. data/spec/lib/pdf_tempura/document/field_common.rb +12 -0
  59. data/spec/lib/pdf_tempura/document/field_set_spec.rb +38 -0
  60. data/spec/lib/pdf_tempura/document/page_spec.rb +57 -0
  61. data/spec/lib/pdf_tempura/document/table_spec.rb +161 -0
  62. data/spec/lib/pdf_tempura/document/text_field_spec.rb +195 -0
  63. data/spec/lib/pdf_tempura/document_spec.rb +131 -0
  64. data/spec/lib/pdf_tempura/extensions/hash/stringify_keys_spec.rb +42 -0
  65. data/spec/lib/pdf_tempura/render/boxed_characters_spec.rb +68 -0
  66. data/spec/lib/pdf_tempura/render/checkbox_field_spec.rb +39 -0
  67. data/spec/lib/pdf_tempura/render/debug/annotation_renderer/base_spec.rb +45 -0
  68. data/spec/lib/pdf_tempura/render/debug/checkbox_field_annotation_spec.rb +45 -0
  69. data/spec/lib/pdf_tempura/render/debug/grid_spec.rb +15 -0
  70. data/spec/lib/pdf_tempura/render/debug/text_field_annotation_spec.rb +46 -0
  71. data/spec/lib/pdf_tempura/render/field_data_mapper_spec.rb +31 -0
  72. data/spec/lib/pdf_tempura/render/field_set_spec.rb +41 -0
  73. data/spec/lib/pdf_tempura/render/field_spec.rb +37 -0
  74. data/spec/lib/pdf_tempura/render/page_spec.rb +77 -0
  75. data/spec/lib/pdf_tempura/render/table_spec.rb +44 -0
  76. data/spec/lib/pdf_tempura/render/text_field_spec.rb +39 -0
  77. data/spec/lib/pdf_tempura/renderer_spec.rb +79 -0
  78. data/spec/spec_helper.rb +29 -0
  79. data/spec/support/shared_examples/field_examples.rb +265 -0
  80. metadata +219 -0
@@ -0,0 +1,12 @@
1
+ shared_examples "a document field methods" do
2
+
3
+ describe "method expectations" do
4
+ it { should respond_to(:x) }
5
+ it { should respond_to(:y) }
6
+ it { should respond_to(:width) }
7
+ it { should respond_to(:height) }
8
+ it { should respond_to(:name) }
9
+ it { should respond_to(:padding) }
10
+ end
11
+
12
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe PdfTempura::Document::FieldSet do
4
+
5
+ let(:group_name) { "group" }
6
+ subject{ described_class.new(group_name) }
7
+ it_behaves_like "a field that accepts default commands"
8
+
9
+ describe "#new" do
10
+ it "should have no fields" do
11
+ subject = described_class.new(group_name)
12
+ subject.fields.should be_empty
13
+ end
14
+
15
+ it "should yield" do
16
+ expect { |b|
17
+ described_class.new(group_name,&b)
18
+ }.to yield_control
19
+ end
20
+ end
21
+
22
+ describe "coordinate calculation" do
23
+ it "calculates correct coordinates with one and two text fields" do
24
+ subject.text_field :name,[5,30],[20,20]
25
+ subject.width.should == 20
26
+ subject.x.should == 5
27
+ subject.y.should == 30
28
+ subject.height.should == 20
29
+
30
+ subject.text_field :bar,[0,30], [50,10]
31
+ subject.width.should == 50
32
+ subject.height.should == 20
33
+ subject.x.should == 0
34
+ subject.y.should == 30
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe PdfTempura::Document::Page do
4
+
5
+ subject{ described_class.new(100) }
6
+
7
+ its(:number){ should == 100 }
8
+ its(:fields){ should == [] }
9
+
10
+ it_behaves_like "a field that accepts default commands"
11
+
12
+ describe "#validation" do
13
+
14
+ context "when passed an invalid page number" do
15
+ it "raise an argument error" do
16
+ expect{
17
+ described_class.new("one")
18
+ }.to raise_error ArgumentError, "Number must be of type Numeric."
19
+ end
20
+ end
21
+
22
+ context "when passed a valid page number" do
23
+ it "returns a Page object" do
24
+ described_class.new(1).should be_a(described_class)
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ describe "#==" do
31
+ context "when they have the same page number" do
32
+ let(:other){ described_class.new(100) }
33
+
34
+ it{ should == other }
35
+ end
36
+
37
+ context "when they have different page numbers" do
38
+ let(:other){ described_class.new(200) }
39
+
40
+ it{ should_not == other }
41
+ end
42
+ end
43
+
44
+ describe "#data" do
45
+ let(:data){ { woo: "yes"} }
46
+
47
+ it "returns an empty hash when it has no data" do
48
+ subject.data == {}
49
+ end
50
+
51
+ it "returns the data" do
52
+ subject.data = { name: "Bruce" }
53
+ subject.data.should == { "name" => "Bruce" }
54
+ end
55
+ end
56
+
57
+ end
@@ -0,0 +1,161 @@
1
+ require 'spec_helper'
2
+ require_relative 'field_common'
3
+
4
+ describe PdfTempura::Document::Table do
5
+
6
+ context "interface test" do
7
+ subject { described_class.new("foo", [0,0], height: 100, number_of_rows: 10) }
8
+ it_should_behave_like "a document field methods"
9
+ end
10
+
11
+ describe "init" do
12
+
13
+ let(:name) { :table }
14
+ let(:origin) { [0,0] }
15
+ let(:options) { {} }
16
+ let(:valid_options) { {height: 100, row_height: 10, number_of_rows: 10}}
17
+
18
+ describe "option validation" do
19
+ shared_examples "failing option test" do
20
+ it "should complain" do
21
+ expect {
22
+ described_class.new(name, origin, options)
23
+ }.to raise_exception(ArgumentError, "You must pass number_of_rows and either height or row_height")
24
+ end
25
+ end
26
+
27
+ context "only number_of_rows is passed" do
28
+ let(:options) { {:number_of_rows => 10} }
29
+ it_should_behave_like "failing option test"
30
+ end
31
+
32
+ context "only height is passed" do
33
+ let(:options) { {:height => 100} }
34
+ it_should_behave_like "failing option test"
35
+ end
36
+
37
+ context "only row_height is passed" do
38
+ let(:options) { {:row_height => 10} }
39
+ it_should_behave_like "failing option test"
40
+ end
41
+
42
+ end
43
+
44
+ context "valid options" do
45
+ shared_examples "passing options" do
46
+ it "should not complain" do
47
+ expect {
48
+ described_class.new(name, origin, options)
49
+ }.not_to raise_exception
50
+ end
51
+
52
+ it "should be 100 tall with 10 row_height" do
53
+ subject = described_class.new(name,origin,options)
54
+ subject.height.should == 100
55
+ subject.row_height.should == 10
56
+ end
57
+ end
58
+
59
+ context "height and number of rows" do
60
+ let(:options) {{ height: 100, number_of_rows: 10}}
61
+ it_should_behave_like "passing options"
62
+ end
63
+
64
+ context "row_height and number of rows" do
65
+ let(:options) {{ row_height: 10, number_of_rows: 10}}
66
+ it_should_behave_like "passing options"
67
+ end
68
+ end
69
+
70
+
71
+ describe "yielding" do
72
+ it "should yield" do
73
+ expect { |b| described_class.new(name,origin,valid_options,&b)}.to yield_control
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "#text_column" do
79
+ let(:options) { {height: 100, number_of_rows: 10} }
80
+ let(:subject) { described_class.new(:table,[0,0],options)}
81
+
82
+ it "should add a column to the table" do
83
+ subject.text_column(:pin, 50)
84
+ subject.columns.count.should == 1
85
+ subject.columns.first.should be_kind_of(PdfTempura::Document::Table::TextColumn)
86
+ end
87
+ end
88
+
89
+ describe "#checkbox_column" do
90
+ let(:options) { {height: 100, number_of_rows: 10} }
91
+ let(:subject) { described_class.new(:table,[0,0],options)}
92
+
93
+ it "should add a column to the table" do
94
+ subject.checkbox_column(:pin, 50)
95
+ subject.columns.count.should == 1
96
+ subject.columns.first.should be_kind_of(PdfTempura::Document::Table::CheckboxColumn)
97
+ end
98
+
99
+ it "should get a field at the correct coordinates" do
100
+ subject.checkbox_column(:pin,50)
101
+ field = subject.columns.first.field_at([50,50])
102
+ field.coordinates.should == [50,50]
103
+ field.dimensions.should == [50,10]
104
+ end
105
+
106
+ end
107
+
108
+ describe ".boxed_character_column" do
109
+ let(:options) { {height: 100, number_of_rows: 10} }
110
+ let(:subject) { described_class.new(:table,[0,0],options)}
111
+
112
+ it "should add a column to the table" do
113
+ subject.boxed_character_column(:pin, box_width: 10, box_spacing: 1)
114
+ subject.columns.count.should == 1
115
+ subject.columns.first.should be_kind_of(PdfTempura::Document::Table::BoxedCharacterColumn)
116
+ end
117
+ end
118
+
119
+ describe "#space" do
120
+ let(:options) { {height: 100, number_of_rows: 10} }
121
+ let(:subject) { described_class.new(:table,[0,0],options)}
122
+
123
+ it "should add a space to the table" do
124
+ subject.space(5)
125
+ subject.columns.count.should == 1
126
+ subject.columns.first.should be_kind_of(PdfTempura::Document::Table::Spacer)
127
+ end
128
+ end
129
+
130
+ describe "#width" do
131
+ subject { described_class.new(:table,[0,0],options) }
132
+
133
+ context "no padding" do
134
+ let(:options) { {height: 100, number_of_rows: 10} }
135
+
136
+ it "calculates width correctly" do
137
+ subject.text_column :a,10
138
+ subject.width.should == 10
139
+ subject.text_column :b,15
140
+ subject.width.should == 25
141
+ subject.space 5
142
+ subject.width.should == 30
143
+ end
144
+ end
145
+
146
+ context "with padding" do
147
+ let(:options) { {height: 100, number_of_rows: 10, cell_padding: 2} }
148
+
149
+ it "calculates width correctly" do
150
+ subject.text_column :a,10
151
+ subject.width.should == 10
152
+ subject.text_column :b,15
153
+ subject.width.should == 27
154
+ subject.space 5
155
+ subject.width.should == 34
156
+ end
157
+
158
+ end
159
+ end
160
+ end
161
+
@@ -0,0 +1,195 @@
1
+ require 'spec_helper'
2
+
3
+ describe PdfTempura::Document::TextField do
4
+
5
+ it_behaves_like "a document field"
6
+
7
+ let(:name){ :text_field }
8
+ let(:coordinates){ [10, 20] }
9
+ let(:dimensions){ [200, 100] }
10
+ let(:default_value){ "Bruce" }
11
+
12
+ let(:options) do
13
+ {
14
+ default_value: default_value,
15
+ font_name: font_name,
16
+ font_size: font_size,
17
+ bold: bold,
18
+ italic: italic,
19
+ alignment: alignment,
20
+ multi_line: multi_line,
21
+ padding: padding,
22
+ valign: valign,
23
+ leading: leading
24
+ }
25
+ end
26
+
27
+ let(:font_name){ "Helvetica" }
28
+ let(:font_size){ 13 }
29
+ let(:bold){ true }
30
+ let(:italic){ true }
31
+ let(:alignment){ :center }
32
+ let(:multi_line){ true }
33
+ let(:padding) { [1,2,3,4] }
34
+ let(:leading) { 5 }
35
+ let(:valign) {"center"}
36
+
37
+ subject{ described_class.new(name, coordinates, dimensions, options) }
38
+
39
+ its(:default_value){ should == "Bruce" }
40
+ its(:font_name){ should == "Helvetica" }
41
+ its(:font_size){ should == 13 }
42
+ it{ should be_bold }
43
+ it{ should be_italic }
44
+ its(:alignment){ should == "center" }
45
+ it{ should be_multi_line }
46
+ its(:padding) { should == [1,2,3,4] }
47
+ its(:valign) { should == "center"}
48
+ its(:leading) { should == 5}
49
+
50
+ describe "defaults" do
51
+ subject{ described_class.new(name, coordinates, dimensions) }
52
+
53
+ its(:default_value){ should nil }
54
+ its(:font_size){ should == 10 }
55
+ it{ should_not be_bold }
56
+ its(:alignment){ should == "left" }
57
+ its(:padding) { should == [0,0,0,0] }
58
+ it{ should_not be_multi_line }
59
+ end
60
+
61
+ describe "validation" do
62
+ context "when passed valid attributes" do
63
+ it "returns a field object" do
64
+ described_class.new(name, coordinates, dimensions, options).should be_a(described_class)
65
+ end
66
+ end
67
+
68
+ context "when passed invalid options" do
69
+ context "as an object other than a hash" do
70
+ let(:options){ "these are bogus options" }
71
+
72
+ it "throws an error" do
73
+ expect{
74
+ described_class.new(name, coordinates, dimensions, options)
75
+ }.to raise_error ArgumentError, "Options must be a hash."
76
+ end
77
+ end
78
+
79
+ context "font_name" do
80
+ let(:font_name){ 0 }
81
+
82
+ it "throws an error" do
83
+ expect{
84
+ described_class.new(name, coordinates, dimensions, options)
85
+ }.to raise_error ArgumentError, "Font_name must be of type String."
86
+ end
87
+ end
88
+
89
+
90
+ context "font_size" do
91
+ let(:font_size){ "twenty" }
92
+
93
+ it "throws an error" do
94
+ expect{
95
+ described_class.new(name, coordinates, dimensions, options)
96
+ }.to raise_error ArgumentError, "Font_size must be of type Numeric."
97
+ end
98
+ end
99
+
100
+ context "bold" do
101
+ let(:bold){ 3 }
102
+
103
+ it "throws an error" do
104
+ expect{
105
+ described_class.new(name, coordinates, dimensions, options)
106
+ }.to raise_error ArgumentError, "Bold must be one of the following values: true, false."
107
+ end
108
+ end
109
+
110
+ context "italic" do
111
+ let(:italic){ 3 }
112
+
113
+ it "throws an error" do
114
+ expect{
115
+ described_class.new(name, coordinates, dimensions, options)
116
+ }.to raise_error ArgumentError, "Italic must be one of the following values: true, false."
117
+ end
118
+ end
119
+
120
+
121
+ context "alignment" do
122
+ let(:alignment){ :opposite }
123
+
124
+ it "throws an error" do
125
+ expect{
126
+ described_class.new(name, coordinates, dimensions, options)
127
+ }.to raise_error ArgumentError, "Alignment must be one of the following values: left, right, center."
128
+ end
129
+ end
130
+
131
+ context "multi_line" do
132
+ let(:multi_line){ "x" }
133
+
134
+ it "throws an error" do
135
+ expect{
136
+ described_class.new(name, coordinates, dimensions, options)
137
+ }.to raise_error ArgumentError, "Multi_line must be one of the following values: true, false."
138
+ end
139
+ end
140
+
141
+ context "default_value" do
142
+ let(:default_value){ [] }
143
+
144
+ it "throws an error" do
145
+ expect{
146
+ described_class.new(name, coordinates, dimensions, options)
147
+ }.to raise_error ArgumentError, "Default_value must be of type String."
148
+ end
149
+ end
150
+
151
+ context "padding" do
152
+ context "as an object other than Array" do
153
+ let(:padding){ "1x1" }
154
+
155
+ it "throws an error" do
156
+ expect{
157
+ described_class.new(name, coordinates, dimensions, options)
158
+ }.to raise_error ArgumentError, "Padding must be of type Array."
159
+ end
160
+ end
161
+
162
+ context "by passing an invalid x or y coordinate" do
163
+ let(:padding){ ["a", "b" ] }
164
+
165
+ it "throws an error" do
166
+ expect{
167
+ described_class.new(name, coordinates, dimensions, options)
168
+ }.to raise_error ArgumentError, "Padding must contain only Numeric values."
169
+ end
170
+ end
171
+
172
+ context "by passing not enough coordinates" do
173
+ let(:padding){ [1] }
174
+
175
+ it "throws an error" do
176
+ expect{
177
+ described_class.new(name, coordinates, dimensions, options)
178
+ }.to raise_error ArgumentError, "Padding must contain 4 values."
179
+ end
180
+ end
181
+
182
+ context "by passing too many coordinates" do
183
+ let(:padding){ [1, 2, 3] }
184
+
185
+ it "throws an error" do
186
+ expect{
187
+ described_class.new(name, coordinates, dimensions, options)
188
+ }.to raise_error ArgumentError, "Padding must contain 4 values."
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+
195
+ end