pdf_ravager 0.0.8 → 0.1.0
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/.travis.yml +2 -7
- data/LICENSE +1 -1
- data/README.md +37 -19
- data/Rakefile +1 -1
- data/lib/pdf_ravager.rb +1 -2
- data/lib/pdf_ravager/field_types/acro_form.rb +36 -0
- data/lib/pdf_ravager/field_types/xfa.rb +65 -0
- data/lib/pdf_ravager/fields/checkbox.rb +36 -0
- data/lib/pdf_ravager/fields/radio.rb +38 -0
- data/lib/pdf_ravager/fields/rich_text.rb +62 -0
- data/lib/pdf_ravager/fields/text.rb +22 -0
- data/lib/pdf_ravager/fieldsets/checkbox_group.rb +20 -0
- data/lib/pdf_ravager/fieldsets/radio_group.rb +16 -0
- data/lib/pdf_ravager/kernel.rb +7 -0
- data/lib/pdf_ravager/ravager.rb +35 -113
- data/lib/pdf_ravager/template.rb +61 -0
- data/lib/pdf_ravager/version.rb +2 -2
- data/pdf_ravager.gemspec +2 -2
- data/spec/integration/integration_helper.rb +5 -5
- data/spec/integration/multiline_text_field/spec.rb +3 -3
- data/spec/integration/text_field/spec.rb +3 -3
- data/spec/unit/fields/checkbox_spec.rb +27 -0
- data/spec/unit/fields/fields_helper.rb +1 -0
- data/spec/unit/kernel_spec.rb +27 -0
- data/spec/unit/template_spec.rb +61 -0
- metadata +48 -40
- data/lib/pdf_ravager/pdf.rb +0 -105
- data/spec/unit/pdf_spec.rb +0 -48
data/.travis.yml
CHANGED
@@ -1,14 +1,9 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
-
|
4
|
-
- "1.9.3"
|
3
|
+
- jruby-18mode
|
5
4
|
- jruby-19mode
|
6
|
-
-
|
7
|
-
matrix:
|
8
|
-
allow_failures:
|
9
|
-
- rvm: jruby-19mode
|
5
|
+
- jruby-head
|
10
6
|
before_install:
|
11
7
|
- sudo add-apt-repository "deb http://archive.canonical.com/ $(lsb_release -sc) partner" -y
|
12
8
|
- sudo apt-get update -y
|
13
9
|
- sudo apt-get install acroread ghostscript -y
|
14
|
-
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -11,33 +11,47 @@ XFA documents.
|
|
11
11
|
## Synopsis
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
require 'pdf_ravager'
|
14
|
+
require 'pdf_ravager/kernel'
|
15
15
|
|
16
|
-
data = {:
|
16
|
+
data = {name: 'Bob', gender: 'm', relation: 'Uncle' }
|
17
17
|
|
18
|
-
|
19
|
-
text
|
20
|
-
|
21
|
-
radio_group 'sex' do
|
22
|
-
fill 'male' if data[:gender] == 'm'
|
23
|
-
fill 'female' if data[:gender] == 'f'
|
18
|
+
template = pdf do |p|
|
19
|
+
p.text 'name', data[:name]
|
20
|
+
p.rich_text 'name_stylized', "<b>#{data[:name]}</b>"
|
21
|
+
p.radio_group 'sex' do |rg|
|
22
|
+
rg.fill 'male' if data[:gender] == 'm'
|
23
|
+
rg.fill 'female' if data[:gender] == 'f'
|
24
24
|
end
|
25
|
-
check 'related' if data[:relation]
|
26
|
-
checkbox_group 'relation' do
|
25
|
+
p.check 'related' if data[:relation]
|
26
|
+
p.checkbox_group 'relation' do |cg|
|
27
27
|
case data[:relation]
|
28
28
|
when 'Mom', 'Dad'
|
29
|
-
check 'parent'
|
29
|
+
cg.check 'parent'
|
30
30
|
when 'Brother', 'Sister'
|
31
|
-
check 'sibling'
|
31
|
+
cg.check 'sibling'
|
32
32
|
else
|
33
|
-
check 'other'
|
33
|
+
cg.check 'other'
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
template.ravage '/tmp/info.pdf', out_file: '/tmp/info_filled.pdf'
|
39
39
|
# if you'd like the populated form to be read-only:
|
40
|
-
|
40
|
+
template.ravage '/tmp/info.pdf', out_file: '/tmp/info_filled.pdf', read_only: true
|
41
|
+
```
|
42
|
+
|
43
|
+
If you don't want the global `pdf` method, the default `require 'pdf_ravager'`
|
44
|
+
actually doesn't add it. You just need to be more wordy in this case:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
require 'pdf_ravager'
|
48
|
+
|
49
|
+
data = {name: 'Bob', gender: 'm', relation: 'Uncle' }
|
50
|
+
|
51
|
+
template = PDFRavager::Template.new do |p|
|
52
|
+
p.text 'name', data[:name]
|
53
|
+
# ...
|
54
|
+
end
|
41
55
|
```
|
42
56
|
|
43
57
|
## Usage
|
@@ -66,20 +80,24 @@ Because there is no such thing as a "checkbox group," the
|
|
66
80
|
example,
|
67
81
|
|
68
82
|
```ruby
|
69
|
-
|
70
|
-
|
83
|
+
pdf do |p|
|
84
|
+
p.checkbox_group 'relation' do |cg|
|
85
|
+
cg.check 'parent'
|
86
|
+
end
|
71
87
|
end
|
72
88
|
```
|
73
89
|
|
74
90
|
is equivalent to
|
75
91
|
|
76
92
|
```ruby
|
77
|
-
|
93
|
+
pdf do |p|
|
94
|
+
p.check 'relation.parent'
|
95
|
+
end
|
78
96
|
```
|
79
97
|
|
80
98
|
## Copyright
|
81
99
|
|
82
|
-
Copyright (c) 2012 Abe Voelker. Released under the terms of the
|
100
|
+
Copyright (c) 2012-2013 Abe Voelker. Released under the terms of the
|
83
101
|
MIT license. See LICENSE for details.
|
84
102
|
|
85
103
|
The [version of iText][2] vendored is licensed under the LGPL.
|
data/Rakefile
CHANGED
data/lib/pdf_ravager.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'java'
|
2
|
+
require File.dirname(__FILE__) + '/../../../vendor/iText-4.2.0'
|
3
|
+
|
4
|
+
module PDFRavager
|
5
|
+
module FieldTypes
|
6
|
+
module AcroForm
|
7
|
+
|
8
|
+
module SOM
|
9
|
+
def self.short_name(str)
|
10
|
+
com.lowagie.text.pdf.XfaForm::Xml2Som.getShortName(self.escape(str))
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.escape(str)
|
14
|
+
com.lowagie.text.pdf.XfaForm::Xml2Som.escapeSom(str) # just does: str.gsub(/\./) { '\\.' }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def acro_form_name
|
19
|
+
@name
|
20
|
+
end
|
21
|
+
|
22
|
+
def acro_form_value
|
23
|
+
@value.to_s
|
24
|
+
end
|
25
|
+
|
26
|
+
def set_acro_form_value(acro_fields)
|
27
|
+
begin
|
28
|
+
acro_fields.setField(SOM.short_name(acro_form_name), acro_form_value)
|
29
|
+
rescue java.lang.NullPointerException
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module PDFRavager
|
4
|
+
module FieldTypes
|
5
|
+
module XFA
|
6
|
+
|
7
|
+
def xfa_node_type
|
8
|
+
'text'
|
9
|
+
end
|
10
|
+
|
11
|
+
def xfa_name
|
12
|
+
@name
|
13
|
+
end
|
14
|
+
|
15
|
+
def xfa_value
|
16
|
+
@value.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_xfa_value(xfa)
|
20
|
+
# the double-load is to work around a Nokogiri bug I found:
|
21
|
+
# https://github.com/sparklemotion/nokogiri/issues/781
|
22
|
+
doc = Nokogiri::XML(Nokogiri::XML::Document.wrap(xfa.getDomDocument).to_xml)
|
23
|
+
# first, assume the user-provided field name is an xpath and use it directly:
|
24
|
+
strict_match =
|
25
|
+
begin
|
26
|
+
doc.xpath(xfa_name)
|
27
|
+
rescue Nokogiri::XML::XPath::SyntaxError
|
28
|
+
[]
|
29
|
+
end
|
30
|
+
# otherwise, we'll loosely match the field name anywhere in the document:
|
31
|
+
loose_match = doc.xpath("//*[local-name()='field'][@name='#{xfa_name}']")
|
32
|
+
matched_nodes = strict_match.any? ? strict_match : loose_match
|
33
|
+
matched_nodes.each do |node|
|
34
|
+
value_node = node.at_xpath("*[local-name()='value']")
|
35
|
+
if value_node
|
36
|
+
text_node = value_node.at_xpath("*[local-name()='#{xfa_node_type}']")
|
37
|
+
if text_node
|
38
|
+
# Complete node structure already exists - just set the value
|
39
|
+
text_node.content = xfa_value
|
40
|
+
else
|
41
|
+
# <value> node exists, but without child <text> node
|
42
|
+
Nokogiri::XML::Builder.with(value_node) do |xml|
|
43
|
+
xml.text_ {
|
44
|
+
xml.send("#{xfa_node_type}_", xfa_value)
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
else
|
49
|
+
# No <value> node exists - create whole structure
|
50
|
+
Nokogiri::XML::Builder.with(node) do |xml|
|
51
|
+
xml.value_ {
|
52
|
+
xml.send("#{xfa_node_type}_") {
|
53
|
+
xml.text xfa_value
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
xfa.setDomDocument(doc.to_java)
|
60
|
+
xfa.setChanged(true)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'pdf_ravager/field_types/acro_form'
|
2
|
+
require 'pdf_ravager/field_types/xfa'
|
3
|
+
|
4
|
+
module PDFRavager
|
5
|
+
module Fields
|
6
|
+
class Checkbox
|
7
|
+
include FieldTypes::AcroForm
|
8
|
+
include FieldTypes::XFA
|
9
|
+
|
10
|
+
attr_reader :name, :value
|
11
|
+
|
12
|
+
def initialize(name, value, opts={})
|
13
|
+
@name, @value = name, value
|
14
|
+
@true_value = opts[:true_value] ? opts[:true_value] : '1'
|
15
|
+
@false_value = opts[:false_value] ? opts[:false_value] : '0'
|
16
|
+
end
|
17
|
+
|
18
|
+
def ==(other)
|
19
|
+
self.name == other.name && self.value == other.value
|
20
|
+
end
|
21
|
+
|
22
|
+
def xfa_node_type
|
23
|
+
'integer'
|
24
|
+
end
|
25
|
+
|
26
|
+
def xfa_value
|
27
|
+
@value ? @true_value : @false_value
|
28
|
+
end
|
29
|
+
|
30
|
+
def acro_form_value
|
31
|
+
@value ? @true_value : @false_value
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'pdf_ravager/field_types/acro_form'
|
2
|
+
require 'pdf_ravager/field_types/xfa'
|
3
|
+
|
4
|
+
module PDFRavager
|
5
|
+
module Fields
|
6
|
+
class Radio
|
7
|
+
include FieldTypes::AcroForm
|
8
|
+
include FieldTypes::XFA
|
9
|
+
|
10
|
+
attr_reader :group_name, :name
|
11
|
+
|
12
|
+
def initialize(group_name, name)
|
13
|
+
@group_name, @name = group_name, name
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
self.group_name == other.group_name && self.name == other.name
|
18
|
+
end
|
19
|
+
|
20
|
+
def acro_form_name
|
21
|
+
@group_name
|
22
|
+
end
|
23
|
+
|
24
|
+
def xfa_name
|
25
|
+
@group_name
|
26
|
+
end
|
27
|
+
|
28
|
+
def acro_form_value
|
29
|
+
@name
|
30
|
+
end
|
31
|
+
|
32
|
+
def xfa_value
|
33
|
+
@name
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'pdf_ravager/field_types/xfa'
|
2
|
+
|
3
|
+
module PDFRavager
|
4
|
+
module Fields
|
5
|
+
class RichText
|
6
|
+
include FieldTypes::XFA
|
7
|
+
|
8
|
+
attr_reader :name, :value
|
9
|
+
|
10
|
+
def initialize(name, value)
|
11
|
+
@name, @value = name, value
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
self.name == other.name && self.value == other.value
|
16
|
+
end
|
17
|
+
|
18
|
+
def set_xfa_value(xfa)
|
19
|
+
# the double-load is to work around a Nokogiri bug I found:
|
20
|
+
# https://github.com/sparklemotion/nokogiri/issues/781
|
21
|
+
doc = Nokogiri::XML(Nokogiri::XML::Document.wrap(xfa.getDomDocument).to_xml)
|
22
|
+
# first, assume the user-provided field name is an xpath and use it directly:
|
23
|
+
strict_match =
|
24
|
+
begin
|
25
|
+
doc.xpath(xfa_name)
|
26
|
+
rescue Nokogiri::XML::XPath::SyntaxError
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
# otherwise, we'll loosely match the field name anywhere in the document:
|
30
|
+
loose_match = doc.xpath("//*[local-name()='field'][@name='#{xfa_name}']")
|
31
|
+
matched_nodes = strict_match.any? ? strict_match : loose_match
|
32
|
+
matched_nodes.each do |node|
|
33
|
+
value_node = node.at_xpath("*[local-name()='value']")
|
34
|
+
if value_node
|
35
|
+
# <value> node exists - just create <exData>
|
36
|
+
Nokogiri::XML::Builder.with(value_node) do |xml|
|
37
|
+
xml.exData('contentType' => 'text/html') do
|
38
|
+
xml.body_('xmlns' => "http://www.w3.org/1999/xhtml", 'xmlns:xfa' => "http://www.xfa.org/schema/xfa-data/1.0/") do
|
39
|
+
xml << xfa_value # Note: this value is not sanitized/escaped!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
else
|
44
|
+
# No <value> node exists - create whole structure
|
45
|
+
Nokogiri::XML::Builder.with(node) do |xml|
|
46
|
+
xml.value_ do
|
47
|
+
xml.exData('contentType' => 'text/html') do
|
48
|
+
xml.body_('xmlns' => "http://www.w3.org/1999/xhtml", 'xmlns:xfa' => "http://www.xfa.org/schema/xfa-data/1.0/") do
|
49
|
+
xml << xfa_value # Note: this value is not sanitized/escaped!
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
xfa.setDomDocument(doc.to_java)
|
57
|
+
xfa.setChanged(true)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'pdf_ravager/field_types/acro_form'
|
2
|
+
require 'pdf_ravager/field_types/xfa'
|
3
|
+
|
4
|
+
module PDFRavager
|
5
|
+
module Fields
|
6
|
+
class Text
|
7
|
+
include FieldTypes::AcroForm
|
8
|
+
include FieldTypes::XFA
|
9
|
+
|
10
|
+
attr_reader :name, :value
|
11
|
+
|
12
|
+
def initialize(name, value)
|
13
|
+
@name, @value = name, value
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
self.name == other.name && self.value == other.value
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module PDFRavager
|
2
|
+
module Fieldsets
|
3
|
+
class CheckboxGroup
|
4
|
+
|
5
|
+
def initialize(template, name)
|
6
|
+
@template, @name = template, name
|
7
|
+
yield self if block_given?
|
8
|
+
end
|
9
|
+
|
10
|
+
def check(name, opts={})
|
11
|
+
@template.check("#{@name}.#{name}", opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def uncheck(name, opts={})
|
15
|
+
@template.uncheck("#{@name}.#{name}", opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/pdf_ravager/ravager.rb
CHANGED
@@ -1,90 +1,38 @@
|
|
1
|
+
unless RUBY_PLATFORM =~ /java/
|
2
|
+
raise "You can only ravage PDFs using JRuby, not #{RUBY_PLATFORM}!"
|
3
|
+
end
|
4
|
+
|
1
5
|
require 'java'
|
2
6
|
require 'nokogiri'
|
3
7
|
require File.dirname(__FILE__) + '/../../vendor/iText-4.2.0'
|
4
8
|
|
5
|
-
java_import "com.lowagie.text.pdf.AcroFields"
|
6
|
-
java_import "com.lowagie.text.pdf.PdfArray"
|
7
|
-
java_import "com.lowagie.text.pdf.PdfDictionary"
|
8
|
-
java_import "com.lowagie.text.pdf.PdfName"
|
9
|
-
java_import "com.lowagie.text.pdf.PdfObject"
|
10
|
-
java_import "com.lowagie.text.pdf.PdfReader"
|
11
|
-
java_import "com.lowagie.text.pdf.PdfStamper"
|
12
|
-
java_import "com.lowagie.text.pdf.PdfStream"
|
13
|
-
java_import "com.lowagie.text.pdf.PdfWriter"
|
14
|
-
java_import "com.lowagie.text.pdf.XfaForm"
|
15
|
-
java_import "com.lowagie.text.pdf.XfdfReader"
|
16
|
-
|
17
9
|
module PDFRavager
|
18
10
|
class Ravager
|
19
11
|
private_class_method :new
|
20
12
|
|
21
|
-
def self.
|
13
|
+
def self.ravage(template, opts={})
|
22
14
|
opts = {:in_file => opts} if opts.is_a? String
|
23
15
|
out = if opts[:out_file]
|
24
16
|
java.io.FileOutputStream.new(opts[:out_file])
|
25
17
|
else
|
26
18
|
java.io.ByteArrayOutputStream.new
|
27
19
|
end
|
28
|
-
|
29
|
-
ravager
|
30
|
-
|
31
|
-
ravager.destroy
|
20
|
+
ravager = new(template, opts.merge({:out => out}))
|
21
|
+
ravager.send(:set_field_values)
|
22
|
+
ravager.send(:set_read_only) if opts[:read_only]
|
23
|
+
ravager.send(:destroy)
|
32
24
|
out
|
33
25
|
end
|
34
26
|
|
35
|
-
def set_field_value(name, value, type=nil, options={})
|
36
|
-
return set_rich_text_field(name, value) if options && options[:rich]
|
37
|
-
begin
|
38
|
-
# First try AcroForms method of setting value
|
39
|
-
@afields.setField(SOM.short_name(name), value)
|
40
|
-
rescue java.lang.NullPointerException
|
41
|
-
end
|
42
|
-
# Also look for the XDP node and set that value
|
43
|
-
# Note: the double-load is to work around a Nokogiri bug I found:
|
44
|
-
# https://github.com/sparklemotion/nokogiri/issues/781
|
45
|
-
doc = Nokogiri::XML(Nokogiri::XML::Document.wrap(@xfa.getDomDocument).to_xml)
|
46
|
-
node_type = type == :checkbox ? 'integer' : 'text'
|
47
|
-
doc.xpath("//*[local-name()='field'][@name='#{name}']").each do |node|
|
48
|
-
value_node = node.at_xpath("*[local-name()='value']")
|
49
|
-
if value_node
|
50
|
-
text_node = value_node.at_xpath("*[local-name()='#{node_type}']")
|
51
|
-
if text_node
|
52
|
-
# Complete node structure already exists - just set the value
|
53
|
-
text_node.content = value
|
54
|
-
else
|
55
|
-
# <value> node exists, but without child <text> node
|
56
|
-
Nokogiri::XML::Builder.with(value_node) do |xml|
|
57
|
-
xml.text_ {
|
58
|
-
xml.send("#{node_type}_", value)
|
59
|
-
}
|
60
|
-
end
|
61
|
-
end
|
62
|
-
else
|
63
|
-
# No <value> node exists - create whole structure
|
64
|
-
Nokogiri::XML::Builder.with(node) do |xml|
|
65
|
-
xml.value_ {
|
66
|
-
xml.send("#{node_type}_") {
|
67
|
-
xml.text value
|
68
|
-
}
|
69
|
-
}
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
@xfa.setDomDocument(doc.to_java)
|
74
|
-
@xfa.setChanged(true)
|
75
|
-
end
|
76
|
-
|
77
|
-
def destroy
|
78
|
-
read_only! if @opts[:read_only]
|
79
|
-
@stamper.close
|
80
|
-
end
|
81
|
-
|
82
27
|
private
|
83
28
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
29
|
+
# instantiation is private because there is a lot of state mutation
|
30
|
+
# and some invariants that need to be cleaned up. therefore, Ravager's
|
31
|
+
# lifecycle is managed by the public class method `ravage`.
|
32
|
+
def initialize(template, opts={})
|
33
|
+
@template, @opts = template, opts
|
34
|
+
@reader = com.lowagie.text.pdf.PdfReader.new(opts[:in_file])
|
35
|
+
@stamper = com.lowagie.text.pdf.PdfStamper.new(@reader, opts[:out])
|
88
36
|
@afields = @stamper.getAcroFields
|
89
37
|
@xfa = @afields.getXfa
|
90
38
|
@som = @xfa.getDatasetsSom
|
@@ -95,62 +43,36 @@ module PDFRavager
|
|
95
43
|
end
|
96
44
|
end
|
97
45
|
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
111
|
-
else
|
112
|
-
# No <value> node exists - create whole structure
|
113
|
-
Nokogiri::XML::Builder.with(node) do |xml|
|
114
|
-
xml.value_ do
|
115
|
-
xml.exData('contentType' => 'text/html') do
|
116
|
-
xml.body_('xmlns' => "http://www.w3.org/1999/xhtml", 'xmlns:xfa' => "http://www.xfa.org/schema/xfa-data/1.0/") do
|
117
|
-
xml << value # Note: this value is not sanitized/escaped!
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
46
|
+
def destroy
|
47
|
+
@stamper.close
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_field_values
|
51
|
+
case @type
|
52
|
+
when :acro_forms
|
53
|
+
@template.fields.each{|f| f.set_acro_form_value(@afields) }
|
54
|
+
when :xfa
|
55
|
+
@template.fields.each do |f|
|
56
|
+
f.set_acro_form_value(@afields) if f.respond_to? :set_acro_form_value
|
57
|
+
f.set_xfa_value(@xfa) if f.respond_to? :set_xfa_value
|
122
58
|
end
|
123
59
|
end
|
124
|
-
@xfa.setDomDocument(doc.to_java)
|
125
|
-
@xfa.setChanged(true)
|
126
60
|
end
|
127
61
|
|
128
|
-
def
|
62
|
+
def set_read_only
|
129
63
|
case @type
|
130
64
|
when :acro_forms
|
131
65
|
@stamper.setFormFlattening(true)
|
132
66
|
when :xfa
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
doc = Nokogiri::XML(Nokogiri::XML::Document.wrap(@xfa.getDomDocument).to_xml)
|
137
|
-
doc.xpath("//*[local-name()='field']").each do |node|
|
138
|
-
node["access"] = "readOnly"
|
139
|
-
end
|
140
|
-
@xfa.setDomDocument(doc.to_java)
|
141
|
-
@xfa.setChanged(true)
|
67
|
+
doc = Nokogiri::XML(Nokogiri::XML::Document.wrap(@xfa.getDomDocument).to_xml)
|
68
|
+
doc.xpath("//*[local-name()='field']").each do |node|
|
69
|
+
node["access"] = "readOnly"
|
142
70
|
end
|
71
|
+
@xfa.setDomDocument(doc.to_java)
|
72
|
+
@xfa.setChanged(true)
|
143
73
|
end
|
144
74
|
end
|
145
|
-
end
|
146
|
-
|
147
|
-
class SOM
|
148
|
-
def self.short_name(str)
|
149
|
-
XfaForm::Xml2Som.getShortName(self.escape(str))
|
150
|
-
end
|
151
75
|
|
152
|
-
def self.escape(str)
|
153
|
-
XfaForm::Xml2Som.escapeSom(str) # just does: str.gsub(/\./) { '\\.' }
|
154
|
-
end
|
155
76
|
end
|
77
|
+
|
156
78
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'pdf_ravager/fields/text'
|
2
|
+
require 'pdf_ravager/fields/rich_text'
|
3
|
+
require 'pdf_ravager/fields/checkbox'
|
4
|
+
require 'pdf_ravager/fields/radio'
|
5
|
+
require 'pdf_ravager/fieldsets/checkbox_group'
|
6
|
+
require 'pdf_ravager/fieldsets/radio_group'
|
7
|
+
require 'pdf_ravager/ravager' if RUBY_PLATFORM =~ /java/
|
8
|
+
|
9
|
+
module PDFRavager
|
10
|
+
class Template
|
11
|
+
attr_reader :name, :fields
|
12
|
+
|
13
|
+
def initialize(name=nil)
|
14
|
+
@name, @fields = name, []
|
15
|
+
yield self if block_given?
|
16
|
+
end
|
17
|
+
|
18
|
+
def text(name, value)
|
19
|
+
@fields << PDFRavager::Fields::Text.new(name, value)
|
20
|
+
end
|
21
|
+
|
22
|
+
def rich_text(name, value)
|
23
|
+
@fields << PDFRavager::Fields::RichText.new(name, value)
|
24
|
+
end
|
25
|
+
|
26
|
+
def check(name, opts={})
|
27
|
+
@fields << PDFRavager::Fields::Checkbox.new(name, true, opts)
|
28
|
+
end
|
29
|
+
|
30
|
+
def uncheck(name, opts={})
|
31
|
+
@fields << PDFRavager::Fields::Checkbox.new(name, false, opts)
|
32
|
+
end
|
33
|
+
|
34
|
+
def fill(group_name, name)
|
35
|
+
@fields << PDFRavager::Fields::Radio.new(group_name, name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def checkbox_group(group_name, &blk)
|
39
|
+
PDFRavager::Fieldsets::CheckboxGroup.new(self, group_name, &blk)
|
40
|
+
end
|
41
|
+
|
42
|
+
def radio_group(group_name, &blk)
|
43
|
+
PDFRavager::Fieldsets::RadioGroup.new(self, group_name, &blk)
|
44
|
+
end
|
45
|
+
|
46
|
+
if RUBY_PLATFORM =~ /java/
|
47
|
+
def ravage(file, opts={})
|
48
|
+
PDFRavager::Ravager.ravage(self, opts.merge({:in_file => file}))
|
49
|
+
end
|
50
|
+
else
|
51
|
+
def ravage(file, opts={})
|
52
|
+
raise "You can only ravage PDFs using JRuby, not #{RUBY_PLATFORM}!"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def ==(other)
|
57
|
+
self.fields == other.fields
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
data/lib/pdf_ravager/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module PDFRavager
|
2
|
-
VERSION = "0.0
|
3
|
-
end
|
2
|
+
VERSION = "0.1.0"
|
3
|
+
end
|
data/pdf_ravager.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.homepage = 'https://github.com/abevoelker/pdf_ravager'
|
10
10
|
s.summary = %q{DSL to aid filling out AcroForms PDF and XFA documents}
|
11
11
|
s.description = %q{DSL to aid filling out AcroForms PDF and XFA documents}
|
12
|
+
s.license = 'MIT'
|
12
13
|
|
13
|
-
s.add_dependency "json"
|
14
14
|
s.add_dependency "nokogiri"
|
15
15
|
s.add_development_dependency "bundler", "~> 1.0"
|
16
16
|
s.add_development_dependency "minitest", "~> 4.1"
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.add_development_dependency "chunky_png", "~> 1.2"
|
20
20
|
|
21
21
|
s.files = `git ls-files`.split("\n")
|
22
|
-
s.test_files = `git ls-files -- {
|
22
|
+
s.test_files = ['test','spec','features'].map{|d| `git ls-files -- #{d}/*`.split("\n")}.flatten
|
23
23
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
24
24
|
s.require_paths = ["lib"]
|
25
25
|
end
|
@@ -3,20 +3,20 @@ require 'rspec'
|
|
3
3
|
require 'pdf_ravager'
|
4
4
|
require 'securerandom'
|
5
5
|
require 'chunky_png'
|
6
|
+
require 'tempfile'
|
6
7
|
|
7
|
-
def mktemp
|
8
|
-
|
9
|
-
"/tmp/#{SecureRandom.uuid}"
|
8
|
+
def mktemp(ext)
|
9
|
+
Tempfile.new(['', ext]).path
|
10
10
|
end
|
11
11
|
|
12
12
|
def pdf_to_ps(pdf_file, out_file=nil)
|
13
|
-
out_file ||=
|
13
|
+
out_file ||= mktemp('.ps')
|
14
14
|
system("acroread -toPostScript -markupsOn -pairs #{pdf_file} #{out_file} >/dev/null 2>&1")
|
15
15
|
out_file
|
16
16
|
end
|
17
17
|
|
18
18
|
def ps_to_png(ps_file, out_file=nil)
|
19
|
-
out_file ||=
|
19
|
+
out_file ||= mktemp('.png')
|
20
20
|
system("gs -dSAFER -dBATCH -dNOPAUSE -r150 -sDEVICE=png16m -dTextAlphaBits=4 -sOutputFile=#{out_file} #{ps_file} >/dev/null 2>&1")
|
21
21
|
out_file
|
22
22
|
end
|
@@ -3,11 +3,11 @@ require File.dirname(__FILE__) + '/../integration_helper'
|
|
3
3
|
describe 'a PDF with a multiline text field' do
|
4
4
|
describe 'filled with FOO' do
|
5
5
|
before(:each) do
|
6
|
-
p =
|
7
|
-
text 'multilinetext', 'FOO' * 10000
|
6
|
+
p = PDFRavager::Template.new do |t|
|
7
|
+
t.text 'multilinetext', 'FOO' * 10000
|
8
8
|
end
|
9
9
|
pdf_file = File.join(File.dirname(__FILE__), "pdf")
|
10
|
-
@pdf_file =
|
10
|
+
@pdf_file = mktemp('.pdf')
|
11
11
|
@pdf = p.ravage pdf_file, :out_file => @pdf_file
|
12
12
|
end
|
13
13
|
|
@@ -3,11 +3,11 @@ require 'integration/integration_helper'
|
|
3
3
|
describe 'a PDF with a text field' do
|
4
4
|
describe 'filled with foo' do
|
5
5
|
before(:each) do
|
6
|
-
p =
|
7
|
-
text 'text_field', 'foo'
|
6
|
+
p = PDFRavager::Template.new do |t|
|
7
|
+
t.text 'text_field', 'foo'
|
8
8
|
end
|
9
9
|
pdf_file = File.join(File.dirname(__FILE__), "pdf")
|
10
|
-
@pdf_file =
|
10
|
+
@pdf_file = mktemp('.pdf')
|
11
11
|
@pdf = p.ravage pdf_file, :out_file => @pdf_file
|
12
12
|
end
|
13
13
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/fields_helper'
|
2
|
+
require 'pdf_ravager/template'
|
3
|
+
|
4
|
+
class TestCheckbox < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@checked = PDFRavager::Fields::Checkbox.new('checkbox1', true, :true_value => 'foo', :false_value => 'bar')
|
8
|
+
@unchecked = PDFRavager::Fields::Checkbox.new('checkbox2', false, :true_value => 'foo', :false_value => 'bar')
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_that_custom_checked_acro_form_value_is_set
|
12
|
+
assert_equal @checked.acro_form_value, 'foo'
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_that_custom_checked_xfa_value_is_set
|
16
|
+
assert_equal @checked.xfa_value, 'foo'
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_that_custom_unchecked_acro_form_value_is_set
|
20
|
+
assert_equal @unchecked.acro_form_value, 'bar'
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_that_custom_unchecked_xfa_value_is_set
|
24
|
+
assert_equal @unchecked.xfa_value, 'bar'
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../unit_helper'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/unit_helper'
|
2
|
+
require 'pdf_ravager/kernel'
|
3
|
+
|
4
|
+
class TestKernelIntegration < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@template = pdf do |p|
|
8
|
+
p.text 'text', 'foo'
|
9
|
+
p.rich_text 'rich_text', '<b>foo</b>'
|
10
|
+
p.check 'checkbox1'
|
11
|
+
p.uncheck 'checkbox2'
|
12
|
+
p.fill 'radio_group', 'button'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_that_dsl_template_equals_longform_template
|
17
|
+
template = PDFRavager::Template.new do |t|
|
18
|
+
t.text 'text', 'foo'
|
19
|
+
t.rich_text 'rich_text', '<b>foo</b>'
|
20
|
+
t.check 'checkbox1'
|
21
|
+
t.uncheck 'checkbox2'
|
22
|
+
t.fill 'radio_group', 'button'
|
23
|
+
end
|
24
|
+
assert_equal @template, template
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/unit_helper'
|
2
|
+
require 'pdf_ravager/template'
|
3
|
+
|
4
|
+
class TestTemplate < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@template = PDFRavager::Template.new do |t|
|
8
|
+
t.text 'text', 'foo'
|
9
|
+
t.rich_text 'rich_text', '<b>foo</b>'
|
10
|
+
t.check 'checkbox1'
|
11
|
+
t.uncheck 'checkbox2'
|
12
|
+
t.checkbox_group 'cbox_group' do |cb|
|
13
|
+
cb.check 'checked'
|
14
|
+
cb.uncheck 'unchecked'
|
15
|
+
end
|
16
|
+
t.fill 'radio_group', 'button'
|
17
|
+
t.radio_group 'better_radio_group' do |rg|
|
18
|
+
rg.fill 'button'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
@template_with_name = PDFRavager::Template.new('template'){}
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_that_text_is_set
|
26
|
+
assert_includes @template.fields, PDFRavager::Fields::Text.new('text', 'foo')
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_that_rich_text_is_set
|
30
|
+
assert_includes @template.fields, PDFRavager::Fields::RichText.new('rich_text', '<b>foo</b>')
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_that_checkbox_is_set
|
34
|
+
assert_includes @template.fields, PDFRavager::Fields::Checkbox.new('checkbox1', true)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_that_checkbox_is_unset
|
38
|
+
assert_includes @template.fields, PDFRavager::Fields::Checkbox.new('checkbox2', false)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_that_radio_button_is_filled
|
42
|
+
assert_includes @template.fields, PDFRavager::Fields::Radio.new('radio_group', 'button')
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_that_name_is_set
|
46
|
+
assert_equal @template_with_name.name, 'template'
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_that_checkbox_group_box_is_checked
|
50
|
+
assert_includes @template.fields, PDFRavager::Fields::Checkbox.new('cbox_group.checked', true)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_that_checkbox_group_box_is_unchecked
|
54
|
+
assert_includes @template.fields, PDFRavager::Fields::Checkbox.new('cbox_group.unchecked', false)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_that_radio_group_button_is_filled
|
58
|
+
assert_includes @template.fields, PDFRavager::Fields::Radio.new('better_radio_group', 'button')
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pdf_ravager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,38 +9,20 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-05-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: json
|
16
|
-
version_requirements: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - ! '>='
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: !binary |-
|
21
|
-
MA==
|
22
|
-
none: false
|
23
|
-
requirement: !ruby/object:Gem::Requirement
|
24
|
-
requirements:
|
25
|
-
- - ! '>='
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: !binary |-
|
28
|
-
MA==
|
29
|
-
none: false
|
30
|
-
prerelease: false
|
31
|
-
type: :runtime
|
32
14
|
- !ruby/object:Gem::Dependency
|
33
15
|
name: nokogiri
|
34
16
|
version_requirements: !ruby/object:Gem::Requirement
|
35
17
|
requirements:
|
36
|
-
- -
|
18
|
+
- - ">="
|
37
19
|
- !ruby/object:Gem::Version
|
38
20
|
version: !binary |-
|
39
21
|
MA==
|
40
22
|
none: false
|
41
23
|
requirement: !ruby/object:Gem::Requirement
|
42
24
|
requirements:
|
43
|
-
- -
|
25
|
+
- - ">="
|
44
26
|
- !ruby/object:Gem::Version
|
45
27
|
version: !binary |-
|
46
28
|
MA==
|
@@ -51,13 +33,13 @@ dependencies:
|
|
51
33
|
name: bundler
|
52
34
|
version_requirements: !ruby/object:Gem::Requirement
|
53
35
|
requirements:
|
54
|
-
- - ~>
|
36
|
+
- - "~>"
|
55
37
|
- !ruby/object:Gem::Version
|
56
38
|
version: '1.0'
|
57
39
|
none: false
|
58
40
|
requirement: !ruby/object:Gem::Requirement
|
59
41
|
requirements:
|
60
|
-
- - ~>
|
42
|
+
- - "~>"
|
61
43
|
- !ruby/object:Gem::Version
|
62
44
|
version: '1.0'
|
63
45
|
none: false
|
@@ -67,13 +49,13 @@ dependencies:
|
|
67
49
|
name: minitest
|
68
50
|
version_requirements: !ruby/object:Gem::Requirement
|
69
51
|
requirements:
|
70
|
-
- - ~>
|
52
|
+
- - "~>"
|
71
53
|
- !ruby/object:Gem::Version
|
72
54
|
version: '4.1'
|
73
55
|
none: false
|
74
56
|
requirement: !ruby/object:Gem::Requirement
|
75
57
|
requirements:
|
76
|
-
- - ~>
|
58
|
+
- - "~>"
|
77
59
|
- !ruby/object:Gem::Version
|
78
60
|
version: '4.1'
|
79
61
|
none: false
|
@@ -83,13 +65,13 @@ dependencies:
|
|
83
65
|
name: rspec
|
84
66
|
version_requirements: !ruby/object:Gem::Requirement
|
85
67
|
requirements:
|
86
|
-
- - ~>
|
68
|
+
- - "~>"
|
87
69
|
- !ruby/object:Gem::Version
|
88
70
|
version: '2.11'
|
89
71
|
none: false
|
90
72
|
requirement: !ruby/object:Gem::Requirement
|
91
73
|
requirements:
|
92
|
-
- - ~>
|
74
|
+
- - "~>"
|
93
75
|
- !ruby/object:Gem::Version
|
94
76
|
version: '2.11'
|
95
77
|
none: false
|
@@ -99,13 +81,13 @@ dependencies:
|
|
99
81
|
name: rake
|
100
82
|
version_requirements: !ruby/object:Gem::Requirement
|
101
83
|
requirements:
|
102
|
-
- - ~>
|
84
|
+
- - "~>"
|
103
85
|
- !ruby/object:Gem::Version
|
104
86
|
version: '0.9'
|
105
87
|
none: false
|
106
88
|
requirement: !ruby/object:Gem::Requirement
|
107
89
|
requirements:
|
108
|
-
- - ~>
|
90
|
+
- - "~>"
|
109
91
|
- !ruby/object:Gem::Version
|
110
92
|
version: '0.9'
|
111
93
|
none: false
|
@@ -115,13 +97,13 @@ dependencies:
|
|
115
97
|
name: chunky_png
|
116
98
|
version_requirements: !ruby/object:Gem::Requirement
|
117
99
|
requirements:
|
118
|
-
- - ~>
|
100
|
+
- - "~>"
|
119
101
|
- !ruby/object:Gem::Version
|
120
102
|
version: '1.2'
|
121
103
|
none: false
|
122
104
|
requirement: !ruby/object:Gem::Requirement
|
123
105
|
requirements:
|
124
|
-
- - ~>
|
106
|
+
- - "~>"
|
125
107
|
- !ruby/object:Gem::Version
|
126
108
|
version: '1.2'
|
127
109
|
none: false
|
@@ -133,15 +115,24 @@ executables: []
|
|
133
115
|
extensions: []
|
134
116
|
extra_rdoc_files: []
|
135
117
|
files:
|
136
|
-
- .gitignore
|
137
|
-
- .travis.yml
|
118
|
+
- ".gitignore"
|
119
|
+
- ".travis.yml"
|
138
120
|
- Gemfile
|
139
121
|
- LICENSE
|
140
122
|
- README.md
|
141
123
|
- Rakefile
|
142
124
|
- lib/pdf_ravager.rb
|
143
|
-
- lib/pdf_ravager/
|
125
|
+
- lib/pdf_ravager/field_types/acro_form.rb
|
126
|
+
- lib/pdf_ravager/field_types/xfa.rb
|
127
|
+
- lib/pdf_ravager/fields/checkbox.rb
|
128
|
+
- lib/pdf_ravager/fields/radio.rb
|
129
|
+
- lib/pdf_ravager/fields/rich_text.rb
|
130
|
+
- lib/pdf_ravager/fields/text.rb
|
131
|
+
- lib/pdf_ravager/fieldsets/checkbox_group.rb
|
132
|
+
- lib/pdf_ravager/fieldsets/radio_group.rb
|
133
|
+
- lib/pdf_ravager/kernel.rb
|
144
134
|
- lib/pdf_ravager/ravager.rb
|
135
|
+
- lib/pdf_ravager/template.rb
|
145
136
|
- lib/pdf_ravager/version.rb
|
146
137
|
- pdf_ravager.gemspec
|
147
138
|
- spec/integration/integration_helper.rb
|
@@ -152,18 +143,22 @@ files:
|
|
152
143
|
- spec/integration/text_field/pdf
|
153
144
|
- spec/integration/text_field/spec.rb
|
154
145
|
- spec/spec_helper.rb
|
155
|
-
- spec/unit/
|
146
|
+
- spec/unit/fields/checkbox_spec.rb
|
147
|
+
- spec/unit/fields/fields_helper.rb
|
148
|
+
- spec/unit/kernel_spec.rb
|
149
|
+
- spec/unit/template_spec.rb
|
156
150
|
- spec/unit/unit_helper.rb
|
157
151
|
- vendor/iText-4.2.0.jar
|
158
152
|
homepage: https://github.com/abevoelker/pdf_ravager
|
159
|
-
licenses:
|
153
|
+
licenses:
|
154
|
+
- MIT
|
160
155
|
post_install_message:
|
161
156
|
rdoc_options: []
|
162
157
|
require_paths:
|
163
158
|
- lib
|
164
159
|
required_ruby_version: !ruby/object:Gem::Requirement
|
165
160
|
requirements:
|
166
|
-
- -
|
161
|
+
- - ">="
|
167
162
|
- !ruby/object:Gem::Version
|
168
163
|
segments:
|
169
164
|
- 0
|
@@ -173,7 +168,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
173
168
|
none: false
|
174
169
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
170
|
requirements:
|
176
|
-
- -
|
171
|
+
- - ">="
|
177
172
|
- !ruby/object:Gem::Version
|
178
173
|
segments:
|
179
174
|
- 0
|
@@ -187,4 +182,17 @@ rubygems_version: 1.8.24
|
|
187
182
|
signing_key:
|
188
183
|
specification_version: 3
|
189
184
|
summary: DSL to aid filling out AcroForms PDF and XFA documents
|
190
|
-
test_files:
|
185
|
+
test_files:
|
186
|
+
- spec/integration/integration_helper.rb
|
187
|
+
- spec/integration/multiline_text_field/expected.png
|
188
|
+
- spec/integration/multiline_text_field/pdf
|
189
|
+
- spec/integration/multiline_text_field/spec.rb
|
190
|
+
- spec/integration/text_field/expected.png
|
191
|
+
- spec/integration/text_field/pdf
|
192
|
+
- spec/integration/text_field/spec.rb
|
193
|
+
- spec/spec_helper.rb
|
194
|
+
- spec/unit/fields/checkbox_spec.rb
|
195
|
+
- spec/unit/fields/fields_helper.rb
|
196
|
+
- spec/unit/kernel_spec.rb
|
197
|
+
- spec/unit/template_spec.rb
|
198
|
+
- spec/unit/unit_helper.rb
|
data/lib/pdf_ravager/pdf.rb
DELETED
@@ -1,105 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'pdf_ravager/ravager' if RUBY_PLATFORM =~ /java/
|
3
|
-
|
4
|
-
module PDFRavager
|
5
|
-
class PDF
|
6
|
-
attr_reader :name, :fields
|
7
|
-
|
8
|
-
def initialize(name=nil, opts={})
|
9
|
-
@name = name if name
|
10
|
-
@fields = opts[:fields] || []
|
11
|
-
end
|
12
|
-
|
13
|
-
def text(name, value, opts={})
|
14
|
-
if opts.empty?
|
15
|
-
@fields << {:name => name, :value => value, :type => :text}
|
16
|
-
else
|
17
|
-
@fields << {:name => name, :value => value, :type => :text, :options => opts}
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def check(name, opts={})
|
22
|
-
@fields << {:name => name, :value => true, :type => :checkbox}
|
23
|
-
end
|
24
|
-
|
25
|
-
def radio_group(gname, &blk)
|
26
|
-
fields = []
|
27
|
-
# TODO: replace w/ singleton method?
|
28
|
-
PDF.instance_eval do
|
29
|
-
send(:define_method, :fill) do |name, opts={}|
|
30
|
-
fields << {:name => gname, :value => name, :type => :radio}
|
31
|
-
end
|
32
|
-
blk.call
|
33
|
-
send(:undef_method, :fill)
|
34
|
-
end
|
35
|
-
|
36
|
-
@fields += fields
|
37
|
-
end
|
38
|
-
|
39
|
-
def checkbox_group(gname, &blk)
|
40
|
-
# TODO: replace w/ singleton method?
|
41
|
-
PDF.instance_eval do
|
42
|
-
alias_method :__check_original__, :check
|
43
|
-
send(:define_method, :check) do |name, opts={}|
|
44
|
-
__check_original__("#{gname}.#{name}", opts)
|
45
|
-
end
|
46
|
-
blk.call
|
47
|
-
# restore check method back to normal
|
48
|
-
alias_method :check, :__check_original__
|
49
|
-
send(:undef_method, :__check_original__)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
if RUBY_PLATFORM =~ /java/
|
54
|
-
def ravage(file, opts={})
|
55
|
-
PDFRavager::Ravager.open(opts.merge(:in_file => file)) do |pdf|
|
56
|
-
@fields.each do |f|
|
57
|
-
value = if f[:type] == :checkbox
|
58
|
-
!!f[:value] ? '1' : '0' # Checkbox default string values
|
59
|
-
else
|
60
|
-
f[:value]
|
61
|
-
end
|
62
|
-
pdf.set_field_value(f[:name], value, f[:type], f[:options])
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
else
|
67
|
-
def ravage(file, opts={})
|
68
|
-
raise "You can only ravage .pdfs using JRuby, not #{RUBY_PLATFORM}!"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def ==(other)
|
73
|
-
self.name == other.name && self.fields == other.fields
|
74
|
-
end
|
75
|
-
|
76
|
-
def to_json(*args)
|
77
|
-
{
|
78
|
-
"json_class" => self.class.name,
|
79
|
-
"data" => {"name" => @name, "fields" => @fields }
|
80
|
-
}.to_json(*args)
|
81
|
-
end
|
82
|
-
|
83
|
-
def self.json_create(obj)
|
84
|
-
fields = obj["data"]["fields"].map do |f|
|
85
|
-
# symbolize the root keys
|
86
|
-
f = f.inject({}){|h,(k,v)| h[k.to_sym] = v; h}
|
87
|
-
f[:type] = f[:type].to_sym if f[:type]
|
88
|
-
# symbolize the :options keys
|
89
|
-
if f[:options]
|
90
|
-
f[:options] = f[:options].inject({}){|h,(k,v)| h[k.to_sym] = v; h}
|
91
|
-
end
|
92
|
-
f
|
93
|
-
end
|
94
|
-
o = new(obj["data"]["name"], :fields => fields)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
module Kernel
|
100
|
-
def pdf(name=nil, opts={}, &blk)
|
101
|
-
r = PDFRavager::PDF.new(name, opts)
|
102
|
-
r.instance_eval(&blk)
|
103
|
-
r
|
104
|
-
end
|
105
|
-
end
|
data/spec/unit/pdf_spec.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/unit_helper'
|
2
|
-
require 'pdf_ravager/pdf'
|
3
|
-
|
4
|
-
class TestPDF < MiniTest::Unit::TestCase
|
5
|
-
def setup
|
6
|
-
@pdf = pdf 'foo.pdf' do
|
7
|
-
text 'text', 'foo'
|
8
|
-
text 'rich_text', '<b>foo</b>', :rich => true
|
9
|
-
check 'checkbox'
|
10
|
-
checkbox_group 'checkbox_group' do
|
11
|
-
check 'foo'
|
12
|
-
end
|
13
|
-
radio_group 'radio_group' do
|
14
|
-
fill 'foo'
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
@pdf_from_json = JSON.parse(@pdf.to_json)
|
19
|
-
end
|
20
|
-
|
21
|
-
def test_that_name_is_set
|
22
|
-
assert_equal @pdf.name, 'foo.pdf'
|
23
|
-
end
|
24
|
-
|
25
|
-
def test_that_text_is_set
|
26
|
-
assert_includes @pdf.fields, {:name => 'text', :value => 'foo', :type => :text}
|
27
|
-
end
|
28
|
-
|
29
|
-
def test_that_rich_text_is_set
|
30
|
-
assert_includes @pdf.fields, {:name => 'rich_text', :value => '<b>foo</b>', :type => :text, :options => {:rich => true}}
|
31
|
-
end
|
32
|
-
|
33
|
-
def test_that_checkbox_is_set
|
34
|
-
assert_includes @pdf.fields, {:name => 'checkbox', :value => true, :type => :checkbox}
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_that_checkbox_group_is_set
|
38
|
-
assert_includes @pdf.fields, {:name => 'checkbox_group.foo', :value => true, :type => :checkbox}
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_that_radio_group_is_set
|
42
|
-
assert_includes @pdf.fields, {:name => 'radio_group', :value => 'foo', :type => :radio}
|
43
|
-
end
|
44
|
-
|
45
|
-
def test_json_serialization
|
46
|
-
assert_equal @pdf, @pdf_from_json
|
47
|
-
end
|
48
|
-
end
|