pdfkit 0.8.2 → 0.8.3
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 +5 -5
- data/.ruby-version +1 -1
- data/.travis.yml +4 -0
- data/README.md +19 -4
- data/lib/pdfkit.rb +3 -0
- data/lib/pdfkit/configuration.rb +15 -2
- data/lib/pdfkit/html_preprocessor.rb +23 -0
- data/lib/pdfkit/middleware.rb +25 -28
- data/lib/pdfkit/os.rb +19 -0
- data/lib/pdfkit/pdfkit.rb +25 -95
- data/lib/pdfkit/version.rb +1 -1
- data/lib/pdfkit/wkhtmltopdf.rb +80 -0
- data/pdfkit.gemspec +4 -1
- data/spec/configuration_spec.rb +0 -11
- data/spec/html_preprocessor_spec.rb +69 -0
- data/spec/middleware_spec.rb +73 -53
- data/spec/os_spec.rb +65 -0
- data/spec/pdfkit_spec.rb +1 -1
- metadata +36 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bed642993a544476d0b9ed06d2b6dcdb6bcac722eee1c3decbc0a6c0d307668d
|
4
|
+
data.tar.gz: 4ad6010df3d11509774cee9d74477c463258db0e4a845e77243d42ad1d517353
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7dd8eee00c8793c11011056b7cc4f4ae83f487972aabddd3a55f14341d75b2263baf09501202ace3921417d50bc902be616fd75268bc0c395fcab0a071b041c4
|
7
|
+
data.tar.gz: 4b0ecd0f3ca2ba8ad8b5eb7beca56a1c15ba72902664dfe602daeb8e3fb8bf880496e77566d5bfe0d1159b5690599001fd6c4523a95aa2c3b73aa39abbdc9c50
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.5.1
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -43,8 +43,22 @@ PDFKit.new('<html><head><meta name="pdfkit-page_size" content="Letter"')
|
|
43
43
|
PDFKit.new('<html><head><meta name="pdfkit-cookie cookie_name1" content="cookie_value1"')
|
44
44
|
PDFKit.new('<html><head><meta name="pdfkit-cookie cookie_name2" content="cookie_value2"')
|
45
45
|
```
|
46
|
+
|
47
|
+
### Resolving relative URLs and protocols
|
48
|
+
|
49
|
+
If the source HTML has relative URLs (`/images/cat.png`) or
|
50
|
+
[protocols](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#prurl)
|
51
|
+
(`//example.com/site.css`) that need to be resolved, you can pass `:root_url`
|
52
|
+
and `:protocol` options to PDFKit:
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
PDFKit.new(html, root_url: 'http://mysite.com/').to_file
|
56
|
+
# or:
|
57
|
+
PDFKit.new(html, protocol: 'https').to_file
|
58
|
+
```
|
59
|
+
|
46
60
|
### Using cookies in scraping
|
47
|
-
If you want to pass a cookie to cookie to pdfkit to scrape a website, you can
|
61
|
+
If you want to pass a cookie to cookie to pdfkit to scrape a website, you can
|
48
62
|
pass it in a hash:
|
49
63
|
```ruby
|
50
64
|
kit = PDFKit.new(url, cookie: {cookie_name: :cookie_value})
|
@@ -62,6 +76,7 @@ PDFKit.configure do |config|
|
|
62
76
|
}
|
63
77
|
# Use only if your external hostname is unavailable on the server.
|
64
78
|
config.root_url = "http://localhost"
|
79
|
+
config.protocol = 'http'
|
65
80
|
config.verbose = false
|
66
81
|
end
|
67
82
|
```
|
@@ -127,8 +142,8 @@ Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent
|
|
127
142
|
like Passenger or try to embed your resources within your HTML to
|
128
143
|
avoid extra HTTP requests.
|
129
144
|
|
130
|
-
Example solution (rails / bundler), add unicorn to the development
|
131
|
-
group in your Gemfile `gem 'unicorn'` then run `bundle`. Next, add a
|
145
|
+
Example solution (rails / bundler), add unicorn to the development
|
146
|
+
group in your Gemfile `gem 'unicorn'` then run `bundle`. Next, add a
|
132
147
|
file `config/unicorn.conf` with
|
133
148
|
|
134
149
|
worker_processes 3
|
@@ -146,7 +161,7 @@ Will cause the .pdf to be saved to `path/to/saved.pdf` in addition to being sent
|
|
146
161
|
asset host.
|
147
162
|
|
148
163
|
* **Mangled output in the browser:** Be sure that your HTTP response
|
149
|
-
headers specify "Content-Type: application/pdf"
|
164
|
+
headers specify "Content-Type: application/pdf"
|
150
165
|
|
151
166
|
## Note on Patches/Pull Requests
|
152
167
|
|
data/lib/pdfkit.rb
CHANGED
data/lib/pdfkit/configuration.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class PDFKit
|
2
2
|
class Configuration
|
3
3
|
attr_accessor :meta_tag_prefix, :default_options, :root_url
|
4
|
-
attr_writer :
|
4
|
+
attr_writer :verbose
|
5
5
|
|
6
6
|
def initialize
|
7
7
|
@verbose = false
|
@@ -19,7 +19,20 @@ class PDFKit
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def wkhtmltopdf
|
22
|
-
@wkhtmltopdf ||=
|
22
|
+
@wkhtmltopdf ||= default_wkhtmltopdf
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_wkhtmltopdf
|
26
|
+
@default_command_path ||= (defined?(Bundler::GemfileError) && File.exists?('Gemfile') ? `bundle exec which wkhtmltopdf` : `which wkhtmltopdf`).chomp
|
27
|
+
end
|
28
|
+
|
29
|
+
def wkhtmltopdf=(path)
|
30
|
+
if File.exist?(path)
|
31
|
+
@wkhtmltopdf = path
|
32
|
+
else
|
33
|
+
warn "No executable found at #{path}. Will fall back to #{default_wkhtmltopdf}" unless File.exist?(path)
|
34
|
+
@wkhtmltopdf = default_wkhtmltopdf
|
35
|
+
end
|
23
36
|
end
|
24
37
|
|
25
38
|
def quiet?
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class PDFKit
|
2
|
+
module HTMLPreprocessor
|
3
|
+
|
4
|
+
# Change relative paths to absolute, and relative protocols to absolute protocols
|
5
|
+
def self.process(html, root_url, protocol)
|
6
|
+
html = translate_relative_paths(html, root_url) if root_url
|
7
|
+
html = translate_relative_protocols(html, protocol) if protocol
|
8
|
+
html
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def self.translate_relative_paths(html, root_url)
|
14
|
+
# Try out this regexp using rubular http://rubular.com/r/hiAxBNX7KE
|
15
|
+
html.gsub(/(href|src)=(['"])\/([^\/"']([^\"']*|[^"']*))?['"]/, "\\1=\\2#{root_url}\\3\\2")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.translate_relative_protocols(body, protocol)
|
19
|
+
# Try out this regexp using rubular http://rubular.com/r/0Ohk0wFYxV
|
20
|
+
body.gsub(/(href|src)=(['"])\/\/([^\"']*|[^"']*)['"]/, "\\1=\\2#{protocol}://\\3\\2")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/pdfkit/middleware.rb
CHANGED
@@ -18,7 +18,16 @@ class PDFKit
|
|
18
18
|
if rendering_pdf? && headers['Content-Type'] =~ /text\/html|application\/xhtml\+xml/
|
19
19
|
body = response.respond_to?(:body) ? response.body : response.join
|
20
20
|
body = body.join if body.is_a?(Array)
|
21
|
-
|
21
|
+
|
22
|
+
root_url = root_url(env)
|
23
|
+
protocol = protocol(env)
|
24
|
+
options = @options.merge(root_url: root_url, protocol: protocol)
|
25
|
+
|
26
|
+
if headers['PDFKit-javascript-delay']
|
27
|
+
options.merge!(javascript_delay: headers.delete('PDFKit-javascript-delay').to_i)
|
28
|
+
end
|
29
|
+
|
30
|
+
body = PDFKit.new(body, options).to_pdf
|
22
31
|
response = [body]
|
23
32
|
|
24
33
|
if headers['PDFKit-save-pdf']
|
@@ -32,8 +41,8 @@ class PDFKit
|
|
32
41
|
headers.delete('Cache-Control')
|
33
42
|
end
|
34
43
|
|
35
|
-
headers['Content-Length']
|
36
|
-
headers['Content-Type']
|
44
|
+
headers['Content-Length'] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
|
45
|
+
headers['Content-Type'] = 'application/pdf'
|
37
46
|
end
|
38
47
|
|
39
48
|
[status, headers, response]
|
@@ -41,22 +50,12 @@ class PDFKit
|
|
41
50
|
|
42
51
|
private
|
43
52
|
|
44
|
-
|
45
|
-
|
46
|
-
body = translate_relative_paths(body, env)
|
47
|
-
translate_relative_protocols(body, env)
|
53
|
+
def root_url(env)
|
54
|
+
PDFKit.configuration.root_url || "#{env['rack.url_scheme']}://#{env['HTTP_HOST']}/"
|
48
55
|
end
|
49
56
|
|
50
|
-
def
|
51
|
-
|
52
|
-
# Try out this regexp using rubular http://rubular.com/r/hiAxBNX7KE
|
53
|
-
body.gsub(/(href|src)=(['"])\/([^\/"']([^\"']*|[^"']*))?['"]/, "\\1=\\2#{root}\\3\\2")
|
54
|
-
end
|
55
|
-
|
56
|
-
def translate_relative_protocols(body, env)
|
57
|
-
protocol = "#{env['rack.url_scheme']}://"
|
58
|
-
# Try out this regexp using rubular http://rubular.com/r/0Ohk0wFYxV
|
59
|
-
body.gsub(/(href|src)=(['"])\/\/([^\"']*|[^"']*)['"]/, "\\1=\\2#{protocol}\\3\\2")
|
57
|
+
def protocol(env)
|
58
|
+
env['rack.url_scheme']
|
60
59
|
end
|
61
60
|
|
62
61
|
def rendering_pdf?
|
@@ -65,20 +64,18 @@ class PDFKit
|
|
65
64
|
|
66
65
|
def render_as_pdf?
|
67
66
|
request_path = @request.path
|
68
|
-
|
67
|
+
return false unless request_path.end_with?('.pdf')
|
69
68
|
|
70
|
-
if
|
69
|
+
if @conditions[:only]
|
71
70
|
conditions_as_regexp(@conditions[:only]).any? do |pattern|
|
72
|
-
|
71
|
+
pattern === request_path
|
73
72
|
end
|
74
|
-
elsif
|
75
|
-
conditions_as_regexp(@conditions[:except]).
|
76
|
-
|
73
|
+
elsif @conditions[:except]
|
74
|
+
conditions_as_regexp(@conditions[:except]).none? do |pattern|
|
75
|
+
pattern === request_path
|
77
76
|
end
|
78
|
-
|
79
|
-
return true
|
80
77
|
else
|
81
|
-
|
78
|
+
true
|
82
79
|
end
|
83
80
|
end
|
84
81
|
|
@@ -99,8 +96,8 @@ class PDFKit
|
|
99
96
|
end
|
100
97
|
|
101
98
|
def conditions_as_regexp(conditions)
|
102
|
-
|
103
|
-
pattern.is_a?(Regexp) ? pattern : Regexp.new(
|
99
|
+
Array(conditions).map do |pattern|
|
100
|
+
pattern.is_a?(Regexp) ? pattern : Regexp.new("^#{pattern}")
|
104
101
|
end
|
105
102
|
end
|
106
103
|
end
|
data/lib/pdfkit/os.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
class PDFKit
|
4
|
+
module OS
|
5
|
+
def self.host_is_windows?
|
6
|
+
!(RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince/).nil?
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.shell_escape_for_os(args)
|
10
|
+
if (host_is_windows?)
|
11
|
+
# Windows reserved shell characters are: & | ( ) < > ^
|
12
|
+
# See http://technet.microsoft.com/en-us/library/cc723564.aspx#XSLTsection123121120120
|
13
|
+
args.map { |arg| arg.gsub(/([&|()<>^])/,'^\1') }.join(" ")
|
14
|
+
else
|
15
|
+
args.shelljoin
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/pdfkit/pdfkit.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'shellwords'
|
2
|
-
require 'rbconfig'
|
3
2
|
|
4
3
|
class PDFKit
|
5
4
|
class NoExecutableError < StandardError
|
@@ -17,24 +16,27 @@ class PDFKit
|
|
17
16
|
end
|
18
17
|
|
19
18
|
attr_accessor :source, :stylesheets
|
20
|
-
attr_reader :
|
19
|
+
attr_reader :renderer
|
21
20
|
|
22
21
|
def initialize(url_file_or_html, options = {})
|
23
22
|
@source = Source.new(url_file_or_html)
|
24
23
|
|
25
24
|
@stylesheets = []
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
@
|
26
|
+
options = PDFKit.configuration.default_options.merge(options)
|
27
|
+
options.delete(:quiet) if PDFKit.configuration.verbose?
|
28
|
+
options.merge! find_options_in_meta(url_file_or_html) unless source.url?
|
29
|
+
@root_url = options.delete(:root_url)
|
30
|
+
@protocol = options.delete(:protocol)
|
31
|
+
@renderer = WkHTMLtoPDF.new options
|
32
|
+
@renderer.normalize_options
|
31
33
|
|
32
34
|
raise NoExecutableError.new unless File.exists?(PDFKit.configuration.wkhtmltopdf)
|
33
35
|
end
|
34
36
|
|
35
37
|
def command(path = nil)
|
36
|
-
args = @
|
37
|
-
shell_escaped_command = [executable, shell_escape_for_os(args)].join ' '
|
38
|
+
args = @renderer.options_for_command
|
39
|
+
shell_escaped_command = [executable, OS::shell_escape_for_os(args)].join ' '
|
38
40
|
|
39
41
|
# In order to allow for URL parameters (e.g. https://www.google.com/search?q=pdfkit) we do
|
40
42
|
# not escape the source. The user is responsible for ensuring that no vulnerabilities exist
|
@@ -45,17 +47,17 @@ class PDFKit
|
|
45
47
|
"#{shell_escaped_command} #{input_for_command} #{output_for_command}"
|
46
48
|
end
|
47
49
|
|
50
|
+
def options
|
51
|
+
# TODO(cdwort,sigmavirus24): Replace this with an attr_reader for @renderer instead in 1.0.0
|
52
|
+
@renderer.options
|
53
|
+
end
|
54
|
+
|
48
55
|
def executable
|
49
|
-
|
50
|
-
return default if default !~ /^\// # its not a path, so nothing we can do
|
51
|
-
if File.exist?(default)
|
52
|
-
default
|
53
|
-
else
|
54
|
-
default.split('/').last
|
55
|
-
end
|
56
|
+
PDFKit.configuration.wkhtmltopdf
|
56
57
|
end
|
57
58
|
|
58
59
|
def to_pdf(path=nil)
|
60
|
+
preprocess_html
|
59
61
|
append_stylesheets
|
60
62
|
|
61
63
|
invoke = command(path)
|
@@ -79,11 +81,6 @@ class PDFKit
|
|
79
81
|
|
80
82
|
protected
|
81
83
|
|
82
|
-
# Pulled from:
|
83
|
-
# https://github.com/wkhtmltopdf/wkhtmltopdf/blob/ebf9b6cfc4c58a31349fb94c568b254fac37b3d3/README_WKHTMLTOIMAGE#L27
|
84
|
-
REPEATABLE_OPTIONS = %w[--allow --cookie --custom-header --post --post-file --run-script]
|
85
|
-
SPECIAL_OPTIONS = %w[cover toc]
|
86
|
-
|
87
84
|
def find_options_in_meta(content)
|
88
85
|
# Read file if content is a File
|
89
86
|
content = content.read if content.is_a?(File)
|
@@ -111,6 +108,13 @@ class PDFKit
|
|
111
108
|
"<style>#{File.read(stylesheet)}</style>"
|
112
109
|
end
|
113
110
|
|
111
|
+
def preprocess_html
|
112
|
+
if @source.html?
|
113
|
+
processed_html = PDFKit::HTMLPreprocessor.process(@source.to_s, @root_url, @protocol)
|
114
|
+
@source = Source.new(processed_html)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
114
118
|
def append_stylesheets
|
115
119
|
raise ImproperSourceError.new('Stylesheets may only be added to an HTML source') if stylesheets.any? && !@source.html?
|
116
120
|
|
@@ -123,65 +127,12 @@ class PDFKit
|
|
123
127
|
end
|
124
128
|
end
|
125
129
|
|
126
|
-
def normalize_options(options)
|
127
|
-
normalized_options = {}
|
128
|
-
|
129
|
-
options.each do |key, value|
|
130
|
-
next if !value
|
131
|
-
|
132
|
-
# The actual option for wkhtmltopdf
|
133
|
-
normalized_key = normalize_arg key
|
134
|
-
normalized_key = "--#{normalized_key}" unless SPECIAL_OPTIONS.include?(normalized_key)
|
135
|
-
|
136
|
-
# If the option is repeatable, attempt to normalize all values
|
137
|
-
if REPEATABLE_OPTIONS.include? normalized_key
|
138
|
-
normalize_repeatable_value(normalized_key, value) do |normalized_unique_key, normalized_value|
|
139
|
-
normalized_options[normalized_unique_key] = normalized_value
|
140
|
-
end
|
141
|
-
else # Otherwise, just normalize it like usual
|
142
|
-
normalized_options[normalized_key] = normalize_value(value)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
normalized_options
|
147
|
-
end
|
148
|
-
|
149
|
-
def normalize_arg(arg)
|
150
|
-
arg.to_s.downcase.gsub(/[^a-z0-9]/,'-')
|
151
|
-
end
|
152
|
-
|
153
|
-
def normalize_value(value)
|
154
|
-
case value
|
155
|
-
when nil
|
156
|
-
nil
|
157
|
-
when TrueClass, 'true' #ie, ==true, see http://www.ruby-doc.org/core-1.9.3/TrueClass.html
|
158
|
-
nil
|
159
|
-
when Hash
|
160
|
-
value.to_a.flatten.collect{|x| normalize_value(x)}.compact
|
161
|
-
when Array
|
162
|
-
value.flatten.collect{|x| x.to_s}
|
163
|
-
else
|
164
|
-
(host_is_windows? && value.to_s.index(' ')) ? "'#{ value.to_s }'" : value.to_s
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def normalize_repeatable_value(option_name, value)
|
169
|
-
case value
|
170
|
-
when Hash, Array
|
171
|
-
value.each do |(key, val)|
|
172
|
-
yield [[option_name, normalize_value(key)], normalize_value(val)]
|
173
|
-
end
|
174
|
-
else
|
175
|
-
yield [[option_name, normalize_value(value)], nil]
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
130
|
def successful?(status)
|
180
131
|
return true if status.success?
|
181
132
|
|
182
133
|
# Some of the codes: https://code.google.com/p/wkhtmltopdf/issues/detail?id=1088
|
183
134
|
# returned when assets are missing (404): https://code.google.com/p/wkhtmltopdf/issues/detail?id=548
|
184
|
-
return true if status.exitstatus == 2 && error_handling?
|
135
|
+
return true if status.exitstatus == 2 && @renderer.error_handling?
|
185
136
|
|
186
137
|
false
|
187
138
|
end
|
@@ -189,25 +140,4 @@ class PDFKit
|
|
189
140
|
def empty_result?(path, result)
|
190
141
|
(path && File.size(path) == 0) || (path.nil? && result.to_s.strip.empty?)
|
191
142
|
end
|
192
|
-
|
193
|
-
def error_handling?
|
194
|
-
@options.key?('--ignore-load-errors') ||
|
195
|
-
# wkhtmltopdf v0.10.0 beta4 replaces ignore-load-errors with load-error-handling
|
196
|
-
# https://code.google.com/p/wkhtmltopdf/issues/detail?id=55
|
197
|
-
%w(skip ignore).include?(@options['--load-error-handling'])
|
198
|
-
end
|
199
|
-
|
200
|
-
def host_is_windows?
|
201
|
-
@host_is_windows ||= !(RbConfig::CONFIG['host_os'] =~ /mswin|msys|mingw|cygwin|bccwin|wince/).nil?
|
202
|
-
end
|
203
|
-
|
204
|
-
def shell_escape_for_os(args)
|
205
|
-
if (host_is_windows?)
|
206
|
-
# Windows reserved shell characters are: & | ( ) < > ^
|
207
|
-
# See http://technet.microsoft.com/en-us/library/cc723564.aspx#XSLTsection123121120120
|
208
|
-
args.map { |arg| arg.gsub(/([&|()<>^])/,'^\1') }.join(" ")
|
209
|
-
else
|
210
|
-
args.shelljoin
|
211
|
-
end
|
212
|
-
end
|
213
143
|
end
|
data/lib/pdfkit/version.rb
CHANGED
@@ -0,0 +1,80 @@
|
|
1
|
+
class PDFKit
|
2
|
+
class WkHTMLtoPDF
|
3
|
+
attr_reader :options
|
4
|
+
# Pulled from:
|
5
|
+
# https://github.com/wkhtmltopdf/wkhtmltopdf/blob/ebf9b6cfc4c58a31349fb94c568b254fac37b3d3/README_WKHTMLTOIMAGE#L27
|
6
|
+
REPEATABLE_OPTIONS = %w[--allow --cookie --custom-header --post --post-file --run-script]
|
7
|
+
SPECIAL_OPTIONS = %w[cover toc]
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def normalize_options
|
14
|
+
# TODO(cdwort,sigmavirus24): Make this method idempotent in a future release so it can be called repeatedly
|
15
|
+
normalized_options = {}
|
16
|
+
|
17
|
+
@options.each do |key, value|
|
18
|
+
next if !value
|
19
|
+
|
20
|
+
# The actual option for wkhtmltopdf
|
21
|
+
normalized_key = normalize_arg key
|
22
|
+
normalized_key = "--#{normalized_key}" unless SPECIAL_OPTIONS.include?(normalized_key)
|
23
|
+
|
24
|
+
# If the option is repeatable, attempt to normalize all values
|
25
|
+
if REPEATABLE_OPTIONS.include? normalized_key
|
26
|
+
normalize_repeatable_value(normalized_key, value) do |normalized_unique_key, normalized_value|
|
27
|
+
normalized_options[normalized_unique_key] = normalized_value
|
28
|
+
end
|
29
|
+
else # Otherwise, just normalize it like usual
|
30
|
+
normalized_options[normalized_key] = normalize_value(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
@options = normalized_options
|
35
|
+
end
|
36
|
+
|
37
|
+
def error_handling?
|
38
|
+
@options.key?('--ignore-load-errors') ||
|
39
|
+
# wkhtmltopdf v0.10.0 beta4 replaces ignore-load-errors with load-error-handling
|
40
|
+
# https://code.google.com/p/wkhtmltopdf/issues/detail?id=55
|
41
|
+
%w(skip ignore).include?(@options['--load-error-handling'])
|
42
|
+
end
|
43
|
+
|
44
|
+
def options_for_command
|
45
|
+
@options.to_a.flatten.compact
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def normalize_arg(arg)
|
51
|
+
arg.to_s.downcase.gsub(/[^a-z0-9]/,'-')
|
52
|
+
end
|
53
|
+
|
54
|
+
def normalize_value(value)
|
55
|
+
case value
|
56
|
+
when nil
|
57
|
+
nil
|
58
|
+
when TrueClass, 'true' #ie, ==true, see http://www.ruby-doc.org/core-1.9.3/TrueClass.html
|
59
|
+
nil
|
60
|
+
when Hash
|
61
|
+
value.to_a.flatten.collect{|x| normalize_value(x)}.compact
|
62
|
+
when Array
|
63
|
+
value.flatten.collect{|x| x.to_s}
|
64
|
+
else
|
65
|
+
(OS::host_is_windows? && value.to_s.index(' ')) ? "'#{ value.to_s }'" : value.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def normalize_repeatable_value(option_name, value)
|
70
|
+
case value
|
71
|
+
when Hash, Array
|
72
|
+
value.each do |(key, val)|
|
73
|
+
yield [[option_name, normalize_value(key)], normalize_value(val)]
|
74
|
+
end
|
75
|
+
else
|
76
|
+
yield [[option_name, normalize_value(value)], nil]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/pdfkit.gemspec
CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.homepage = "https://github.com/pdfkit/pdfkit"
|
12
12
|
s.summary = "HTML+CSS -> PDF"
|
13
13
|
s.description = "Uses wkhtmltopdf to create PDFs using HTML"
|
14
|
+
s.license = "MIT"
|
14
15
|
|
15
16
|
s.rubyforge_project = "pdfkit"
|
16
17
|
|
@@ -19,7 +20,9 @@ Gem::Specification.new do |s|
|
|
19
20
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
21
|
s.require_paths = ["lib"]
|
21
22
|
|
22
|
-
|
23
|
+
s.requirements << "wkhtmltopdf"
|
24
|
+
|
25
|
+
# Development Dependencies
|
23
26
|
s.add_development_dependency(%q<activesupport>, [">= 3.0.8"])
|
24
27
|
s.add_development_dependency(%q<mocha>, [">= 0.9.10"])
|
25
28
|
s.add_development_dependency(%q<rack-test>, [">= 0.5.6"])
|
data/spec/configuration_spec.rb
CHANGED
@@ -3,17 +3,6 @@ require 'spec_helper'
|
|
3
3
|
describe PDFKit::Configuration do
|
4
4
|
subject { PDFKit::Configuration.new }
|
5
5
|
describe "#wkhtmltopdf" do
|
6
|
-
it "can be configured" do
|
7
|
-
subject.wkhtmltopdf = '/my/bin/wkhtmltopdf'
|
8
|
-
expect(subject.wkhtmltopdf).to eql '/my/bin/wkhtmltopdf'
|
9
|
-
end
|
10
|
-
|
11
|
-
# This test documents existing functionality. Feel free to fix.
|
12
|
-
it "can be poorly configured" do
|
13
|
-
subject.wkhtmltopdf = 1234
|
14
|
-
expect(subject.wkhtmltopdf).to eql 1234
|
15
|
-
end
|
16
|
-
|
17
6
|
context "when not explicitly configured" do
|
18
7
|
it "detects the existance of bundler" do
|
19
8
|
# Test assumes bundler is installed in your test environment
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PDFKit::HTMLPreprocessor do
|
4
|
+
describe "#process" do
|
5
|
+
let(:preprocessor) { PDFKit::HTMLPreprocessor }
|
6
|
+
let(:root_url) { 'http://example.com/' } # This mirrors Middleware#root_url's response
|
7
|
+
let(:protocol) { 'http' }
|
8
|
+
|
9
|
+
it "correctly parses host-relative url with single quotes" do
|
10
|
+
original_body = %{<html><head><link href='/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="/test.png" /></body></html>}
|
11
|
+
body = preprocessor.process original_body, root_url, protocol
|
12
|
+
expect(body).to eq("<html><head><link href='http://example.com/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src=\"http://example.com/test.png\" /></body></html>")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "correctly parses host-relative url with double quotes" do
|
16
|
+
original_body = %{<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />}
|
17
|
+
body = preprocessor.process original_body, root_url, protocol
|
18
|
+
expect(body).to eq("<link href=\"http://example.com/stylesheets/application.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "correctly parses protocol-relative url with single quotes" do
|
22
|
+
original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>}
|
23
|
+
body = preprocessor.process original_body, root_url, protocol
|
24
|
+
expect(body).to eq("<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "correctly parses protocol-relative url with double quotes" do
|
28
|
+
original_body = %{<link href="//fonts.googleapis.com/css?family=Open+Sans:400,600" rel='stylesheet' type='text/css'>}
|
29
|
+
body = preprocessor.process original_body, root_url, protocol
|
30
|
+
expect(body).to eq("<link href=\"http://fonts.googleapis.com/css?family=Open+Sans:400,600\" rel='stylesheet' type='text/css'>")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "correctly parses multiple tags where first one is root url" do
|
34
|
+
original_body = %{<a href='/'><img src='/logo.jpg' ></a>}
|
35
|
+
body = preprocessor.process original_body, root_url, protocol
|
36
|
+
expect(body).to eq "<a href='http://example.com/'><img src='http://example.com/logo.jpg' ></a>"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns the body even if there are no valid substitutions found" do
|
40
|
+
original_body = "NO MATCH"
|
41
|
+
body = preprocessor.process original_body, root_url, protocol
|
42
|
+
expect(body).to eq("NO MATCH")
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when root_url is nil' do
|
46
|
+
it "returns the body safely, without interpolating" do
|
47
|
+
original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
|
48
|
+
body = preprocessor.process original_body, nil, protocol
|
49
|
+
expect(body).to eq(%{<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>})
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when protocol is nil' do
|
54
|
+
it "returns the body safely, without interpolating" do
|
55
|
+
original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
|
56
|
+
body = preprocessor.process original_body, root_url, nil
|
57
|
+
expect(body).to eq(%{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='http://example.com/'><img src='http://example.com/logo.jpg'></a>})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when root_url and protocol are both nil' do
|
62
|
+
it "returns the body safely, without interpolating" do
|
63
|
+
original_body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'><a href='/'><img src='/logo.jpg'></a>}
|
64
|
+
body = preprocessor.process original_body, nil, nil
|
65
|
+
expect(body).to eq original_body
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/spec/middleware_spec.rb
CHANGED
@@ -236,22 +236,22 @@ describe PDFKit::Middleware do
|
|
236
236
|
end
|
237
237
|
|
238
238
|
describe "saving generated pdf to disk" do
|
239
|
-
|
239
|
+
before do
|
240
240
|
#make sure tests don't find an old test_save.pdf
|
241
241
|
File.delete('spec/test_save.pdf') if File.exists?('spec/test_save.pdf')
|
242
242
|
expect(File.exists?('spec/test_save.pdf')).to eq(false)
|
243
|
-
|
243
|
+
end
|
244
244
|
|
245
245
|
context "when header PDFKit-save-pdf is present" do
|
246
246
|
it "saves the .pdf to disk" do
|
247
|
-
|
247
|
+
headers = { 'PDFKit-save-pdf' => 'spec/test_save.pdf' }
|
248
248
|
mock_app({}, {only: '/public'}, headers)
|
249
|
-
|
249
|
+
get 'http://www.example.org/public/test_save.pdf'
|
250
250
|
expect(File.exists?('spec/test_save.pdf')).to eq(true)
|
251
|
-
|
251
|
+
end
|
252
252
|
|
253
253
|
it "does not raise when target directory does not exist" do
|
254
|
-
|
254
|
+
headers = { 'PDFKit-save-pdf' => '/this/dir/does/not/exist/spec/test_save.pdf' }
|
255
255
|
mock_app({}, {only: '/public'}, headers)
|
256
256
|
expect {
|
257
257
|
get 'http://www.example.com/public/test_save.pdf'
|
@@ -262,15 +262,60 @@ describe PDFKit::Middleware do
|
|
262
262
|
context "when header PDFKit-save-pdf is not present" do
|
263
263
|
it "does not saved the .pdf to disk" do
|
264
264
|
mock_app({}, {only: '/public'}, {} )
|
265
|
-
|
265
|
+
get 'http://www.example.org/public/test_save.pdf'
|
266
266
|
expect(File.exists?('spec/test_save.pdf')).to eq(false)
|
267
267
|
end
|
268
268
|
end
|
269
269
|
end
|
270
|
+
|
271
|
+
describe 'javascript delay' do
|
272
|
+
context 'when header PDFKit-javascript-delay is present' do
|
273
|
+
it 'passes header value through to PDFKit initialiser' do
|
274
|
+
expect(PDFKit).to receive(:new).with('Hello world!', {
|
275
|
+
root_url: 'http://www.example.com/', protocol: 'http', javascript_delay: 4321
|
276
|
+
}).and_call_original
|
277
|
+
|
278
|
+
headers = { 'PDFKit-javascript-delay' => '4321' }
|
279
|
+
mock_app({}, { only: '/public' }, headers)
|
280
|
+
get 'http://www.example.com/public/test_save.pdf'
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'handles invalid content in header' do
|
284
|
+
expect(PDFKit).to receive(:new).with('Hello world!', {
|
285
|
+
root_url: 'http://www.example.com/', protocol: 'http', javascript_delay: 0
|
286
|
+
}).and_call_original
|
287
|
+
|
288
|
+
headers = { 'PDFKit-javascript-delay' => 'invalid' }
|
289
|
+
mock_app({}, { only: '/public' }, headers)
|
290
|
+
get 'http://www.example.com/public/test_save.pdf'
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'overrides default option' do
|
294
|
+
expect(PDFKit).to receive(:new).with('Hello world!', {
|
295
|
+
root_url: 'http://www.example.com/', protocol: 'http', javascript_delay: 4321
|
296
|
+
}).and_call_original
|
297
|
+
|
298
|
+
headers = { 'PDFKit-javascript-delay' => '4321' }
|
299
|
+
mock_app({ javascript_delay: 1234 }, { only: '/public' }, headers)
|
300
|
+
get 'http://www.example.com/public/test_save.pdf'
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'when header PDFKit-javascript-delay is not present' do
|
305
|
+
it 'passes through default option' do
|
306
|
+
expect(PDFKit).to receive(:new).with('Hello world!', {
|
307
|
+
root_url: 'http://www.example.com/', protocol: 'http', javascript_delay: 1234
|
308
|
+
}).and_call_original
|
309
|
+
|
310
|
+
mock_app({ javascript_delay: 1234 }, { only: '/public' }, { })
|
311
|
+
get 'http://www.example.com/public/test_save.pdf'
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
270
315
|
end
|
271
316
|
|
272
|
-
|
273
|
-
|
317
|
+
describe "remove .pdf from PATH_INFO and REQUEST_URI" do
|
318
|
+
before { mock_app }
|
274
319
|
|
275
320
|
context "matching" do
|
276
321
|
|
@@ -319,61 +364,36 @@ describe PDFKit::Middleware do
|
|
319
364
|
end
|
320
365
|
end
|
321
366
|
|
322
|
-
describe "#
|
367
|
+
describe "#root_url and #protocol" do
|
323
368
|
before do
|
324
369
|
@pdf = PDFKit::Middleware.new({})
|
325
370
|
@env = { 'REQUEST_URI' => 'http://example.com/document.pdf', 'rack.url_scheme' => 'http', 'HTTP_HOST' => 'example.com' }
|
326
371
|
end
|
327
372
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
end
|
333
|
-
|
334
|
-
it "correctly parses relative url with double quotes" do
|
335
|
-
@body = %{<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />}
|
336
|
-
body = @pdf.send :translate_paths, @body, @env
|
337
|
-
expect(body).to eq("<link href=\"http://example.com/stylesheets/application.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />")
|
338
|
-
end
|
339
|
-
|
340
|
-
it "correctly parses relative url with double quotes" do
|
341
|
-
@body = %{<link href='//fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>}
|
342
|
-
body = @pdf.send :translate_paths, @body, @env
|
343
|
-
expect(body).to eq("<link href='http://fonts.googleapis.com/css?family=Open+Sans:400,600' rel='stylesheet' type='text/css'>")
|
344
|
-
end
|
345
|
-
|
346
|
-
it "correctly parses multiple tags where first one is root url" do
|
347
|
-
@body = %{<a href='/'><img src='/logo.jpg' ></a>}
|
348
|
-
body = @pdf.send :translate_paths, @body, @env
|
349
|
-
expect(body).to eq "<a href='http://example.com/'><img src='http://example.com/logo.jpg' ></a>"
|
350
|
-
end
|
373
|
+
context 'when root_url is not configured' do
|
374
|
+
it "infers the root_url and protocol from the environment" do
|
375
|
+
root_url = @pdf.send(:root_url, @env)
|
376
|
+
protocol = @pdf.send(:protocol, @env)
|
351
377
|
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
expect(body).to eq("NO MATCH")
|
378
|
+
expect(root_url).to eq('http://example.com/')
|
379
|
+
expect(protocol).to eq('http')
|
380
|
+
end
|
356
381
|
end
|
357
|
-
end
|
358
382
|
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
383
|
+
context 'when root_url is configured' do
|
384
|
+
before do
|
385
|
+
PDFKit.configuration.root_url = 'http://example.net/'
|
386
|
+
end
|
387
|
+
after do
|
388
|
+
PDFKit.configuration.root_url = nil
|
365
389
|
end
|
366
|
-
end
|
367
390
|
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
expect(body).to eq("<html><head><link href='http://example.net/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src=\"http://example.net/test.png\" /></body></html>")
|
372
|
-
end
|
391
|
+
it "takes the root_url from the configuration, and infers the protocol from the environment" do
|
392
|
+
root_url = @pdf.send(:root_url, @env)
|
393
|
+
protocol = @pdf.send(:protocol, @env)
|
373
394
|
|
374
|
-
|
375
|
-
|
376
|
-
config.root_url = nil
|
395
|
+
expect(root_url).to eq('http://example.net/')
|
396
|
+
expect(protocol).to eq('http')
|
377
397
|
end
|
378
398
|
end
|
379
399
|
end
|
data/spec/os_spec.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'rbconfig'
|
4
|
+
|
5
|
+
describe 'OS' do
|
6
|
+
subject { PDFKit::OS }
|
7
|
+
|
8
|
+
describe 'host_is_windows?' do
|
9
|
+
it 'is callable' do
|
10
|
+
expect(subject).to respond_to(:host_is_windows?)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_is_windows(bool, host_os)
|
14
|
+
allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return(host_os)
|
15
|
+
|
16
|
+
expect(subject.host_is_windows?).to be bool
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'returns true if the host_os is set to "mswin"' do
|
20
|
+
test_is_windows(true, 'mswin')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns true if the host_os is set to "msys"' do
|
24
|
+
test_is_windows(true, 'msys')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns false if the host_os is set to "linux-gnu"' do
|
28
|
+
test_is_windows(false, 'linux-gnu')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns false if the host_os is set to "darwin14.1.0"' do
|
32
|
+
test_is_windows(false, 'darwin14.1.0')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'shell_escape_for_os' do
|
37
|
+
it 'is callable' do
|
38
|
+
expect(subject).to respond_to(:shell_escape_for_os)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'calls shelljoin on linux' do
|
42
|
+
args = double(:shelljoin)
|
43
|
+
allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return('linux-gnu')
|
44
|
+
|
45
|
+
expect(args).to receive(:shelljoin)
|
46
|
+
PDFKit::OS.shell_escape_for_os(args)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'calls shelljoin on darwin14.1.10' do
|
50
|
+
args = double(:shelljoin)
|
51
|
+
allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return('darwin14.1.10-gnu')
|
52
|
+
|
53
|
+
expect(args).to receive(:shelljoin)
|
54
|
+
PDFKit::OS.shell_escape_for_os(args)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'escapes special characters on Windows' do
|
58
|
+
args = ['foo|bar', 'biz(baz)', 'foo<baz>bar', 'hello^world&goodbye']
|
59
|
+
allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return('mswin')
|
60
|
+
|
61
|
+
escaped_args = PDFKit::OS.shell_escape_for_os(args)
|
62
|
+
expect(escaped_args).to eq('foo^|bar biz^(baz^) foo^<baz^>bar hello^^world^&goodbye')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/spec/pdfkit_spec.rb
CHANGED
@@ -386,7 +386,7 @@ describe PDFKit do
|
|
386
386
|
|
387
387
|
context "on windows" do
|
388
388
|
before do
|
389
|
-
|
389
|
+
allow(PDFKit::OS).to receive(:host_is_windows?).and_return(true)
|
390
390
|
end
|
391
391
|
|
392
392
|
it "escapes special windows characters" do
|
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
|
+
version: 0.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jared Pace
|
@@ -9,104 +9,104 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-02-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: 3.0.8
|
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
27
|
version: 3.0.8
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: mocha
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: 0.9.10
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: 0.9.10
|
42
42
|
- !ruby/object:Gem::Dependency
|
43
43
|
name: rack-test
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- -
|
46
|
+
- - ">="
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: 0.5.6
|
49
49
|
type: :development
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- -
|
53
|
+
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: 0.5.6
|
56
56
|
- !ruby/object:Gem::Dependency
|
57
57
|
name: i18n
|
58
58
|
requirement: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
|
-
- - ~>
|
60
|
+
- - "~>"
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: 0.6.11
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
|
-
- - ~>
|
67
|
+
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: 0.6.11
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: rake
|
72
72
|
requirement: !ruby/object:Gem::Requirement
|
73
73
|
requirements:
|
74
|
-
- - ~>
|
74
|
+
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
76
|
version: 0.9.2
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
|
-
- - ~>
|
81
|
+
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: 0.9.2
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: rdoc
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- - ~>
|
88
|
+
- - "~>"
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: 4.0.1
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
93
|
version_requirements: !ruby/object:Gem::Requirement
|
94
94
|
requirements:
|
95
|
-
- - ~>
|
95
|
+
- - "~>"
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: 4.0.1
|
98
98
|
- !ruby/object:Gem::Dependency
|
99
99
|
name: rspec
|
100
100
|
requirement: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
|
-
- - ~>
|
102
|
+
- - "~>"
|
103
103
|
- !ruby/object:Gem::Version
|
104
104
|
version: '3.0'
|
105
105
|
type: :development
|
106
106
|
prerelease: false
|
107
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
108
|
requirements:
|
109
|
-
- - ~>
|
109
|
+
- - "~>"
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '3.0'
|
112
112
|
description: Uses wkhtmltopdf to create PDFs using HTML
|
@@ -116,12 +116,12 @@ executables: []
|
|
116
116
|
extensions: []
|
117
117
|
extra_rdoc_files: []
|
118
118
|
files:
|
119
|
-
- .document
|
120
|
-
- .gitignore
|
121
|
-
- .rspec
|
122
|
-
- .ruby-gemset
|
123
|
-
- .ruby-version
|
124
|
-
- .travis.yml
|
119
|
+
- ".document"
|
120
|
+
- ".gitignore"
|
121
|
+
- ".rspec"
|
122
|
+
- ".ruby-gemset"
|
123
|
+
- ".ruby-version"
|
124
|
+
- ".travis.yml"
|
125
125
|
- CHANGELOG.md
|
126
126
|
- Gemfile
|
127
127
|
- LICENSE
|
@@ -130,21 +130,27 @@ files:
|
|
130
130
|
- Rakefile
|
131
131
|
- lib/pdfkit.rb
|
132
132
|
- lib/pdfkit/configuration.rb
|
133
|
+
- lib/pdfkit/html_preprocessor.rb
|
133
134
|
- lib/pdfkit/middleware.rb
|
135
|
+
- lib/pdfkit/os.rb
|
134
136
|
- lib/pdfkit/pdfkit.rb
|
135
137
|
- lib/pdfkit/source.rb
|
136
138
|
- lib/pdfkit/version.rb
|
139
|
+
- lib/pdfkit/wkhtmltopdf.rb
|
137
140
|
- pdfkit.gemspec
|
138
141
|
- spec/configuration_spec.rb
|
139
142
|
- spec/fixtures/example.css
|
140
143
|
- spec/fixtures/example.html
|
141
144
|
- spec/fixtures/example_with_hex_symbol.css
|
145
|
+
- spec/html_preprocessor_spec.rb
|
142
146
|
- spec/middleware_spec.rb
|
147
|
+
- spec/os_spec.rb
|
143
148
|
- spec/pdfkit_spec.rb
|
144
149
|
- spec/source_spec.rb
|
145
150
|
- spec/spec_helper.rb
|
146
151
|
homepage: https://github.com/pdfkit/pdfkit
|
147
|
-
licenses:
|
152
|
+
licenses:
|
153
|
+
- MIT
|
148
154
|
metadata: {}
|
149
155
|
post_install_message:
|
150
156
|
rdoc_options: []
|
@@ -152,17 +158,18 @@ require_paths:
|
|
152
158
|
- lib
|
153
159
|
required_ruby_version: !ruby/object:Gem::Requirement
|
154
160
|
requirements:
|
155
|
-
- -
|
161
|
+
- - ">="
|
156
162
|
- !ruby/object:Gem::Version
|
157
163
|
version: '0'
|
158
164
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
165
|
requirements:
|
160
|
-
- -
|
166
|
+
- - ">="
|
161
167
|
- !ruby/object:Gem::Version
|
162
168
|
version: '0'
|
163
|
-
requirements:
|
169
|
+
requirements:
|
170
|
+
- wkhtmltopdf
|
164
171
|
rubyforge_project: pdfkit
|
165
|
-
rubygems_version: 2.
|
172
|
+
rubygems_version: 2.7.6
|
166
173
|
signing_key:
|
167
174
|
specification_version: 4
|
168
175
|
summary: HTML+CSS -> PDF
|
@@ -171,7 +178,9 @@ test_files:
|
|
171
178
|
- spec/fixtures/example.css
|
172
179
|
- spec/fixtures/example.html
|
173
180
|
- spec/fixtures/example_with_hex_symbol.css
|
181
|
+
- spec/html_preprocessor_spec.rb
|
174
182
|
- spec/middleware_spec.rb
|
183
|
+
- spec/os_spec.rb
|
175
184
|
- spec/pdfkit_spec.rb
|
176
185
|
- spec/source_spec.rb
|
177
186
|
- spec/spec_helper.rb
|