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.
@@ -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.* release
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.0.23fx2 an exact version
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").scan(%r{<version>([^<]+)</version>}).flatten.map(&:strip)
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 4.* release; with snapshots: true, the most
66
- # recent 4.* build) or an exact one such as '4.0.23fx2'.
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
- version = select_version(available_versions(repository), snapshots: snapshots, jakarta: jakarta) if version == 'latest'
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pd4ml
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.1'
5
5
  end
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pd4ml
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - PD4ML