renorb-pdf_filler 0.3.4

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.
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