renorb-pdf_filler 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Great Basin Solutions, LLC dba Great Basin Development
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,117 @@
1
+ = pdf_filler
2
+
3
+ The <b>pdf_filler</b> Rails plugin makes it easy to update existing PDFs that have form fields defined.
4
+ Rather then building PDFs in Ruby using something like PDF-Writer, it is much easier to create a PDF in Acrobat,
5
+ define fields, and update those fields using pdf_filler. An example would be a First/Last name field on a PDF that is possible to update.
6
+
7
+
8
+ == Requirements
9
+
10
+ This plugin requires RJB (Ruby Java Bridge), so you will need to set your JAVA_HOME environment variable to point your installation of Java.
11
+
12
+ If your JAVA_HOME environment variable is not setup correctly you will get something like:
13
+
14
+
15
+ Building native extensions. This could take a while...
16
+ ERROR: Error installing pdf_filler-0.1.0.gem:
17
+ ERROR: Failed to build gem native extension.
18
+
19
+ /opt/local/bin/ruby extconf.rb
20
+ *** extconf.rb failed ***
21
+ Could not create Makefile due to some reason, probably lack of
22
+ necessary libraries and/or headers. Check the mkmf.log file for more
23
+ details. You may need configuration options.
24
+
25
+ Provided configuration options:
26
+ --with-opt-dir
27
+ --without-opt-dir
28
+ --with-opt-include
29
+ --without-opt-include=${opt-dir}/include
30
+ --with-opt-lib
31
+ --without-opt-lib=${opt-dir}/lib
32
+ --with-make-prog
33
+ --without-make-prog
34
+ --srcdir=.
35
+ --curdir
36
+ --ruby=/opt/local/bin/ruby
37
+ extconf.rb:45: JAVA_HOME is not set. (RuntimeError)
38
+
39
+ Gem files will remain installed in /opt/local/lib/ruby/gems/1.8/gems/rjb-1.1.7 for inspection.
40
+ Results logged to /opt/local/lib/ruby/gems/1.8/gems/rjb-1.1.7/ext/gem_make.out
41
+
42
+
43
+
44
+ <b>On my Mac I set JAVA_HOME to be "/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Home".</b>
45
+
46
+
47
+ == Installing
48
+
49
+ The recommended method to enable pdf_filler in your project is adding the pdf_filler gem to your environment. Add the following code to your Rails configuration in <tt>config/environment.rb</tt>:
50
+
51
+ Rails::Initializer.run do |config|
52
+ ...
53
+ config.gem 'gbdev-pdf_filler', :lib => 'pdf_filler', source => 'http://gems.github.com/'
54
+ end
55
+
56
+ Run <tt>sudo rake gems:install</tt> to install the gem.
57
+
58
+ Another alternative is to install pdf_filler as a Rails plugin:
59
+
60
+ script/plugin install git://github.com/gbdev/pdf_filler.git
61
+
62
+
63
+ == Usage
64
+
65
+ 1. You will need a PDF that has form fields to fill.
66
+
67
+ 2. A writable directory to store the generated PDFs.
68
+
69
+ 3. For a single page use the Page object?
70
+
71
+ // ** Single page **
72
+ page = GBDev::PDF::Page.new('/path/to/template.pdf')
73
+ page.set_text(:full_name, 'Wes Hays')
74
+ page.save_to('/path/to/save.pdf')
75
+
76
+ 4. For a collection of pages to be added to a single PDF use a Book object.
77
+
78
+ book = GBDev::PDF::Book.new
79
+
80
+ page1 = GBDev::PDF::Page.new('/path/to/template1.pdf')
81
+ page1.set_text(:full_name, 'Wes Hays')
82
+
83
+ page2 = GBDev::PDF::Page.new('/path/to/template2.pdf')
84
+ page2.set_text(:full_name, 'Darren Johnson')
85
+
86
+ book.add_page(page1)
87
+ book.add_page(page2)
88
+
89
+ book.save_to('/page/to/book.pdf')
90
+
91
+ 5. Rather then setting all the fields manually a PDF can be mapped to an ActiveRecord model.
92
+ The model must use the acts_as_pdf_db_mapper module. (<b><i>See rdocs on acts_as_pdf_db_mapper for more options</i></b>)
93
+
94
+ class User < ActiveRecord::Base
95
+ ...
96
+ acts_as_pdf_db_mapper
97
+ ...
98
+ end
99
+
100
+ user = User.first
101
+ page = GBDev::PDF::Page.new('/path/to/template1.pdf')
102
+ page.map_to_object(user)
103
+ page.save_to('/path/to/save.pdf)
104
+
105
+
106
+ Note: You can use the shorter kernel methods PDFPage instead of GBDev::PDF::Page.new. The same goes for PDFBook instead of GBDev::PDF::Book.new.
107
+
108
+ Example:
109
+
110
+ page = PDFPage('/path/to/template.pdf')
111
+ book = PDFBook()
112
+
113
+
114
+ == License
115
+
116
+ This plugin is released under the MIT license. Please contact weshays (http://github.com/weshays)
117
+ or djohnson (http://github.com/djohnson) for any questions.
@@ -0,0 +1,4 @@
1
+ Dir['tasks/*.rake'].each { |file| load(file) }
2
+
3
+ desc 'Default: run spec tests.'
4
+ task :default => [:spec]
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'pdf_filler'
Binary file
@@ -0,0 +1,50 @@
1
+ require 'fileutils'
2
+ require 'rjb'
3
+
4
+ load_path = File.expand_path(File.dirname(__FILE__) + '/iText-2.1.7.jar')
5
+ options = ['-Djava.awt.headless=true']
6
+ Rjb::load load_path, options
7
+
8
+ FileOutputStream = Rjb::import('java.io.FileOutputStream')
9
+ ByteArrayOutputStream = Rjb::import('java.io.ByteArrayOutputStream')
10
+ ByteArrayInputStream = Rjb::import('java.io.ByteArrayInputStream')
11
+ PdfWriter = Rjb::import('com.lowagie.text.pdf.PdfWriter')
12
+ PdfReader = Rjb::import('com.lowagie.text.pdf.PdfReader')
13
+ PdfCopy = Rjb::import('com.lowagie.text.pdf.PdfCopy')
14
+ PdfImportedPage = Rjb::import('com.lowagie.text.pdf.PdfImportedPage')
15
+ Document = Rjb::import('com.lowagie.text.Document')
16
+ Paragraph = Rjb::import('com.lowagie.text.Paragraph')
17
+ AcroFields = Rjb::import('com.lowagie.text.pdf.AcroFields')
18
+ PdfStamper = Rjb::import('com.lowagie.text.pdf.PdfStamper')
19
+ HashMap = Rjb::import('java.util.HashMap')
20
+ Iterator = Rjb::import('java.util.Iterator')
21
+
22
+ require 'pdf_filler/util_methods'
23
+ require 'pdf_filler/page'
24
+ require 'pdf_filler/book'
25
+ require 'pdf_filler/pdf_db_mapper'
26
+
27
+
28
+ module Kernel
29
+
30
+ # A shortcut kernel method for creating a new PDF Page without having to specify the full path to the page.
31
+ # Therefore,
32
+ # * PDFPage(template)
33
+ # and
34
+ # * RenoRB::PDF::Page.new(template)
35
+ # are the same thing.
36
+ def PDFPage(template)
37
+ RenoRB::PDF::Page.new(template)
38
+ end
39
+
40
+ # A shortcut kernel method for creating a new PDF Book without having to specify the full path to the book.
41
+ # Therefore,
42
+ # * PDFBook()
43
+ # and
44
+ # * RenoRB::PDF::Book.new
45
+ # are the same thing.
46
+ def PDFBook()
47
+ RenoRB::PDF::Book.new
48
+ end
49
+
50
+ end
@@ -0,0 +1,94 @@
1
+ module RenoRB
2
+
3
+ module PDF
4
+
5
+ # A book that represents collection of PDF page.
6
+ class Book
7
+
8
+ def initialize()
9
+ @pages = []
10
+ end
11
+
12
+ # Add a page to the book
13
+ #
14
+ # * new_page - The page object of type RenoRB::PDF::Page
15
+ def add_page(new_page)
16
+ @pages << new_page
17
+ end
18
+
19
+ # Renders the PDF Book and saves it to the specified file.
20
+ #
21
+ # * filename - A path to the file to be created.
22
+ def save_to(filename)
23
+ dir = File.dirname(filename)
24
+ temp_dir = [dir, "collection_temp_#{build_random_string}"].join('/')
25
+ Dir.mkdir(temp_dir)
26
+ @pages.each_with_index do |page, indx|
27
+ page.save_to([temp_dir, "#{indx}_#{build_random_file_name}"].join('/'))
28
+ end
29
+ temp_files = Dir[[temp_dir,'*'].join('/')].sort
30
+
31
+ document = Document.new
32
+ copier = PdfCopy.new(document, FileOutputStream.new(filename))
33
+
34
+ document.open
35
+ temp_files.each do |read_target|
36
+ reader = PdfReader.new(read_target)
37
+ n_pages = reader.getNumberOfPages
38
+ n_pages.times do |i|
39
+ copier.addPage( copier.getImportedPage(reader, i+1)) if copier
40
+ end
41
+ end
42
+ document.close
43
+
44
+ FileUtils.rm_rf(temp_dir, {:secure => true})
45
+ end
46
+
47
+ # Renders the template with the given data and returns that buffer.
48
+ def to_buffer
49
+ dir = defined?(RAILS_ROOT) ? [RAILS_ROOT, 'tmp'].join('/') : File.expand_path(File.dirname(__FILE__) + '/../../spec/output')
50
+ temp_dir = [dir, "collection_temp_#{build_random_string}"].join('/')
51
+ Dir.mkdir(temp_dir)
52
+ @pages.each_with_index do |page, indx|
53
+ page.save_to([temp_dir, "#{indx}_#{build_random_file_name}"].join('/'))
54
+ end
55
+ temp_files = Dir[[temp_dir,'*'].join('/')].sort
56
+
57
+ document = Document.new
58
+ baos = ByteArrayOutputStream.new
59
+ copier = PdfCopy.new(document, baos)
60
+
61
+ document.open
62
+
63
+ # This did not work but try working on it again later.
64
+ # @pages.each do |page|
65
+ # bais = ByteArrayInputStream.new_with_sig(page.to_buffer)
66
+ # reader = PdfReader.new(bais)
67
+ # reader = page.get_pdf_reader
68
+ # n_pages = reader.getNumberOfPages
69
+ # n_pages.times do |i|
70
+ # copier.addPage( copier.getImportedPage(reader, i+1)) if copier
71
+ # end
72
+ # end
73
+
74
+ temp_files.each do |read_target|
75
+ reader = PdfReader.new(read_target)
76
+ n_pages = reader.getNumberOfPages
77
+ n_pages.times do |i|
78
+ copier.addPage( copier.getImportedPage(reader, i+1)) if copier
79
+ end
80
+ end
81
+ document.close
82
+
83
+ #FileUtils.rm_rf(temp_dir, {:secure => true})
84
+
85
+ return baos.toByteArray()
86
+ end
87
+
88
+ include RenoRB::Utils::PrivateMethods
89
+
90
+ end # End Filler
91
+
92
+ end # End PDF
93
+
94
+ end # End RenoRB
@@ -0,0 +1,246 @@
1
+ module RenoRB
2
+
3
+ module PDF
4
+
5
+ # A page that represents a PDF page.
6
+ class Page
7
+
8
+ CHECK_BOX = 'Check Box'
9
+ COMBO_BOX = 'Combo Box'
10
+ LIST = 'List'
11
+ PUSH_BUTTON = 'Push Button'
12
+ RADIO_BUTTON = 'Radio Button'
13
+ SIGNATURE = 'Signature'
14
+ TEXT_FIELD = 'Text Field'
15
+ NONE = 'None'
16
+ UNKNOWN = '?'
17
+
18
+ # String template : A path to the template file
19
+ def initialize(template)
20
+ @template = template
21
+
22
+ @pdf_fields = {}
23
+
24
+ @check_boxes = {}
25
+ @images = {}
26
+ @radio_buttons = {}
27
+ @signature_fields = {}
28
+ @text_fields = {}
29
+
30
+ @pdf_reader = nil
31
+ end
32
+
33
+ # Returns a hash where the keys are the field names in the template PDF and the values are the field types.
34
+ def get_pdf_fields
35
+ return @pdf_fields unless @pdf_fields.empty?
36
+
37
+ reader = PdfReader.new(@template)
38
+ form = reader.getAcroFields()
39
+ fields = form.getFields()
40
+ i = fields.keySet().iterator()
41
+
42
+ while(i.hasNext())
43
+ key = i.next()
44
+
45
+ case(form.getFieldType(key))
46
+ when AcroFields.FIELD_TYPE_CHECKBOX
47
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::CHECK_BOX
48
+ when AcroFields.FIELD_TYPE_COMBO
49
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::COMBO_BOX
50
+ when AcroFields.FIELD_TYPE_LIST
51
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::LIST
52
+ when AcroFields.FIELD_TYPE_NONE
53
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::NONE
54
+ when AcroFields.FIELD_TYPE_PUSHBUTTON
55
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::PUSH_BUTTON
56
+ when AcroFields.FIELD_TYPE_RADIOBUTTON
57
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::RADIO_BUTTON
58
+ when AcroFields.FIELD_TYPE_SIGNATURE
59
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::SIGNATURE
60
+ when AcroFields.FIELD_TYPE_TEXT
61
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::TEXT_FIELD
62
+ else
63
+ @pdf_fields[key.to_string().to_sym] = RenoRB::PDF::Page::UNKNOWN
64
+ end
65
+ end
66
+
67
+ return @pdf_fields
68
+ end
69
+
70
+ # Returns an array of field states. For example if the field type is a list an array
71
+ # with all possible choices in the list will be returned.
72
+ #
73
+ # * field_name - The field name to get all the possible states for.
74
+ def get_field_states(field_name)
75
+ reader = PdfReader.new(@template)
76
+ form = reader.getAcroFields()
77
+ form.getAppearanceStates(field_name.to_s);
78
+ end
79
+
80
+
81
+ # Sets a know checkbox in the PDF template.
82
+ #
83
+ # * key - A known checkbox in the PDF.
84
+ # * value - The checkbox to update.
85
+ def set_checkbox(key, value)
86
+ @check_boxes[key] = value
87
+ end
88
+
89
+ # Alias for the set_checkbox method
90
+ alias :checkbox :set_checkbox
91
+
92
+ # NOT WORING YET
93
+ # Sets a known image area in the PDF template.
94
+ #
95
+ # * key - A known image in the PDF.
96
+ # * value - The image to apply to the know image area.
97
+ def set_image(key, value)
98
+ raise 'Image not working yet'
99
+ @images[key] = value
100
+ end
101
+
102
+ # Alias for the set_image method
103
+ alias :image :set_image
104
+
105
+
106
+ # Sets a known radio button in the PDF template.
107
+ #
108
+ # * key - A known radio button group in the PDF.
109
+ # * value - The radio button group to update.
110
+ def set_radio_button(key, value)
111
+ @radio_buttons[key] = value
112
+ end
113
+
114
+ # Alias for the set_checkbox method
115
+ alias :radio_button :set_radio_button
116
+
117
+
118
+ # NOT WORKING YET
119
+ # Sets a known signature field in the PDF template.
120
+ #
121
+ # * key - A known signature field in the PDF.
122
+ # * value - The value to apply to the know field.
123
+ def set_signature_field(key, value)
124
+ raise 'Signature field not working yet'
125
+ @signature_fields[key] = value
126
+ end
127
+
128
+ # Alias for set_signature_field method
129
+ alias :signature_field :set_signature_field
130
+
131
+
132
+ # Sets a known text field in the PDF template.
133
+ #
134
+ # * key - A known text field in the PDF.
135
+ # * value - The value to apply to the know field.
136
+ def set_text_field(key, value)
137
+ @text_fields[key] = value
138
+ end
139
+
140
+ # Alias for set_text method
141
+ alias :text_field :set_text_field
142
+
143
+ # Maps PDF fields to an ActiveRecord object. The ActiveRecord object must use the
144
+ # acts_as_pdf_db_mapper module.
145
+ #
146
+ # * object - An ActiveRecord object that uses the acts_as_pdf_db_mapper module.
147
+ def map_to_object(object)
148
+ if object.methods.include?('mapped_fields')
149
+ fields = self.get_pdf_fields
150
+ object.mapped_fields.each do |mapped_field|
151
+
152
+ if mapped_field.class.to_s == 'Hash'
153
+ key_value_pair = mapped_field.first.to_a.flatten
154
+ key = key_value_pair[0]
155
+ value = key_value_pair[1]
156
+ else
157
+ key = mapped_field
158
+ value = mapped_field
159
+ end
160
+
161
+ case(fields[key])
162
+ when RenoRB::PDF::Page::CHECK_BOX
163
+ self.set_checkbox(key, object.send(value))
164
+ when RenoRB::PDF::Page::COMBO_BOX
165
+ #self.set_combobox(key, object.send(value))
166
+ when RenoRB::PDF::Page::LIST
167
+ #self.set_list(key, object.send(value))
168
+ when RenoRB::PDF::Page::NONE
169
+ #self.set_none(key, object.send(value))
170
+ when RenoRB::PDF::Page::PUSH_BUTTON
171
+ #self.set_push_button(key, object.send(value))
172
+ when RenoRB::PDF::Page::RADIO_BUTTON
173
+ self.set_radio_button(key, object.send(value))
174
+ when RenoRB::PDF::Page::SIGNATURE
175
+ self.set_signature_field(key, object.send(value))
176
+ when RenoRB::PDF::Page::TEXT_FIELD
177
+ self.set_text_field(key, object.send(value))
178
+ end
179
+
180
+ end
181
+ end
182
+ end
183
+
184
+
185
+ # Renders the template with the given data and saves to the given filename path.
186
+ #
187
+ # * filename - A path to the file to be created.
188
+ def save_to(filename)
189
+ field_cache = HashMap.new
190
+ reader = PdfReader.new(@template)
191
+ stamper = PdfStamper.new( reader, FileOutputStream.new(filename) )
192
+ form = stamper.getAcroFields()
193
+ form.setFieldCache(field_cache)
194
+
195
+ all_fields = {}
196
+ all_fields.merge!(@check_boxes)
197
+ all_fields.merge!(@radio_buttons)
198
+ all_fields.merge!(@signature_fields)
199
+ all_fields.merge!(@text_fields)
200
+
201
+ all_fields.each do |field, value|
202
+ form.setField(field.to_s, value.to_s)
203
+ end
204
+
205
+ # TODO: do something with @images
206
+
207
+ stamper.setFormFlattening(true)
208
+ stamper.close
209
+ end
210
+
211
+
212
+ # Renders the template with the given data and returns that buffer.
213
+ def to_buffer
214
+ field_cache = HashMap.new
215
+ reader = PdfReader.new(@template)
216
+ baos = ByteArrayOutputStream.new
217
+ stamper = PdfStamper.new( reader, baos )
218
+ form = stamper.getAcroFields()
219
+ form.setFieldCache(field_cache)
220
+
221
+ all_fields = {}
222
+ all_fields.merge!(@check_boxes)
223
+ all_fields.merge!(@radio_buttons)
224
+ all_fields.merge!(@signature_fields)
225
+ all_fields.merge!(@text_fields)
226
+
227
+ all_fields.each do |field, value|
228
+ form.setField(field.to_s, value.to_s)
229
+ end
230
+
231
+ # TODO: do something with @images
232
+
233
+ stamper.setFormFlattening(true)
234
+ stamper.close
235
+
236
+ return baos.toByteArray()
237
+ end
238
+
239
+
240
+ include RenoRB::Utils::PrivateMethods
241
+
242
+ end # End Page
243
+
244
+ end # End PDF
245
+
246
+ end # End RenoRB
@@ -0,0 +1,74 @@
1
+ require 'active_record'
2
+
3
+ module RenoRB #:nodoc:
4
+ module PDF #:nodoc:
5
+ module Acts #:nodoc:
6
+ module PDFDBMapper # :nodoc:
7
+
8
+ def self.included(mod)
9
+ mod.extend(ClassMethods)
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ # Automatically maps database fields to fields found in the template PDF with the same name.
15
+ # Database fields not found in the template PDF are ignored. If no options are specified then
16
+ # by default all table fields will attempt to be mapped.
17
+ #
18
+ # Configuration options are:
19
+ #
20
+ # * :only - Only map the database fields specified. i.e :only => [:first_name, :last_name]
21
+ # * :except - Map all the table fields except those specified. i.e. :except => [:middle_name]
22
+ # * :include - Allows for a method to map to a field in the PDF. If you have a method called full_name
23
+ # that combines the first name and last name, you could map that method to a PDF text field called full_name.
24
+ # :include => [:full_name].
25
+ # You could all specify a model attribute/method to map to a different PDF field.
26
+ # i.e. :include => [{:full_name => :dog_name}]
27
+ # :include will still work with :only and :except.
28
+ # * :only_include - Will ignore :only and :except and only includes the manual mappings specified.
29
+ # i.e. :only_include => [:full_name, {:animal_name => :dog_name}]
30
+ def acts_as_pdf_db_mapper(*fields)
31
+
32
+ # Make sure that the table to be mapped actually exists
33
+ if self.table_exists?
34
+
35
+ # Get a collection of fields to be searched on.
36
+ if fields.first.class.to_s == 'Hash'
37
+
38
+ if fields.first.has_key?(:only_include)
39
+ fields_to_map = fields.first[:only_include]
40
+ else
41
+ if fields.first.has_key?(:only)
42
+ # only map on these fields.
43
+ fields_to_map = fields.first[:only]
44
+ elsif fields.first.has_key?(:except)
45
+ # Get all the fields and remove any that are in the -except- list.
46
+ fields_to_map = self.column_names.collect { |column| fields.first[:except].include?(column.to_sym) ? nil : column.to_sym }.compact
47
+ else
48
+ fields_to_map = self.column_names.collect { |column| column.to_sym }
49
+ end
50
+
51
+ if fields.first.has_key?(:include)
52
+ fields_to_map += fields.first[:include]
53
+ end
54
+ end
55
+ else
56
+ fields_to_map = self.column_names.collect { |column| column.to_sym }
57
+ end
58
+
59
+ # Set the appropriate class attributes.
60
+ self.cattr_accessor :mapped_fields
61
+ self.mapped_fields = fields_to_map
62
+
63
+ end # End table exists check
64
+
65
+ end # acts_as_pdf_db_mapper
66
+
67
+ end # ClassMethods
68
+
69
+ end # PDFDBMapper
70
+ end # Acts
71
+ end # PDF
72
+ end # RenoRB
73
+
74
+ ActiveRecord::Base.send(:include, RenoRB::PDF::Acts::PDFDBMapper)
@@ -0,0 +1,50 @@
1
+ module RenoRB #:nodoc: all
2
+
3
+ module Utils
4
+
5
+ module PrivateMethods
6
+
7
+ def build_random_string # :nodoc:
8
+ letters_array = [('a'..'z'),('A'..'Z')].collect{|i| i.to_a}.flatten
9
+ (1..10).collect{ letters_array[ rand(letters_array.length) ] }.join
10
+ end
11
+
12
+ def build_random_file_name # :nodoc:
13
+ build_random_string << '.pdf'
14
+ end
15
+
16
+ end
17
+
18
+
19
+ # Include these controller methods to prompt the user to download the PDF.
20
+ #
21
+ # * include RenoRB::Utils::ControllerMethods
22
+ module ControllerMethods
23
+
24
+ # Used to display the PDF without saving it to disk.
25
+ #
26
+ # * buffer - A Page buffer or Book buffer.
27
+ # * filename - The filename to apply to the buffer when prompted to download.
28
+ def display_pdf(buffer, filename)
29
+ send_data(buffer, {:type => 'application/pdf',
30
+ :disposition => 'attachment',
31
+ :filename => filename} )
32
+ end
33
+
34
+
35
+ # From here: http://railspdfplugin.rubyforge.org/wiki/wiki.pl
36
+ # Suggested code so errors will always show in browser
37
+ def rescue_action_in_public(exception) # :nodoc:
38
+ headers.delete("Content-Disposition")
39
+ super
40
+ end
41
+
42
+ def rescue_action_locally(exception) # :nodoc:
43
+ headers.delete("Content-Disposition")
44
+ super
45
+ end
46
+
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,74 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe 'Book' do
4
+
5
+ it 'should create the book of pages and write to the output directory' do
6
+ book = RenoRB::PDF::Book.new
7
+
8
+ template_file = File.expand_path(File.dirname(__FILE__) + '/../templates/certificate_template.pdf')
9
+ pdf_book = File.expand_path(File.dirname(__FILE__) + '/../output/certs.pdf')
10
+
11
+ page1 = RenoRB::PDF::Page.new(template_file)
12
+ page1.set_text_field(:full_name, 'Wes Hays')
13
+
14
+ page2 = RenoRB::PDF::Page.new(template_file)
15
+ page2.set_text_field(:full_name, 'Darren Johnson')
16
+
17
+ page3 = RenoRB::PDF::Page.new(template_file)
18
+ page3.set_text_field(:full_name, 'John Dell')
19
+
20
+ book.add_page(page1)
21
+ book.add_page(page2)
22
+ book.add_page(page3)
23
+
24
+ book.save_to(pdf_book)
25
+
26
+ File.exist?(pdf_book).should be_true
27
+ end
28
+
29
+ it 'should create the book of pages and write to the output directory with Kernel method' do
30
+ book = PDFBook()
31
+
32
+ template_file = File.expand_path(File.dirname(__FILE__) + '/../templates/certificate_template.pdf')
33
+ pdf_book = File.expand_path(File.dirname(__FILE__) + '/../output/certs.pdf')
34
+
35
+ page1 = RenoRB::PDF::Page.new(template_file)
36
+ page1.set_text_field(:full_name, 'Wes Hays')
37
+
38
+ page2 = RenoRB::PDF::Page.new(template_file)
39
+ page2.set_text_field(:full_name, 'Darren Johnson')
40
+
41
+ page3 = RenoRB::PDF::Page.new(template_file)
42
+ page3.set_text_field(:full_name, 'John Dell')
43
+
44
+ book.add_page(page1)
45
+ book.add_page(page2)
46
+ book.add_page(page3)
47
+
48
+ book.save_to(pdf_book)
49
+
50
+ File.exist?(pdf_book).should be_true
51
+ end
52
+
53
+ it 'should return the buffer without writing to disk' do
54
+ book = PDFBook()
55
+
56
+ template_file = File.expand_path(File.dirname(__FILE__) + '/../templates/certificate_template.pdf')
57
+
58
+ page1 = RenoRB::PDF::Page.new(template_file)
59
+ page1.set_text_field(:full_name, 'Wes Hays')
60
+
61
+ page2 = RenoRB::PDF::Page.new(template_file)
62
+ page2.set_text_field(:full_name, 'Darren Johnson')
63
+
64
+ page3 = RenoRB::PDF::Page.new(template_file)
65
+ page3.set_text_field(:full_name, 'John Dell')
66
+
67
+ book.add_page(page1)
68
+ book.add_page(page2)
69
+ book.add_page(page3)
70
+
71
+ book.to_buffer.should_not be_blank
72
+ end
73
+
74
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe 'PDF_DB_Mapper' do
4
+
5
+ before(:each) do
6
+ Address.create_corpus!
7
+ end
8
+
9
+ after(:each) do
10
+ Address.destroy_all
11
+ end
12
+
13
+ it 'should allow all database columns to be mapped if no :only or :except is specified' do
14
+ address = Address.first
15
+ fields_array = address.mapped_fields.collect{|f| f.to_s}.sort
16
+ fields_array.should == ['id', 'address1', 'address2', 'city', 'state', 'postal_code'].sort
17
+ end
18
+
19
+ it 'should only map the fields specified by :only' do
20
+ address = ClientAddress.first
21
+ fields_array = address.mapped_fields.collect{|f| f.to_s}.sort
22
+ fields_array.should == ['city', 'state'].sort
23
+ end
24
+
25
+ it 'should map all the fields except the fields specified by :except' do
26
+ address = ContactAddress.first
27
+ fields_array = address.mapped_fields.collect{|f| f.to_s}.sort
28
+ fields_array.should == ['address2', 'city', 'state'].sort
29
+ end
30
+
31
+ it 'should include the additional mappings specified by :include' do
32
+ address = UserAddress.first
33
+ fields_array = address.mapped_fields.collect{|f| f.class.to_s == 'Hash' ? f.first.to_a.flatten.join('::') : f.to_s}.sort
34
+ fields_array.should == ['id', 'address1', 'address2', 'city', 'state', 'postal_code','full_address::address'].sort
35
+ end
36
+
37
+ it 'should only include the mappings specified by :only_include' do
38
+ address = FamilyAddress.first
39
+ fields_array = address.mapped_fields.collect{|f| f.first.to_a.flatten.join('::')}.sort
40
+ fields_array.should == ['full_address::address'].sort
41
+ end
42
+
43
+ it 'should map the specified fields for a single record to a single page' do
44
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/address_template.pdf'))
45
+ address = Address.first
46
+ page.map_to_object(address)
47
+ page.save_to(File.expand_path(File.dirname(__FILE__) + '/../output/db_address.pdf'))
48
+ File.exist?(File.dirname(__FILE__) + '/../output/db_address.pdf').should be_true
49
+ end
50
+
51
+ end
@@ -0,0 +1,89 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../spec_helper")
2
+
3
+ describe 'Page' do
4
+
5
+ it 'should create the page and write to the output directory' do
6
+ page = RenoRB::PDF::Page.new(File.expand_path(File.dirname(__FILE__) + '/../templates/certificate_template.pdf'))
7
+ page.set_text_field(:full_name, 'Wes Hays')
8
+ page.save_to(File.expand_path(File.dirname(__FILE__) + '/../output/wes_hays.pdf'))
9
+ File.exist?(File.dirname(__FILE__) + '/../output/wes_hays.pdf').should be_true
10
+ end
11
+
12
+ it 'should create the page and write to the output directory with Kernel method' do
13
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/certificate_template.pdf'))
14
+ page.set_text_field(:full_name, 'Wes Hays')
15
+ page.save_to(File.expand_path(File.dirname(__FILE__) + '/../output/wes_hays.pdf'))
16
+ File.exist?(File.dirname(__FILE__) + '/../output/wes_hays.pdf').should be_true
17
+ end
18
+
19
+ it 'should find all three fields: text field, checkbox and radio buttons' do
20
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/form_template.pdf'))
21
+ fields = page.get_pdf_fields
22
+
23
+ fields.has_key?(:full_name).should be_true
24
+ fields[:full_name].should == RenoRB::PDF::Page::TEXT_FIELD
25
+
26
+ fields.has_key?(:home_owner).should be_true
27
+ fields[:home_owner].should == RenoRB::PDF::Page::RADIO_BUTTON
28
+
29
+ fields.has_key?(:newsletter).should be_true
30
+ fields[:newsletter].should == RenoRB::PDF::Page::CHECK_BOX
31
+
32
+ fields.has_key?(:car_types).should be_true
33
+ fields[:car_types].should == RenoRB::PDF::Page::LIST
34
+
35
+ fields.has_key?(:sibling_count).should be_true
36
+ fields[:sibling_count].should == RenoRB::PDF::Page::COMBO_BOX
37
+
38
+ # fields.has_key?(:owner_signature).should be_true
39
+ # fields[:owner_signature].should == RenoRB::PDF::Page::SIGNATURE
40
+ #
41
+ # fields.has_key?(:submit_button).should be_true
42
+ # fields[:submit_button].should == RenoRB::PDF::Page::PUSH_BUTTON
43
+ #
44
+ # fields.has_key?(:photo).should be_true
45
+ # fields[:photo].should == RenoRB::PDF::Page::IMAGE
46
+ end
47
+
48
+ it 'should find all the valid states for the check box' do
49
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/form_template.pdf'))
50
+ states = page.get_field_states(:newsletter) # Checkbox
51
+ states.should == ['Yes','Off']
52
+ end
53
+
54
+ it 'should find all the valid states for the radio button' do
55
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/form_template.pdf'))
56
+ states = page.get_field_states(:home_owner) # radio button
57
+ states.should == ['Yes','No','Off'] # Off will not be used but AcroFields returns it anyway.
58
+ end
59
+
60
+ it 'should find all the valid states for the list' do
61
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/form_template.pdf'))
62
+ states = page.get_field_states(:car_types) # List
63
+ states.sort.should == ['Chevy', 'Ford', 'Honda', 'Jeep', 'Toyota'].sort
64
+ end
65
+
66
+ it 'should find all the valid states for the combo box' do
67
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/form_template.pdf'))
68
+ states = page.get_field_states(:sibling_count) # List
69
+ states.sort.should == ['Zero','One','Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten'].sort
70
+ end
71
+
72
+ it 'should fill all fields' do
73
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/form_template.pdf'))
74
+ page.set_text_field(:full_name, 'Anna Hays')
75
+ page.set_checkbox(:home_owner, 'Yes')
76
+ page.set_checkbox(:newsletter, 'Yes')
77
+ page.set_checkbox(:car_types, 'Jeep')
78
+ page.set_checkbox(:sibling_count, 'One')
79
+ page.save_to(File.expand_path(File.dirname(__FILE__) + '/../output/form_test.pdf'))
80
+ File.exist?(File.dirname(__FILE__) + '/../output/form_test.pdf').should be_true
81
+ end
82
+
83
+ it 'should return the buffer without writing to disk' do
84
+ page = PDFPage(File.expand_path(File.dirname(__FILE__) + '/../templates/certificate_template.pdf'))
85
+ page.set_text_field(:full_name, 'Wes Hays')
86
+ pdf_data = page.to_buffer
87
+ pdf_data.should_not be_blank
88
+ end
89
+ end
@@ -0,0 +1,111 @@
1
+ require 'spec'
2
+ require 'rubygems'
3
+ require 'ruby-debug'
4
+ require 'activerecord'
5
+
6
+ ##################
7
+ #### <CUSTOM> ####
8
+ ##################
9
+ # Aliased "lambda" with "doing" so that when checking
10
+ # whether or not something raises an exception it will
11
+ # read like other rspec operations. For example:
12
+ # instead of
13
+ # lambda { ... }.should_not raise_error
14
+ # you can have
15
+ # doing { ... }.should_not raise_error
16
+ alias :doing :lambda
17
+ ###################
18
+ #### </CUSTOM> ####
19
+ ###################
20
+
21
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
22
+ ActiveRecord::Base.configurations = true
23
+
24
+ ActiveRecord::Schema.verbose = false
25
+ ActiveRecord::Schema.define(:version => 1) do
26
+ create_table :clients do |t|
27
+ t.string :first_name
28
+ t.string :last_name
29
+ end
30
+
31
+ create_table :addresses do |t|
32
+ t.string :address1
33
+ t.string :address2
34
+ t.string :city
35
+ t.string :state
36
+ t.string :postal_code
37
+ end
38
+ end
39
+
40
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
41
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
42
+ require 'pdf_filler'
43
+
44
+
45
+ module RenoRB
46
+ module TestData
47
+ module Addresses
48
+ def create_corpus!
49
+ create!(:address1 => '111 AAA St', :address2 => 'Suite 444', :city => 'Reno', :state => 'Nevada', :postal_code => '89506')
50
+ create!(:address1 => '222 BBB St', :address2 => 'Suite 555', :city => 'Sparks', :state => 'Nevada', :postal_code => '89434')
51
+ create!(:address1 => '333 CCC St', :address2 => 'Suite 666', :city => 'Fernley', :state => 'Nevada', :postal_code => '89408')
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+
58
+ Spec::Runner.configure do |config|
59
+ config.before(:each) do
60
+ class Client < ActiveRecord::Base
61
+ acts_as_pdf_db_mapper :only => [:first_name, :last_name]
62
+ has_many :addresses, :dependent => :destroy
63
+
64
+ def full_name
65
+ [self.first_name, self.last_name].join(' ')
66
+ end
67
+ end
68
+
69
+ class Address < ActiveRecord::Base
70
+ acts_as_pdf_db_mapper
71
+ belongs_to :client
72
+ extend RenoRB::TestData::Addresses
73
+ end
74
+
75
+ class ClientAddress < ActiveRecord::Base
76
+ set_table_name :addresses
77
+ acts_as_pdf_db_mapper :only => [:state, :city]
78
+ end
79
+
80
+ class ContactAddress < ActiveRecord::Base
81
+ set_table_name :addresses
82
+ acts_as_pdf_db_mapper :except => [:id, :address1, :postal_code]
83
+ end
84
+
85
+ class UserAddress < ActiveRecord::Base
86
+ set_table_name :addresses
87
+ acts_as_pdf_db_mapper :include => [{:full_address => :address}]
88
+
89
+ def full_address
90
+ [self.address1, self.address2].join(', ')
91
+ end
92
+ end
93
+
94
+ class FamilyAddress < ActiveRecord::Base
95
+ set_table_name :addresses
96
+ acts_as_pdf_db_mapper :only_include => [{:full_address => :address}]
97
+
98
+ def full_address
99
+ [self.address1, self.address2].join(', ')
100
+ end
101
+ end
102
+
103
+ Client.destroy_all
104
+ Address.destroy_all
105
+ end
106
+
107
+ config.after(:each) do
108
+ Object.send(:remove_const, :Client)
109
+ Object.send(:remove_const, :Address)
110
+ end
111
+ end
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = 'pdf_filler'
8
+ #gem.version = '0.1.1' # In version file
9
+ gem.date = '2009-08-25'
10
+
11
+ gem.summary = "A Rails plugin to fill a PDF form using RJB and iText."
12
+ gem.description = "PDF Filler makes it easy to file your PDFs."
13
+
14
+ gem.authors = ['Reno Ruby Group']
15
+ gem.email = ['renorb@renorb.org']
16
+ gem.homepage = 'http://wiki.github.com/renorb/pdf_filler'
17
+
18
+ gem.has_rdoc = true
19
+ gem.rdoc_options << '--title' << gem.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
20
+ gem.extra_rdoc_files = ['README.rdoc']
21
+
22
+ gem.files = ['LICENSE',
23
+ 'README.rdoc',
24
+ 'Rakefile',
25
+ 'init.rb',
26
+ 'lib/iText-2.1.7.jar',
27
+ 'lib/pdf_filler.rb',
28
+ 'lib/pdf_filler/page.rb',
29
+ 'lib/pdf_filler/book.rb',
30
+ 'lib/pdf_filler/pdf_db_mapper.rb',
31
+ 'lib/pdf_filler/util_methods.rb',
32
+ 'tasks/documentation.rake',
33
+ 'tasks/build_gem.rake',
34
+ 'spec/spec_helper.rb',
35
+ 'spec/lib/pdf_page_spec.rb',
36
+ 'spec/lib/pdf_book_spec.rb',
37
+ 'spec/lib/pdf_db_mapper_spec.rb',
38
+ 'spec/output',
39
+ 'spec/templates/certificate_template.pdf']
40
+
41
+ gem.test_files = ['spec/lib/pdf_page_spec.rb',
42
+ 'spec/lib/pdf_book_spec.rb']
43
+
44
+ gem.add_dependency 'rjb', '>= 1.1.7'
45
+ end
46
+ rescue LoadError
47
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
48
+ end
49
+
50
+ require 'spec/rake/spectask'
51
+ Spec::Rake::SpecTask.new(:spec) do |spec|
52
+ spec.libs << 'lib' << 'spec'
53
+ spec.spec_files = FileList['spec/**/*_spec.rb']
54
+ end
55
+
56
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
57
+ spec.libs << 'lib' << 'spec'
58
+ spec.pattern = 'spec/**/*_spec.rb'
59
+ spec.rcov = true
60
+ end
@@ -0,0 +1,32 @@
1
+ require 'rubygems'
2
+ require 'rake/rdoctask'
3
+
4
+ desc 'Generate documentation for PDF-Filler.'
5
+ Rake::RDocTask.new do |rdoc|
6
+ rdoc.rdoc_dir = 'doc/html'
7
+ rdoc.title = 'pdf_filler'
8
+ rdoc.options << '--line-numbers' << '--inline-source'
9
+ rdoc.main = 'README.rdoc'
10
+ rdoc.rdoc_files.include('LICENSE', 'lib/')
11
+ end
12
+
13
+
14
+ begin
15
+ require 'rcov/rcovtask'
16
+ Rcov::RcovTask.new do |t|
17
+ t.test_files = Dir[ "spec/**/*_spec.rb" ]
18
+ end
19
+ rescue LoadError
20
+ nil
21
+ end
22
+
23
+ begin
24
+ require 'rcov/rcovtask'
25
+ desc 'Runs spec:rcov and then displays the coverage/index.html file in the browser.'
26
+ task :rcov_display => [:clobber_rcov, :rcov] do
27
+ system("open coverage/index.html")
28
+ end
29
+ rescue LoadError
30
+ nil
31
+ end
32
+
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: renorb-pdf_filler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.4
5
+ platform: ruby
6
+ authors:
7
+ - Reno Ruby Group
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-25 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rjb
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.7
24
+ version:
25
+ description: PDF Filler makes it easy to file your PDFs.
26
+ email:
27
+ - renorb@renorb.org
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - README.rdoc
34
+ files:
35
+ - LICENSE
36
+ - README.rdoc
37
+ - Rakefile
38
+ - init.rb
39
+ - lib/iText-2.1.7.jar
40
+ - lib/pdf_filler.rb
41
+ - lib/pdf_filler/book.rb
42
+ - lib/pdf_filler/page.rb
43
+ - lib/pdf_filler/pdf_db_mapper.rb
44
+ - lib/pdf_filler/util_methods.rb
45
+ - spec/lib/pdf_book_spec.rb
46
+ - spec/lib/pdf_db_mapper_spec.rb
47
+ - spec/lib/pdf_page_spec.rb
48
+ - spec/spec_helper.rb
49
+ - spec/templates/certificate_template.pdf
50
+ - tasks/build_gem.rake
51
+ - tasks/documentation.rake
52
+ has_rdoc: false
53
+ homepage: http://wiki.github.com/renorb/pdf_filler
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ - --title
58
+ - pdf_filler
59
+ - --main
60
+ - README.rdoc
61
+ - --line-numbers
62
+ - --inline-source
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ version:
77
+ requirements: []
78
+
79
+ rubyforge_project:
80
+ rubygems_version: 1.2.0
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: A Rails plugin to fill a PDF form using RJB and iText.
84
+ test_files:
85
+ - spec/lib/pdf_page_spec.rb
86
+ - spec/lib/pdf_book_spec.rb