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.
@@ -1,19 +1,48 @@
1
1
  require 'net/http'
2
- # If webpacker is used, need to check for version
3
- require 'webpacker/version' if defined?(Webpacker)
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 defined?(Webpacker) && defined?(Webpacker::VERSION)
206
+ return unless webpacker_version
207
+
165
208
  # In Webpacker 3.2.0 asset_pack_url is introduced
166
- if Webpacker::VERSION >= '3.2.0'
167
- asset_pack_url(source)
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 defined?(Webpacker)
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
- @exe_path = wkhtmltopdf_binary_path || find_wkhtmltopdf_binary_path
30
- raise "Location of #{EXE_NAME} unknown" if @exe_path.empty?
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
- retrieve_binary_version
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 = WickedPdfTempfile.new('wicked_pdf.html', options[:temp_path])
45
- string_file.binmode
46
- string_file.write(string)
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
- string_file.close! if string_file
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 = WickedPdfTempfile.new('wicked_pdf_generated_file.pdf', options[:temp_path])
59
- command = [@exe_path]
60
- command += parse_options(options)
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.popen3(*command) do |_stdin, _stdout, stderr|
70
- stderr.read
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
- generated_pdf_file.rewind
78
- generated_pdf_file.binmode
79
- pdf = generated_pdf_file.read
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 retrieve_binary_version
105
- _stdin, stdout, _stderr = Open3.popen3(@exe_path + ' -V')
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 parse_outline(options)
263
- r = []
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
- def parse_margins(options)
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 [:base, :patched], ac.render(:cats)
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