wicked_pdf_rails_2 0.7.9.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Miles Z. Sterret
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,245 @@
1
+ # Wicked PDF
2
+
3
+ ## A PDF generation plugin for Ruby on Rails
4
+
5
+ Wicked PDF uses the shell utility [wkhtmltopdf](http://code.google.com/p/wkhtmltopdf/) to serve a PDF file to a user from HTML. In other words, rather than dealing with a PDF generation DSL of some sort, you simply write an HTML view as you would normally, then let Wicked take care of the hard stuff.
6
+
7
+ _Wicked PDF has been verified to work on Ruby 1.8.7 and 1.9.2; Rails 2 and Rails 3_
8
+
9
+ ### Installation
10
+
11
+ First, be sure to install [wkhtmltopdf](http://code.google.com/p/wkhtmltopdf/).
12
+ Note that versions before 0.9.0 [have problems](http://code.google.com/p/wkhtmltopdf/issues/detail?id=82&q=vodnik) on some machines with reading/writing to streams.
13
+ This plugin relies on streams to communicate with wkhtmltopdf.
14
+
15
+ More information about [wkhtmltopdf](http://code.google.com/p/wkhtmltopdf/) could be found [here](http://madalgo.au.dk/~jakobt/wkhtmltoxdoc/wkhtmltopdf-0.9.9-doc.html).
16
+
17
+ Next:
18
+
19
+ script/plugin install git://github.com/mileszs/wicked_pdf.git
20
+ script/generate wicked_pdf
21
+
22
+ or add this to your Gemfile:
23
+
24
+ gem 'wicked_pdf'
25
+
26
+ ### Basic Usage
27
+
28
+ class ThingsController < ApplicationController
29
+ def show
30
+ respond_to do |format|
31
+ format.html
32
+ format.pdf do
33
+ render :pdf => "file_name"
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+ ### Advanced Usage with all available options
40
+
41
+ class ThingsController < ApplicationController
42
+ def show
43
+ respond_to do |format|
44
+ format.html
45
+ format.pdf do
46
+ render :pdf => 'file_name',
47
+ :disposition => 'attachment', # default 'inline'
48
+ :template => 'things/show.pdf.erb',
49
+ :layout => 'pdf.html', # use 'pdf.html' for a pdf.html.erb file
50
+ :wkhtmltopdf => '/usr/local/bin/wkhtmltopdf', # path to binary
51
+ :show_as_html => params[:debug].present?, # allow debuging based on url param
52
+ :orientation => 'Landscape', # default Portrait
53
+ :page_size => 'A4, Letter, ...', # default A4
54
+ :save_to_file => Rails.root.join('pdfs', "#{filename}.pdf"),
55
+ :save_only => false, # depends on :save_to_file being set first
56
+ :proxy => 'TEXT',
57
+ :basic_auth => false # when true username & password are automatically sent from session
58
+ :username => 'TEXT',
59
+ :password => 'TEXT',
60
+ :cover => 'URL',
61
+ :dpi => 'dpi',
62
+ :encoding => 'TEXT',
63
+ :user_style_sheet => 'URL',
64
+ :cookie => ['_session_id SESSION_ID'], # could be an array or a single string in a 'name value' format
65
+ :post => ['query QUERY_PARAM'], # could be an array or a single string in a 'name value' format
66
+ :redirect_delay => NUMBER,
67
+ :zoom => FLOAT,
68
+ :page_offset => NUMBER,
69
+ :book => true,
70
+ :default_header => true,
71
+ :disable_javascript => false,
72
+ :grayscale => true,
73
+ :lowquality => true,
74
+ :enable_plugins => true,
75
+ :disable_internal_links => true,
76
+ :disable_external_links => true,
77
+ :print_media_type => true,
78
+ :disable_smart_shrinking => true,
79
+ :use_xserver => true,
80
+ :no_background => true,
81
+ :extra => '' # directly inserted into the command to wkhtmltopdf
82
+ :margin => {:top => SIZE, # default 10 (mm)
83
+ :bottom => SIZE,
84
+ :left => SIZE,
85
+ :right => SIZE},
86
+ :header => {:html => { :template => 'users/header.pdf.erb', # use :template OR :url
87
+ :layout => 'pdf_plain.html', # optional, use 'pdf_plain.html' for a pdf_plain.html.erb file, defaults to main layout
88
+ :url => 'www.example.com',
89
+ :locals => { :foo => @bar }},
90
+ :center => 'TEXT',
91
+ :font_name => 'NAME',
92
+ :font_size => SIZE,
93
+ :left => 'TEXT',
94
+ :right => 'TEXT',
95
+ :spacing => REAL,
96
+ :line => true,
97
+ :content => 'HTML CONTENT ALREADY RENDERED'}, # optionally you can pass plain html already rendered (useful if using pdf_from_string)
98
+ :footer => {:html => { :template => 'shared/footer.pdf.erb', # use :template OR :url
99
+ :layout => 'pdf_plain.html', # optional, use 'pdf_plain.html' for a pdf_plain.html.erb file, defaults to main layout
100
+ :url => 'www.example.com',
101
+ :locals => { :foo => @bar }},
102
+ :center => 'TEXT',
103
+ :font_name => 'NAME',
104
+ :font_size => SIZE,
105
+ :left => 'TEXT',
106
+ :right => 'TEXT',
107
+ :spacing => REAL,
108
+ :line => true,
109
+ :content => 'HTML CONTENT ALREADY RENDERED'}, # optionally you can pass plain html already rendered (useful if using pdf_from_string)
110
+ :toc => {:font_name => "NAME",
111
+ :depth => LEVEL,
112
+ :header_text => "TEXT",
113
+ :header_fs => SIZE,
114
+ :l1_font_size => SIZE,
115
+ :l2_font_size => SIZE,
116
+ :l3_font_size => SIZE,
117
+ :l4_font_size => SIZE,
118
+ :l5_font_size => SIZE,
119
+ :l6_font_size => SIZE,
120
+ :l7_font_size => SIZE,
121
+ :l1_indentation => NUM,
122
+ :l2_indentation => NUM,
123
+ :l3_indentation => NUM,
124
+ :l4_indentation => NUM,
125
+ :l5_indentation => NUM,
126
+ :l6_indentation => NUM,
127
+ :l7_indentation => NUM,
128
+ :no_dots => true,
129
+ :disable_links => true,
130
+ :disable_back_links => true},
131
+ :outline => {:outline => true,
132
+ :outline_depth => LEVEL}
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ By default, it will render without a layout (:layout => false) and the template for the current controller and action.
139
+
140
+ ### Super Advanced Usage ###
141
+
142
+ If you need to just create a pdf and not display it:
143
+
144
+ # create a pdf from a string
145
+ pdf = WickedPdf.new.pdf_from_string('<h1>Hello There!</h1>')
146
+
147
+ # create a pdf from string using templates, layouts and content option for header or footer
148
+ WickedPdf.new.pdf_from_string(
149
+ render_to_string(:pdf => "pdf_file.pdf", :template => 'templates/pdf.html.erb', :layout => 'pdfs/layout_pdf'),
150
+ :footer => {:content => render_to_string({:template => 'templates/pdf_footer.html.erb', :layout => 'pdfs/layout_pdf'})}
151
+
152
+ # or from your controller, using views & templates and all wicked_pdf options as normal
153
+ pdf = render_to_string :pdf => "some_file_name"
154
+
155
+ # then save to a file
156
+ save_path = Rails.root.join('pdfs','filename.pdf')
157
+ File.open(save_path, 'wb') do |file|
158
+ file << pdf
159
+ end
160
+
161
+ If you need to display utf encoded characters, add this to your pdf views or layouts:
162
+
163
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
164
+
165
+ ### Styles
166
+
167
+ You must define absolute paths to CSS files, images, and javascripts; the best option is to use the *wicked_pdf_stylesheet_link_tag*, *wicked_pdf_image_tag*, and *wicked_pdf_javascript_include_tag* helpers.
168
+
169
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
170
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
171
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
172
+ <head>
173
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
174
+ <%= wicked_pdf_stylesheet_link_tag "pdf" -%>
175
+ <%= wicked_pdf_javascript_include_tag "number_pages" %>
176
+ </head>
177
+ <body onload='number_pages'>
178
+ <div id="header">
179
+ <%= wicked_pdf_image_tag 'mysite.jpg' %>
180
+ </div>
181
+ <div id="content">
182
+ <%= yield %>
183
+ </div>
184
+ </body>
185
+ </html>
186
+
187
+ ### Page Numbering
188
+
189
+ A bit of javascript can help you number your pages. Create a template or header/footer file with this:
190
+
191
+ <html>
192
+ <head>
193
+ <script>
194
+ function number_pages() {
195
+ var vars={};
196
+ var x=document.location.search.substring(1).split('&');
197
+ for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
198
+ var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
199
+ for(var i in x) {
200
+ var y = document.getElementsByClassName(x[i]);
201
+ for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
202
+ }
203
+ }
204
+ </script>
205
+ </head>
206
+ <body onload="number_pages()">
207
+ Page <span class="page"></span> of <span class="topage"></span>
208
+ </body>
209
+ </html>
210
+
211
+ Anything with a class listed in "var x" above will be auto-filled at render time.
212
+
213
+ If you do not have explicit page breaks (and therefore do not have any "page" class), you can also use wkhtmltopdf's built in page number generation by setting one of the headers to "[page]":
214
+
215
+ render :pdf => 'filename', :header => { :right => '[page] of [topage]' }
216
+
217
+ ### Configuration
218
+
219
+ You can put your default configuration, applied to all pdf's at "wicked_pdf.rb" initializer.
220
+
221
+ ### Further Reading
222
+
223
+ Andreas Happe's post [Generating PDFs from Ruby on Rails](http://snikt.net/rails/2012/04/26/wicked-pdf/)
224
+
225
+ StackOverflow [questions with the tag "wicked-pdf"](http://stackoverflow.com/questions/tagged/wicked-pdf)
226
+
227
+ ### Debugging
228
+
229
+ Now you can use a debug param on the URL that shows you the content of the pdf in plain html to design it faster.
230
+
231
+ First of all you must configure the render parameter ":show_as_html => params[:debug]" and then just use it like normally but adding "debug=1" as a param:
232
+
233
+ http://localhost:3001/CONTROLLER/X.pdf?debug=1
234
+
235
+ However, the wicked_pdf_* helpers will use file:// paths for assets when using :show_as_html, and your browser's cross-domain safety feature will kick in, and not render them. To get around this, you can load your assets like so in your templates:
236
+
237
+ <%= params[:debug].present? ? image_tag('foo') : wicked_pdf_image_tag('foo') %>
238
+
239
+ ### Inspiration
240
+
241
+ You may have noticed: this plugin is heavily inspired by the PrinceXML plugin [princely](http://github.com/mbleigh/princely/tree/master). PrinceXML's cost was prohibitive for me. So, with a little help from some friends (thanks [jqr](http://github.com/jqr)), I tracked down wkhtmltopdf, and here we are.
242
+
243
+ ### Awesome Peoples
244
+
245
+ Also, thanks to [unixmonkey](https://github.com/Unixmonkey), [galdomedia](http://github.com/galdomedia), [jcrisp](http://github.com/jcrisp), [lleirborras](http://github.com/lleirborras), [tiennou](http://github.com/tiennou), and everyone else for all their hard work and patience with my delays in merging in their enhancements.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the wicked_pdf plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the wicked_pdf plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'WickedPdf'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,11 @@
1
+ if defined?(Rails) && Rails::VERSION::MAJOR != 2
2
+
3
+ # Rails3 generator invoked with 'rails generate wicked_pdf'
4
+ class WickedPdfGenerator < Rails::Generators::Base
5
+ source_root(File.expand_path(File.dirname(__FILE__) + "/../../generators/wicked_pdf/templates"))
6
+ def copy_initializer
7
+ copy_file 'wicked_pdf.rb', 'config/initializers/wicked_pdf.rb'
8
+ end
9
+ end
10
+
11
+ end
data/lib/pdf_helper.rb ADDED
@@ -0,0 +1,90 @@
1
+ module PdfHelper
2
+ require 'wicked_pdf'
3
+ require 'wicked_pdf_tempfile'
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ alias_method_chain :render, :wicked_pdf
8
+ alias_method_chain :render_to_string, :wicked_pdf
9
+ after_filter :clean_temp_files
10
+ end
11
+ end
12
+
13
+ def render_with_wicked_pdf(options = nil, *args, &block)
14
+ if options.is_a?(Hash) && options.has_key?(:pdf)
15
+ log_pdf_creation
16
+ options[:basic_auth] = set_basic_auth(options)
17
+ make_and_send_pdf(options.delete(:pdf), (WickedPdf.config || {}).merge(options))
18
+ else
19
+ render_without_wicked_pdf(options, *args, &block)
20
+ end
21
+ end
22
+
23
+ def render_to_string_with_wicked_pdf(options = nil, *args, &block)
24
+ if options.is_a?(Hash) && options.has_key?(:pdf)
25
+ log_pdf_creation
26
+ options[:basic_auth] = set_basic_auth(options)
27
+ options.delete :pdf
28
+ make_pdf((WickedPdf.config || {}).merge(options))
29
+ else
30
+ render_to_string_without_wicked_pdf(options, *args, &block)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def log_pdf_creation
37
+ logger.info '*'*15 + 'WICKED' + '*'*15
38
+ end
39
+
40
+ def set_basic_auth(options={})
41
+ options[:basic_auth] ||= WickedPdf.config.fetch(:basic_auth){ false }
42
+ if options[:basic_auth] && request.env["HTTP_AUTHORIZATION"]
43
+ request.env["HTTP_AUTHORIZATION"].split(" ").last
44
+ end
45
+ end
46
+
47
+ def clean_temp_files
48
+ if defined?(@hf_tempfiles)
49
+ @hf_tempfiles.each { |tf| tf.close! }
50
+ end
51
+ end
52
+
53
+ def make_pdf(options = {})
54
+ html_string = render_to_string(:template => options[:template], :layout => options[:layout], :formats => options[:formats], :handlers => options[:handlers])
55
+ options = prerender_header_and_footer(options)
56
+ w = WickedPdf.new(options[:wkhtmltopdf])
57
+ w.pdf_from_string(html_string, options)
58
+ end
59
+
60
+ def make_and_send_pdf(pdf_name, options={})
61
+ options[:wkhtmltopdf] ||= nil
62
+ options[:layout] ||= false
63
+ options[:template] ||= File.join(controller_path, action_name)
64
+ options[:disposition] ||= "inline"
65
+ if options[:show_as_html]
66
+ render :template => options[:template], :layout => options[:layout], :formats => options[:formats], :handlers => options[:handlers], :content_type => "text/html"
67
+ else
68
+ pdf_content = make_pdf(options)
69
+ File.open(options[:save_to_file], 'wb') {|file| file << pdf_content } if options[:save_to_file]
70
+ send_data(pdf_content, :filename => pdf_name + '.pdf', :type => 'application/pdf', :disposition => options[:disposition]) unless options[:save_only]
71
+ end
72
+ end
73
+
74
+ # Given an options hash, prerenders content for the header and footer sections
75
+ # to temp files and return a new options hash including the URLs to these files.
76
+ def prerender_header_and_footer(options)
77
+ [:header, :footer].each do |hf|
78
+ if options[hf] && options[hf][:html] && options[hf][:html][:template]
79
+ @hf_tempfiles = [] if ! defined?(@hf_tempfiles)
80
+ @hf_tempfiles.push( tf=WickedPdfTempfile.new("wicked_#{hf}_pdf.html") )
81
+ options[hf][:html][:layout] ||= options[:layout]
82
+ tf.write render_to_string(:template => options[hf][:html][:template], :layout => options[hf][:html][:layout], :locals => options[hf][:html][:locals], :formats => options[hf][:html][:formats], :handlers => options[hf][:html][:handlers])
83
+ tf.flush
84
+ options[hf][:html].delete(:template)
85
+ options[hf][:html][:url] = "file://#{tf.path}"
86
+ end
87
+ end
88
+ options
89
+ end
90
+ end
data/lib/wicked_pdf.rb ADDED
@@ -0,0 +1,214 @@
1
+ # wkhtml2pdf Ruby interface
2
+ # http://code.google.com/p/wkhtmltopdf/
3
+
4
+ require 'logger'
5
+ require 'digest/md5'
6
+ require 'rbconfig'
7
+ require RbConfig::CONFIG['target_os'] == 'mingw32' && !(RUBY_VERSION =~ /1.9/) ? 'win32/open3' : 'open3'
8
+ require 'active_support/core_ext/class/attribute_accessors'
9
+
10
+ begin
11
+ require 'active_support/core_ext/object/blank'
12
+ rescue LoadError
13
+ require 'active_support/core_ext/blank'
14
+ end
15
+
16
+ require 'wicked_pdf_railtie'
17
+ require 'wicked_pdf_tempfile'
18
+
19
+ class WickedPdf
20
+ EXE_NAME = "wkhtmltopdf"
21
+ @@config = {}
22
+ cattr_accessor :config
23
+
24
+ def initialize(wkhtmltopdf_binary_path = nil)
25
+ @exe_path = wkhtmltopdf_binary_path || find_wkhtmltopdf_binary_path
26
+ raise "Location of #{EXE_NAME} unknown" if @exe_path.empty?
27
+ raise "Bad #{EXE_NAME}'s path" unless File.exists?(@exe_path)
28
+ raise "#{EXE_NAME} is not executable" unless File.executable?(@exe_path)
29
+ end
30
+
31
+ def pdf_from_string(string, options={})
32
+ command = "\"#{@exe_path}\" #{'-q ' unless on_windows?}#{parse_options(options)} - - " # -q for no errors on stdout
33
+ print_command(command) if in_development_mode?
34
+ pdf, err = Open3.popen3(command) do |stdin, stdout, stderr|
35
+ stdin.binmode
36
+ stdout.binmode
37
+ stderr.binmode
38
+ stdin.write(string)
39
+ stdin.close
40
+ [stdout.read, stderr.read]
41
+ end
42
+ raise "PDF could not be generated!" if pdf and pdf.rstrip.length == 0
43
+ pdf
44
+ rescue Exception => e
45
+ raise "Failed to execute:\n#{command}\nError: #{e}"
46
+ end
47
+
48
+ private
49
+
50
+ def in_development_mode?
51
+ (defined?(Rails) && Rails.env == 'development') ||
52
+ (defined?(RAILS_ENV) && RAILS_ENV == 'development')
53
+ end
54
+
55
+ def on_windows?
56
+ RbConfig::CONFIG['target_os'] == 'mingw32'
57
+ end
58
+
59
+ def print_command(cmd)
60
+ p "*"*15 + cmd + "*"*15
61
+ end
62
+
63
+ def parse_options(options)
64
+ [
65
+ parse_extra(options),
66
+ parse_header_footer(:header => options.delete(:header),
67
+ :footer => options.delete(:footer),
68
+ :layout => options[:layout]),
69
+ parse_toc(options.delete(:toc)),
70
+ parse_outline(options.delete(:outline)),
71
+ parse_margins(options.delete(:margin)),
72
+ parse_others(options),
73
+ parse_basic_auth(options)
74
+ ].join(' ')
75
+ end
76
+
77
+ def parse_extra(options)
78
+ options[:extra].nil? ? '' : options[:extra]
79
+ end
80
+
81
+ def parse_basic_auth(options)
82
+ if options[:basic_auth]
83
+ user, passwd = Base64.decode64(options[:basic_auth]).split(":")
84
+ "--username '#{user}' --password '#{passwd}'"
85
+ else
86
+ ""
87
+ end
88
+ end
89
+
90
+ def make_option(name, value, type=:string)
91
+ if value.is_a?(Array)
92
+ return value.collect { |v| make_option(name, v, type) }.join('')
93
+ end
94
+ "--#{name.gsub('_', '-')} " + case type
95
+ when :boolean then ""
96
+ when :numeric then value.to_s
97
+ when :name_value then value.to_s
98
+ else "\"#{value}\""
99
+ end + " "
100
+ end
101
+
102
+ def make_options(options, names, prefix="", type=:string)
103
+ names.collect {|o| make_option("#{prefix.blank? ? "" : prefix + "-"}#{o.to_s}", options[o], type) unless options[o].blank?}.join
104
+ end
105
+
106
+ def parse_header_footer(options)
107
+ r=""
108
+ [:header, :footer].collect do |hf|
109
+ unless options[hf].blank?
110
+ opt_hf = options[hf]
111
+ r += make_options(opt_hf, [:center, :font_name, :left, :right], "#{hf.to_s}")
112
+ r += make_options(opt_hf, [:font_size, :spacing], "#{hf.to_s}", :numeric)
113
+ r += make_options(opt_hf, [:line], "#{hf.to_s}", :boolean)
114
+ if options[hf] && options[hf][:content]
115
+ @hf_tempfiles = [] if ! defined?(@hf_tempfiles)
116
+ @hf_tempfiles.push( tf=WickedPdfTempfile.new("wicked_#{hf}_pdf.html") )
117
+ tf.write options[hf][:content]
118
+ tf.flush
119
+ options[hf].delete(:content)
120
+ options[hf][:html] = {}
121
+ options[hf][:html][:url] = "file://#{tf.path}"
122
+ end
123
+ unless opt_hf[:html].blank?
124
+ r += make_option("#{hf.to_s}-html", opt_hf[:html][:url]) unless opt_hf[:html][:url].blank?
125
+ end
126
+ end
127
+ end unless options.blank?
128
+ r
129
+ end
130
+
131
+ def parse_toc(options)
132
+ r = '--toc ' unless options.nil?
133
+ unless options.blank?
134
+ r += make_options(options, [ :font_name, :header_text], "toc")
135
+ r +=make_options(options, [ :depth,
136
+ :header_fs,
137
+ :l1_font_size,
138
+ :l2_font_size,
139
+ :l3_font_size,
140
+ :l4_font_size,
141
+ :l5_font_size,
142
+ :l6_font_size,
143
+ :l7_font_size,
144
+ :l1_indentation,
145
+ :l2_indentation,
146
+ :l3_indentation,
147
+ :l4_indentation,
148
+ :l5_indentation,
149
+ :l6_indentation,
150
+ :l7_indentation], "toc", :numeric)
151
+ r +=make_options(options, [ :no_dots,
152
+ :disable_links,
153
+ :disable_back_links], "toc", :boolean)
154
+ end
155
+ return r
156
+ end
157
+
158
+ def parse_outline(options)
159
+ unless options.blank?
160
+ r = make_options(options, [:outline], "", :boolean)
161
+ r +=make_options(options, [:outline_depth], "", :numeric)
162
+ end
163
+ end
164
+
165
+ def parse_margins(options)
166
+ make_options(options, [:top, :bottom, :left, :right], "margin", :numeric) unless options.blank?
167
+ end
168
+
169
+ def parse_others(options)
170
+ unless options.blank?
171
+ r = make_options(options, [ :orientation,
172
+ :page_size,
173
+ :page_width,
174
+ :page_height,
175
+ :proxy,
176
+ :username,
177
+ :password,
178
+ :cover,
179
+ :dpi,
180
+ :encoding,
181
+ :user_style_sheet])
182
+ r +=make_options(options, [ :cookie,
183
+ :post], "", :name_value)
184
+ r +=make_options(options, [ :redirect_delay,
185
+ :zoom,
186
+ :page_offset,
187
+ :javascript_delay], "", :numeric)
188
+ r +=make_options(options, [ :book,
189
+ :default_header,
190
+ :disable_javascript,
191
+ :grayscale,
192
+ :lowquality,
193
+ :enable_plugins,
194
+ :disable_internal_links,
195
+ :disable_external_links,
196
+ :print_media_type,
197
+ :disable_smart_shrinking,
198
+ :use_xserver,
199
+ :no_background], "", :boolean)
200
+ end
201
+ end
202
+
203
+ def find_wkhtmltopdf_binary_path
204
+ possible_locations = (ENV['PATH'].split(':')+%w[/usr/bin /usr/local/bin ~/bin]).uniq
205
+ exe_path ||= WickedPdf.config[:exe_path] unless WickedPdf.config.empty?
206
+ exe_path ||= begin
207
+ (defined?(Bundler) ? `bundle exec which wkhtmltopdf` : `which wkhtmltopdf`).chomp
208
+ rescue Exception => e
209
+ nil
210
+ end
211
+ exe_path ||= possible_locations.map{|l| File.expand_path("#{l}/#{EXE_NAME}") }.find{|location| File.exists? location}
212
+ exe_path || ''
213
+ end
214
+ end
@@ -0,0 +1,78 @@
1
+ module WickedPdfHelper
2
+ def wicked_pdf_stylesheet_link_tag(*sources)
3
+
4
+ if Rails.root.kind_of?(Pathname)
5
+ root_pathname = Rails.root
6
+ elsif Rails.root.kind_of?(String)
7
+ root_obj = Pathname(Rails.root)
8
+ end
9
+
10
+ css_dir = root_obj.join('public','stylesheets')
11
+
12
+ begin
13
+ sources.collect { |source|
14
+ "<style type='text/css'>#{File.read(css_dir.join(source+'.css'))}</style>"
15
+ }.join("\n").html_safe
16
+ rescue NoMethodError
17
+ sources.collect { |source|
18
+ "<style type='text/css'>#{File.read(css_dir.join(source+'.css'))}</style>"
19
+ }.join("\n")
20
+ end
21
+ end
22
+
23
+ def wicked_pdf_image_tag(img, options={})
24
+ image_tag "file:///#{root_obj.join('public', 'images', img)}", options
25
+ end
26
+
27
+ def wicked_pdf_javascript_src_tag(jsfile, options={})
28
+ javascript_src_tag "file:///#{root_obj.join('public','javascripts',jsfile)}", options
29
+ end
30
+
31
+ def wicked_pdf_javascript_include_tag(*sources)
32
+ begin
33
+ sources.collect{ |source| wicked_pdf_javascript_src_tag(source, {}) }.join("\n").html_safe
34
+ rescue NoMethodError
35
+ sources.collect{ |source| wicked_pdf_javascript_src_tag(source, {}) }.join("\n")
36
+ end
37
+ end
38
+
39
+ module Assets
40
+ def wicked_pdf_stylesheet_link_tag(*sources)
41
+ sources.collect { |source|
42
+ "<style type='text/css'>#{read_asset(source+".css")}</style>"
43
+ }.join("\n").html_safe
44
+ end
45
+
46
+ def wicked_pdf_image_tag(img, options={})
47
+ image_tag "file://#{asset_pathname(img).to_s}", options
48
+ end
49
+
50
+ def wicked_pdf_javascript_src_tag(jsfile, options={})
51
+ javascript_include_tag "file://#{asset_pathname(jsfile).to_s}", options
52
+ end
53
+
54
+ def wicked_pdf_javascript_include_tag(*sources)
55
+ sources.collect { |source|
56
+ "<script type='text/javascript'>#{read_asset(source+".js")}</script>"
57
+ }.join("\n").html_safe
58
+ end
59
+
60
+ private
61
+
62
+ def asset_pathname(source)
63
+ if Rails.configuration.assets.compile == false
64
+ File.join(Rails.public_path, asset_path(source))
65
+ else
66
+ Rails.application.assets.find_asset(source).pathname
67
+ end
68
+ end
69
+
70
+ def read_asset(source)
71
+ if Rails.configuration.assets.compile == false
72
+ IO.read(asset_pathname(source))
73
+ else
74
+ Rails.application.assets.find_asset(source).to_s
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,34 @@
1
+ require 'pdf_helper'
2
+ require 'wicked_pdf_helper'
3
+
4
+ if defined?(Rails)
5
+
6
+ if Rails::VERSION::MAJOR == 2
7
+
8
+ unless ActionController::Base.instance_methods.include? "render_with_wicked_pdf"
9
+ ActionController::Base.send :include, PdfHelper
10
+ end
11
+ unless ActionView::Base.instance_methods.include? "wicked_pdf_stylesheet_link_tag"
12
+ ActionView::Base.send :include, WickedPdfHelper
13
+ end
14
+
15
+ else
16
+
17
+ class WickedRailtie < Rails::Railtie
18
+ initializer "wicked_pdf.register" do |app|
19
+ ActionController::Base.send :include, PdfHelper
20
+ if Rails::VERSION::MINOR > 0
21
+ ActionView::Base.send :include, WickedPdfHelper::Assets
22
+ else
23
+ ActionView::Base.send :include, WickedPdfHelper
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ if Mime::Type.lookup_by_extension(:pdf).nil?
31
+ Mime::Type.register('application/pdf', :pdf)
32
+ end
33
+
34
+ end
@@ -0,0 +1,10 @@
1
+ require 'tempfile'
2
+
3
+ class WickedPdfTempfile < Tempfile
4
+ # Replaces Tempfile's +make_tmpname+ with one that honors file extensions.
5
+ def make_tmpname(basename, n)
6
+ extension = File.extname(basename)
7
+ sprintf("%s_%d_%d%s", File.basename(basename, extension), $$, n.to_i, extension)
8
+ end
9
+ end
10
+
@@ -0,0 +1 @@
1
+ /* Wicked styles */
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ class Base
5
+ def render_to_string opts={}
6
+ opts.to_s
7
+ end
8
+ end
9
+ end
10
+
11
+ class PdfHelperTest < ActionController::TestCase
12
+ def setup
13
+ @ac = ActionController::Base.new
14
+ end
15
+
16
+ def teardown
17
+ @ac=nil
18
+ end
19
+
20
+ test "should prerender header and footer :template options" do
21
+ options = @ac.send( :prerender_header_and_footer,
22
+ :header => {:html => { :template => 'hf.html.erb'}});
23
+ assert !options[:header][:html].has_key?(:template)
24
+ assert_match /^file:\/\/.*wicked_header_pdf.*\.html/, options[:header][:html][:url]
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ require 'test/unit'
2
+ require 'rails'
3
+ require 'action_controller/test_case'
4
+ require 'wicked_pdf'
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+ require 'action_view/test_case'
3
+
4
+ class WickedPdfHelperTest < ActionView::TestCase
5
+ test 'wicked_pdf_stylesheet_link_tag should inline the stylesheets passed in' do
6
+ assert_equal "<style type='text/css'>/* Wicked styles */\n</style>",
7
+ wicked_pdf_stylesheet_link_tag('../../vendor/plugins/wicked_pdf/test/fixtures/wicked')
8
+ end
9
+
10
+ test 'wicked_pdf_image_tag should return the same as image_tag when passed a full path' do
11
+ assert_equal image_tag("file://#{Rails.root.join('public','images','pdf')}"),
12
+ wicked_pdf_image_tag('pdf')
13
+ end
14
+
15
+ test 'wicked_pdf_javascript_src_tag should return the same as javascript_src_tag when passed a full path' do
16
+ assert_equal javascript_src_tag("file://#{Rails.root.join('public','javascripts','pdf')}", {}),
17
+ wicked_pdf_javascript_src_tag('pdf')
18
+ end
19
+
20
+ test 'wicked_pdf_include_tag should return many wicked_pdf_javascript_src_tags' do
21
+ assert_equal [wicked_pdf_javascript_src_tag('foo'), wicked_pdf_javascript_src_tag('bar')].join("\n"),
22
+ wicked_pdf_javascript_include_tag('foo', 'bar')
23
+ end
24
+ end
@@ -0,0 +1,147 @@
1
+ require 'test_helper'
2
+
3
+ WickedPdf.config = { :exe_path => '/usr/local/bin/wkhtmltopdf' }
4
+ HTML_DOCUMENT = "<html><body>Hello World</body></html>"
5
+
6
+ # Provide a public accessor to the normally-private parse_options function
7
+ class WickedPdf
8
+ def get_parsed_options(opts)
9
+ parse_options(opts)
10
+ end
11
+ end
12
+
13
+ class WickedPdfTest < ActiveSupport::TestCase
14
+
15
+ test "should generate PDF from html document" do
16
+ wp = WickedPdf.new
17
+ pdf = wp.pdf_from_string HTML_DOCUMENT
18
+ assert pdf.start_with?("%PDF-1.4")
19
+ assert pdf.rstrip.end_with?("%%EOF")
20
+ assert pdf.length > 100
21
+ end
22
+
23
+ test "should raise exception when no path to wkhtmltopdf" do
24
+ assert_raise RuntimeError do
25
+ WickedPdf.new " "
26
+ end
27
+ end
28
+
29
+ test "should raise exception when wkhtmltopdf path is wrong" do
30
+ assert_raise RuntimeError do
31
+ WickedPdf.new "/i/do/not/exist/notwkhtmltopdf"
32
+ end
33
+ end
34
+
35
+ test "should raise exception when wkhtmltopdf is not executable" do
36
+ begin
37
+ tmp = Tempfile.new('wkhtmltopdf')
38
+ fp = tmp.path
39
+ File.chmod 0000, fp
40
+ assert_raise RuntimeError do
41
+ WickedPdf.new fp
42
+ end
43
+ ensure
44
+ tmp.delete
45
+ end
46
+ end
47
+
48
+ test "should raise exception when pdf generation fails" do
49
+ begin
50
+ tmp = Tempfile.new('wkhtmltopdf')
51
+ fp = tmp.path
52
+ File.chmod 0777, fp
53
+ wp = WickedPdf.new fp
54
+ assert_raise RuntimeError do
55
+ wp.pdf_from_string HTML_DOCUMENT
56
+ end
57
+ ensure
58
+ tmp.delete
59
+ end
60
+ end
61
+
62
+ test "should parse header and footer options" do
63
+ wp = WickedPdf.new
64
+
65
+ [:header, :footer].each do |hf|
66
+ [:center, :font_name, :left, :right].each do |o|
67
+ assert_equal "--#{hf.to_s}-#{o.to_s.gsub('_', '-')} \"header_footer\"",
68
+ wp.get_parsed_options(hf => {o => "header_footer"}).strip
69
+ end
70
+
71
+ [:font_size, :spacing].each do |o|
72
+ assert_equal "--#{hf.to_s}-#{o.to_s.gsub('_', '-')} 12",
73
+ wp.get_parsed_options(hf => {o => "12"}).strip
74
+ end
75
+
76
+ assert_equal "--#{hf.to_s}-line",
77
+ wp.get_parsed_options(hf => {:line => true}).strip
78
+ assert_equal "--#{hf.to_s}-html \"http://www.abc.com\"",
79
+ wp.get_parsed_options(hf => {:html => {:url => 'http://www.abc.com'}}).strip
80
+ end
81
+ end
82
+
83
+ test "should parse toc options" do
84
+ wp = WickedPdf.new
85
+
86
+ [:font_name, :header_text].each do |o|
87
+ assert_equal "--toc-#{o.to_s.gsub('_', '-')} \"toc\"",
88
+ wp.get_parsed_options(:toc => {o => "toc"}).strip
89
+ end
90
+
91
+ [ :depth, :header_fs, :l1_font_size, :l2_font_size, :l3_font_size, :l4_font_size,
92
+ :l5_font_size, :l6_font_size, :l7_font_size, :l1_indentation, :l2_indentation,
93
+ :l3_indentation, :l4_indentation, :l5_indentation, :l6_indentation, :l7_indentation
94
+ ].each do |o|
95
+ assert_equal "--toc-#{o.to_s.gsub('_', '-')} 5",
96
+ wp.get_parsed_options(:toc => {o => 5}).strip
97
+ end
98
+
99
+ [:no_dots, :disable_links, :disable_back_links].each do |o|
100
+ assert_equal "--toc-#{o.to_s.gsub('_', '-')}",
101
+ wp.get_parsed_options(:toc => {o => true}).strip
102
+ end
103
+ end
104
+
105
+ test "should parse outline options" do
106
+ wp = WickedPdf.new
107
+
108
+ assert_equal "--outline", wp.get_parsed_options(:outline => {:outline => true}).strip
109
+ assert_equal "--outline-depth 5", wp.get_parsed_options(:outline => {:outline_depth => 5}).strip
110
+ end
111
+
112
+ test "should parse margins options" do
113
+ wp = WickedPdf.new
114
+
115
+ [:top, :bottom, :left, :right].each do |o|
116
+ assert_equal "--margin-#{o.to_s} 12", wp.get_parsed_options(:margin => {o => "12"}).strip
117
+ end
118
+ end
119
+
120
+ test "should parse other options" do
121
+ wp = WickedPdf.new
122
+
123
+ [ :orientation, :page_size, :proxy, :username, :password, :cover, :dpi,
124
+ :encoding, :user_style_sheet
125
+ ].each do |o|
126
+ assert_equal "--#{o.to_s.gsub('_', '-')} \"opts\"", wp.get_parsed_options(o => "opts").strip
127
+ end
128
+
129
+ [:cookie, :post].each do |o|
130
+ assert_equal "--#{o.to_s.gsub('_', '-')} name value", wp.get_parsed_options(o => "name value").strip
131
+
132
+ nv_formatter = ->(number){ "--#{o.to_s.gsub('_', '-')} par#{number} val#{number}" }
133
+ assert_equal "#{nv_formatter.call(1)} #{nv_formatter.call(2)}", wp.get_parsed_options(o => ['par1 val1', 'par2 val2']).strip
134
+ end
135
+
136
+ [:redirect_delay, :zoom, :page_offset].each do |o|
137
+ assert_equal "--#{o.to_s.gsub('_', '-')} 5", wp.get_parsed_options(o => 5).strip
138
+ end
139
+
140
+ [ :book, :default_header, :disable_javascript, :grayscale, :lowquality,
141
+ :enable_plugins, :disable_internal_links, :disable_external_links,
142
+ :print_media_type, :disable_smart_shrinking, :use_xserver, :no_background
143
+ ].each do |o|
144
+ assert_equal "--#{o.to_s.gsub('_', '-')}", wp.get_parsed_options(o => true).strip
145
+ end
146
+ end
147
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wicked_pdf_rails_2
3
+ version: !ruby/object:Gem::Version
4
+ hash: 81
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 7
9
+ - 9
10
+ - 1
11
+ version: 0.7.9.1
12
+ platform: ruby
13
+ authors:
14
+ - Miles Z. Sterret
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2012-07-12 00:00:00 Z
20
+ dependencies: []
21
+
22
+ description: |
23
+ This is a fork of the wicked_pdf gem which allows Rails < 2.3.4 to run. Basically no really big
24
+ changes, so I am leaving most of this the same, and hopefully it will be pulled into the master.
25
+
26
+ Wicked PDF uses the shell utility wkhtmltopdf to serve a PDF file to a user from HTML.
27
+ In other words, rather than dealing with a PDF generation DSL of some sort,
28
+ you simply write an HTML view as you would normally, and let Wicked take care of the hard stuff.
29
+
30
+ email: miles.sterrett@gmail.com
31
+ executables: []
32
+
33
+ extensions: []
34
+
35
+ extra_rdoc_files: []
36
+
37
+ files:
38
+ - README.md
39
+ - Rakefile
40
+ - MIT-LICENSE
41
+ - lib/wicked_pdf_railtie.rb
42
+ - lib/wicked_pdf_helper.rb
43
+ - lib/pdf_helper.rb
44
+ - lib/generators/wicked_pdf_generator.rb
45
+ - lib/wicked_pdf_tempfile.rb
46
+ - lib/wicked_pdf.rb
47
+ - test/pdf_helper_test.rb
48
+ - test/test_helper.rb
49
+ - test/fixtures/wicked.css
50
+ - test/wicked_pdf_helper_test.rb
51
+ - test/wicked_pdf_test.rb
52
+ homepage: https://github.com/d3vkit/wicked_pdf
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ hash: 3
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 3
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.8.24
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: PDF generator (from HTML) plugin for Ruby on Rails
85
+ test_files: []
86
+