pd4ml 1.0.0 → 1.1.1
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.
- checksums.yaml +4 -4
- data/README.md +21 -15
- data/docs/api.md +155 -3
- data/docs/guide.md +937 -782
- data/exe/pd4ml +6 -1
- data/lib/pd4ml/bridge.rb +362 -362
- data/lib/pd4ml/installer.rb +45 -6
- data/lib/pd4ml/java.rb +22 -2
- data/lib/pd4ml/pd4ml.rb +31 -1
- data/lib/pd4ml/version.rb +1 -1
- data/lib/pd4ml.rb +13 -0
- metadata +1 -1
data/lib/pd4ml/installer.rb
CHANGED
|
@@ -9,9 +9,10 @@ require 'time'
|
|
|
9
9
|
module Pd4ml
|
|
10
10
|
# Downloads a PD4ML build from the PD4ML Maven repository and makes it the gem's default:
|
|
11
11
|
#
|
|
12
|
-
# pd4ml install the most recent 4
|
|
12
|
+
# pd4ml install the most recent release from MINIMUM_VERSION (4.2.0) on;
|
|
13
|
+
# until there is one, the most recent 4.2.x snapshot
|
|
13
14
|
# pd4ml install --snapshots the most recent 4.* build, snapshots included
|
|
14
|
-
# pd4ml install 4.
|
|
15
|
+
# pd4ml install 4.1.2 an exact version
|
|
15
16
|
#
|
|
16
17
|
# or Pd4ml.install from code. The jar is stored in the user's cache directory (PD4ML_HOME to
|
|
17
18
|
# choose another) with the Bouncy Castle jars PD4ML needs for encryption and signing, every
|
|
@@ -26,6 +27,9 @@ module Pd4ml
|
|
|
26
27
|
BOUNCYCASTLE = %w[bcprov-jdk18on bcpkix-jdk18on bcutil-jdk18on].freeze
|
|
27
28
|
MANIFEST = 'installed.json'
|
|
28
29
|
VERSION_PATTERN = /\A(\d+)\.(\d+)\.(\d+)(?:fx(\d+)(?:a(\d+))?)?(-jakarta)?(-SNAPSHOT)?\z/
|
|
30
|
+
# The oldest PD4ML a plain install takes: the gem's PD4ML 4.2 API (read_eml/read_mht,
|
|
31
|
+
# add_allowed_resource_location, add_metadata, the DOM API) needs it.
|
|
32
|
+
MINIMUM_VERSION = '4.2.0'
|
|
29
33
|
|
|
30
34
|
module_function
|
|
31
35
|
|
|
@@ -54,20 +58,55 @@ module Pd4ml
|
|
|
54
58
|
sort_versions(candidates).last
|
|
55
59
|
end
|
|
56
60
|
|
|
61
|
+
# The version a plain install takes: the most recent release of the minimum's major line (4.*)
|
|
62
|
+
# at least `minimum`; while there is none, the most recent snapshot of the minimum's line
|
|
63
|
+
# (4.2.x for 4.2.0); while there is none of those either (the -jakarta variant has no 4.2
|
|
64
|
+
# build yet), the most recent 4.* release, as before. So installs move to the release once it
|
|
65
|
+
# is out, and snapshots of later lines (or a 5.x) are never picked by accident. With
|
|
66
|
+
# `jakarta`, a -jakarta variant by that rule if there is one, else the plain build of the same
|
|
67
|
+
# rule: PD4ML 4.2 publishes no -jakarta variant, its builds contain the Jakarta tag library
|
|
68
|
+
# (com.pd4ml.taglib.jakarta); only without either, the most recent -jakarta release.
|
|
69
|
+
def default_version(versions, jakarta: false, minimum: MINIMUM_VERSION)
|
|
70
|
+
min = version_key(minimum)
|
|
71
|
+
(jakarta ? [true, false] : [false]).each do |variant|
|
|
72
|
+
candidates = versions.select do |v|
|
|
73
|
+
k = version_key(v)
|
|
74
|
+
k && k[0] == min[0] && v.include?('-jakarta') == variant
|
|
75
|
+
end
|
|
76
|
+
releases = candidates.select { |v| !v.end_with?('-SNAPSHOT') && (version_key(v) <=> min) >= 0 }
|
|
77
|
+
return sort_versions(releases).last unless releases.empty?
|
|
78
|
+
|
|
79
|
+
snapshots = candidates.select { |v| v.end_with?('-SNAPSHOT') && version_key(v)[0, 2] == min[0, 2] }
|
|
80
|
+
return sort_versions(snapshots).last unless snapshots.empty?
|
|
81
|
+
end
|
|
82
|
+
select_version(versions, major: min[0], jakarta: jakarta)
|
|
83
|
+
end
|
|
84
|
+
|
|
57
85
|
# The versions the repository lists.
|
|
58
86
|
def available_versions(repository = REPOSITORY)
|
|
59
|
-
fetch("#{repository}/#{GROUP_PATH}/maven-metadata.xml")
|
|
87
|
+
parse_versions(fetch("#{repository}/#{GROUP_PATH}/maven-metadata.xml"))
|
|
60
88
|
end
|
|
61
89
|
|
|
90
|
+
# The versions a maven-metadata.xml document lists.
|
|
91
|
+
def parse_versions(xml) = xml.scan(%r{<version>([^<]+)</version>}).flatten.map(&:strip)
|
|
92
|
+
|
|
62
93
|
# ------------------------------------------------------------------------------ install
|
|
63
94
|
|
|
64
95
|
# Downloads a PD4ML build (unless already there) and makes it the default one; returns the
|
|
65
|
-
# jar's path. version: 'latest' (the most recent
|
|
66
|
-
# recent 4
|
|
96
|
+
# jar's path. version: 'latest' (default_version: the most recent release from MINIMUM_VERSION
|
|
97
|
+
# on, else the most recent 4.2.x snapshot; with snapshots: true, the most recent 4.* build) or
|
|
98
|
+
# an exact one such as '4.1.2' or '4.0.23fx2'.
|
|
67
99
|
def install(version = 'latest', snapshots: false, jakarta: false, repository: REPOSITORY, home: nil,
|
|
68
100
|
force: false, quiet: false, bouncycastle: true)
|
|
69
101
|
home ||= default_home
|
|
70
|
-
|
|
102
|
+
if version == 'latest'
|
|
103
|
+
versions = available_versions(repository)
|
|
104
|
+
version = if snapshots
|
|
105
|
+
select_version(versions, snapshots: true, jakarta: jakarta)
|
|
106
|
+
else
|
|
107
|
+
default_version(versions, jakarta: jakarta)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
71
110
|
name = jar_name(version, repository)
|
|
72
111
|
jar = File.join(home, name)
|
|
73
112
|
download("#{repository}/#{GROUP_PATH}/#{version}/#{name}", jar, force, quiet)
|
data/lib/pd4ml/java.rb
CHANGED
|
@@ -42,7 +42,9 @@ module Pd4ml
|
|
|
42
42
|
|
|
43
43
|
# A Java object living in the bridge. Call its Java methods by their Java names or in Ruby
|
|
44
44
|
# style (`size.rotate`, `pd.set_page_size(...)`, `pd.demo_mode?`). Public fields: `obj[:width]`
|
|
45
|
-
# / `obj[:width] = v`. Released in Java when garbage collected.
|
|
45
|
+
# / `obj[:width] = v`. Released in Java when garbage collected. The DOM API's objects
|
|
46
|
+
# (com.pd4ml.dom) return their Java lists and sets as Ruby Arrays, maps as Hashes
|
|
47
|
+
# (`doc.query_selector_all('p').each { ... }`); `call_java` returns them as they are.
|
|
46
48
|
class JavaObject < BasicObject
|
|
47
49
|
def initialize(bridge, handle, java_class, enum_name)
|
|
48
50
|
@bridge = bridge
|
|
@@ -110,7 +112,9 @@ module Pd4ml
|
|
|
110
112
|
::Kernel.raise ::NoMethodError, "set Java fields with obj[:#{name.to_s.chomp('=')}] = value" if name.to_s.end_with?('=')
|
|
111
113
|
::Kernel.raise ::ArgumentError, 'Java methods take no block' if block
|
|
112
114
|
|
|
113
|
-
@bridge.call(self, Naming.resolve(@bridge, @java_class, name, false), args)
|
|
115
|
+
result = @bridge.call(self, Naming.resolve(@bridge, @java_class, name, false), args)
|
|
116
|
+
# the DOM API's lists, sets and maps are snapshots: Ruby Arrays and Hashes
|
|
117
|
+
@java_class.start_with?('com.pd4ml.dom.') ? Java.to_ruby(result) : result
|
|
114
118
|
end
|
|
115
119
|
|
|
116
120
|
def respond_to_missing?(_name, _include_private = false) = true
|
|
@@ -205,5 +209,21 @@ module Pd4ml
|
|
|
205
209
|
|
|
206
210
|
Bridge.get.proxy(iface, &block)
|
|
207
211
|
end
|
|
212
|
+
|
|
213
|
+
# A Java collection (List, Set...) as a Ruby Array and a Java Map as a Hash, in one or two
|
|
214
|
+
# bridge calls; any other value as it is.
|
|
215
|
+
def self.to_ruby(value)
|
|
216
|
+
return value unless value.is_a?(JavaObject) && value.java_class.start_with?('java.util.')
|
|
217
|
+
|
|
218
|
+
if value.instance_of_java?('java.util.Collection')
|
|
219
|
+
value.call_java('toArray')
|
|
220
|
+
elsif value.instance_of_java?('java.util.Map')
|
|
221
|
+
keys = value.call_java('keySet').call_java('toArray')
|
|
222
|
+
values = value.call_java('values').call_java('toArray')
|
|
223
|
+
keys.zip(values).to_h
|
|
224
|
+
else
|
|
225
|
+
value
|
|
226
|
+
end
|
|
227
|
+
end
|
|
208
228
|
end
|
|
209
229
|
end
|
data/lib/pd4ml/pd4ml.rb
CHANGED
|
@@ -5,7 +5,9 @@ module Pd4ml
|
|
|
5
5
|
# engine by default. Every Java method is available by its Java name or in Ruby style
|
|
6
6
|
# (`set_page_size`, `add_style`, `use_ttf`); these take Ruby I/O: read_html (a path, URL or
|
|
7
7
|
# binary String/IO), read_html_string, write_pdf/write_docx/write_rtf (the document returned as
|
|
8
|
-
# a binary String, or written to a path or IO), render_as_images and monitor_progress_with (a block)
|
|
8
|
+
# a binary String, or written to a path or IO), render_as_images and monitor_progress_with (a block);
|
|
9
|
+
# read_eml/read_mht (e-mail messages, saved web pages) as read_html. get_document and layout (the
|
|
10
|
+
# DOM API, v42 engine) return com.pd4ml.dom objects, whose lists come back as Ruby Arrays.
|
|
9
11
|
#
|
|
10
12
|
# pd = Pd4ml::PD4ML.new
|
|
11
13
|
# pd.set_page_size(Pd4ml::PageSize::A4)
|
|
@@ -117,6 +119,24 @@ module Pd4ml
|
|
|
117
119
|
end
|
|
118
120
|
alias readHtmlString read_html_string
|
|
119
121
|
|
|
122
|
+
# Reads an e-mail message (.eml) to convert: its body, HTML if it has one, with the images it
|
|
123
|
+
# embeds, after a block with From, Date, To, Cc, Subject and the attachments, which are
|
|
124
|
+
# embedded in the PDF. `source` as for read_html: a path or URL, or the message itself (a
|
|
125
|
+
# binary String or IO). Of resources outside the message only https:// ones are loaded;
|
|
126
|
+
# add_allowed_resource_location replaces that. read_html recognizes messages too; this is the
|
|
127
|
+
# way for mail from outside your control. PD4ML 4.2 and later.
|
|
128
|
+
def read_eml(source)
|
|
129
|
+
read_mime('readEML', source)
|
|
130
|
+
end
|
|
131
|
+
alias readEML read_eml
|
|
132
|
+
|
|
133
|
+
# Reads a web page saved as a single file (.mht, .mhtml), with the images, style sheets and
|
|
134
|
+
# fonts saved in it; `source` as for read_eml. PD4ML 4.2 and later.
|
|
135
|
+
def read_mht(source)
|
|
136
|
+
read_mime('readMHT', source)
|
|
137
|
+
end
|
|
138
|
+
alias readMHT read_mht
|
|
139
|
+
|
|
120
140
|
# -------------------------------------------------------------------------------- output
|
|
121
141
|
|
|
122
142
|
# Writes the PDF: to `target` (a path or an IO), or returned as a binary String. spec: a
|
|
@@ -175,6 +195,16 @@ module Pd4ml
|
|
|
175
195
|
|
|
176
196
|
private
|
|
177
197
|
|
|
198
|
+
def read_mime(method, source)
|
|
199
|
+
arg = if location?(source)
|
|
200
|
+
Pd4ml.to_url(source)
|
|
201
|
+
else
|
|
202
|
+
source.is_a?(JavaObject) ? source : Pd4ml.binary(source)
|
|
203
|
+
end
|
|
204
|
+
Bridge.get.call(@java, method, [arg])
|
|
205
|
+
nil
|
|
206
|
+
end
|
|
207
|
+
|
|
178
208
|
def location?(source)
|
|
179
209
|
source.is_a?(Pathname) || source.is_a?(URI::Generic) ||
|
|
180
210
|
(source.is_a?(String) && source.encoding != Encoding::BINARY && !source.lstrip.start_with?('<')) ||
|
data/lib/pd4ml/version.rb
CHANGED
data/lib/pd4ml.rb
CHANGED
|
@@ -35,6 +35,19 @@ module Pd4ml
|
|
|
35
35
|
ResourceProvider = Java.type('com.pd4ml.ResourceProvider')
|
|
36
36
|
CustomTag = Java.type('com.pd4ml.CustomTag')
|
|
37
37
|
|
|
38
|
+
# The DOM API (com.pd4ml.dom, PD4ML 4.2, v42 engine; DMS and UA editions): PD4ML#get_document and
|
|
39
|
+
# PD4ML#layout return its objects. Their Java lists and sets come back as Ruby Arrays, maps as Hashes.
|
|
40
|
+
module Dom
|
|
41
|
+
Node = Java.type('com.pd4ml.dom.Node')
|
|
42
|
+
Document = Java.type('com.pd4ml.dom.Document')
|
|
43
|
+
Element = Java.type('com.pd4ml.dom.Element')
|
|
44
|
+
Text = Java.type('com.pd4ml.dom.Text')
|
|
45
|
+
Comment = Java.type('com.pd4ml.dom.Comment')
|
|
46
|
+
DocumentType = Java.type('com.pd4ml.dom.DocumentType')
|
|
47
|
+
Layout = Java.type('com.pd4ml.dom.Layout')
|
|
48
|
+
LayoutBox = Java.type('com.pd4ml.dom.LayoutBox')
|
|
49
|
+
end
|
|
50
|
+
|
|
38
51
|
FORMATS = %w[PDF PDFA PDFUA].freeze
|
|
39
52
|
|
|
40
53
|
class << self
|