wicked_pdf 2.0.2 → 2.7.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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +56 -0
- data/.rubocop.yml +57 -1
- data/.rubocop_todo.yml +29 -117
- data/CHANGELOG.md +88 -4
- data/README.md +58 -16
- data/Rakefile +3 -10
- data/gemfiles/5.0.gemfile +2 -2
- data/gemfiles/5.1.gemfile +2 -2
- data/gemfiles/5.2.gemfile +3 -4
- data/gemfiles/6.0.gemfile +3 -4
- data/gemfiles/6.1.gemfile +11 -0
- data/gemfiles/7.0.gemfile +11 -0
- data/generators/wicked_pdf/templates/wicked_pdf.rb +9 -0
- data/lib/wicked_pdf/binary.rb +65 -0
- data/lib/wicked_pdf/option_parser.rb +230 -0
- data/lib/wicked_pdf/pdf_helper.rb +29 -44
- data/lib/wicked_pdf/railtie.rb +3 -12
- data/lib/wicked_pdf/tempfile.rb +33 -3
- data/lib/wicked_pdf/version.rb +1 -1
- data/lib/wicked_pdf/wicked_pdf_helper/assets.rb +62 -6
- data/lib/wicked_pdf.rb +32 -260
- data/test/functional/pdf_helper_test.rb +1 -1
- data/test/unit/wicked_pdf_binary_test.rb +26 -0
- data/test/unit/wicked_pdf_option_parser_test.rb +133 -0
- data/test/unit/wicked_pdf_test.rb +0 -157
- data/test/unit/wkhtmltopdf_location_test.rb +0 -2
- data/wicked_pdf.gemspec +3 -5
- metadata +33 -29
- data/.travis.yml +0 -79
- data/gemfiles/4.0.gemfile +0 -7
- data/gemfiles/4.1.gemfile +0 -7
- data/gemfiles/4.2.gemfile +0 -9
- data/gemfiles/rails_edge.gemfile +0 -9
@@ -1,19 +1,48 @@
|
|
1
1
|
require 'net/http'
|
2
|
-
|
3
|
-
require '
|
2
|
+
require 'delegate'
|
3
|
+
require 'stringio'
|
4
4
|
|
5
5
|
class WickedPdf
|
6
6
|
module WickedPdfHelper
|
7
7
|
module Assets
|
8
8
|
ASSET_URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/
|
9
9
|
|
10
|
+
class PropshaftAsset < SimpleDelegator
|
11
|
+
def content_type
|
12
|
+
super.to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
content
|
17
|
+
end
|
18
|
+
|
19
|
+
def filename
|
20
|
+
path.to_s
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
10
24
|
def wicked_pdf_asset_base64(path)
|
11
25
|
asset = find_asset(path)
|
12
26
|
raise "Could not find asset '#{path}'" if asset.nil?
|
27
|
+
|
13
28
|
base64 = Base64.encode64(asset.to_s).gsub(/\s+/, '')
|
14
29
|
"data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
|
15
30
|
end
|
16
31
|
|
32
|
+
# Using `image_tag` with URLs when generating PDFs (specifically large PDFs with lots of pages) can cause buffer/stack overflows.
|
33
|
+
#
|
34
|
+
def wicked_pdf_url_base64(url)
|
35
|
+
response = Net::HTTP.get_response(URI(url))
|
36
|
+
|
37
|
+
if response.is_a?(Net::HTTPSuccess)
|
38
|
+
base64 = Base64.encode64(response.body).gsub(/\s+/, '')
|
39
|
+
"data:#{response.content_type};base64,#{Rack::Utils.escape(base64)}"
|
40
|
+
else
|
41
|
+
Rails.logger.warn("[wicked_pdf] #{response.code} #{response.message}: #{url}")
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
17
46
|
def wicked_pdf_stylesheet_link_tag(*sources)
|
18
47
|
stylesheet_contents = sources.collect do |source|
|
19
48
|
source = WickedPdfHelper.add_extension(source, 'css')
|
@@ -31,6 +60,7 @@ class WickedPdf
|
|
31
60
|
|
32
61
|
def wicked_pdf_stylesheet_pack_tag(*sources)
|
33
62
|
return unless defined?(Webpacker)
|
63
|
+
|
34
64
|
if running_in_development?
|
35
65
|
stylesheet_pack_tag(*sources)
|
36
66
|
else
|
@@ -79,6 +109,16 @@ class WickedPdf
|
|
79
109
|
end
|
80
110
|
end
|
81
111
|
|
112
|
+
def wicked_pdf_asset_pack_path(asset)
|
113
|
+
return unless defined?(Webpacker)
|
114
|
+
|
115
|
+
if running_in_development?
|
116
|
+
asset_pack_path(asset)
|
117
|
+
else
|
118
|
+
wicked_pdf_asset_path webpacker_source_url(asset)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
82
122
|
private
|
83
123
|
|
84
124
|
# borrowed from actionpack/lib/action_view/helpers/asset_url_helper.rb
|
@@ -108,6 +148,8 @@ class WickedPdf
|
|
108
148
|
def find_asset(path)
|
109
149
|
if Rails.application.assets.respond_to?(:find_asset)
|
110
150
|
Rails.application.assets.find_asset(path, :base_path => Rails.application.root.to_s)
|
151
|
+
elsif defined?(Propshaft::Assembly) && Rails.application.assets.is_a?(Propshaft::Assembly)
|
152
|
+
PropshaftAsset.new(Rails.application.assets.load_path.find(path))
|
111
153
|
else
|
112
154
|
Sprockets::Railtie.build_environment(Rails.application).find_asset(path, :base_path => Rails.application.root.to_s)
|
113
155
|
end
|
@@ -161,10 +203,15 @@ class WickedPdf
|
|
161
203
|
end
|
162
204
|
|
163
205
|
def webpacker_source_url(source)
|
164
|
-
return unless
|
206
|
+
return unless webpacker_version
|
207
|
+
|
165
208
|
# In Webpacker 3.2.0 asset_pack_url is introduced
|
166
|
-
if
|
167
|
-
|
209
|
+
if webpacker_version >= '3.2.0'
|
210
|
+
if (host = Rails.application.config.asset_host)
|
211
|
+
asset_pack_path(source, :host => host)
|
212
|
+
else
|
213
|
+
asset_pack_url(source)
|
214
|
+
end
|
168
215
|
else
|
169
216
|
source_path = asset_pack_path(source)
|
170
217
|
# Remove last slash from root path
|
@@ -173,7 +220,8 @@ class WickedPdf
|
|
173
220
|
end
|
174
221
|
|
175
222
|
def running_in_development?
|
176
|
-
return unless
|
223
|
+
return unless webpacker_version
|
224
|
+
|
177
225
|
# :dev_server method was added in webpacker 3.0.0
|
178
226
|
if Webpacker.respond_to?(:dev_server)
|
179
227
|
Webpacker.dev_server.running?
|
@@ -181,6 +229,14 @@ class WickedPdf
|
|
181
229
|
Rails.env.development? || Rails.env.test?
|
182
230
|
end
|
183
231
|
end
|
232
|
+
|
233
|
+
def webpacker_version
|
234
|
+
if defined?(Shakapacker)
|
235
|
+
Shakapacker::VERSION
|
236
|
+
elsif defined?(Webpacker)
|
237
|
+
Webpacker::VERSION
|
238
|
+
end
|
239
|
+
end
|
184
240
|
end
|
185
241
|
end
|
186
242
|
end
|
data/lib/wicked_pdf.rb
CHANGED
@@ -11,27 +11,25 @@ require 'active_support/core_ext/object/blank'
|
|
11
11
|
|
12
12
|
require 'wicked_pdf/version'
|
13
13
|
require 'wicked_pdf/railtie'
|
14
|
+
require 'wicked_pdf/option_parser'
|
14
15
|
require 'wicked_pdf/tempfile'
|
16
|
+
require 'wicked_pdf/binary'
|
15
17
|
require 'wicked_pdf/middleware'
|
16
18
|
require 'wicked_pdf/progress'
|
17
19
|
|
18
20
|
class WickedPdf
|
19
21
|
DEFAULT_BINARY_VERSION = Gem::Version.new('0.9.9')
|
20
|
-
BINARY_VERSION_WITHOUT_DASHES = Gem::Version.new('0.12.0')
|
21
|
-
EXE_NAME = 'wkhtmltopdf'.freeze
|
22
22
|
@@config = {}
|
23
23
|
cattr_accessor :config
|
24
|
-
attr_accessor :binary_version
|
25
24
|
|
26
25
|
include Progress
|
27
26
|
|
28
27
|
def initialize(wkhtmltopdf_binary_path = nil)
|
29
|
-
@
|
30
|
-
|
31
|
-
raise "Bad #{EXE_NAME}'s path: #{@exe_path}" unless File.exist?(@exe_path)
|
32
|
-
raise "#{EXE_NAME} is not executable" unless File.executable?(@exe_path)
|
28
|
+
@binary = Binary.new(wkhtmltopdf_binary_path, DEFAULT_BINARY_VERSION)
|
29
|
+
end
|
33
30
|
|
34
|
-
|
31
|
+
def binary_version
|
32
|
+
@binary.version
|
35
33
|
end
|
36
34
|
|
37
35
|
def pdf_from_html_file(filepath, options = {})
|
@@ -41,23 +39,24 @@ class WickedPdf
|
|
41
39
|
def pdf_from_string(string, options = {})
|
42
40
|
options = options.dup
|
43
41
|
options.merge!(WickedPdf.config) { |_key, option, _config| option }
|
44
|
-
string_file =
|
45
|
-
string_file.
|
46
|
-
string_file.
|
47
|
-
string_file.close
|
48
|
-
|
49
|
-
pdf = pdf_from_html_file(string_file.path, options)
|
50
|
-
pdf
|
42
|
+
string_file = WickedPdf::Tempfile.new('wicked_pdf.html', options[:temp_path])
|
43
|
+
string_file.write_in_chunks(string)
|
44
|
+
pdf_from_html_file(string_file.path, options)
|
51
45
|
ensure
|
52
|
-
|
46
|
+
if options[:delete_temporary_files] && string_file
|
47
|
+
string_file.close!
|
48
|
+
elsif string_file
|
49
|
+
string_file.close
|
50
|
+
end
|
53
51
|
end
|
54
52
|
|
55
|
-
def pdf_from_url(url, options = {})
|
53
|
+
def pdf_from_url(url, options = {}) # rubocop:disable Metrics/CyclomaticComplexity
|
56
54
|
# merge in global config options
|
57
55
|
options.merge!(WickedPdf.config) { |_key, option, _config| option }
|
58
|
-
generated_pdf_file =
|
59
|
-
command = [@
|
60
|
-
command
|
56
|
+
generated_pdf_file = WickedPdf::Tempfile.new('wicked_pdf_generated_file.pdf', options[:temp_path])
|
57
|
+
command = [@binary.path]
|
58
|
+
command.unshift(@binary.xvfb_run_path) if options[:use_xvfb]
|
59
|
+
command += option_parser.parse(options)
|
61
60
|
command << url
|
62
61
|
command << generated_pdf_file.path.to_s
|
63
62
|
|
@@ -66,23 +65,24 @@ class WickedPdf
|
|
66
65
|
if track_progress?(options)
|
67
66
|
invoke_with_progress(command, options)
|
68
67
|
else
|
69
|
-
err = Open3.
|
70
|
-
|
71
|
-
end
|
68
|
+
_out, err, status = Open3.capture3(*command)
|
69
|
+
err = [status.to_s, err].join("\n") if !err.empty? || !status.success?
|
72
70
|
end
|
73
71
|
if options[:return_file]
|
74
72
|
return_file = options.delete(:return_file)
|
75
73
|
return generated_pdf_file
|
76
74
|
end
|
77
|
-
|
78
|
-
generated_pdf_file.
|
79
|
-
|
75
|
+
|
76
|
+
pdf = generated_pdf_file.read_in_chunks
|
77
|
+
|
80
78
|
raise "Error generating PDF\n Command Error: #{err}" if options[:raise_on_all_errors] && !err.empty?
|
81
79
|
raise "PDF could not be generated!\n Command Error: #{err}" if pdf && pdf.rstrip.empty?
|
80
|
+
|
82
81
|
pdf
|
83
82
|
rescue StandardError => e
|
84
83
|
raise "Failed to execute:\n#{command}\nError: #{e}"
|
85
84
|
ensure
|
85
|
+
clean_temp_files
|
86
86
|
generated_pdf_file.close! if generated_pdf_file && !return_file
|
87
87
|
end
|
88
88
|
|
@@ -90,6 +90,7 @@ class WickedPdf
|
|
90
90
|
|
91
91
|
def in_development_mode?
|
92
92
|
return Rails.env == 'development' if defined?(Rails.env)
|
93
|
+
|
93
94
|
RAILS_ENV == 'development' if defined?(RAILS_ENV)
|
94
95
|
end
|
95
96
|
|
@@ -101,242 +102,13 @@ class WickedPdf
|
|
101
102
|
Rails.logger.debug '[wicked_pdf]: ' + cmd
|
102
103
|
end
|
103
104
|
|
104
|
-
def
|
105
|
-
|
106
|
-
@binary_version = parse_version(stdout.gets(nil))
|
107
|
-
rescue StandardError
|
108
|
-
DEFAULT_BINARY_VERSION
|
109
|
-
end
|
110
|
-
|
111
|
-
def parse_version(version_info)
|
112
|
-
match_data = /wkhtmltopdf\s*(\d*\.\d*\.\d*\w*)/.match(version_info)
|
113
|
-
if match_data && (match_data.length == 2)
|
114
|
-
Gem::Version.new(match_data[1])
|
115
|
-
else
|
116
|
-
DEFAULT_BINARY_VERSION
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def parse_options(options)
|
121
|
-
[
|
122
|
-
parse_extra(options),
|
123
|
-
parse_others(options),
|
124
|
-
parse_global(options),
|
125
|
-
parse_outline(options.delete(:outline)),
|
126
|
-
parse_header_footer(:header => options.delete(:header),
|
127
|
-
:footer => options.delete(:footer),
|
128
|
-
:layout => options[:layout]),
|
129
|
-
parse_cover(options.delete(:cover)),
|
130
|
-
parse_toc(options.delete(:toc)),
|
131
|
-
parse_basic_auth(options)
|
132
|
-
].flatten
|
133
|
-
end
|
134
|
-
|
135
|
-
def parse_extra(options)
|
136
|
-
return [] if options[:extra].nil?
|
137
|
-
return options[:extra].split if options[:extra].respond_to?(:split)
|
138
|
-
options[:extra]
|
139
|
-
end
|
140
|
-
|
141
|
-
def parse_basic_auth(options)
|
142
|
-
if options[:basic_auth]
|
143
|
-
user, passwd = Base64.decode64(options[:basic_auth]).split(':')
|
144
|
-
['--username', user, '--password', passwd]
|
145
|
-
else
|
146
|
-
[]
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def make_option(name, value, type = :string)
|
151
|
-
if value.is_a?(Array)
|
152
|
-
return value.collect { |v| make_option(name, v, type) }
|
153
|
-
end
|
154
|
-
if type == :name_value
|
155
|
-
parts = value.to_s.split(' ')
|
156
|
-
["--#{name.tr('_', '-')}", *parts]
|
157
|
-
elsif type == :boolean
|
158
|
-
if value
|
159
|
-
["--#{name.tr('_', '-')}"]
|
160
|
-
else
|
161
|
-
[]
|
162
|
-
end
|
163
|
-
else
|
164
|
-
["--#{name.tr('_', '-')}", value.to_s]
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def valid_option(name)
|
169
|
-
if binary_version < BINARY_VERSION_WITHOUT_DASHES
|
170
|
-
"--#{name}"
|
171
|
-
else
|
172
|
-
name
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def make_options(options, names, prefix = '', type = :string)
|
177
|
-
return [] if options.nil?
|
178
|
-
names.collect do |o|
|
179
|
-
if options[o].blank?
|
180
|
-
[]
|
181
|
-
else
|
182
|
-
make_option("#{prefix.blank? ? '' : prefix + '-'}#{o}",
|
183
|
-
options[o],
|
184
|
-
type)
|
185
|
-
end
|
186
|
-
end
|
187
|
-
end
|
188
|
-
|
189
|
-
def parse_header_footer(options)
|
190
|
-
r = []
|
191
|
-
unless options.blank?
|
192
|
-
[:header, :footer].collect do |hf|
|
193
|
-
next if options[hf].blank?
|
194
|
-
opt_hf = options[hf]
|
195
|
-
r += make_options(opt_hf, [:center, :font_name, :left, :right], hf.to_s)
|
196
|
-
r += make_options(opt_hf, [:font_size, :spacing], hf.to_s, :numeric)
|
197
|
-
r += make_options(opt_hf, [:line], hf.to_s, :boolean)
|
198
|
-
if options[hf] && options[hf][:content]
|
199
|
-
@hf_tempfiles = [] unless defined?(@hf_tempfiles)
|
200
|
-
@hf_tempfiles.push(tf = WickedPdfTempfile.new("wicked_#{hf}_pdf.html"))
|
201
|
-
tf.write options[hf][:content]
|
202
|
-
tf.flush
|
203
|
-
options[hf][:html] = {}
|
204
|
-
options[hf][:html][:url] = "file:///#{tf.path}"
|
205
|
-
end
|
206
|
-
unless opt_hf[:html].blank?
|
207
|
-
r += make_option("#{hf}-html", opt_hf[:html][:url]) unless opt_hf[:html][:url].blank?
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
r
|
212
|
-
end
|
213
|
-
|
214
|
-
def parse_cover(argument)
|
215
|
-
arg = argument.to_s
|
216
|
-
return [] if arg.blank?
|
217
|
-
# Filesystem path or URL - hand off to wkhtmltopdf
|
218
|
-
if argument.is_a?(Pathname) || (arg[0, 4] == 'http')
|
219
|
-
[valid_option('cover'), arg]
|
220
|
-
else # HTML content
|
221
|
-
@hf_tempfiles ||= []
|
222
|
-
@hf_tempfiles << tf = WickedPdfTempfile.new('wicked_cover_pdf.html')
|
223
|
-
tf.write arg
|
224
|
-
tf.flush
|
225
|
-
[valid_option('cover'), tf.path]
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def parse_toc(options)
|
230
|
-
return [] if options.nil?
|
231
|
-
r = [valid_option('toc')]
|
232
|
-
unless options.blank?
|
233
|
-
r += make_options(options, [:font_name, :header_text], 'toc')
|
234
|
-
r += make_options(options, [:xsl_style_sheet])
|
235
|
-
r += make_options(options, [:depth,
|
236
|
-
:header_fs,
|
237
|
-
:text_size_shrink,
|
238
|
-
:l1_font_size,
|
239
|
-
:l2_font_size,
|
240
|
-
:l3_font_size,
|
241
|
-
:l4_font_size,
|
242
|
-
:l5_font_size,
|
243
|
-
:l6_font_size,
|
244
|
-
:l7_font_size,
|
245
|
-
:level_indentation,
|
246
|
-
:l1_indentation,
|
247
|
-
:l2_indentation,
|
248
|
-
:l3_indentation,
|
249
|
-
:l4_indentation,
|
250
|
-
:l5_indentation,
|
251
|
-
:l6_indentation,
|
252
|
-
:l7_indentation], 'toc', :numeric)
|
253
|
-
r += make_options(options, [:no_dots,
|
254
|
-
:disable_links,
|
255
|
-
:disable_back_links], 'toc', :boolean)
|
256
|
-
r += make_options(options, [:disable_dotted_lines,
|
257
|
-
:disable_toc_links], nil, :boolean)
|
258
|
-
end
|
259
|
-
r
|
105
|
+
def option_parser
|
106
|
+
@option_parser ||= OptionParser.new(binary_version)
|
260
107
|
end
|
261
108
|
|
262
|
-
def
|
263
|
-
|
264
|
-
unless options.blank?
|
265
|
-
r = make_options(options, [:outline], '', :boolean)
|
266
|
-
r += make_options(options, [:outline_depth], '', :numeric)
|
267
|
-
end
|
268
|
-
r
|
269
|
-
end
|
109
|
+
def clean_temp_files
|
110
|
+
return unless option_parser.hf_tempfiles.present?
|
270
111
|
|
271
|
-
|
272
|
-
make_options(options, [:top, :bottom, :left, :right], 'margin', :numeric)
|
273
|
-
end
|
274
|
-
|
275
|
-
def parse_global(options)
|
276
|
-
r = []
|
277
|
-
unless options.blank?
|
278
|
-
r += make_options(options, [:orientation,
|
279
|
-
:dpi,
|
280
|
-
:page_size,
|
281
|
-
:page_width,
|
282
|
-
:title,
|
283
|
-
:log_level])
|
284
|
-
r += make_options(options, [:lowquality,
|
285
|
-
:grayscale,
|
286
|
-
:no_pdf_compression,
|
287
|
-
:quiet], '', :boolean)
|
288
|
-
r += make_options(options, [:image_dpi,
|
289
|
-
:image_quality,
|
290
|
-
:page_height], '', :numeric)
|
291
|
-
r += parse_margins(options.delete(:margin))
|
292
|
-
end
|
293
|
-
r
|
294
|
-
end
|
295
|
-
|
296
|
-
def parse_others(options)
|
297
|
-
r = []
|
298
|
-
unless options.blank?
|
299
|
-
r += make_options(options, [:proxy,
|
300
|
-
:username,
|
301
|
-
:password,
|
302
|
-
:encoding,
|
303
|
-
:user_style_sheet,
|
304
|
-
:viewport_size,
|
305
|
-
:window_status])
|
306
|
-
r += make_options(options, [:cookie,
|
307
|
-
:post], '', :name_value)
|
308
|
-
r += make_options(options, [:redirect_delay,
|
309
|
-
:zoom,
|
310
|
-
:page_offset,
|
311
|
-
:javascript_delay], '', :numeric)
|
312
|
-
r += make_options(options, [:book,
|
313
|
-
:default_header,
|
314
|
-
:disable_javascript,
|
315
|
-
:enable_plugins,
|
316
|
-
:disable_internal_links,
|
317
|
-
:disable_external_links,
|
318
|
-
:print_media_type,
|
319
|
-
:disable_smart_shrinking,
|
320
|
-
:use_xserver,
|
321
|
-
:no_background,
|
322
|
-
:images,
|
323
|
-
:no_images,
|
324
|
-
:no_stop_slow_scripts], '', :boolean)
|
325
|
-
end
|
326
|
-
r
|
327
|
-
end
|
328
|
-
|
329
|
-
def find_wkhtmltopdf_binary_path
|
330
|
-
possible_locations = (ENV['PATH'].split(':') + %w[/usr/bin /usr/local/bin]).uniq
|
331
|
-
possible_locations += %w[~/bin] if ENV.key?('HOME')
|
332
|
-
exe_path ||= WickedPdf.config[:exe_path] unless WickedPdf.config.empty?
|
333
|
-
exe_path ||= begin
|
334
|
-
detected_path = (defined?(Bundler) ? Bundler.which('wkhtmltopdf') : `which wkhtmltopdf`).chomp
|
335
|
-
detected_path.present? && detected_path
|
336
|
-
rescue StandardError
|
337
|
-
nil
|
338
|
-
end
|
339
|
-
exe_path ||= possible_locations.map { |l| File.expand_path("#{l}/#{EXE_NAME}") }.find { |location| File.exist?(location) }
|
340
|
-
exe_path || ''
|
112
|
+
option_parser.hf_tempfiles.each { |file| File.delete(file) }
|
341
113
|
end
|
342
114
|
end
|
@@ -76,7 +76,7 @@ class PdfHelperTest < ActionController::TestCase
|
|
76
76
|
|
77
77
|
# test that calling render does not trigger infinite loop
|
78
78
|
ac = ActionController::Base.new
|
79
|
-
assert_equal [
|
79
|
+
assert_equal %i[base patched], ac.render(:cats)
|
80
80
|
rescue SystemStackError
|
81
81
|
assert_equal true, false # force spec failure
|
82
82
|
ensure
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class WickedPdfBinaryTest < ActiveSupport::TestCase
|
4
|
+
test 'should extract old wkhtmltopdf version' do
|
5
|
+
version_info_sample = "Name:\n wkhtmltopdf 0.9.9\n\nLicense:\n Copyright (C) 2008,2009 Wkhtmltopdf Authors.\n\n\n\n License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n This is free software: you are free to change and redistribute it. There is NO\n WARRANTY, to the extent permitted by law.\n\nAuthors:\n Written by Jakob Truelsen. Patches by Mrio Silva, Benoit Garret and Emmanuel\n Bouthenot.\n"
|
6
|
+
assert_equal WickedPdf::DEFAULT_BINARY_VERSION, binary.parse_version_string(version_info_sample)
|
7
|
+
end
|
8
|
+
|
9
|
+
test 'should extract new wkhtmltopdf version' do
|
10
|
+
version_info_sample = "Name:\n wkhtmltopdf 0.11.0 rc2\n\nLicense:\n Copyright (C) 2010 wkhtmltopdf/wkhtmltoimage Authors.\n\n\n\n License LGPLv3+: GNU Lesser General Public License version 3 or later\n <http://gnu.org/licenses/lgpl.html>. This is free software: you are free to\n change and redistribute it. There is NO WARRANTY, to the extent permitted by\n law.\n\nAuthors:\n Written by Jan Habermann, Christian Sciberras and Jakob Truelsen. Patches by\n Mehdi Abbad, Lyes Amazouz, Pascal Bach, Emmanuel Bouthenot, Benoit Garret and\n Mario Silva."
|
11
|
+
assert_equal Gem::Version.new('0.11.0'), binary.parse_version_string(version_info_sample)
|
12
|
+
end
|
13
|
+
|
14
|
+
test 'should extract wkhtmltopdf version with nondigit symbols' do
|
15
|
+
version_info_sample = "Name:\n wkhtmltopdf 0.10.4b\n\nLicense:\n Copyright (C) 2008,2009 Wkhtmltopdf Authors.\n\n\n\n License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n This is free software: you are free to change and redistribute it. There is NO\n WARRANTY, to the extent permitted by law.\n\nAuthors:\n Written by Jakob Truelsen. Patches by Mrio Silva, Benoit Garret and Emmanuel\n Bouthenot.\n"
|
16
|
+
assert_equal Gem::Version.new('0.10.4b'), binary.parse_version_string(version_info_sample)
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'should fallback to default version on parse error' do
|
20
|
+
assert_equal WickedPdf::DEFAULT_BINARY_VERSION, binary.parse_version_string('')
|
21
|
+
end
|
22
|
+
|
23
|
+
def binary(path = nil)
|
24
|
+
WickedPdf::Binary.new(path)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class WickedPdfOptionParserTest < ActiveSupport::TestCase
|
4
|
+
test 'should parse header and footer options' do
|
5
|
+
%i[header footer].each do |hf|
|
6
|
+
%i[center font_name left right].each do |o|
|
7
|
+
assert_equal "--#{hf}-#{o.to_s.tr('_', '-')} header_footer",
|
8
|
+
parse_options(hf => { o => 'header_footer' }).strip
|
9
|
+
end
|
10
|
+
|
11
|
+
%i[font_size spacing].each do |o|
|
12
|
+
assert_equal "--#{hf}-#{o.to_s.tr('_', '-')} 12",
|
13
|
+
parse_options(hf => { o => '12' }).strip
|
14
|
+
end
|
15
|
+
|
16
|
+
assert_equal "--#{hf}-line",
|
17
|
+
parse_options(hf => { :line => true }).strip
|
18
|
+
assert_equal "--#{hf}-html http://www.abc.com",
|
19
|
+
parse_options(hf => { :html => { :url => 'http://www.abc.com' } }).strip
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
test 'should parse toc options' do
|
24
|
+
toc_option = option_parser.valid_option('toc')
|
25
|
+
|
26
|
+
%i[font_name header_text].each do |o|
|
27
|
+
assert_equal "#{toc_option} --toc-#{o.to_s.tr('_', '-')} toc",
|
28
|
+
parse_options(:toc => { o => 'toc' }).strip
|
29
|
+
end
|
30
|
+
|
31
|
+
%i[
|
32
|
+
depth header_fs l1_font_size l2_font_size l3_font_size l4_font_size
|
33
|
+
l5_font_size l6_font_size l7_font_size l1_indentation l2_indentation
|
34
|
+
l3_indentation l4_indentation l5_indentation l6_indentation l7_indentation
|
35
|
+
].each do |o|
|
36
|
+
assert_equal "#{toc_option} --toc-#{o.to_s.tr('_', '-')} 5",
|
37
|
+
parse_options(:toc => { o => 5 }).strip
|
38
|
+
end
|
39
|
+
|
40
|
+
%i[no_dots disable_links disable_back_links].each do |o|
|
41
|
+
assert_equal "#{toc_option} --toc-#{o.to_s.tr('_', '-')}",
|
42
|
+
parse_options(:toc => { o => true }).strip
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
test 'should parse outline options' do
|
47
|
+
assert_equal '--outline', parse_options(:outline => { :outline => true }).strip
|
48
|
+
assert_equal '--outline-depth 5', parse_options(:outline => { :outline_depth => 5 }).strip
|
49
|
+
end
|
50
|
+
|
51
|
+
test 'should parse no_images option' do
|
52
|
+
assert_equal '--no-images', parse_options(:no_images => true).strip
|
53
|
+
assert_equal '--images', parse_options(:images => true).strip
|
54
|
+
end
|
55
|
+
|
56
|
+
test 'should parse margins options' do
|
57
|
+
%i[top bottom left right].each do |o|
|
58
|
+
assert_equal "--margin-#{o} 12", parse_options(:margin => { o => '12' }).strip
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
test 'should parse cover' do
|
63
|
+
cover_option = option_parser.valid_option('cover')
|
64
|
+
|
65
|
+
pathname = Rails.root.join('app', 'views', 'pdf', 'file.html')
|
66
|
+
assert_equal "#{cover_option} http://example.org", parse_options(:cover => 'http://example.org').strip, 'URL'
|
67
|
+
assert_equal "#{cover_option} #{pathname}", parse_options(:cover => pathname).strip, 'Pathname'
|
68
|
+
assert_match(/#{cover_option} .+wicked_cover_pdf.+\.html/, parse_options(:cover => '<html><body>HELLO</body></html>').strip, 'HTML')
|
69
|
+
end
|
70
|
+
|
71
|
+
test 'should parse other options' do
|
72
|
+
%i[
|
73
|
+
orientation page_size proxy username password dpi
|
74
|
+
encoding user_style_sheet
|
75
|
+
].each do |o|
|
76
|
+
assert_equal "--#{o.to_s.tr('_', '-')} opts", parse_options(o => 'opts').strip
|
77
|
+
end
|
78
|
+
|
79
|
+
%i[allow].each do |o|
|
80
|
+
assert_equal "--#{o.to_s.tr('_', '-')} opts", parse_options(o => 'opts').strip
|
81
|
+
assert_equal "--#{o.to_s.tr('_', '-')} opts1 --#{o.to_s.tr('_', '-')} opts2", parse_options(o => %w[opts1 opts2]).strip
|
82
|
+
end
|
83
|
+
|
84
|
+
%i[cookie post].each do |o|
|
85
|
+
assert_equal "--#{o.to_s.tr('_', '-')} name value", parse_options(o => 'name value').strip
|
86
|
+
|
87
|
+
nv_formatter = proc { |number| "--#{o.to_s.tr('_', '-')} par#{number} val#{number}" }
|
88
|
+
assert_equal "#{nv_formatter.call(1)} #{nv_formatter.call(2)}", parse_options(o => ['par1 val1', 'par2 val2']).strip
|
89
|
+
end
|
90
|
+
|
91
|
+
%i[redirect_delay zoom page_offset].each do |o|
|
92
|
+
assert_equal "--#{o.to_s.tr('_', '-')} 5", parse_options(o => 5).strip
|
93
|
+
end
|
94
|
+
|
95
|
+
%i[
|
96
|
+
book default_header disable_javascript grayscale lowquality
|
97
|
+
enable_plugins disable_internal_links disable_external_links
|
98
|
+
print_media_type disable_smart_shrinking use_xserver no_background disable_local_file_access
|
99
|
+
].each do |o|
|
100
|
+
assert_equal "--#{o.to_s.tr('_', '-')}", parse_options(o => true).strip
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
test 'should not use double dash options for version without dashes' do
|
105
|
+
op = option_parser(WickedPdf::OptionParser::BINARY_VERSION_WITHOUT_DASHES)
|
106
|
+
|
107
|
+
%w[toc cover].each do |name|
|
108
|
+
assert_equal op.valid_option(name), name
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
test 'should use double dash options for version with dashes' do
|
113
|
+
op = option_parser(Gem::Version.new('0.11.0'))
|
114
|
+
|
115
|
+
%w[toc cover].each do |name|
|
116
|
+
assert_equal op.valid_option(name), "--#{name}"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
test '-- options should not be given after object' do
|
121
|
+
options = { :header => { :center => 3 }, :cover => 'http://example.org', :disable_javascript => true }
|
122
|
+
cover_option = option_parser.valid_option('cover')
|
123
|
+
assert_equal parse_options(options), "--disable-javascript --header-center 3 #{cover_option} http://example.org"
|
124
|
+
end
|
125
|
+
|
126
|
+
def parse_options(options, version = WickedPdf::DEFAULT_BINARY_VERSION)
|
127
|
+
option_parser(version).parse(options).join(' ')
|
128
|
+
end
|
129
|
+
|
130
|
+
def option_parser(version = WickedPdf::DEFAULT_BINARY_VERSION)
|
131
|
+
WickedPdf::OptionParser.new(version)
|
132
|
+
end
|
133
|
+
end
|