wicked_pdf 1.1.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/issue_template.md +15 -0
- data/.rubocop.yml +11 -0
- data/.rubocop_todo.yml +160 -30
- data/.travis.yml +56 -34
- data/CHANGELOG.md +115 -40
- data/README.md +93 -19
- data/Rakefile +14 -4
- data/gemfiles/4.0.gemfile +1 -0
- data/gemfiles/4.1.gemfile +1 -0
- data/gemfiles/4.2.gemfile +3 -0
- data/gemfiles/5.0.gemfile +2 -0
- data/gemfiles/5.1.gemfile +8 -0
- data/gemfiles/5.2.gemfile +10 -0
- data/gemfiles/6.0.gemfile +11 -0
- data/gemfiles/rails_edge.gemfile +5 -2
- data/generators/wicked_pdf/templates/wicked_pdf.rb +6 -0
- data/lib/generators/wicked_pdf_generator.rb +5 -9
- data/lib/wicked_pdf.rb +62 -48
- data/lib/wicked_pdf/middleware.rb +1 -1
- data/lib/wicked_pdf/pdf_helper.rb +29 -21
- data/lib/wicked_pdf/progress.rb +33 -0
- data/lib/wicked_pdf/railtie.rb +9 -38
- data/lib/wicked_pdf/version.rb +1 -1
- data/lib/wicked_pdf/wicked_pdf_helper.rb +2 -1
- data/lib/wicked_pdf/wicked_pdf_helper/assets.rb +73 -7
- data/test/fixtures/database.yml +4 -0
- data/test/fixtures/manifest.js +3 -0
- data/test/functional/pdf_helper_test.rb +71 -0
- data/test/test_helper.rb +11 -8
- data/test/unit/wicked_pdf_test.rb +22 -3
- data/test/unit/wkhtmltopdf_location_test.rb +50 -0
- data/wicked_pdf.gemspec +20 -12
- metadata +53 -28
- data/gemfiles/2.3.gemfile +0 -10
- data/gemfiles/3.0.gemfile +0 -12
- data/gemfiles/3.1.gemfile +0 -13
- data/gemfiles/3.2.gemfile +0 -12
@@ -80,7 +80,7 @@ class WickedPdf
|
|
80
80
|
|
81
81
|
def set_request_to_render_as_pdf(env)
|
82
82
|
@render_pdf = true
|
83
|
-
%w
|
83
|
+
%w[PATH_INFO REQUEST_URI].each { |e| env[e] = env[e].sub(%r{\.pdf\b}, '') }
|
84
84
|
env['HTTP_ACCEPT'] = concat(env['HTTP_ACCEPT'], Rack::Mime.mime_type('.html'))
|
85
85
|
env['Rack-Middleware-WickedPdf'] = 'true'
|
86
86
|
end
|
@@ -8,7 +8,11 @@ class WickedPdf
|
|
8
8
|
base.class_eval do
|
9
9
|
alias_method_chain :render, :wicked_pdf
|
10
10
|
alias_method_chain :render_to_string, :wicked_pdf
|
11
|
-
|
11
|
+
if respond_to?(:after_action)
|
12
|
+
after_action :clean_temp_files
|
13
|
+
else
|
14
|
+
after_filter :clean_temp_files
|
15
|
+
end
|
12
16
|
end
|
13
17
|
end
|
14
18
|
|
@@ -19,47 +23,46 @@ class WickedPdf
|
|
19
23
|
|
20
24
|
base.class_eval do
|
21
25
|
after_action :clean_temp_files
|
26
|
+
end
|
27
|
+
end
|
22
28
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def render(options = nil, *args, &block)
|
27
|
-
render_with_wicked_pdf(options, *args, &block)
|
28
|
-
end
|
29
|
+
def render(options = nil, *args, &block)
|
30
|
+
render_with_wicked_pdf(options, *args, &block)
|
31
|
+
end
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
33
|
+
def render_to_string(options = nil, *args, &block)
|
34
|
+
render_to_string_with_wicked_pdf(options, *args, &block)
|
34
35
|
end
|
35
36
|
|
36
37
|
def render_with_wicked_pdf(options = nil, *args, &block)
|
37
38
|
if options.is_a?(Hash) && options.key?(:pdf)
|
38
|
-
log_pdf_creation
|
39
39
|
options[:basic_auth] = set_basic_auth(options)
|
40
40
|
make_and_send_pdf(options.delete(:pdf), (WickedPdf.config || {}).merge(options))
|
41
|
-
|
41
|
+
elsif respond_to?(:render_without_wicked_pdf)
|
42
|
+
# support alias_method_chain (module included)
|
42
43
|
render_without_wicked_pdf(options, *args, &block)
|
44
|
+
else
|
45
|
+
# support inheritance (module prepended)
|
46
|
+
method(:render).super_method.call(options, *args, &block)
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
46
50
|
def render_to_string_with_wicked_pdf(options = nil, *args, &block)
|
47
51
|
if options.is_a?(Hash) && options.key?(:pdf)
|
48
|
-
log_pdf_creation
|
49
52
|
options[:basic_auth] = set_basic_auth(options)
|
50
53
|
options.delete :pdf
|
51
54
|
make_pdf((WickedPdf.config || {}).merge(options))
|
52
|
-
|
55
|
+
elsif respond_to?(:render_to_string_without_wicked_pdf)
|
56
|
+
# support alias_method_chain (module included)
|
53
57
|
render_to_string_without_wicked_pdf(options, *args, &block)
|
58
|
+
else
|
59
|
+
# support inheritance (module prepended)
|
60
|
+
method(:render_to_string).super_method.call(options, *args, &block)
|
54
61
|
end
|
55
62
|
end
|
56
63
|
|
57
64
|
private
|
58
65
|
|
59
|
-
def log_pdf_creation
|
60
|
-
logger.info '*' * 15 + 'WICKED' + '*' * 15 if logger && logger.respond_to?(:info)
|
61
|
-
end
|
62
|
-
|
63
66
|
def set_basic_auth(options = {})
|
64
67
|
options[:basic_auth] ||= WickedPdf.config.fetch(:basic_auth) { false }
|
65
68
|
return unless options[:basic_auth] && request.env['HTTP_AUTHORIZATION']
|
@@ -76,8 +79,10 @@ class WickedPdf
|
|
76
79
|
:template => options[:template],
|
77
80
|
:layout => options[:layout],
|
78
81
|
:formats => options[:formats],
|
79
|
-
:handlers => options[:handlers]
|
82
|
+
:handlers => options[:handlers],
|
83
|
+
:assigns => options[:assigns]
|
80
84
|
}
|
85
|
+
render_opts[:inline] = options[:inline] if options[:inline]
|
81
86
|
render_opts[:locals] = options[:locals] if options[:locals]
|
82
87
|
render_opts[:file] = options[:file] if options[:file]
|
83
88
|
html_string = render_to_string(render_opts)
|
@@ -97,8 +102,10 @@ class WickedPdf
|
|
97
102
|
:layout => options[:layout],
|
98
103
|
:formats => options[:formats],
|
99
104
|
:handlers => options[:handlers],
|
105
|
+
:assigns => options[:assigns],
|
100
106
|
:content_type => 'text/html'
|
101
107
|
}
|
108
|
+
render_opts[:inline] = options[:inline] if options[:inline]
|
102
109
|
render_opts[:locals] = options[:locals] if options[:locals]
|
103
110
|
render_opts[:file] = options[:file] if options[:file]
|
104
111
|
render(render_opts)
|
@@ -121,7 +128,8 @@ class WickedPdf
|
|
121
128
|
:template => options[hf][:html][:template],
|
122
129
|
:layout => options[hf][:html][:layout],
|
123
130
|
:formats => options[hf][:html][:formats],
|
124
|
-
:handlers => options[hf][:html][:handlers]
|
131
|
+
:handlers => options[hf][:html][:handlers],
|
132
|
+
:assigns => options[hf][:html][:assigns]
|
125
133
|
}
|
126
134
|
render_opts[:locals] = options[hf][:html][:locals] if options[hf][:html][:locals]
|
127
135
|
render_opts[:file] = options[hf][:html][:file] if options[:file]
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class WickedPdf
|
2
|
+
module Progress
|
3
|
+
require 'pty' if RbConfig::CONFIG['target_os'] !~ /mswin|mingw/ # no support for windows
|
4
|
+
require 'English'
|
5
|
+
|
6
|
+
def track_progress?(options)
|
7
|
+
options[:progress] && !on_windows?
|
8
|
+
end
|
9
|
+
|
10
|
+
def invoke_with_progress(command, options)
|
11
|
+
output = []
|
12
|
+
begin
|
13
|
+
PTY.spawn(command.join(' ')) do |stdout, _stdin, pid|
|
14
|
+
begin
|
15
|
+
stdout.sync
|
16
|
+
stdout.each_line("\r") do |line|
|
17
|
+
output << line.chomp
|
18
|
+
options[:progress].call(line) if options[:progress]
|
19
|
+
end
|
20
|
+
rescue Errno::EIO # rubocop:disable Lint/HandleExceptions
|
21
|
+
# child process is terminated, this is expected behaviour
|
22
|
+
ensure
|
23
|
+
::Process.wait pid
|
24
|
+
end
|
25
|
+
end
|
26
|
+
rescue PTY::ChildExited
|
27
|
+
puts 'The child process exited!'
|
28
|
+
end
|
29
|
+
err = output.join('\n')
|
30
|
+
raise "#{command} failed (exitstatus 0). Output was: #{err}" unless $CHILD_STATUS && $CHILD_STATUS.exitstatus.zero?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/wicked_pdf/railtie.rb
CHANGED
@@ -3,48 +3,19 @@ require 'wicked_pdf/wicked_pdf_helper'
|
|
3
3
|
require 'wicked_pdf/wicked_pdf_helper/assets'
|
4
4
|
|
5
5
|
class WickedPdf
|
6
|
-
if defined?(Rails)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
ActionView::Base.send :include, WickedPdfHelper::Assets
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
elsif Rails::VERSION::MAJOR == 4
|
18
|
-
|
19
|
-
class WickedRailtie < Rails::Railtie
|
20
|
-
initializer 'wicked_pdf.register' do |_app|
|
21
|
-
ActionController::Base.send :include, PdfHelper
|
22
|
-
ActionView::Base.send :include, WickedPdfHelper::Assets
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
elsif Rails::VERSION::MAJOR == 3
|
27
|
-
|
28
|
-
class WickedRailtie < Rails::Railtie
|
29
|
-
initializer 'wicked_pdf.register' do |_app|
|
30
|
-
ActionController::Base.send :include, PdfHelper
|
31
|
-
if Rails::VERSION::MINOR > 0 && Rails.configuration.assets.enabled
|
32
|
-
ActionView::Base.send :include, WickedPdfHelper::Assets
|
6
|
+
if defined?(Rails.env)
|
7
|
+
class WickedRailtie < Rails::Railtie
|
8
|
+
initializer 'wicked_pdf.register', :after => 'remotipart.controller_helper' do |_app|
|
9
|
+
ActiveSupport.on_load(:action_controller) do
|
10
|
+
if ActionController::Base.respond_to?(:prepend) &&
|
11
|
+
Object.method(:new).respond_to?(:super_method)
|
12
|
+
ActionController::Base.send :prepend, PdfHelper
|
33
13
|
else
|
34
|
-
|
14
|
+
ActionController::Base.send :include, PdfHelper
|
35
15
|
end
|
16
|
+
ActionView::Base.send :include, WickedPdfHelper::Assets
|
36
17
|
end
|
37
18
|
end
|
38
|
-
|
39
|
-
elsif Rails::VERSION::MAJOR == 2
|
40
|
-
|
41
|
-
unless ActionController::Base.instance_methods.include? 'render_with_wicked_pdf'
|
42
|
-
ActionController::Base.send :include, PdfHelper
|
43
|
-
end
|
44
|
-
unless ActionView::Base.instance_methods.include? 'wicked_pdf_stylesheet_link_tag'
|
45
|
-
ActionView::Base.send :include, WickedPdfHelper
|
46
|
-
end
|
47
|
-
|
48
19
|
end
|
49
20
|
|
50
21
|
if Mime::Type.lookup_by_extension(:pdf).nil?
|
data/lib/wicked_pdf/version.rb
CHANGED
@@ -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' =>
|
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)
|
@@ -1,4 +1,6 @@
|
|
1
|
-
require '
|
1
|
+
require 'net/http'
|
2
|
+
# If webpacker is used, need to check for version
|
3
|
+
require 'webpacker/version' if defined?(Webpacker)
|
2
4
|
|
3
5
|
class WickedPdf
|
4
6
|
module WickedPdfHelper
|
@@ -27,6 +29,32 @@ class WickedPdf
|
|
27
29
|
end.html_safe
|
28
30
|
end
|
29
31
|
|
32
|
+
def wicked_pdf_stylesheet_pack_tag(*sources)
|
33
|
+
return unless defined?(Webpacker)
|
34
|
+
if running_in_development?
|
35
|
+
stylesheet_pack_tag(*sources)
|
36
|
+
else
|
37
|
+
css_text = sources.collect do |source|
|
38
|
+
source = WickedPdfHelper.add_extension(source, 'css')
|
39
|
+
wicked_pdf_stylesheet_link_tag(webpacker_source_url(source))
|
40
|
+
end.join("\n")
|
41
|
+
css_text.respond_to?(:html_safe) ? css_text.html_safe : css_text
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def wicked_pdf_javascript_pack_tag(*sources)
|
46
|
+
return unless defined?(Webpacker)
|
47
|
+
|
48
|
+
if running_in_development?
|
49
|
+
javascript_pack_tag(*sources)
|
50
|
+
else
|
51
|
+
sources.collect do |source|
|
52
|
+
source = WickedPdfHelper.add_extension(source, 'js')
|
53
|
+
"<script type='text/javascript'>#{read_asset(webpacker_source_url(source))}</script>"
|
54
|
+
end.join("\n").html_safe
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
30
58
|
def wicked_pdf_image_tag(img, options = {})
|
31
59
|
image_tag wicked_pdf_asset_path(img), options
|
32
60
|
end
|
@@ -51,6 +79,16 @@ class WickedPdf
|
|
51
79
|
end
|
52
80
|
end
|
53
81
|
|
82
|
+
def wicked_pdf_asset_pack_path(asset)
|
83
|
+
return unless defined?(Webpacker)
|
84
|
+
|
85
|
+
if running_in_development?
|
86
|
+
asset_pack_path(asset)
|
87
|
+
else
|
88
|
+
wicked_pdf_asset_path webpacker_source_url(asset)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
54
92
|
private
|
55
93
|
|
56
94
|
# borrowed from actionpack/lib/action_view/helpers/asset_url_helper.rb
|
@@ -68,15 +106,20 @@ class WickedPdf
|
|
68
106
|
end
|
69
107
|
else
|
70
108
|
asset = find_asset(source)
|
71
|
-
|
109
|
+
if asset
|
110
|
+
# older versions need pathname, Sprockets 4 supports only filename
|
111
|
+
asset.respond_to?(:filename) ? asset.filename : asset.pathname
|
112
|
+
else
|
113
|
+
File.join(Rails.public_path, source)
|
114
|
+
end
|
72
115
|
end
|
73
116
|
end
|
74
117
|
|
75
118
|
def find_asset(path)
|
76
119
|
if Rails.application.assets.respond_to?(:find_asset)
|
77
|
-
Rails.application.assets.find_asset(path)
|
120
|
+
Rails.application.assets.find_asset(path, :base_path => Rails.application.root.to_s)
|
78
121
|
else
|
79
|
-
Sprockets::Railtie.build_environment(Rails.application).find_asset(path)
|
122
|
+
Sprockets::Railtie.build_environment(Rails.application).find_asset(path, :base_path => Rails.application.root.to_s)
|
80
123
|
end
|
81
124
|
end
|
82
125
|
|
@@ -93,7 +136,8 @@ class WickedPdf
|
|
93
136
|
end
|
94
137
|
|
95
138
|
def precompiled_or_absolute_asset?(source)
|
96
|
-
Rails.configuration.assets
|
139
|
+
!Rails.configuration.respond_to?(:assets) ||
|
140
|
+
Rails.configuration.assets.compile == false ||
|
97
141
|
source.to_s[0] == '/' ||
|
98
142
|
source.to_s.match(/\Ahttps?\:\/\//)
|
99
143
|
end
|
@@ -112,8 +156,8 @@ class WickedPdf
|
|
112
156
|
end
|
113
157
|
|
114
158
|
def read_from_uri(uri)
|
115
|
-
|
116
|
-
asset
|
159
|
+
asset = Net::HTTP.get(URI(uri))
|
160
|
+
asset.force_encoding('UTF-8') if asset
|
117
161
|
asset = gzip(asset) if WickedPdf.config[:expect_gzipped_remote_assets]
|
118
162
|
asset
|
119
163
|
end
|
@@ -125,6 +169,28 @@ class WickedPdf
|
|
125
169
|
rescue Zlib::GzipFile::Error
|
126
170
|
nil
|
127
171
|
end
|
172
|
+
|
173
|
+
def webpacker_source_url(source)
|
174
|
+
return unless defined?(Webpacker) && defined?(Webpacker::VERSION)
|
175
|
+
# In Webpacker 3.2.0 asset_pack_url is introduced
|
176
|
+
if Webpacker::VERSION >= '3.2.0'
|
177
|
+
asset_pack_url(source)
|
178
|
+
else
|
179
|
+
source_path = asset_pack_path(source)
|
180
|
+
# Remove last slash from root path
|
181
|
+
root_url[0...-1] + source_path
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def running_in_development?
|
186
|
+
return unless defined?(Webpacker)
|
187
|
+
# :dev_server method was added in webpacker 3.0.0
|
188
|
+
if Webpacker.respond_to?(:dev_server)
|
189
|
+
Webpacker.dev_server.running?
|
190
|
+
else
|
191
|
+
Rails.env.development? || Rails.env.test?
|
192
|
+
end
|
193
|
+
end
|
128
194
|
end
|
129
195
|
end
|
130
196
|
end
|
@@ -5,10 +5,32 @@ module ActionController
|
|
5
5
|
def render_to_string(opts = {})
|
6
6
|
opts.to_s
|
7
7
|
end
|
8
|
+
|
9
|
+
def self.alias_method_chain(_target, _feature); end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ActionControllerMock
|
14
|
+
class Base
|
15
|
+
def render(_)
|
16
|
+
[:base]
|
17
|
+
end
|
18
|
+
|
19
|
+
def render_to_string; end
|
20
|
+
|
21
|
+
def self.after_action(_); end
|
8
22
|
end
|
9
23
|
end
|
10
24
|
|
11
25
|
class PdfHelperTest < ActionController::TestCase
|
26
|
+
module SomePatch
|
27
|
+
def render(_)
|
28
|
+
super.tap do |s|
|
29
|
+
s << :patched
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
12
34
|
def setup
|
13
35
|
@ac = ActionController::Base.new
|
14
36
|
end
|
@@ -22,4 +44,53 @@ class PdfHelperTest < ActionController::TestCase
|
|
22
44
|
:header => { :html => { :template => 'hf.html.erb' } })
|
23
45
|
assert_match %r{^file:\/\/\/.*wicked_header_pdf.*\.html}, options[:header][:html][:url]
|
24
46
|
end
|
47
|
+
|
48
|
+
test 'should not interfere with already prepended patches' do
|
49
|
+
# Emulate railtie
|
50
|
+
if Rails::VERSION::MAJOR >= 5
|
51
|
+
# this spec tests the following:
|
52
|
+
# if another gem prepends a render method to ActionController::Base
|
53
|
+
# before wicked_pdf does, does calling render trigger an infinite loop?
|
54
|
+
# this spec fails with 6392bea1fe3a41682dfd7c20fd9c179b5a758f59 because PdfHelper
|
55
|
+
# aliases the render method prepended by the other gem to render_without_pdf, then
|
56
|
+
# base_evals its own definition of render, which calls render_with_pdf -> render_without_pdf.
|
57
|
+
# If the other gem uses the prepend inhertinance pattern (calling super instead of aliasing),
|
58
|
+
# when it calls super it calls the base_eval'd version of render instead of going up the
|
59
|
+
# inheritance chain, causing an infinite loop.
|
60
|
+
|
61
|
+
# This fiddling with consts is required to get around the fact that PdfHelper checks
|
62
|
+
# that it is being prepended to ActionController::Base
|
63
|
+
OriginalBase = ActionController::Base
|
64
|
+
ActionController.send(:remove_const, :Base)
|
65
|
+
ActionController.const_set(:Base, ActionControllerMock::Base)
|
66
|
+
|
67
|
+
# Emulate another gem being loaded before wicked
|
68
|
+
ActionController::Base.prepend(SomePatch)
|
69
|
+
ActionController::Base.prepend(::WickedPdf::PdfHelper)
|
70
|
+
|
71
|
+
begin
|
72
|
+
# test that wicked's render method is actually called
|
73
|
+
ac = ActionController::Base.new
|
74
|
+
ac.expects(:render_with_wicked_pdf)
|
75
|
+
ac.render(:cats)
|
76
|
+
|
77
|
+
# test that calling render does not trigger infinite loop
|
78
|
+
ac = ActionController::Base.new
|
79
|
+
assert_equal [:base, :patched], ac.render(:cats)
|
80
|
+
rescue SystemStackError
|
81
|
+
assert_equal true, false # force spec failure
|
82
|
+
ensure
|
83
|
+
ActionController.send(:remove_const, :Base)
|
84
|
+
ActionController.const_set(:Base, OriginalBase)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
test 'should call after_action instead of after_filter when able' do
|
90
|
+
ActionController::Base.expects(:after_filter).with(:clean_temp_files).never
|
91
|
+
ActionController::Base.expects(:after_action).with(:clean_temp_files).once
|
92
|
+
ActionController::Base.class_eval do
|
93
|
+
include ::WickedPdf::PdfHelper
|
94
|
+
end
|
95
|
+
end
|
25
96
|
end
|