pdf_tempura 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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