pdftk_forms 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +25 -0
- data/CHANGELOG.rdoc +13 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.rdoc +92 -0
- data/Rakefile +18 -0
- data/lib/pdftk_forms.rb +5 -0
- data/lib/pdftk_forms/fdf.rb +89 -0
- data/lib/pdftk_forms/field.rb +72 -0
- data/lib/pdftk_forms/version.rb +3 -0
- data/lib/pdftk_forms/wrapper.rb +61 -0
- data/lib/pdftk_forms/xfdf.rb +37 -0
- data/pdftk_forms.gemspec +24 -0
- data/spec/pdftk_forms/fdf_spec.rb +35 -0
- data/spec/pdftk_forms/field_spec.rb +216 -0
- data/spec/pdftk_forms/wrapper_spec.rb +104 -0
- data/spec/pdftk_forms/xfdf_spec.rb +13 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/xfdf_helper.rb +15 -0
- data/spec/test_pdfs/fields.pdf +0 -0
- metadata +125 -0
data/.gitignore
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## PROJECT::GENERAL
|
17
|
+
coverage
|
18
|
+
rdoc
|
19
|
+
pkg
|
20
|
+
|
21
|
+
## PROJECT::SPECIFIC
|
22
|
+
Gemfile.lock
|
23
|
+
*.gem
|
24
|
+
pkg/*
|
25
|
+
.bundle
|
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
= Changelog
|
2
|
+
|
3
|
+
== v 0.1.0 - 05/09/11
|
4
|
+
|
5
|
+
* Initial Release of the new gem
|
6
|
+
* Combined the 2 projects here:
|
7
|
+
1. https://github.com/devfu/pdftk
|
8
|
+
2. https://github.com/jkraemer/pdf-forms
|
9
|
+
* Added xfdf support for generating the combined pdf
|
10
|
+
* Added a bunch of field helper methods that make creating forms much easier
|
11
|
+
1. #field_type (returns a string of 'text_field', 'text_area', 'check_box', 'radio_button', 'select' or 'push button')
|
12
|
+
2. #required?
|
13
|
+
3. #multiline? (for text_areas)
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Tom Cocca
|
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.
|
data/README.rdoc
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
= PdftkForms
|
2
|
+
|
3
|
+
This gem is intended to be a wrapper for the PDFTK command line utility for working with pdfs, mainly editable pdfs.
|
4
|
+
|
5
|
+
You must have PDFTK (http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/) installed.
|
6
|
+
|
7
|
+
Currently this gem is intended to make the following much easier with pdftk:
|
8
|
+
1. Get all the form fields on the pdf along with the important information for those fields such as 'type', 'required?', options (for selects), etc..
|
9
|
+
2. Pass 'answers' for those form fields to be inserted into a new compressed pdf and returned
|
10
|
+
|
11
|
+
|
12
|
+
== Props
|
13
|
+
|
14
|
+
Props to this gem go out to jkraemer (Jens Krämer) for creating https://github.com/jkraemer/pdf-forms and devfu (Dev Fu!) for creating https://github.com/devfu/pdftk.
|
15
|
+
|
16
|
+
This gem is based on the work of those two projects and expands upon their functionality.
|
17
|
+
|
18
|
+
|
19
|
+
== Installation
|
20
|
+
|
21
|
+
gem install pdftk_forms
|
22
|
+
|
23
|
+
In a rails 2.3.x app
|
24
|
+
|
25
|
+
config.gem 'pdftk_forms'
|
26
|
+
|
27
|
+
|
28
|
+
== Usage
|
29
|
+
|
30
|
+
=== PdftkForms::Wrapper
|
31
|
+
|
32
|
+
This is the class you will interact with. You can optionally pass a full path to your 'pdftk' library or the gem assumes pdftk is in your path by default:
|
33
|
+
|
34
|
+
@pdftk = PdftkForms::Wrapper.new
|
35
|
+
@pdftk.path # => 'pdftk'
|
36
|
+
|
37
|
+
@pdftk = PdftkForms::Wrapper.new('/usr/local/bin/pdftk')
|
38
|
+
@pdftk.path # => '/usr/local/bin/pdftk'
|
39
|
+
|
40
|
+
==== To get the fields from a form:
|
41
|
+
|
42
|
+
@pdftk.fields('/path/to/form.pdf')
|
43
|
+
|
44
|
+
This will return an array of PdftkForms::Field objects. Each field responds to the following methods
|
45
|
+
|
46
|
+
#field_type => returns one of 'text_field', 'text_area', 'check_box', 'radio_button', 'select' or 'push button'. All pdf Choice fields (combo box or list box) come back as 'select'.
|
47
|
+
#required? => returns true if the field is a required field
|
48
|
+
#options => returns an array of options if the field is a 'select', 'check_box' or 'radio_button'
|
49
|
+
|
50
|
+
There are also some useful fields used internally but that are exposed for determing the field_type
|
51
|
+
#multiline? => returns true if the field is a Text field and is specified as multiline (used to determine text_field vs. text_area)
|
52
|
+
#push_button?, #radio_button, #check_box? => Used to determine the different types of field based on the field flags when the original field type is 'Button'
|
53
|
+
|
54
|
+
Finally there are methods to get the original PDF field data:
|
55
|
+
#name => returns the FieldName from the pdf field
|
56
|
+
#type => returns the original FieldType (one of 'Text', 'Button', 'Choice')
|
57
|
+
#value => returns the original FieldValue for pre-filled text or options
|
58
|
+
#flags => returns the original FieldFlags a number that is used to determine information on the form such as required, radio vs. check box, multiline, etc ...
|
59
|
+
#alt_name => returns the FieldNameAlt data
|
60
|
+
|
61
|
+
==== To fill out a form with answers
|
62
|
+
|
63
|
+
The method for filling out the form take 3 required parameters, the path to the form, the destination for the new flattened pdf, the answer data.
|
64
|
+
|
65
|
+
Also, there is a 4th optional param, whether or not to use an xfdf template to fill out the form, it defaults to true. PDFTK added support for xfdf in version 1.40 released on September 19, 2006.
|
66
|
+
|
67
|
+
You can pass false in as a 4th param if your pdftk version does not support xfdf to use the standard fdf format.
|
68
|
+
|
69
|
+
@pdftk.fill_form('/path/to/form.pdf', '/path/to/destination_file.pdf', {'field_one' => 'value1', 'field_two' => 'value2'})
|
70
|
+
|
71
|
+
or
|
72
|
+
|
73
|
+
@pdftk.fill_form('/path/to/form.pdf', '/path/to/destination_file.pdf', {'field_one' => 'value1', 'field_two' => 'value2'}, false)
|
74
|
+
|
75
|
+
The data (3rd param) is a hash where the keys are the #name of the field and the value is the answer you are submitting for that field.
|
76
|
+
This method submits the data and created a flattened uneditable version of the completed pdf and puts it in your destination path.
|
77
|
+
|
78
|
+
|
79
|
+
== Note on Patches/Pull Requests
|
80
|
+
|
81
|
+
* Fork the project.
|
82
|
+
* Make your feature addition or bug fix.
|
83
|
+
* Add tests for it. This is important so I don't break it in a
|
84
|
+
future version unintentionally.
|
85
|
+
* Commit, do not mess with rakefile, version, or history.
|
86
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
87
|
+
* Send me a pull request. Bonus points for topic branches.
|
88
|
+
|
89
|
+
|
90
|
+
== Copyright
|
91
|
+
|
92
|
+
Copyright (c) 2010-2011 Tom Cocca. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
task :test => :spec
|
8
|
+
task :default => :spec
|
9
|
+
|
10
|
+
require 'rake/rdoctask'
|
11
|
+
Rake::RDocTask.new do |rdoc|
|
12
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
13
|
+
|
14
|
+
rdoc.rdoc_dir = 'rdoc'
|
15
|
+
rdoc.title = "rash #{version}"
|
16
|
+
rdoc.rdoc_files.include('README*')
|
17
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
18
|
+
end
|
data/lib/pdftk_forms.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
module PdftkForms
|
2
|
+
|
3
|
+
# Map keys and values to Adobe's FDF format.
|
4
|
+
#
|
5
|
+
# Straight port of Perl's PDF::FDF::Simple by Steffen Schwigon.
|
6
|
+
# Parsing FDF files is not supported (yet).
|
7
|
+
class Fdf
|
8
|
+
|
9
|
+
attr_reader :options
|
10
|
+
|
11
|
+
def initialize(data = {}, options = {})
|
12
|
+
@data = data
|
13
|
+
@options = {
|
14
|
+
:file => nil,
|
15
|
+
:ufile => nil,
|
16
|
+
:id => nil
|
17
|
+
}.merge(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
# generate FDF content
|
21
|
+
def to_fdf
|
22
|
+
fdf = header
|
23
|
+
|
24
|
+
@data.each do |key, value|
|
25
|
+
if Hash === value
|
26
|
+
value.each do |sub_key, sub_value|
|
27
|
+
fdf << field("#{key}_#{sub_key}", sub_value)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
fdf << field(key, value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
fdf << footer
|
35
|
+
return fdf
|
36
|
+
end
|
37
|
+
|
38
|
+
# write fdf content to path
|
39
|
+
def save_to(path)
|
40
|
+
(File.open(path, 'w') << to_fdf).close
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
def header
|
46
|
+
header = "%FDF-1.2\n\n1 0 obj\n<<\n/FDF << /Fields 2 0 R"
|
47
|
+
|
48
|
+
# /F
|
49
|
+
header << "/F (#{options[:file]})" if options[:file]
|
50
|
+
# /UF
|
51
|
+
header << "/UF (#{options[:ufile]})" if options[:ufile]
|
52
|
+
# /ID
|
53
|
+
header << "/ID[" << options[:id].join << "]" if options[:id]
|
54
|
+
|
55
|
+
header << ">>\n>>\nendobj\n2 0 obj\n["
|
56
|
+
return header
|
57
|
+
end
|
58
|
+
|
59
|
+
def field(key, value)
|
60
|
+
"<</T(#{key})/V" +
|
61
|
+
(Array === value ? "[#{value.map{ |v|"(#{quote(v)})" }.join}]" : "(#{quote(value)})") +
|
62
|
+
">>\n"
|
63
|
+
end
|
64
|
+
|
65
|
+
def quote(value)
|
66
|
+
value.to_s.strip.
|
67
|
+
gsub( /\\/, '\\' ).
|
68
|
+
gsub( /\(/, '\(' ).
|
69
|
+
gsub( /\)/, '\)' ).
|
70
|
+
gsub( /\n/, '\r' )
|
71
|
+
end
|
72
|
+
|
73
|
+
FOOTER =<<-EOFOOTER
|
74
|
+
]
|
75
|
+
endobj
|
76
|
+
trailer
|
77
|
+
<<
|
78
|
+
/Root 1 0 R
|
79
|
+
|
80
|
+
>>
|
81
|
+
%%EOF
|
82
|
+
EOFOOTER
|
83
|
+
|
84
|
+
def footer
|
85
|
+
FOOTER
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module PdftkForms
|
2
|
+
# Represents a fillable form field on a particular PDF
|
3
|
+
class Field
|
4
|
+
|
5
|
+
attr_accessor :attributes
|
6
|
+
|
7
|
+
def initialize(attributes)
|
8
|
+
@attributes = attributes
|
9
|
+
end
|
10
|
+
|
11
|
+
def required?
|
12
|
+
check_bit_true(2, 2)
|
13
|
+
end
|
14
|
+
|
15
|
+
def multiline?
|
16
|
+
self.type == 'Text' && check_bit_true(4096, 13)
|
17
|
+
end
|
18
|
+
|
19
|
+
def push_button?
|
20
|
+
self.type == 'Button' && check_bit_true(65536, 17)
|
21
|
+
end
|
22
|
+
|
23
|
+
def radio_button?
|
24
|
+
self.type == 'Button' && !push_button? && check_bit_true(32768, 16)
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_box?
|
28
|
+
self.type == 'Button' && !push_button? && !radio_button?
|
29
|
+
end
|
30
|
+
|
31
|
+
def field_type
|
32
|
+
if self.type == 'Button'
|
33
|
+
if push_button?
|
34
|
+
'push_button'
|
35
|
+
elsif radio_button?
|
36
|
+
'radio_button'
|
37
|
+
else
|
38
|
+
'check_box'
|
39
|
+
end
|
40
|
+
elsif self.type == 'Text'
|
41
|
+
multiline? ? 'text_area' : 'text_field'
|
42
|
+
elsif self.type == 'Choice'
|
43
|
+
'select'
|
44
|
+
else
|
45
|
+
self.type.downcase
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.alias_attribute method_name, attribute_name
|
50
|
+
define_method(method_name) do
|
51
|
+
attributes[attribute_name]
|
52
|
+
end
|
53
|
+
define_method("#{method_name}=") do |value|
|
54
|
+
attributes[attribute_name] = value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
alias_attribute :name, 'FieldName'
|
59
|
+
alias_attribute :type, 'FieldType'
|
60
|
+
alias_attribute :value, 'FieldValue'
|
61
|
+
alias_attribute :flags, 'FieldFlags'
|
62
|
+
alias_attribute :alt_name, 'FieldNameAlt'
|
63
|
+
alias_attribute :options, 'FieldStateOption'
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def check_bit_true(min_value, bit_position)
|
68
|
+
self.flags.to_i >= min_value && self.flags.to_i.to_s(2)[-bit_position].chr == "1"
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
module PdftkForms
|
3
|
+
# Wraps calls to PdfTk
|
4
|
+
class Wrapper
|
5
|
+
|
6
|
+
attr_reader :path, :options
|
7
|
+
|
8
|
+
# PdftkWrapper.new('/usr/bin/pdftk', :encrypt => true, :encrypt_options => 'allow Printing')
|
9
|
+
# Or
|
10
|
+
# PdftkWrapper.new #assumes 'pdftk' is in the users path
|
11
|
+
def initialize(pdftk_path = nil, options = {})
|
12
|
+
@path = pdftk_path || "pdftk"
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
# pdftk.fill_form('/path/to/form.pdf', '/path/to/destination.pdf', :field1 => 'value 1')
|
17
|
+
# if your version of pdftk does not support xfdf then call
|
18
|
+
# pdftk.fill_form('/path/to/form.pdf', '/path/to/destination.pdf', {:field1 => 'value 1'}, false)
|
19
|
+
def fill_form(template, destination, data = {}, xfdf_input = true)
|
20
|
+
input = xfdf_input ? Xfdf.new(data) : Fdf.new(data)
|
21
|
+
tmp = Tempfile.new('pdf_forms_input')
|
22
|
+
tmp.close
|
23
|
+
input.save_to tmp.path
|
24
|
+
call_pdftk template, 'fill_form', tmp.path, 'output', destination, 'flatten', encrypt_options(tmp.path)
|
25
|
+
tmp.unlink
|
26
|
+
end
|
27
|
+
|
28
|
+
def fields(template_path)
|
29
|
+
unless @all_fields
|
30
|
+
field_output = call_pdftk(template_path, 'dump_data_fields')
|
31
|
+
raw_fields = field_output.split(/^---\n/).reject {|text| text.empty? }
|
32
|
+
@all_fields = raw_fields.map do |field_text|
|
33
|
+
attributes = {}
|
34
|
+
field_text.scan(/^(\w+): (.*)$/) do |key, value|
|
35
|
+
if key == "FieldStateOption"
|
36
|
+
attributes[key] ||= []
|
37
|
+
attributes[key] << value
|
38
|
+
else
|
39
|
+
attributes[key] = value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
Field.new(attributes)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
@all_fields
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def encrypt_options(pwd)
|
51
|
+
if options[:encrypt]
|
52
|
+
['encrypt_128bit', 'owner_pw', pwd, options[:encrypt_options]]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def call_pdftk(*args)
|
57
|
+
%x{#{path} #{args.flatten.compact.join ' '}}
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module PdftkForms
|
2
|
+
class Xfdf
|
3
|
+
|
4
|
+
def initialize(data = {})
|
5
|
+
@data = data
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_xfdf
|
9
|
+
xfdf = Builder::XmlMarkup.new
|
10
|
+
xfdf.instruct!
|
11
|
+
xfdf.xfdf(:xmlns => "http://ns.adobe.com/xfdf/", :"xml:space" => "preserve") do
|
12
|
+
xfdf.fields do
|
13
|
+
@data.each do |key, value|
|
14
|
+
if Hash === value
|
15
|
+
value.each do |sub_key, sub_value|
|
16
|
+
xfdf.field(:name => "#{key}_#{sub_key}") do
|
17
|
+
xfdf.value sub_value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
else
|
21
|
+
xfdf.field(:name => key) do
|
22
|
+
xfdf.value value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
xfdf
|
29
|
+
end
|
30
|
+
|
31
|
+
def save_to(path)
|
32
|
+
xml = to_xfdf.target!
|
33
|
+
(File.open(path, 'w') << xml).close
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/pdftk_forms.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "pdftk_forms/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "pdftk_forms"
|
7
|
+
s.version = PdftkForms::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Tom Cocca"]
|
10
|
+
s.email = ["tom.cocca@gmail.com"]
|
11
|
+
s.homepage = "http://github.com/tcocca/pdftk_forms"
|
12
|
+
s.summary = "Fill out PDF forms with pdftk."
|
13
|
+
s.description = "Fill out editable PDF forms with pdftk (http://www.accesspdf.com/pdftk/)."
|
14
|
+
|
15
|
+
s.rubyforge_project = "pdftk_forms"
|
16
|
+
|
17
|
+
s.add_dependency "builder", '>= 2.1.2'
|
18
|
+
s.add_development_dependency "rspec", "~> 2.5.0"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdftkForms::Fdf do
|
4
|
+
context "multiple fields" do
|
5
|
+
before do
|
6
|
+
@fdf = PdftkForms::Fdf.new :field1 => 'fieldvalue1', :other_field => 'some other value'
|
7
|
+
@fdf_text = @fdf.to_fdf
|
8
|
+
end
|
9
|
+
|
10
|
+
it { @fdf_text.should_not be_nil }
|
11
|
+
it { @fdf_text.should match(%r{<</T\(field1\)/V\(fieldvalue1\)>>}) }
|
12
|
+
it { @fdf_text.should match(%r{<</T\(other_field\)/V\(some other value\)>>}) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context "quoting fields" do
|
16
|
+
before do
|
17
|
+
@fdf = PdftkForms::Fdf.new :field1 => 'field(va)lue1'
|
18
|
+
@fdf_text = @fdf.to_fdf
|
19
|
+
end
|
20
|
+
|
21
|
+
it { @fdf_text.should_not be_nil }
|
22
|
+
it { @fdf_text.should match(%r{<</T\(field1\)/V\(field\\\(va\\\)lue1\)>>}) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "multi-value fields" do
|
26
|
+
before do
|
27
|
+
@fdf = PdftkForms::Fdf.new :field1 => %w(one two)
|
28
|
+
@fdf_text = @fdf.to_fdf
|
29
|
+
end
|
30
|
+
|
31
|
+
it { @fdf_text.should_not be_nil }
|
32
|
+
it { @fdf_text.should match(%r{<</T\(field1\)/V\[\(one\)\(two\)\]>>}) }
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdftkForms::Field do
|
4
|
+
|
5
|
+
context "aliased attributes" do
|
6
|
+
before do
|
7
|
+
@field = PdftkForms::Field.new(
|
8
|
+
'FieldName' => 'test',
|
9
|
+
'FieldType' => 'Text',
|
10
|
+
'FieldValue' => '',
|
11
|
+
'FieldFlags' => 4096
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should respond to" do
|
16
|
+
@field.should respond_to(:name)
|
17
|
+
@field.should respond_to(:type)
|
18
|
+
@field.should respond_to(:value)
|
19
|
+
@field.should respond_to(:flags)
|
20
|
+
@field.should respond_to(:alt_name)
|
21
|
+
@field.should respond_to(:options)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should return the attribute values for the aliased methods" do
|
25
|
+
@field.name.should == 'test'
|
26
|
+
@field.type.should == 'Text'
|
27
|
+
@field.value.should == ''
|
28
|
+
@field.flags.should == 4096
|
29
|
+
@field.alt_name.should be_nil
|
30
|
+
@field.options.should be_nil
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'required?' do
|
35
|
+
before do
|
36
|
+
@attributes = {
|
37
|
+
'FieldName' => 'test',
|
38
|
+
'FieldType' => 'Text',
|
39
|
+
'FieldValue' => '',
|
40
|
+
'FieldFlags' => 0
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should be false" do
|
45
|
+
@field1 = PdftkForms::Field.new(@attributes)
|
46
|
+
@field1.required?.should be_false
|
47
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 1))
|
48
|
+
@field2.required?.should be_false
|
49
|
+
@field3 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 4))
|
50
|
+
@field3.required?.should be_false
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should be true" do
|
54
|
+
@field1 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 2))
|
55
|
+
@field1.required?.should be_true
|
56
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 3))
|
57
|
+
@field2.required?.should be_true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'multiline? text fields' do
|
62
|
+
before do
|
63
|
+
@attributes = {
|
64
|
+
'FieldName' => 'test',
|
65
|
+
'FieldType' => 'Text',
|
66
|
+
'FieldValue' => '',
|
67
|
+
'FieldFlags' => 0
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should be false" do
|
72
|
+
@field1 = PdftkForms::Field.new(@attributes)
|
73
|
+
@field1.multiline?.should be_false
|
74
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 4096))
|
75
|
+
@field2.multiline?.should be_false
|
76
|
+
@field3 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 4095))
|
77
|
+
@field3.multiline?.should be_false
|
78
|
+
@field3 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 8192))
|
79
|
+
@field3.multiline?.should be_false
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should be true" do
|
83
|
+
@field1 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 4096))
|
84
|
+
@field1.multiline?.should be_true
|
85
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 12288))
|
86
|
+
@field2.multiline?.should be_true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'push_button?' do
|
91
|
+
before do
|
92
|
+
@attributes = {
|
93
|
+
'FieldName' => 'test',
|
94
|
+
'FieldType' => 'Button',
|
95
|
+
'FieldValue' => '',
|
96
|
+
'FieldFlags' => 0
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should be false" do
|
101
|
+
@field1 = PdftkForms::Field.new(@attributes)
|
102
|
+
@field1.push_button?.should be_false
|
103
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 32768))
|
104
|
+
@field2.push_button?.should be_false
|
105
|
+
@field3 = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 131072))
|
106
|
+
@field3.push_button?.should be_false
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should be true" do
|
110
|
+
@field1 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 65536))
|
111
|
+
@field1.push_button?.should be_true
|
112
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 196608))
|
113
|
+
@field2.push_button?.should be_true
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'radio_button?' do
|
118
|
+
before do
|
119
|
+
@attributes = {
|
120
|
+
'FieldName' => 'test',
|
121
|
+
'FieldType' => 'Button',
|
122
|
+
'FieldValue' => '',
|
123
|
+
'FieldFlags' => 0
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should be false" do
|
128
|
+
@field1 = PdftkForms::Field.new(@attributes)
|
129
|
+
@field1.radio_button?.should be_false
|
130
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 65536))
|
131
|
+
@field2.radio_button?.should be_false
|
132
|
+
@field3 = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 32767))
|
133
|
+
@field3.radio_button?.should be_false
|
134
|
+
@field4 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 98304))
|
135
|
+
@field4.radio_button?.should be_false
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should be true" do
|
139
|
+
@field1 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 32768))
|
140
|
+
@field1.radio_button?.should be_true
|
141
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 49153))
|
142
|
+
@field2.radio_button?.should be_true
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context 'check_box?' do
|
147
|
+
before do
|
148
|
+
@attributes = {
|
149
|
+
'FieldName' => 'test',
|
150
|
+
'FieldType' => 'Button',
|
151
|
+
'FieldValue' => '',
|
152
|
+
'FieldFlags' => 0
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should be false" do
|
157
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 65536))
|
158
|
+
@field2.check_box?.should be_false
|
159
|
+
@field3 = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 32768))
|
160
|
+
@field3.check_box?.should be_false
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should be true" do
|
164
|
+
@field1 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 0))
|
165
|
+
@field1.check_box?.should be_true
|
166
|
+
@field2 = PdftkForms::Field.new(@attributes.merge('FieldFlags' => 32767))
|
167
|
+
@field2.check_box?.should be_true
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context 'field_type' do
|
172
|
+
before do
|
173
|
+
@attributes = {
|
174
|
+
'FieldName' => 'test',
|
175
|
+
'FieldValue' => '',
|
176
|
+
'FieldFlags' => 0
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should reutrn check_box" do
|
181
|
+
@field = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button'))
|
182
|
+
@field.field_type.should == "check_box"
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should return radio_button" do
|
186
|
+
@field = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 32768))
|
187
|
+
@field.field_type.should == "radio_button"
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should return push_button" do
|
191
|
+
@field = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Button', 'FieldFlags' => 65536))
|
192
|
+
@field.field_type.should == "push_button"
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should return text_field" do
|
196
|
+
@field = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Text'))
|
197
|
+
@field.field_type.should == "text_field"
|
198
|
+
end
|
199
|
+
|
200
|
+
it "should return text_area" do
|
201
|
+
@field = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Text', 'FieldFlags' => 4096))
|
202
|
+
@field.field_type.should == "text_area"
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should return select" do
|
206
|
+
@field = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Choice'))
|
207
|
+
@field.field_type.should == "select"
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should return lowercased FieldType" do
|
211
|
+
@field = PdftkForms::Field.new(@attributes.merge('FieldType' => 'Something'))
|
212
|
+
@field.field_type.should == "something"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdftkForms::Wrapper do
|
4
|
+
|
5
|
+
context "new" do
|
6
|
+
it "should set the default path" do
|
7
|
+
@pdftk = PdftkForms::Wrapper.new
|
8
|
+
@pdftk.path.should == "pdftk"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should allow for custom paths" do
|
12
|
+
@pdftk = PdftkForms::Wrapper.new('/usr/local/bin/pdftk')
|
13
|
+
@pdftk.path.should == "/usr/local/bin/pdftk"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "fields" do
|
18
|
+
before do
|
19
|
+
@pdftk = PdftkForms::Wrapper.new
|
20
|
+
@fields = @pdftk.fields(path_to_pdf('fields'))
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should get the total number of fields" do
|
24
|
+
@fields.size.should == 8
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return an array of PdftkForms::Field objects" do
|
28
|
+
@fields.each do |field|
|
29
|
+
field.should be_kind_of(PdftkForms::Field)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should set the field data" do
|
34
|
+
@fields[0].name.should == "text_not_required"
|
35
|
+
@fields[0].value.should == nil
|
36
|
+
@fields[0].type.should == "Text"
|
37
|
+
@fields[0].flags.should == "0"
|
38
|
+
@fields[0].alt_name.should == nil
|
39
|
+
@fields[0].options.should == nil
|
40
|
+
@fields[0].field_type.should == "text_field"
|
41
|
+
|
42
|
+
@fields[1].name.should == "combo_box"
|
43
|
+
@fields[1].value.should == nil
|
44
|
+
@fields[1].type.should == "Choice"
|
45
|
+
@fields[1].flags.should == "131072"
|
46
|
+
@fields[1].alt_name.should == nil
|
47
|
+
@fields[1].options.should == ["Jason", "Tom"]
|
48
|
+
@fields[1].field_type.should == "select"
|
49
|
+
|
50
|
+
@fields[2].name.should == "text_required"
|
51
|
+
@fields[2].value.should == nil
|
52
|
+
@fields[2].type.should == "Text"
|
53
|
+
@fields[2].flags.should == "2"
|
54
|
+
@fields[2].alt_name.should == nil
|
55
|
+
@fields[2].options.should == nil
|
56
|
+
@fields[2].field_type.should == "text_field"
|
57
|
+
|
58
|
+
@fields[3].name.should == "check_box"
|
59
|
+
@fields[3].value.should == nil
|
60
|
+
@fields[3].type.should == "Button"
|
61
|
+
@fields[3].flags.should == "0"
|
62
|
+
@fields[3].alt_name.should == nil
|
63
|
+
@fields[3].options.should == ["Off", "Yes"]
|
64
|
+
@fields[3].field_type.should == "check_box"
|
65
|
+
|
66
|
+
@fields[4].name.should == "radio_button"
|
67
|
+
@fields[4].value.should == nil
|
68
|
+
@fields[4].type.should == "Button"
|
69
|
+
@fields[4].flags.should == "49152"
|
70
|
+
@fields[4].alt_name.should == nil
|
71
|
+
@fields[4].options.should == ["No", "Off", "Yes"]
|
72
|
+
@fields[4].field_type.should == "radio_button"
|
73
|
+
|
74
|
+
@fields[5].name.should == "list_box"
|
75
|
+
@fields[5].value.should == "sam"
|
76
|
+
@fields[5].type.should == "Choice"
|
77
|
+
@fields[5].flags.should == "0"
|
78
|
+
@fields[5].alt_name.should == nil
|
79
|
+
@fields[5].options.should == ["dave", "sam"]
|
80
|
+
@fields[5].field_type.should == "select"
|
81
|
+
|
82
|
+
@fields[6].name.should == "button"
|
83
|
+
@fields[6].value.should == nil
|
84
|
+
@fields[6].type.should == "Button"
|
85
|
+
@fields[6].flags.should == "65536"
|
86
|
+
@fields[6].alt_name.should == nil
|
87
|
+
@fields[6].options.should == nil
|
88
|
+
@fields[6].field_type.should == "push_button"
|
89
|
+
|
90
|
+
@fields[7].name.should == "text_area"
|
91
|
+
@fields[7].value.should == nil
|
92
|
+
@fields[7].type.should == "Text"
|
93
|
+
@fields[7].flags.should == "4096"
|
94
|
+
@fields[7].alt_name.should == nil
|
95
|
+
@fields[7].options.should == nil
|
96
|
+
@fields[7].field_type.should == "text_area"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def path_to_pdf(filename)
|
101
|
+
File.join File.dirname(__FILE__), '../', 'test_pdfs', "#{filename}.pdf"
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
def valid_xfdf
|
2
|
+
xfdf = Builder::XmlMarkup.new
|
3
|
+
xfdf.instruct!
|
4
|
+
xfdf.xfdf(:xmlns => "http://ns.adobe.com/xfdf/", :"xml:space" => "preserve") do
|
5
|
+
xfdf.fields do
|
6
|
+
xfdf.field(:name => :test) do
|
7
|
+
xfdf.value "one"
|
8
|
+
end
|
9
|
+
xfdf.field(:name => :user) do
|
10
|
+
xfdf.value "tom"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
xfdf
|
15
|
+
end
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pdftk_forms
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Tom Cocca
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-05-09 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: builder
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 15
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 1
|
33
|
+
- 2
|
34
|
+
version: 2.1.2
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 27
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 5
|
49
|
+
- 0
|
50
|
+
version: 2.5.0
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
description: Fill out editable PDF forms with pdftk (http://www.accesspdf.com/pdftk/).
|
54
|
+
email:
|
55
|
+
- tom.cocca@gmail.com
|
56
|
+
executables: []
|
57
|
+
|
58
|
+
extensions: []
|
59
|
+
|
60
|
+
extra_rdoc_files: []
|
61
|
+
|
62
|
+
files:
|
63
|
+
- .gitignore
|
64
|
+
- CHANGELOG.rdoc
|
65
|
+
- Gemfile
|
66
|
+
- Gemfile.lock
|
67
|
+
- LICENSE
|
68
|
+
- README.rdoc
|
69
|
+
- Rakefile
|
70
|
+
- lib/pdftk_forms.rb
|
71
|
+
- lib/pdftk_forms/fdf.rb
|
72
|
+
- lib/pdftk_forms/field.rb
|
73
|
+
- lib/pdftk_forms/version.rb
|
74
|
+
- lib/pdftk_forms/wrapper.rb
|
75
|
+
- lib/pdftk_forms/xfdf.rb
|
76
|
+
- pdftk_forms.gemspec
|
77
|
+
- spec/pdftk_forms/fdf_spec.rb
|
78
|
+
- spec/pdftk_forms/field_spec.rb
|
79
|
+
- spec/pdftk_forms/wrapper_spec.rb
|
80
|
+
- spec/pdftk_forms/xfdf_spec.rb
|
81
|
+
- spec/spec_helper.rb
|
82
|
+
- spec/support/xfdf_helper.rb
|
83
|
+
- spec/test_pdfs/fields.pdf
|
84
|
+
has_rdoc: true
|
85
|
+
homepage: http://github.com/tcocca/pdftk_forms
|
86
|
+
licenses: []
|
87
|
+
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
hash: 3
|
99
|
+
segments:
|
100
|
+
- 0
|
101
|
+
version: "0"
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
hash: 3
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
version: "0"
|
111
|
+
requirements: []
|
112
|
+
|
113
|
+
rubyforge_project: pdftk_forms
|
114
|
+
rubygems_version: 1.4.2
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: Fill out PDF forms with pdftk.
|
118
|
+
test_files:
|
119
|
+
- spec/pdftk_forms/fdf_spec.rb
|
120
|
+
- spec/pdftk_forms/field_spec.rb
|
121
|
+
- spec/pdftk_forms/wrapper_spec.rb
|
122
|
+
- spec/pdftk_forms/xfdf_spec.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
- spec/support/xfdf_helper.rb
|
125
|
+
- spec/test_pdfs/fields.pdf
|