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.
@@ -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(PATH_INFO REQUEST_URI).each { |e| env[e] = env[e].sub(%r{\.pdf\b}, '') }
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
- after_filter :clean_temp_files
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
- alias_method :render_without_wicked_pdf, :render
24
- alias_method :render_to_string_without_wicked_pdf, :render_to_string
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
- def render_to_string(options = nil, *args, &block)
31
- render_to_string_with_wicked_pdf(options, *args, &block)
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
- else
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
- else
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
@@ -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
- if Rails::VERSION::MAJOR >= 5
9
-
10
- class WickedRailtie < Rails::Railtie
11
- initializer 'wicked_pdf.register' do |_app|
12
- ActionController::Base.send :prepend, PdfHelper
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
- ActionView::Base.send :include, WickedPdfHelper
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?
@@ -1,3 +1,3 @@
1
1
  class WickedPdf
2
- VERSION = '1.1.0'.freeze
2
+ VERSION = '2.1.0'.freeze
3
3
  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)
@@ -1,4 +1,6 @@
1
- require 'open-uri'
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
- asset ? asset.pathname : File.join(Rails.public_path, source)
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.compile == false ||
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
- encoding = ':UTF-8' if RUBY_VERSION > '1.8'
116
- asset = open(uri, "r#{encoding}", &:read)
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
@@ -0,0 +1,4 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: ":memory:"
4
+ timeout: 500
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link wicked.js
3
+ //= link wicked.css
@@ -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