pdfkit 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of pdfkit might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de215391f5d6f31b3bb381eca4662d19fda9c628d582862388e5d8180b10c73e
4
- data.tar.gz: 402ec1719d3548fce4550ae150d48090951c1597b7b0ac7f8482682aadacf381
3
+ metadata.gz: 709b9d124eeb6e972d0095d078ce39be54ef3335eb57b4042cc5499a423ac3ba
4
+ data.tar.gz: 7de22b6ec750dc0f4aebe1f0c58b871cba29253a455310b9cc00b5915627ccce
5
5
  SHA512:
6
- metadata.gz: 48e4d2d1460b51560536001e7e9c7874e297b8d365ec4b3c57bf8831d0becbc8f6b381d876ca64f8ae8066084f94db50ddc1289b22f0218e396da8c918289638
7
- data.tar.gz: c785e6cde8040feb20c5d48fa94dc7e736b1d8350441c7418fc542a233b08d92031d00608f0bac47d4d230fb5bed84b4b70fe16b085bfae1c96cc6a90e92746a
6
+ metadata.gz: c76d4d622db3fa8250aa396d5782e6b04d3569da187a740fd600b757956226514c01ccee0ab4e9ffc0d1e9ee828a50efb37d92109aa7a461b0ff0de2e2cdf0e6
7
+ data.tar.gz: a09547f979b4742c9e4d2ddf898fea4ead8c86906ed89c100cbd476c1f022db46ecb3e0d7c6fa614c3f4ea5173699678d5621230706ad0ea3527ef3968b5a989
@@ -0,0 +1,19 @@
1
+ name: Release Drafter
2
+
3
+ on:
4
+ push:
5
+ # branches to consider in the event; optional, defaults to all
6
+ branches:
7
+ - master
8
+
9
+ jobs:
10
+ update_release_draft:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ # Drafts your next Release notes as Pull Requests are merged into "master"
14
+ - uses: release-drafter/release-drafter@v5
15
+ with:
16
+ # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
17
+ # config-name: my-config.yml
18
+ env:
19
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,19 @@
1
+ name: Mark stale issues and pull requests
2
+
3
+ on:
4
+ schedule:
5
+ - cron: "0 0 * * *"
6
+
7
+ jobs:
8
+ stale:
9
+
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - uses: actions/stale@v1
14
+ with:
15
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
16
+ stale-issue-message: 'This issue has been marked as stale and will be automatically closed.'
17
+ stale-pr-message: 'This pull request has been marked as stale and will be automatically closed.'
18
+ stale-issue-label: 'no-issue-activity'
19
+ stale-pr-label: 'no-pr-activity'
@@ -1 +1 @@
1
- 2.5.1
1
+ 2.6.4
@@ -1,16 +1,20 @@
1
+ language: ruby
2
+
1
3
  rvm:
2
- - 2.2
3
- - 2.3
4
- - 2.4
5
4
  - 2.5
5
+ - 2.6
6
+
7
+ env:
8
+ matrix:
9
+ - RAILS_VERSION="~> 4.1"
10
+ - RAILS_VERSION="~> 5.2"
11
+ - RAILS_VERSION="~> 6.0.0"
6
12
 
7
13
  before_install:
8
14
  - gem update --system
9
15
  - gem update bundler
10
16
 
11
17
  before_script:
12
- - "export DISPLAY=:99.0"
13
- - "sh -e /etc/init.d/xvfb start"
14
18
  - "sudo apt-get -qq -y install fontconfig libxrender1"
15
- - "wget https://downloads.wkhtmltopdf.org/0.12/0.12.5/wkhtmltox_0.12.5-1.trusty_amd64.deb"
16
- - "sudo apt-get install ./wkhtmltox_0.12.5-1.trusty_amd64.deb"
19
+ - "wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.5/wkhtmltox_0.12.5-1.xenial_amd64.deb"
20
+ - "sudo apt-get install ./wkhtmltox_0.12.5-1.xenial_amd64.deb"
@@ -1,7 +1,44 @@
1
+ 2021-01-23
2
+ =================
3
+ * Bump to 0.8.5
4
+ * Make `PDFKit::VERSION` public (#484)
5
+ * Fix to render stylesheets as html safe string on Rails 6 (#483)
6
+ * Adds support for Rails 6
7
+
8
+ 2020-08-16
9
+ =================
10
+ * Bump to 0.8.4.3.2
11
+ * Reduce scope of middleware exception handling (#476)
12
+
13
+ 2020-07-05
14
+ =================
15
+ * Bump to 0.8.4.3.1
16
+ * Don't override request level Content-Disposition header if it exists (#466)
17
+ * Update rake (#471)
18
+ * Add missing require statements for tempfile (#467)
19
+ * Only grab last line of bundle exec which output (#464)
20
+ * Return 500 status when an exception is caught in middleware (#469)
21
+ * Update Travis CI URL for wkhtmltopf (#473)
22
+
23
+ 2020-04-01
24
+ =================
25
+ * Bump to 0.8.4.2
26
+ * Improve path detection feedback (#460)
27
+ * Fix typos (#444)
28
+ * Update readme (#439)
29
+
30
+ 2019-02-22
31
+ =================
32
+ * Bump to 0.8.4.1
33
+ * Make PDFkit threadsafe (#377)
34
+ * Update activesupport (#434)
35
+
1
36
  2019-02-21
2
37
  =================
3
38
  * Bump to 0.8.4
4
39
  * Removed support for Ruby < 2.2
40
+ * Xvfb support (#277)
41
+ * Remove 'config.protocol' from the README (#389)
5
42
 
6
43
  2015-08-26
7
44
  =================
data/Gemfile CHANGED
@@ -1,7 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  group :test do
4
- gem 'activesupport', '~> 3.0'
4
+ gem 'activesupport', ENV['RAILS_VERSION'] || '~> 4.1'
5
5
  gem 'simplecov', require: false
6
6
  end
7
7
 
data/README.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  Create PDFs using plain old HTML+CSS. Uses [wkhtmltopdf](http://github.com/antialize/wkhtmltopdf) on the back-end which renders HTML using Webkit.
4
4
 
5
+ ## Supported versions
6
+
7
+ - Ruby 2.5, 2.6
8
+ - Rails 4.2, 5.2, 6.0
9
+
5
10
  ## Install
6
11
 
7
12
  ### PDFKit
@@ -14,7 +19,7 @@ gem install pdfkit
14
19
 
15
20
  <https://github.com/pdfkit/pdfkit/wiki/Installing-WKHTMLTOPDF>
16
21
 
17
- 2. Try using the `wkhtmltopdf-binary` gem (mac + linux i386)
22
+ 2. Try using the `wkhtmltopdf-binary-edge` gem (mac + linux i386)
18
23
  ```
19
24
  gem install wkhtmltopdf-binary
20
25
  ```
@@ -34,7 +39,7 @@ pdf = kit.to_pdf
34
39
  file = kit.to_file('/path/to/save/pdf')
35
40
 
36
41
  # PDFKit.new can optionally accept a URL or a File.
37
- # Stylesheets can not be added when source is provided as a URL of File.
42
+ # Stylesheets can not be added when source is provided as a URL or File.
38
43
  kit = PDFKit.new('http://google.com')
39
44
  kit = PDFKit.new(File.new('/path/to/html'))
40
45
 
@@ -116,6 +121,13 @@ config.middleware.use PDFKit::Middleware, {}, :except => [%r[^/prawn], %r[^/secr
116
121
  # conditions can be strings (either one or an array)
117
122
  config.middleware.use PDFKit::Middleware, {}, :except => ['/secret']
118
123
  ```
124
+ **With conditions to force download**
125
+ ```ruby
126
+ # force download with attachment disposition
127
+ config.middleware.use PDFKit::Middleware, {}, :disposition => 'attachment'
128
+ # conditions can force a filename
129
+ config.middleware.use PDFKit::Middleware, {}, :disposition => 'attachment; filename=report.pdf'
130
+ ```
119
131
  **Saving the generated .pdf to disk**
120
132
 
121
133
  Setting the `PDFKit-save-pdf` header will cause PDFKit to write the generated .pdf to the file indicated by the value of the header.
@@ -125,7 +137,7 @@ For example:
125
137
  headers['PDFKit-save-pdf'] = 'path/to/saved.pdf'
126
138
  ```
127
139
 
128
- Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent back to the client. If the path is not writable/non-existant the write will fail silently. The `PDFKit-save-pdf` header is never sent back to the client.
140
+ Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent back to the client. If the path is not writable/non-existent the write will fail silently. The `PDFKit-save-pdf` header is never sent back to the client.
129
141
 
130
142
  ## Troubleshooting
131
143
 
@@ -140,13 +152,13 @@ Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent
140
152
  around this issue you may want to run a server with multiple workers
141
153
  like Passenger or try to embed your resources within your HTML to
142
154
  avoid extra HTTP requests.
143
-
155
+
144
156
  Example solution (rails / bundler), add unicorn to the development
145
157
  group in your Gemfile `gem 'unicorn'` then run `bundle`. Next, add a
146
158
  file `config/unicorn.conf` with
147
-
159
+
148
160
  worker_processes 3
149
-
161
+
150
162
  Then to run the app `unicorn_rails -c config/unicorn.conf` (from rails_root)
151
163
 
152
164
  * **Resources aren't included in the PDF:** Images, CSS, or JavaScript
@@ -5,3 +5,4 @@ require 'pdfkit/html_preprocessor'
5
5
  require 'pdfkit/os'
6
6
  require 'pdfkit/configuration'
7
7
  require 'pdfkit/wkhtmltopdf'
8
+ require 'pdfkit/version'
@@ -1,7 +1,8 @@
1
1
  class PDFKit
2
2
  class Configuration
3
- attr_accessor :meta_tag_prefix, :default_options, :root_url
3
+ attr_accessor :meta_tag_prefix, :root_url
4
4
  attr_writer :use_xvfb, :verbose
5
+ attr_reader :default_options
5
6
 
6
7
  def initialize
7
8
  @verbose = false
@@ -24,14 +25,19 @@ class PDFKit
24
25
  end
25
26
 
26
27
  def default_wkhtmltopdf
27
- @default_command_path ||= (defined?(Bundler::GemfileError) && File.exists?('Gemfile') ? `bundle exec which wkhtmltopdf` : `which wkhtmltopdf`).chomp
28
+ return @default_command_path if @default_command_path
29
+ if defined?(Bundler::GemfileError) && File.exists?('Gemfile')
30
+ @default_command_path = `bundle exec which wkhtmltopdf`.chomp.lines.last
31
+ end
32
+ @default_command_path = `which wkhtmltopdf`.chomp if @default_command_path.nil? || @default_command_path.empty?
33
+ @default_command_path
28
34
  end
29
35
 
30
36
  def wkhtmltopdf=(path)
31
37
  if File.exist?(path)
32
38
  @wkhtmltopdf = path
33
39
  else
34
- warn "No executable found at #{path}. Will fall back to #{default_wkhtmltopdf}" unless File.exist?(path)
40
+ warn "No executable found at #{path}. Will fall back to #{default_wkhtmltopdf}"
35
41
  @wkhtmltopdf = default_wkhtmltopdf
36
42
  end
37
43
  end
@@ -51,6 +57,10 @@ class PDFKit
51
57
  def verbose?
52
58
  @verbose
53
59
  end
60
+
61
+ def default_options=(options)
62
+ @default_options.merge!(options)
63
+ end
54
64
  end
55
65
 
56
66
  class << self
@@ -9,40 +9,50 @@ class PDFKit
9
9
  end
10
10
 
11
11
  def call(env)
12
+ dup._call(env)
13
+ end
14
+
15
+ def _call(env)
12
16
  @request = Rack::Request.new(env)
13
17
  @render_pdf = false
14
18
 
15
19
  set_request_to_render_as_pdf(env) if render_as_pdf?
16
20
  status, headers, response = @app.call(env)
17
21
 
18
- if rendering_pdf? && headers['Content-Type'] =~ /text\/html|application\/xhtml\+xml/
19
- body = response.respond_to?(:body) ? response.body : response.join
20
- body = body.join if body.is_a?(Array)
22
+ begin
23
+ if rendering_pdf? && headers['Content-Type'] =~ /text\/html|application\/xhtml\+xml/
24
+ body = response.respond_to?(:body) ? response.body : response.join
25
+ body = body.join if body.is_a?(Array)
21
26
 
22
- root_url = root_url(env)
23
- protocol = protocol(env)
24
- options = @options.merge(root_url: root_url, protocol: protocol)
27
+ root_url = root_url(env)
28
+ protocol = protocol(env)
29
+ options = @options.merge(root_url: root_url, protocol: protocol)
25
30
 
26
- if headers['PDFKit-javascript-delay']
27
- options.merge!(javascript_delay: headers.delete('PDFKit-javascript-delay').to_i)
28
- end
31
+ if headers['PDFKit-javascript-delay']
32
+ options.merge!(javascript_delay: headers.delete('PDFKit-javascript-delay').to_i)
33
+ end
29
34
 
30
- body = PDFKit.new(body, options).to_pdf
31
- response = [body]
35
+ body = PDFKit.new(body, options).to_pdf
36
+ response = [body]
32
37
 
33
- if headers['PDFKit-save-pdf']
34
- File.open(headers['PDFKit-save-pdf'], 'wb') { |file| file.write(body) } rescue nil
35
- headers.delete('PDFKit-save-pdf')
36
- end
38
+ if headers['PDFKit-save-pdf']
39
+ File.open(headers['PDFKit-save-pdf'], 'wb') { |file| file.write(body) } rescue nil
40
+ headers.delete('PDFKit-save-pdf')
41
+ end
37
42
 
38
- unless @caching
39
- # Do not cache PDFs
40
- headers.delete('ETag')
41
- headers.delete('Cache-Control')
42
- end
43
+ unless @caching
44
+ # Do not cache PDFs
45
+ headers.delete('ETag')
46
+ headers.delete('Cache-Control')
47
+ end
43
48
 
44
- headers['Content-Length'] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
45
- headers['Content-Type'] = 'application/pdf'
49
+ headers['Content-Length'] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
50
+ headers['Content-Type'] = 'application/pdf'
51
+ headers['Content-Disposition'] ||= @conditions[:disposition] || 'inline'
52
+ end
53
+ rescue StandardError => e
54
+ status = 500
55
+ response = [e.message]
46
56
  end
47
57
 
48
58
  [status, headers, response]
@@ -1,7 +1,10 @@
1
1
  require 'shellwords'
2
+ require 'tempfile'
2
3
 
3
4
  class PDFKit
4
- class NoExecutableError < StandardError
5
+ class Error < StandardError; end
6
+
7
+ class NoExecutableError < Error
5
8
  def initialize
6
9
  msg = "No wkhtmltopdf executable found at #{PDFKit.configuration.wkhtmltopdf}\n"
7
10
  msg << ">> Please install wkhtmltopdf - https://github.com/pdfkit/PDFKit/wiki/Installing-WKHTMLTOPDF"
@@ -9,12 +12,18 @@ class PDFKit
9
12
  end
10
13
  end
11
14
 
12
- class ImproperSourceError < StandardError
15
+ class ImproperSourceError < Error
13
16
  def initialize(msg)
14
17
  super("Improper Source: #{msg}")
15
18
  end
16
19
  end
17
20
 
21
+ class ImproperWkhtmltopdfExitStatus < Error
22
+ def initialize(invoke)
23
+ super("Command failed (exitstatus=#{$?.exitstatus}): #{invoke}")
24
+ end
25
+ end
26
+
18
27
  attr_accessor :source, :stylesheets
19
28
  attr_reader :renderer
20
29
 
@@ -31,7 +40,7 @@ class PDFKit
31
40
  @renderer = WkHTMLtoPDF.new options
32
41
  @renderer.normalize_options
33
42
 
34
- raise NoExecutableError.new unless File.exists?(PDFKit.configuration.wkhtmltopdf)
43
+ raise NoExecutableError unless File.exists?(PDFKit.configuration.wkhtmltopdf)
35
44
  end
36
45
 
37
46
  def command(path = nil)
@@ -70,7 +79,7 @@ class PDFKit
70
79
 
71
80
  # $? is thread safe per
72
81
  # http://stackoverflow.com/questions/2164887/thread-safe-external-process-in-ruby-plus-checking-exitstatus
73
- raise "command failed (exitstatus=#{$?.exitstatus}): #{invoke}" if empty_result?(path, result) or !successful?($?)
82
+ raise ImproperWkhtmltopdfExitStatus, invoke if empty_result?(path, result) || !successful?($?)
74
83
  return result
75
84
  end
76
85
 
@@ -83,7 +92,7 @@ class PDFKit
83
92
 
84
93
  def find_options_in_meta(content)
85
94
  # Read file if content is a File
86
- content = content.read if content.is_a?(File)
95
+ content = content.read if content.is_a?(File) || content.is_a?(Tempfile)
87
96
 
88
97
  found = {}
89
98
  content.scan(/<meta [^>]*>/) do |meta|
@@ -105,7 +114,9 @@ class PDFKit
105
114
  end
106
115
 
107
116
  def style_tag_for(stylesheet)
108
- "<style>#{File.read(stylesheet)}</style>"
117
+ style = "<style>#{File.read(stylesheet)}</style>"
118
+ style = style.html_safe if style.respond_to?(:html_safe)
119
+ style
109
120
  end
110
121
 
111
122
  def preprocess_html
@@ -116,11 +127,13 @@ class PDFKit
116
127
  end
117
128
 
118
129
  def append_stylesheets
119
- raise ImproperSourceError.new('Stylesheets may only be added to an HTML source') if stylesheets.any? && !@source.html?
130
+ raise ImproperSourceError, 'Stylesheets may only be added to an HTML source' if stylesheets.any? && !@source.html?
120
131
 
121
132
  stylesheets.each do |stylesheet|
122
133
  if @source.to_s.match(/<\/head>/)
123
- @source = Source.new(@source.to_s.gsub(/(<\/head>)/) {|s| style_tag_for(stylesheet) + s })
134
+ @source = Source.new(@source.to_s.gsub(/(<\/head>)/) {|s|
135
+ style_tag_for(stylesheet) + (s.respond_to?(:html_safe) ? s.html_safe : s)
136
+ })
124
137
  else
125
138
  @source.to_s.insert(0, style_tag_for(stylesheet))
126
139
  end
@@ -1,3 +1,4 @@
1
+ require 'tempfile'
1
2
  require 'uri'
2
3
 
3
4
  class PDFKit
@@ -13,7 +14,7 @@ class PDFKit
13
14
  end
14
15
 
15
16
  def file?
16
- @is_file ||= @source.kind_of?(File)
17
+ @is_file ||= @source.kind_of?(File) || @source.kind_of?(Tempfile)
17
18
  end
18
19
 
19
20
  def html?
@@ -1,3 +1,3 @@
1
1
  class PDFKit
2
- VERSION = '0.8.4'
2
+ VERSION = '0.8.5'
3
3
  end
@@ -13,21 +13,20 @@ Gem::Specification.new do |s|
13
13
  s.description = "Uses wkhtmltopdf to create PDFs using HTML"
14
14
  s.license = "MIT"
15
15
 
16
- s.rubyforge_project = "pdfkit"
17
-
18
16
  s.files = `git ls-files`.split("\n")
19
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
19
  s.require_paths = ["lib"]
22
20
 
21
+ s.required_ruby_version = '>= 2.5'
22
+
23
23
  s.requirements << "wkhtmltopdf"
24
24
 
25
25
  # Development Dependencies
26
- s.add_development_dependency(%q<activesupport>, [">= 3.0.8"])
26
+ s.add_development_dependency(%q<activesupport>, [">= 4.1.11"])
27
27
  s.add_development_dependency(%q<mocha>, [">= 0.9.10"])
28
28
  s.add_development_dependency(%q<rack-test>, [">= 0.5.6"])
29
- s.add_development_dependency(%q<i18n>, ["~>0.6.11"]) # Ruby 1.9.2 compatibility
30
- s.add_development_dependency(%q<rake>, ["~>0.9.2"])
29
+ s.add_development_dependency(%q<rake>, ["~>12.3.3"])
31
30
  s.add_development_dependency(%q<rdoc>, ["~> 4.0.1"])
32
31
  s.add_development_dependency(%q<rspec>, ["~> 3.0"])
33
32
  end
@@ -3,11 +3,59 @@ require 'spec_helper'
3
3
  describe PDFKit::Configuration do
4
4
  subject { PDFKit::Configuration.new }
5
5
  describe "#wkhtmltopdf" do
6
+ context "when explicitly configured" do
7
+ it "uses configured value and don't detect" do
8
+ expect(subject).not_to receive(:default_wkhtmltopdf)
9
+ subject.wkhtmltopdf = "./Gemfile" # Need a file which exists
10
+ expect(subject.wkhtmltopdf).to eq("./Gemfile")
11
+ end
12
+
13
+ it "falls back to detected binary if configured path doesn't exists" do
14
+ expect(subject).to receive(:default_wkhtmltopdf).twice.and_return("/bin/fallback")
15
+ expect(subject).to receive(:warn).with(/No executable found/)
16
+ subject.wkhtmltopdf = "./missing-file" # Need a file which doesn't exist
17
+ expect(subject.wkhtmltopdf).to eq("/bin/fallback")
18
+ end
19
+ end
20
+
6
21
  context "when not explicitly configured" do
7
- it "detects the existance of bundler" do
8
- # Test assumes bundler is installed in your test environment
9
- expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return('c:\windows\path.exe')
10
- subject.wkhtmltopdf
22
+ context "when running inside bundler" do
23
+ # Simulate the presence of bundler even if it's not here
24
+ before { stub_const("Bundler::GemfileError", Class) }
25
+
26
+ it "detects the existance of bundler" do
27
+ expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return("c:\\windows\\path.exe\n")
28
+ expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
29
+ end
30
+
31
+ it "falls back if bundler path fails" do
32
+ # This happens when there is a wrong (buggy) version of bundler for example
33
+ expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return("")
34
+ expect(subject).to receive(:`).with('which wkhtmltopdf').and_return("c:\\windows\\path.exe\n")
35
+ expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
36
+ end
37
+
38
+ it "returns last line of 'bundle exec which' output" do
39
+ # Happens when the user does not have a HOME directory on their system and runs bundler < 2
40
+ expect(subject).to receive(:`).with('bundle exec which wkhtmltopdf').and_return(<<~EOT
41
+ `/home/myuser` is not a directory.
42
+ Bundler will use `/tmp/bundler/home/myuser' as your home directory temporarily.
43
+ /usr/bin/wkhtmltopdf
44
+ EOT
45
+ )
46
+ expect(subject.wkhtmltopdf).to eq('/usr/bin/wkhtmltopdf')
47
+ end
48
+ end
49
+
50
+ context "when running without bundler" do
51
+ # Simulate the absence of bundler even if it's there
52
+ before { hide_const("Bundler::GemfileError") }
53
+
54
+ it "detects the existance of bundler" do
55
+ expect(subject).not_to receive(:`).with('bundle exec which wkhtmltopdf')
56
+ expect(subject).to receive(:`).with('which wkhtmltopdf').and_return('c:\windows\path.exe')
57
+ expect(subject.wkhtmltopdf).to eq('c:\windows\path.exe')
58
+ end
11
59
  end
12
60
  end
13
61
  end
@@ -40,6 +88,13 @@ describe PDFKit::Configuration do
40
88
  expect(subject.default_options[:quiet]).to eql false
41
89
  expect(subject.default_options[:is_awesome]).to eql true
42
90
  end
91
+
92
+ it "merges additional options with existing defaults" do
93
+ subject.default_options = { quiet: false, is_awesome: true }
94
+ expect(subject.default_options[:quiet]).to eql false
95
+ expect(subject.default_options[:is_awesome]).to eql true
96
+ expect(subject.default_options[:disable_smart_shrinking]).to eql false
97
+ end
43
98
  end
44
99
 
45
100
  describe "#root_url" do
@@ -21,6 +21,35 @@ describe PDFKit::Middleware do
21
21
  end
22
22
 
23
23
  describe "#call" do
24
+
25
+ describe 'threadsafety' do
26
+ before { mock_app }
27
+ it 'is threadsafe' do
28
+ n = 30
29
+ extensions = Array.new(n) { rand > 0.5 ? 'html' : 'pdf' }
30
+ actual_content_types = Hash.new
31
+
32
+ threads = (0...n).map { |i|
33
+ Thread.new do
34
+ resp = get("http://www.example.org/public/test.#{extensions[i]}")
35
+ actual_content_types[i] = resp.content_type
36
+ end
37
+ }
38
+
39
+ threads.each(&:join)
40
+
41
+ extensions.each_with_index do |extension, index|
42
+ result = actual_content_types[index]
43
+ case extension
44
+ when 'html', 'txt', 'csv'
45
+ expect(result).to eq("text/#{extension}")
46
+ when 'pdf'
47
+ expect(result).to eq('application/pdf')
48
+ end
49
+ end
50
+ end
51
+ end
52
+
24
53
  describe "caching" do
25
54
  let(:headers) do
26
55
  {
@@ -312,6 +341,83 @@ describe PDFKit::Middleware do
312
341
  end
313
342
  end
314
343
  end
344
+
345
+ describe ":disposition" do
346
+ describe "doesn't overwrite existing value" do
347
+ let(:headers) do
348
+ super().merge({
349
+ 'Content-Disposition' => 'attachment; filename=report-20200101.pdf'
350
+ })
351
+ end
352
+
353
+ specify do
354
+ mock_app({}, { :disposition => 'inline' })
355
+ get 'http://www.example.org/public/test.pdf'
356
+ expect(last_response.headers["Content-Disposition"]).to eq('attachment; filename=report-20200101.pdf')
357
+ end
358
+ end
359
+
360
+ describe "inline or blank" do
361
+ context "default" do
362
+ specify do
363
+ mock_app
364
+ get 'http://www.example.org/public/test.pdf'
365
+ expect(last_response.headers["Content-Disposition"]).to eq("inline")
366
+ end
367
+ end
368
+
369
+ context "inline" do
370
+ specify do
371
+ mock_app({}, { :disposition => 'inline' })
372
+ get 'http://www.example.org/public/test.pdf'
373
+ expect(last_response.headers["Content-Disposition"]).to eq("inline")
374
+ end
375
+ end
376
+ end
377
+
378
+ describe "attachment" do
379
+ context "attachment" do
380
+ specify do
381
+ mock_app({}, { :disposition => 'attachment' })
382
+ get 'http://www.example.org/public/test.pdf'
383
+ expect(last_response.headers["Content-Disposition"]).to eq("attachment")
384
+ end
385
+ end
386
+
387
+ context "attachment with filename" do
388
+ specify do
389
+ mock_app({}, { :disposition => 'attachment; filename=report.pdf' })
390
+ get 'http://www.example.org/public/test.pdf'
391
+ expect(last_response.headers["Content-Disposition"]).to eq("attachment; filename=report.pdf")
392
+ end
393
+ end
394
+ end
395
+ end
396
+
397
+ describe "error handling" do
398
+ let(:error) { StandardError.new("Something went wrong") }
399
+
400
+ context "errors raised by PDF generation" do
401
+ specify do
402
+ mock_app
403
+ allow(PDFKit).to receive(:new).and_raise(error)
404
+ get 'http://www.example.org/public/test.pdf'
405
+ expect(last_response.status).to eq(500)
406
+ expect(last_response.body).to eq(error.message)
407
+ end
408
+ end
409
+
410
+ context "errors raised upstream" do
411
+ specify do
412
+ mock_app
413
+ allow(@app).to receive(:call).and_raise(error)
414
+
415
+ expect {
416
+ get 'http://www.example.org/public/test.pdf'
417
+ }.to raise_error(error)
418
+ end
419
+ end
420
+ end
315
421
  end
316
422
 
317
423
  describe "remove .pdf from PATH_INFO and REQUEST_URI" do
@@ -397,22 +503,4 @@ describe PDFKit::Middleware do
397
503
  end
398
504
  end
399
505
  end
400
-
401
- it "does not get stuck rendering each request as pdf" do
402
- mock_app
403
- # false by default. No requests.
404
- expect(@app.send(:rendering_pdf?)).to eq(false)
405
-
406
- # Remain false on a normal request
407
- get 'http://www.example.org/public/file'
408
- expect(@app.send(:rendering_pdf?)).to eq(false)
409
-
410
- # Return true on a pdf request.
411
- get 'http://www.example.org/public/file.pdf'
412
- expect(@app.send(:rendering_pdf?)).to eq(true)
413
-
414
- # Restore to false on any non-pdf request.
415
- get 'http://www.example.org/public/file'
416
- expect(@app.send(:rendering_pdf?)).to eq(false)
417
- end
418
506
  end
@@ -23,6 +23,13 @@ describe PDFKit do
23
23
  expect(pdfkit.source.to_s).to eq(file_path)
24
24
  end
25
25
 
26
+ it "accepts a Tempfile as the source" do
27
+ file_path = File.join(SPEC_ROOT,'fixtures','example.html')
28
+ pdfkit = PDFKit.new(Tempfile.new(file_path))
29
+ expect(pdfkit.source).to be_file
30
+ expect(pdfkit.source.to_s).to match /^#{Dir.tmpdir}/
31
+ end
32
+
26
33
  # Options
27
34
  ## options keys
28
35
  it "drops options without values" do
@@ -252,6 +259,12 @@ describe PDFKit do
252
259
  expect(pdfkit.command).to match /#{file_path} -$/
253
260
  end
254
261
 
262
+ it "specifies the path to the source if it is a tempfile" do
263
+ file_path = File.join(SPEC_ROOT,'fixtures','example.html')
264
+ pdfkit = PDFKit.new(Tempfile.new(file_path))
265
+ expect(pdfkit.command).to match /#{Dir.tmpdir}\S+ -$/
266
+ end
267
+
255
268
  it "specifies the path for the ouput if a path is given" do
256
269
  file_path = "/path/to/output.pdf"
257
270
  pdfkit = PDFKit.new("html")
@@ -488,6 +501,14 @@ describe PDFKit do
488
501
  expect(pdfkit.source.to_s).to include("<style>#{File.read(css)}</style></head>")
489
502
  end
490
503
 
504
+ it "can deal with ActiveSupport::SafeBuffer if the HTML doesn't have a head tag" do
505
+ pdfkit = PDFKit.new(ActiveSupport::SafeBuffer.new "<html><body>Hai!</body></html>")
506
+ css = File.join(SPEC_ROOT,'fixtures','example.css')
507
+ pdfkit.stylesheets << css
508
+ pdfkit.to_pdf
509
+ expect(pdfkit.source.to_s).to include("<style>#{File.read(css)}</style>")
510
+ end
511
+
491
512
  it "escapes \\X in stylesheets" do
492
513
  pdfkit = PDFKit.new("<html><head></head><body>Hai!</body></html>")
493
514
  css = File.join(SPEC_ROOT,'fixtures','example_with_hex_symbol.css')
@@ -499,7 +520,7 @@ describe PDFKit do
499
520
  #NOTICE: This test is failed if use wkhtmltopdf-binary (0.9.9.1)
500
521
  it "throws an error if it is unable to connect" do
501
522
  pdfkit = PDFKit.new("http://google.com/this-should-not-be-found/404.html")
502
- expect { pdfkit.to_pdf }.to raise_error /exitstatus=1/
523
+ expect { pdfkit.to_pdf }.to raise_error PDFKit::ImproperWkhtmltopdfExitStatus, /exitstatus=1/
503
524
  end
504
525
 
505
526
  it "does not throw an error if it is unable to connect", pending: 'this test works for wkhtmltopdf-binary (0.9.9.1)' do
@@ -12,6 +12,11 @@ describe PDFKit::Source do
12
12
  expect(source).not_to be_url
13
13
  end
14
14
 
15
+ it "returns false if passed a tempfile" do
16
+ source = PDFKit::Source.new(::Tempfile.new(__FILE__))
17
+ expect(source).not_to be_url
18
+ end
19
+
15
20
  it "returns false if passed HTML" do
16
21
  source = PDFKit::Source.new('<blink>Oh Hai!</blink>')
17
22
  expect(source).not_to be_url
@@ -29,6 +34,11 @@ describe PDFKit::Source do
29
34
  expect(source).to be_file
30
35
  end
31
36
 
37
+ it "returns true if passed a tempfile" do
38
+ source = PDFKit::Source.new(::Tempfile.new(__FILE__))
39
+ expect(source).to be_file
40
+ end
41
+
32
42
  it "returns false if passed a url like string" do
33
43
  source = PDFKit::Source.new('http://google.com')
34
44
  expect(source).not_to be_file
@@ -51,6 +61,11 @@ describe PDFKit::Source do
51
61
  expect(source).not_to be_html
52
62
  end
53
63
 
64
+ it "returns false if passed a tempfile" do
65
+ source = PDFKit::Source.new(::Tempfile.new(__FILE__))
66
+ expect(source).not_to be_html
67
+ end
68
+
54
69
  it "returns false if passed a url like string" do
55
70
  source = PDFKit::Source.new('http://google.com')
56
71
  expect(source).not_to be_html
@@ -77,6 +92,11 @@ describe PDFKit::Source do
77
92
  source = PDFKit::Source.new(::File.new(__FILE__))
78
93
  expect(source.to_input_for_command).to match 'spec/source_spec.rb'
79
94
  end
95
+
96
+ it "returns the file path for tempfile sources" do
97
+ source = PDFKit::Source.new(file = ::Tempfile.new(__FILE__))
98
+ expect(source.to_input_for_command).to match file.path
99
+ end
80
100
  end
81
101
 
82
102
  describe "#to_s" do
@@ -90,6 +110,11 @@ describe PDFKit::Source do
90
110
  expect(source.to_s).to eq(__FILE__)
91
111
  end
92
112
 
113
+ it "returns a path if passed a tempfile" do
114
+ source = PDFKit::Source.new(file = ::Tempfile.new(__FILE__))
115
+ expect(source.to_s).to eq(file.path)
116
+ end
117
+
93
118
  it "returns the url if passed a url like string" do
94
119
  source = PDFKit::Source.new('http://google.com')
95
120
  expect(source.to_s).to eq('http://google.com')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pdfkit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.4
4
+ version: 0.8.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jared Pace
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-02-22 00:00:00.000000000 Z
12
+ date: 2021-01-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -17,14 +17,14 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: 3.0.8
20
+ version: 4.1.11
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: 3.0.8
27
+ version: 4.1.11
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: mocha
30
30
  requirement: !ruby/object:Gem::Requirement
@@ -53,34 +53,20 @@ dependencies:
53
53
  - - ">="
54
54
  - !ruby/object:Gem::Version
55
55
  version: 0.5.6
56
- - !ruby/object:Gem::Dependency
57
- name: i18n
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - "~>"
61
- - !ruby/object:Gem::Version
62
- version: 0.6.11
63
- type: :development
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - "~>"
68
- - !ruby/object:Gem::Version
69
- version: 0.6.11
70
56
  - !ruby/object:Gem::Dependency
71
57
  name: rake
72
58
  requirement: !ruby/object:Gem::Requirement
73
59
  requirements:
74
60
  - - "~>"
75
61
  - !ruby/object:Gem::Version
76
- version: 0.9.2
62
+ version: 12.3.3
77
63
  type: :development
78
64
  prerelease: false
79
65
  version_requirements: !ruby/object:Gem::Requirement
80
66
  requirements:
81
67
  - - "~>"
82
68
  - !ruby/object:Gem::Version
83
- version: 0.9.2
69
+ version: 12.3.3
84
70
  - !ruby/object:Gem::Dependency
85
71
  name: rdoc
86
72
  requirement: !ruby/object:Gem::Requirement
@@ -117,6 +103,8 @@ extensions: []
117
103
  extra_rdoc_files: []
118
104
  files:
119
105
  - ".document"
106
+ - ".github/workflows/release-drafter.yml"
107
+ - ".github/workflows/stale.yml"
120
108
  - ".gitignore"
121
109
  - ".rspec"
122
110
  - ".ruby-gemset"
@@ -160,7 +148,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
160
148
  requirements:
161
149
  - - ">="
162
150
  - !ruby/object:Gem::Version
163
- version: '0'
151
+ version: '2.5'
164
152
  required_rubygems_version: !ruby/object:Gem::Requirement
165
153
  requirements:
166
154
  - - ">="
@@ -168,8 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
168
156
  version: '0'
169
157
  requirements:
170
158
  - wkhtmltopdf
171
- rubyforge_project: pdfkit
172
- rubygems_version: 2.7.6
159
+ rubygems_version: 3.0.3
173
160
  signing_key:
174
161
  specification_version: 4
175
162
  summary: HTML+CSS -> PDF