wicked_pdf 1.1.0 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +5 -5
  2. data/.github/issue_template.md +15 -0
  3. data/.github/workflows/ci.yml +56 -0
  4. data/.rubocop.yml +62 -0
  5. data/.rubocop_todo.yml +81 -39
  6. data/CHANGELOG.md +194 -45
  7. data/README.md +136 -28
  8. data/Rakefile +12 -9
  9. data/gemfiles/5.0.gemfile +3 -1
  10. data/gemfiles/5.1.gemfile +8 -0
  11. data/gemfiles/5.2.gemfile +9 -0
  12. data/gemfiles/6.0.gemfile +10 -0
  13. data/gemfiles/6.1.gemfile +11 -0
  14. data/gemfiles/7.0.gemfile +11 -0
  15. data/generators/wicked_pdf/templates/wicked_pdf.rb +14 -5
  16. data/lib/generators/wicked_pdf_generator.rb +5 -9
  17. data/lib/wicked_pdf/binary.rb +65 -0
  18. data/lib/wicked_pdf/middleware.rb +1 -1
  19. data/lib/wicked_pdf/option_parser.rb +230 -0
  20. data/lib/wicked_pdf/pdf_helper.rb +35 -42
  21. data/lib/wicked_pdf/progress.rb +33 -0
  22. data/lib/wicked_pdf/railtie.rb +6 -44
  23. data/lib/wicked_pdf/tempfile.rb +33 -3
  24. data/lib/wicked_pdf/version.rb +1 -1
  25. data/lib/wicked_pdf/wicked_pdf_helper/assets.rb +200 -17
  26. data/lib/wicked_pdf/wicked_pdf_helper.rb +2 -1
  27. data/lib/wicked_pdf.rb +64 -275
  28. data/test/fixtures/database.yml +4 -0
  29. data/test/fixtures/manifest.js +3 -0
  30. data/test/functional/pdf_helper_test.rb +71 -0
  31. data/test/functional/wicked_pdf_helper_assets_test.rb +61 -0
  32. data/test/test_helper.rb +13 -8
  33. data/test/unit/wicked_pdf_binary_test.rb +26 -0
  34. data/test/unit/wicked_pdf_option_parser_test.rb +133 -0
  35. data/test/unit/wicked_pdf_test.rb +25 -146
  36. data/test/unit/wkhtmltopdf_location_test.rb +48 -0
  37. data/wicked_pdf.gemspec +20 -13
  38. metadata +79 -36
  39. data/.travis.yml +0 -57
  40. data/gemfiles/2.3.gemfile +0 -10
  41. data/gemfiles/3.0.gemfile +0 -12
  42. data/gemfiles/3.1.gemfile +0 -13
  43. data/gemfiles/3.2.gemfile +0 -12
  44. data/gemfiles/4.0.gemfile +0 -6
  45. data/gemfiles/4.1.gemfile +0 -6
  46. data/gemfiles/4.2.gemfile +0 -6
  47. data/gemfiles/rails_edge.gemfile +0 -6
@@ -1,17 +1,99 @@
1
- require 'open-uri'
1
+ require 'net/http'
2
+ require 'delegate'
3
+ require 'stringio'
2
4
 
3
5
  class WickedPdf
4
6
  module WickedPdfHelper
5
7
  module Assets
6
8
  ASSET_URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/
7
9
 
10
+ class MissingAsset < StandardError; end
11
+
12
+ class MissingLocalAsset < MissingAsset
13
+ attr_reader :path
14
+
15
+ def initialize(path)
16
+ @path = path
17
+ super("Could not find asset '#{path}'")
18
+ end
19
+ end
20
+
21
+ class MissingRemoteAsset < MissingAsset
22
+ attr_reader :url, :response
23
+
24
+ def initialize(url, response)
25
+ @url = url
26
+ @response = response
27
+ super("Could not fetch asset '#{url}': server responded with #{response.code} #{response.message}")
28
+ end
29
+ end
30
+
31
+ class PropshaftAsset < SimpleDelegator
32
+ def content_type
33
+ super.to_s
34
+ end
35
+
36
+ def to_s
37
+ content
38
+ end
39
+
40
+ def filename
41
+ path.to_s
42
+ end
43
+ end
44
+
45
+ class SprocketsEnvironment
46
+ def self.instance
47
+ @instance ||= Sprockets::Railtie.build_environment(Rails.application)
48
+ end
49
+
50
+ def self.find_asset(*args)
51
+ instance.find_asset(*args)
52
+ end
53
+ end
54
+
55
+ class LocalAsset
56
+ attr_reader :path
57
+
58
+ def initialize(path)
59
+ @path = path
60
+ end
61
+
62
+ def content_type
63
+ Mime::Type.lookup_by_extension(File.extname(path).delete('.'))
64
+ end
65
+
66
+ def to_s
67
+ IO.read(path)
68
+ end
69
+
70
+ def filename
71
+ path.to_s
72
+ end
73
+ end
74
+
8
75
  def wicked_pdf_asset_base64(path)
9
76
  asset = find_asset(path)
10
- raise "Could not find asset '#{path}'" if asset.nil?
77
+ raise MissingLocalAsset, path if asset.nil?
78
+
11
79
  base64 = Base64.encode64(asset.to_s).gsub(/\s+/, '')
12
80
  "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
13
81
  end
14
82
 
83
+ # Using `image_tag` with URLs when generating PDFs (specifically large PDFs with lots of pages) can cause buffer/stack overflows.
84
+ #
85
+ def wicked_pdf_url_base64(url)
86
+ response = Net::HTTP.get_response(URI(url))
87
+
88
+ if response.is_a?(Net::HTTPSuccess)
89
+ base64 = Base64.encode64(response.body).gsub(/\s+/, '')
90
+ "data:#{response.content_type};base64,#{Rack::Utils.escape(base64)}"
91
+ else
92
+ Rails.logger.warn("[wicked_pdf] #{response.code} #{response.message}: #{url}")
93
+ nil
94
+ end
95
+ end
96
+
15
97
  def wicked_pdf_stylesheet_link_tag(*sources)
16
98
  stylesheet_contents = sources.collect do |source|
17
99
  source = WickedPdfHelper.add_extension(source, 'css')
@@ -27,6 +109,33 @@ class WickedPdf
27
109
  end.html_safe
28
110
  end
29
111
 
112
+ def wicked_pdf_stylesheet_pack_tag(*sources)
113
+ return unless defined?(Webpacker)
114
+
115
+ if running_in_development?
116
+ stylesheet_pack_tag(*sources)
117
+ else
118
+ css_text = sources.collect do |source|
119
+ source = WickedPdfHelper.add_extension(source, 'css')
120
+ wicked_pdf_stylesheet_link_tag(webpacker_source_url(source))
121
+ end.join("\n")
122
+ css_text.respond_to?(:html_safe) ? css_text.html_safe : css_text
123
+ end
124
+ end
125
+
126
+ def wicked_pdf_javascript_pack_tag(*sources)
127
+ return unless defined?(Webpacker)
128
+
129
+ if running_in_development?
130
+ javascript_pack_tag(*sources)
131
+ else
132
+ sources.collect do |source|
133
+ source = WickedPdfHelper.add_extension(source, 'js')
134
+ "<script type='text/javascript'>#{read_asset(webpacker_source_url(source))}</script>"
135
+ end.join("\n").html_safe
136
+ end
137
+ end
138
+
30
139
  def wicked_pdf_image_tag(img, options = {})
31
140
  image_tag wicked_pdf_asset_path(img), options
32
141
  end
@@ -51,6 +160,16 @@ class WickedPdf
51
160
  end
52
161
  end
53
162
 
163
+ def wicked_pdf_asset_pack_path(asset)
164
+ return unless defined?(Webpacker)
165
+
166
+ if running_in_development?
167
+ asset_pack_path(asset)
168
+ else
169
+ wicked_pdf_asset_path webpacker_source_url(asset)
170
+ end
171
+ end
172
+
54
173
  private
55
174
 
56
175
  # borrowed from actionpack/lib/action_view/helpers/asset_url_helper.rb
@@ -68,15 +187,25 @@ class WickedPdf
68
187
  end
69
188
  else
70
189
  asset = find_asset(source)
71
- asset ? asset.pathname : File.join(Rails.public_path, source)
190
+ if asset
191
+ # older versions need pathname, Sprockets 4 supports only filename
192
+ asset.respond_to?(:filename) ? asset.filename : asset.pathname
193
+ else
194
+ File.join(Rails.public_path, source)
195
+ end
72
196
  end
73
197
  end
74
198
 
75
199
  def find_asset(path)
76
200
  if Rails.application.assets.respond_to?(:find_asset)
77
- Rails.application.assets.find_asset(path)
201
+ Rails.application.assets.find_asset(path, :base_path => Rails.application.root.to_s)
202
+ elsif defined?(Propshaft::Assembly) && Rails.application.assets.is_a?(Propshaft::Assembly)
203
+ PropshaftAsset.new(Rails.application.assets.load_path.find(path))
204
+ elsif Rails.application.respond_to?(:assets_manifest)
205
+ asset_path = File.join(Rails.application.assets_manifest.dir, Rails.application.assets_manifest.assets[path])
206
+ LocalAsset.new(asset_path) if File.file?(asset_path)
78
207
  else
79
- Sprockets::Railtie.build_environment(Rails.application).find_asset(path)
208
+ SprocketsEnvironment.find_asset(path, :base_path => Rails.application.root.to_s)
80
209
  end
81
210
  end
82
211
 
@@ -93,27 +222,43 @@ class WickedPdf
93
222
  end
94
223
 
95
224
  def precompiled_or_absolute_asset?(source)
96
- Rails.configuration.assets.compile == false ||
225
+ !Rails.configuration.respond_to?(:assets) ||
226
+ Rails.configuration.assets.compile == false ||
97
227
  source.to_s[0] == '/' ||
98
228
  source.to_s.match(/\Ahttps?\:\/\//)
99
229
  end
100
230
 
101
231
  def read_asset(source)
102
- if precompiled_or_absolute_asset?(source)
103
- pathname = asset_pathname(source)
104
- if pathname =~ URI_REGEXP
105
- read_from_uri(pathname)
106
- elsif File.file?(pathname)
107
- IO.read(pathname)
108
- end
109
- else
110
- find_asset(source).to_s
232
+ asset = find_asset(source)
233
+ return asset.to_s.force_encoding('UTF-8') if asset
234
+
235
+ unless precompiled_or_absolute_asset?(source)
236
+ raise MissingLocalAsset, source if WickedPdf.config[:raise_on_missing_assets]
237
+
238
+ return
239
+ end
240
+
241
+ pathname = asset_pathname(source)
242
+ if pathname =~ URI_REGEXP
243
+ read_from_uri(pathname)
244
+ elsif File.file?(pathname)
245
+ IO.read(pathname)
246
+ elsif WickedPdf.config[:raise_on_missing_assets]
247
+ raise MissingLocalAsset, pathname if WickedPdf.config[:raise_on_missing_assets]
111
248
  end
112
249
  end
113
250
 
114
251
  def read_from_uri(uri)
115
- encoding = ':UTF-8' if RUBY_VERSION > '1.8'
116
- asset = open(uri, "r#{encoding}", &:read)
252
+ response = Net::HTTP.get_response(URI(uri))
253
+
254
+ unless response.is_a?(Net::HTTPSuccess)
255
+ raise MissingRemoteAsset.new(uri, response) if WickedPdf.config[:raise_on_missing_assets]
256
+
257
+ return
258
+ end
259
+
260
+ asset = response.body
261
+ asset.force_encoding('UTF-8') if asset
117
262
  asset = gzip(asset) if WickedPdf.config[:expect_gzipped_remote_assets]
118
263
  asset
119
264
  end
@@ -125,6 +270,44 @@ class WickedPdf
125
270
  rescue Zlib::GzipFile::Error
126
271
  nil
127
272
  end
273
+
274
+ def webpacker_source_url(source)
275
+ return unless webpacker_version
276
+
277
+ # In Webpacker 3.2.0 asset_pack_url is introduced
278
+ if webpacker_version >= '3.2.0'
279
+ if (host = Rails.application.config.asset_host)
280
+ asset_pack_path(source, :host => host)
281
+ else
282
+ asset_pack_url(source)
283
+ end
284
+ else
285
+ source_path = asset_pack_path(source)
286
+ # Remove last slash from root path
287
+ root_url[0...-1] + source_path
288
+ end
289
+ end
290
+
291
+ def running_in_development?
292
+ return unless webpacker_version
293
+
294
+ # :dev_server method was added in webpacker 3.0.0
295
+ if Webpacker.respond_to?(:dev_server)
296
+ Webpacker.dev_server.running?
297
+ else
298
+ Rails.env.development? || Rails.env.test?
299
+ end
300
+ end
301
+
302
+ def webpacker_version
303
+ if defined?(Shakapacker)
304
+ require 'shakapacker/version'
305
+ Shakapacker::VERSION
306
+ elsif defined?(Webpacker)
307
+ require 'webpacker/version'
308
+ Webpacker::VERSION
309
+ end
310
+ end
128
311
  end
129
312
  end
130
313
  end
@@ -23,8 +23,9 @@ class WickedPdf
23
23
 
24
24
  def wicked_pdf_javascript_src_tag(jsfile, options = {})
25
25
  jsfile = WickedPdfHelper.add_extension(jsfile, 'js')
26
+ type = ::Mime.respond_to?(:[]) ? ::Mime[:js] : ::Mime::JS # ::Mime[:js] cannot be used in Rails 2.3.
26
27
  src = "file:///#{WickedPdfHelper.root_path.join('public', 'javascripts', jsfile)}"
27
- content_tag('script', '', { 'type' => Mime::JS, 'src' => path_to_javascript(src) }.merge(options))
28
+ content_tag('script', '', { 'type' => type, 'src' => path_to_javascript(src) }.merge(options))
28
29
  end
29
30
 
30
31
  def wicked_pdf_javascript_include_tag(*sources)
data/lib/wicked_pdf.rb CHANGED
@@ -1,48 +1,52 @@
1
1
  # wkhtml2pdf Ruby interface
2
- # http://code.google.com/p/wkhtmltopdf/
2
+ # http://wkhtmltopdf.org/
3
3
 
4
4
  require 'logger'
5
5
  require 'digest/md5'
6
6
  require 'rbconfig'
7
+ require 'open3'
7
8
 
8
- if (RbConfig::CONFIG['target_os'] =~ /mswin|mingw/) && (RUBY_VERSION < '1.9')
9
- require 'win32/open3'
10
- else
11
- require 'open3'
12
- end
13
-
14
- begin
15
- require 'active_support/core_ext/module/attribute_accessors'
16
- rescue LoadError
17
- require 'active_support/core_ext/class/attribute_accessors'
18
- end
19
-
20
- begin
21
- require 'active_support/core_ext/object/blank'
22
- rescue LoadError
23
- require 'active_support/core_ext/blank'
24
- end
9
+ require 'active_support/core_ext/module/attribute_accessors'
10
+ require 'active_support/core_ext/object/blank'
25
11
 
26
12
  require 'wicked_pdf/version'
27
13
  require 'wicked_pdf/railtie'
14
+ require 'wicked_pdf/option_parser'
28
15
  require 'wicked_pdf/tempfile'
16
+ require 'wicked_pdf/binary'
29
17
  require 'wicked_pdf/middleware'
18
+ require 'wicked_pdf/progress'
30
19
 
31
20
  class WickedPdf
32
21
  DEFAULT_BINARY_VERSION = Gem::Version.new('0.9.9')
33
- BINARY_VERSION_WITHOUT_DASHES = Gem::Version.new('0.12.0')
34
- EXE_NAME = 'wkhtmltopdf'.freeze
35
22
  @@config = {}
36
- cattr_accessor :config
37
- attr_accessor :binary_version
23
+ cattr_accessor :config, :silence_deprecations
24
+
25
+ include Progress
26
+
27
+ def self.config=(config)
28
+ ::Kernel.warn 'WickedPdf.config= is deprecated and will be removed in future versions. Use WickedPdf.configure instead.' unless @@silence_deprecations
29
+
30
+ @@config = config
31
+ end
32
+
33
+ def self.configure
34
+ config = OpenStruct.new(@@config)
35
+ yield config
36
+
37
+ @@config.merge! config.to_h
38
+ end
39
+
40
+ def self.clear_config
41
+ @@config = {}
42
+ end
38
43
 
39
44
  def initialize(wkhtmltopdf_binary_path = nil)
40
- @exe_path = wkhtmltopdf_binary_path || find_wkhtmltopdf_binary_path
41
- raise "Location of #{EXE_NAME} unknown" if @exe_path.empty?
42
- raise "Bad #{EXE_NAME}'s path: #{@exe_path}" unless File.exist?(@exe_path)
43
- raise "#{EXE_NAME} is not executable" unless File.executable?(@exe_path)
45
+ @binary = Binary.new(wkhtmltopdf_binary_path, DEFAULT_BINARY_VERSION)
46
+ end
44
47
 
45
- retrieve_binary_version
48
+ def binary_version
49
+ @binary.version
46
50
  end
47
51
 
48
52
  def pdf_from_html_file(filepath, options = {})
@@ -52,51 +56,58 @@ class WickedPdf
52
56
  def pdf_from_string(string, options = {})
53
57
  options = options.dup
54
58
  options.merge!(WickedPdf.config) { |_key, option, _config| option }
55
- string_file = WickedPdfTempfile.new('wicked_pdf.html', options[:temp_path])
56
- string_file.binmode
57
- string_file.write(string)
58
- string_file.close
59
-
60
- pdf = pdf_from_html_file(string_file.path, options)
61
- pdf
59
+ string_file = WickedPdf::Tempfile.new('wicked_pdf.html', options[:temp_path])
60
+ string_file.write_in_chunks(string)
61
+ pdf_from_html_file(string_file.path, options)
62
62
  ensure
63
- string_file.close! if string_file
63
+ if options[:delete_temporary_files] && string_file
64
+ string_file.close!
65
+ elsif string_file
66
+ string_file.close
67
+ end
64
68
  end
65
69
 
66
- def pdf_from_url(url, options = {})
70
+ def pdf_from_url(url, options = {}) # rubocop:disable Metrics/CyclomaticComplexity
67
71
  # merge in global config options
68
72
  options.merge!(WickedPdf.config) { |_key, option, _config| option }
69
- generated_pdf_file = WickedPdfTempfile.new('wicked_pdf_generated_file.pdf', options[:temp_path])
70
- command = [@exe_path]
71
- command << '-q' unless on_windows? # suppress errors on stdout
72
- command += parse_options(options)
73
+ generated_pdf_file = WickedPdf::Tempfile.new('wicked_pdf_generated_file.pdf', options[:temp_path])
74
+ command = [@binary.path]
75
+ command.unshift(@binary.xvfb_run_path) if options[:use_xvfb]
76
+ command += option_parser.parse(options)
73
77
  command << url
74
78
  command << generated_pdf_file.path.to_s
75
79
 
76
80
  print_command(command.inspect) if in_development_mode?
77
81
 
78
- err = Open3.popen3(*command) do |_stdin, _stdout, stderr|
79
- stderr.read
82
+ if track_progress?(options)
83
+ invoke_with_progress(command, options)
84
+ else
85
+ _out, err, status = Open3.capture3(*command)
86
+ err = [status.to_s, err].join("\n") if !err.empty? || !status.success?
80
87
  end
81
88
  if options[:return_file]
82
89
  return_file = options.delete(:return_file)
83
90
  return generated_pdf_file
84
91
  end
85
- generated_pdf_file.rewind
86
- generated_pdf_file.binmode
87
- pdf = generated_pdf_file.read
92
+
93
+ pdf = generated_pdf_file.read_in_chunks
94
+
95
+ raise "Error generating PDF\n Command Error: #{err}" if options[:raise_on_all_errors] && !err.empty?
88
96
  raise "PDF could not be generated!\n Command Error: #{err}" if pdf && pdf.rstrip.empty?
97
+
89
98
  pdf
90
- rescue => e
99
+ rescue StandardError => e
91
100
  raise "Failed to execute:\n#{command}\nError: #{e}"
92
101
  ensure
102
+ clean_temp_files
93
103
  generated_pdf_file.close! if generated_pdf_file && !return_file
94
104
  end
95
105
 
96
106
  private
97
107
 
98
108
  def in_development_mode?
99
- return Rails.env == 'development' if defined?(Rails)
109
+ return Rails.env == 'development' if defined?(Rails.env)
110
+
100
111
  RAILS_ENV == 'development' if defined?(RAILS_ENV)
101
112
  end
102
113
 
@@ -105,238 +116,16 @@ class WickedPdf
105
116
  end
106
117
 
107
118
  def print_command(cmd)
108
- p '*' * 15 + cmd + '*' * 15
109
- end
110
-
111
- def retrieve_binary_version
112
- _stdin, stdout, _stderr = Open3.popen3(@exe_path + ' -V')
113
- @binary_version = parse_version(stdout.gets(nil))
114
- rescue
115
- DEFAULT_BINARY_VERSION
116
- end
117
-
118
- def parse_version(version_info)
119
- match_data = /wkhtmltopdf\s*(\d*\.\d*\.\d*\w*)/.match(version_info)
120
- if match_data && (2 == match_data.length)
121
- Gem::Version.new(match_data[1])
122
- else
123
- DEFAULT_BINARY_VERSION
124
- end
125
- end
126
-
127
- def parse_options(options)
128
- [
129
- parse_extra(options),
130
- parse_others(options),
131
- parse_global(options),
132
- parse_outline(options.delete(:outline)),
133
- parse_header_footer(:header => options.delete(:header),
134
- :footer => options.delete(:footer),
135
- :layout => options[:layout]),
136
- parse_cover(options.delete(:cover)),
137
- parse_toc(options.delete(:toc)),
138
- parse_basic_auth(options)
139
- ].flatten
140
- end
141
-
142
- def parse_extra(options)
143
- return [] if options[:extra].nil?
144
- return options[:extra].split if options[:extra].respond_to?(:split)
145
- options[:extra]
119
+ Rails.logger.debug '[wicked_pdf]: ' + cmd
146
120
  end
147
121
 
148
- def parse_basic_auth(options)
149
- if options[:basic_auth]
150
- user, passwd = Base64.decode64(options[:basic_auth]).split(':')
151
- ['--username', user, '--password', passwd]
152
- else
153
- []
154
- end
122
+ def option_parser
123
+ @option_parser ||= OptionParser.new(binary_version)
155
124
  end
156
125
 
157
- def make_option(name, value, type = :string)
158
- if value.is_a?(Array)
159
- return value.collect { |v| make_option(name, v, type) }
160
- end
161
- if type == :name_value
162
- parts = value.to_s.split(' ')
163
- ["--#{name.tr('_', '-')}", *parts]
164
- elsif type == :boolean
165
- if value
166
- ["--#{name.tr('_', '-')}"]
167
- else
168
- []
169
- end
170
- else
171
- ["--#{name.tr('_', '-')}", value.to_s]
172
- end
173
- end
126
+ def clean_temp_files
127
+ return unless option_parser.hf_tempfiles.present?
174
128
 
175
- def valid_option(name)
176
- if binary_version < BINARY_VERSION_WITHOUT_DASHES
177
- "--#{name}"
178
- else
179
- name
180
- end
181
- end
182
-
183
- def make_options(options, names, prefix = '', type = :string)
184
- return [] if options.nil?
185
- names.collect do |o|
186
- if options[o].blank?
187
- []
188
- else
189
- make_option("#{prefix.blank? ? '' : prefix + '-'}#{o}",
190
- options[o],
191
- type)
192
- end
193
- end
194
- end
195
-
196
- def parse_header_footer(options)
197
- r = []
198
- [:header, :footer].collect do |hf|
199
- next if options[hf].blank?
200
- opt_hf = options[hf]
201
- r += make_options(opt_hf, [:center, :font_name, :left, :right], hf.to_s)
202
- r += make_options(opt_hf, [:font_size, :spacing], hf.to_s, :numeric)
203
- r += make_options(opt_hf, [:line], hf.to_s, :boolean)
204
- if options[hf] && options[hf][:content]
205
- @hf_tempfiles = [] unless defined?(@hf_tempfiles)
206
- @hf_tempfiles.push(tf = WickedPdfTempfile.new("wicked_#{hf}_pdf.html"))
207
- tf.write options[hf][:content]
208
- tf.flush
209
- options[hf][:html] = {}
210
- options[hf][:html][:url] = "file:///#{tf.path}"
211
- end
212
- unless opt_hf[:html].blank?
213
- r += make_option("#{hf}-html", opt_hf[:html][:url]) unless opt_hf[:html][:url].blank?
214
- end
215
- end unless options.blank?
216
- r
217
- end
218
-
219
- def parse_cover(argument)
220
- arg = argument.to_s
221
- return [] if arg.blank?
222
- # Filesystem path or URL - hand off to wkhtmltopdf
223
- if argument.is_a?(Pathname) || (arg[0, 4] == 'http')
224
- [valid_option('cover'), arg]
225
- else # HTML content
226
- @hf_tempfiles ||= []
227
- @hf_tempfiles << tf = WickedPdfTempfile.new('wicked_cover_pdf.html')
228
- tf.write arg
229
- tf.flush
230
- [valid_option('cover'), tf.path]
231
- end
232
- end
233
-
234
- def parse_toc(options)
235
- return [] if options.nil?
236
- r = [valid_option('toc')]
237
- unless options.blank?
238
- r += make_options(options, [:font_name, :header_text], 'toc')
239
- r += make_options(options, [:xsl_style_sheet])
240
- r += make_options(options, [:depth,
241
- :header_fs,
242
- :text_size_shrink,
243
- :l1_font_size,
244
- :l2_font_size,
245
- :l3_font_size,
246
- :l4_font_size,
247
- :l5_font_size,
248
- :l6_font_size,
249
- :l7_font_size,
250
- :level_indentation,
251
- :l1_indentation,
252
- :l2_indentation,
253
- :l3_indentation,
254
- :l4_indentation,
255
- :l5_indentation,
256
- :l6_indentation,
257
- :l7_indentation], 'toc', :numeric)
258
- r += make_options(options, [:no_dots,
259
- :disable_links,
260
- :disable_back_links], 'toc', :boolean)
261
- r += make_options(options, [:disable_dotted_lines,
262
- :disable_toc_links], nil, :boolean)
263
- end
264
- r
265
- end
266
-
267
- def parse_outline(options)
268
- r = []
269
- unless options.blank?
270
- r = make_options(options, [:outline], '', :boolean)
271
- r += make_options(options, [:outline_depth], '', :numeric)
272
- end
273
- r
274
- end
275
-
276
- def parse_margins(options)
277
- make_options(options, [:top, :bottom, :left, :right], 'margin', :numeric)
278
- end
279
-
280
- def parse_global(options)
281
- r = []
282
- unless options.blank?
283
- r += make_options(options, [:orientation,
284
- :dpi,
285
- :page_size,
286
- :page_width,
287
- :title])
288
- r += make_options(options, [:lowquality,
289
- :grayscale,
290
- :no_pdf_compression], '', :boolean)
291
- r += make_options(options, [:image_dpi,
292
- :image_quality,
293
- :page_height], '', :numeric)
294
- r += parse_margins(options.delete(:margin))
295
- end
296
- r
297
- end
298
-
299
- def parse_others(options)
300
- r = []
301
- unless options.blank?
302
- r += make_options(options, [:proxy,
303
- :username,
304
- :password,
305
- :encoding,
306
- :user_style_sheet,
307
- :viewport_size,
308
- :window_status])
309
- r += make_options(options, [:cookie,
310
- :post], '', :name_value)
311
- r += make_options(options, [:redirect_delay,
312
- :zoom,
313
- :page_offset,
314
- :javascript_delay], '', :numeric)
315
- r += make_options(options, [:book,
316
- :default_header,
317
- :disable_javascript,
318
- :enable_plugins,
319
- :disable_internal_links,
320
- :disable_external_links,
321
- :print_media_type,
322
- :disable_smart_shrinking,
323
- :use_xserver,
324
- :no_background,
325
- :no_stop_slow_scripts], '', :boolean)
326
- end
327
- r
328
- end
329
-
330
- def find_wkhtmltopdf_binary_path
331
- possible_locations = (ENV['PATH'].split(':') + %w(/usr/bin /usr/local/bin ~/bin)).uniq
332
- exe_path ||= WickedPdf.config[:exe_path] unless WickedPdf.config.empty?
333
- exe_path ||= begin
334
- detected_path = (defined?(Bundler) ? `bundle exec which wkhtmltopdf` : `which wkhtmltopdf`).chomp
335
- detected_path.present? && detected_path
336
- rescue
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 || ''
129
+ option_parser.hf_tempfiles.each { |file| File.delete(file) }
341
130
  end
342
131
  end
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+ timeout: 500