go_static 0.0.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) 2012 Lleir Borras Metje
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 go_static 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 go_static plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'GoStatic'
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 go_static'
4
+ class GoStaticGenerator < Rails::Generators::Base
5
+ source_root(File.expand_path(File.dirname(__FILE__) + "/../../generators/go_static/templates"))
6
+ def copy_initializer
7
+ copy_file 'go_static.rb', 'config/initializers/go_static.rb'
8
+ end
9
+ end
10
+
11
+ end
data/lib/go_static.rb ADDED
@@ -0,0 +1,165 @@
1
+ # wkhtml2image 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
+ require 'active_support/core_ext/object/blank'
10
+
11
+ require 'go_static_railtie'
12
+ require 'go_static_tempfile'
13
+
14
+ class GoStatic
15
+ EXE_NAME = "wkhtmltoimage"
16
+ @@config = {}
17
+ cattr_accessor :config
18
+
19
+ def initialize(wkhtmltoimage_binary_path = nil)
20
+ @exe_path = wkhtmltoimage_binary_path || find_wkhtmltoimage_binary_path
21
+ raise "Location of #{EXE_NAME} unknown" if @exe_path.empty?
22
+ raise "Bad #{EXE_NAME}'s path" unless File.exists?(@exe_path)
23
+ raise "#{EXE_NAME} is not executable" unless File.executable?(@exe_path)
24
+ end
25
+
26
+ def png_from_string(string, options={})
27
+ command = "\"#{@exe_path}\" #{parse_options(options)} - - " # -q for no errors on stdout
28
+ print_command(command) if in_development_mode?
29
+ png, err = Open3.popen3(command) do |stdin, stdout, stderr|
30
+ stdin.binmode
31
+ stdout.binmode
32
+ stderr.binmode
33
+ stdin.write(string)
34
+ stdin.close
35
+ [stdout.read, stderr.read]
36
+ end
37
+ raise "IMAGE could not be generated!" if png and png.rstrip.length == 0
38
+ png
39
+ rescue Exception => e
40
+ raise "Failed to execute:\n#{command}\nError: #{e}"
41
+ end
42
+
43
+ private
44
+
45
+ def in_development_mode?
46
+ (defined?(Rails) && Rails.env == 'development') ||
47
+ (defined?(RAILS_ENV) && RAILS_ENV == 'development')
48
+ end
49
+
50
+ def on_windows?
51
+ RbConfig::CONFIG['target_os'] == 'mingw32'
52
+ end
53
+
54
+ def print_command(cmd)
55
+ p "*"*15 + cmd + "*"*15
56
+ end
57
+
58
+ def parse_options(options)
59
+ [
60
+ parse_extra(options),
61
+ parse_basic_auth(options),
62
+ parse_others(options)
63
+ ].join(' ')
64
+ end
65
+
66
+ def parse_extra(options)
67
+ options[:extra].nil? ? '' : options[:extra]
68
+ end
69
+
70
+ def parse_basic_auth(options)
71
+ if options[:basic_auth]
72
+ user, passwd = Base64.decode64(options[:basic_auth]).split(":")
73
+ "--username '#{user}' --password '#{passwd}'"
74
+ else
75
+ ""
76
+ end
77
+ end
78
+
79
+ def make_option(name, value, type=:string)
80
+ if value.is_a?(Array)
81
+ return value.collect { |v| make_option(name, v, type) }.join('')
82
+ end
83
+ "--#{name.gsub('_', '-')} " + case type
84
+ when :boolean then ""
85
+ when :numeric then value.to_s
86
+ when :name_value then value.to_s
87
+ else "\"#{value}\""
88
+ end + " "
89
+ end
90
+
91
+ def make_options(options, names, prefix="", type=:string)
92
+ names.collect {|o| make_option("#{prefix.blank? ? "" : prefix + "-"}#{o.to_s}", options[o], type) unless options[o].blank?}.join
93
+ end
94
+
95
+ def parse_others(options)
96
+ unless options.blank?
97
+ r = make_options(options, [ :cookie,
98
+ :custom_header,
99
+ :post,
100
+ :post_file], "", :name_value)
101
+
102
+ r +=make_options(options, [ :crop_h,
103
+ :crop_w,
104
+ :crop_x,
105
+ :crop_y,
106
+ :minimum_font_size,
107
+ :quality,
108
+ :width,
109
+ :zoom], "", :numeric)
110
+
111
+ r +=make_options(options, [ :custom_header_propagation,
112
+ :no_custom_header_propagation,
113
+ :debug_javascript,
114
+ :no_debug_javascript,
115
+ :help,
116
+ :htmldoc,
117
+ :images,
118
+ :no_images,
119
+ :disable_javascript,
120
+ :enable_javascript,
121
+ :disable_local_file_access,
122
+ :enable_local_file_access,
123
+ :manpage,
124
+ :disable_plugins,
125
+ :enable_plugins,
126
+ :readme,
127
+ :disable_smart_width,
128
+ :stop_slow_scripts,
129
+ :no_stop_slow_scripts,
130
+ :transparent,
131
+ :version,
132
+ :extended_help])
133
+
134
+ r +=make_options(options, [ :allow,
135
+ :checkbox_checked_svg,
136
+ :checkbox_svg,
137
+ :cookie_jar,
138
+ :encoding,
139
+ :format,
140
+ :height,
141
+ :javascript_delay,
142
+ :load_error_handling,
143
+ :password,
144
+ :proxy,
145
+ :radiobutton_checked_svg,
146
+ :radiobutton_svg,
147
+ :run_script,
148
+ :user_style_sheet,
149
+ :username,
150
+ :window_status])
151
+ end
152
+ end
153
+
154
+ def find_wkhtmltoimage_binary_path
155
+ possible_locations = (ENV['PATH'].split(':')+%w[/usr/bin /usr/local/bin ~/bin]).uniq
156
+ exe_path ||= GoStatic.config[:exe_path] unless GoStatic.config.empty?
157
+ exe_path ||= begin
158
+ (defined?(Bundler) ? `bundle exec which wkhtmltoimage` : `which wkhtmltoimage`).chomp
159
+ rescue Exception => e
160
+ nil
161
+ end
162
+ exe_path ||= possible_locations.map{|l| File.expand_path("#{l}/#{EXE_NAME}") }.find{|location| File.exists? location}
163
+ exe_path || ''
164
+ end
165
+ end
@@ -0,0 +1,60 @@
1
+ module GoStaticHelper
2
+ def go_static_stylesheet_link_tag(*sources)
3
+ css_dir = Rails.root.join('public','stylesheets')
4
+ sources.collect { |source|
5
+ "<style type='text/css'>#{File.read(css_dir.join(source+'.css'))}</style>"
6
+ }.join("\n").html_safe
7
+ end
8
+
9
+ def go_static_image_tag(img, options={})
10
+ image_tag "file:///#{Rails.root.join('public', 'images', img)}", options
11
+ end
12
+
13
+ def go_static_javascript_src_tag(jsfile, options={})
14
+ javascript_src_tag "file:///#{Rails.root.join('public','javascripts',jsfile)}", options
15
+ end
16
+
17
+ def go_static_javascript_include_tag(*sources)
18
+ sources.collect{ |source| go_static_javascript_src_tag(source, {}) }.join("\n").html_safe
19
+ end
20
+
21
+ module Assets
22
+ def go_static_stylesheet_link_tag(*sources)
23
+ sources.collect { |source|
24
+ "<style type='text/css'>#{read_asset(source+".css")}</style>"
25
+ }.join("\n").html_safe
26
+ end
27
+
28
+ def go_static_image_tag(img, options={})
29
+ image_tag "file://#{asset_pathname(img).to_s}", options
30
+ end
31
+
32
+ def go_static_javascript_src_tag(jsfile, options={})
33
+ javascript_include_tag "file://#{asset_pathname(jsfile).to_s}", options
34
+ end
35
+
36
+ def go_static_javascript_include_tag(*sources)
37
+ sources.collect { |source|
38
+ "<script type='text/javascript'>#{read_asset(source+".js")}</script>"
39
+ }.join("\n").html_safe
40
+ end
41
+
42
+ private
43
+
44
+ def asset_pathname(source)
45
+ if Rails.configuration.assets.compile == false
46
+ File.join(Rails.public_path, asset_path(source))
47
+ else
48
+ Rails.application.assets.find_asset(source).pathname
49
+ end
50
+ end
51
+
52
+ def read_asset(source)
53
+ if Rails.configuration.assets.compile == false
54
+ IO.read(asset_pathname(source))
55
+ else
56
+ Rails.application.assets.find_asset(source).to_s
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,30 @@
1
+ require 'static_helper'
2
+ require 'go_static_helper'
3
+
4
+ if defined?(Rails)
5
+
6
+ if Rails::VERSION::MAJOR == 2
7
+
8
+ unless ActionController::Base.instance_methods.include? "render_with_go_static"
9
+ ActionController::Base.send :include, StaticHelper
10
+ end
11
+ unless ActionView::Base.instance_methods.include? "go_static_stylesheet_link_tag"
12
+ ActionView::Base.send :include, GoStaticHelper
13
+ end
14
+
15
+ else
16
+
17
+ class StaticRailtie < Rails::Railtie
18
+ initializer "go_static.register" do |app|
19
+ ActionController::Base.send :include, StaticHelper
20
+ if Rails::VERSION::MINOR > 0
21
+ ActionView::Base.send :include, GoStaticHelper::Assets
22
+ else
23
+ ActionView::Base.send :include, GoStaticHelper
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,10 @@
1
+ require 'tempfile'
2
+
3
+ class GoStaticTempfile < 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,72 @@
1
+ module StaticHelper
2
+ require 'go_static'
3
+ require 'go_static_tempfile'
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ alias_method_chain :render, :go_static
8
+ alias_method_chain :render_to_string, :go_static
9
+ after_filter :clean_temp_files
10
+ end
11
+ end
12
+
13
+ def render_with_go_static(options = nil, *args, &block)
14
+ if options.is_a?(Hash) && options.has_key?(:png)
15
+ log_png_creation
16
+ options[:basic_auth] = set_basic_auth(options)
17
+ make_and_send_png(options.delete(:png), (GoStatic.config || {}).merge(options))
18
+ else
19
+ render_without_go_static(options, *args, &block)
20
+ end
21
+ end
22
+
23
+ def render_to_string_with_go_static(options = nil, *args, &block)
24
+ if options.is_a?(Hash) && options.has_key?(:png)
25
+ log_png_creation
26
+ options[:basic_auth] = set_basic_auth(options)
27
+ options.delete :png
28
+ make_png((GoStatic.config || {}).merge(options))
29
+ else
30
+ render_to_string_without_go_static(options, *args, &block)
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def log_png_creation
37
+ logger.info '*'*15 + 'STATIC' + '*'*15
38
+ end
39
+
40
+ def set_basic_auth(options={})
41
+ options[:basic_auth] ||= GoStatic.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_png(options = {})
54
+ html_string = render_to_string(:template => options[:template], :layout => options[:layout], :formats => options[:formats], :handlers => options[:handlers])
55
+ w = GoStatic.new(options[:wkhtmltoimage])
56
+ w.png_from_string(html_string)
57
+ end
58
+
59
+ def make_and_send_png(png_name, options={})
60
+ options[:wkhtmltoimage] ||= nil
61
+ options[:layout] ||= false
62
+ options[:template] ||= File.join(controller_path, action_name)
63
+ options[:disposition] ||= "inline"
64
+ if options[:show_as_html]
65
+ render :template => options[:template], :layout => options[:layout], :formats => options[:formats], :handlers => options[:handlers], :content_type => "text/html"
66
+ else
67
+ png_content = make_png(options)
68
+ File.open(options[:save_to_file], 'wb') {|file| file << png_content } if options[:save_to_file]
69
+ send_data(png_content, :filename => png_name + '.png', :type => 'application/png', :disposition => options[:disposition]) unless options[:save_only]
70
+ end
71
+ end
72
+ end
@@ -0,0 +1 @@
1
+ /* Wicked styles */
@@ -0,0 +1,24 @@
1
+ require 'test_helper'
2
+ require 'action_view/test_case'
3
+
4
+ class GoStaticHelperTest < ActionView::TestCase
5
+ test 'go_static_stylesheet_link_tag should inline the stylesheets passed in' do
6
+ assert_equal "<style type='text/css'>/* Wicked styles */\n</style>",
7
+ go_static_stylesheet_link_tag('../../vendor/plugins/go_static/test/fixtures/wicked')
8
+ end
9
+
10
+ test 'go_static_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','png')}"),
12
+ go_static_image_tag('png')
13
+ end
14
+
15
+ test 'go_static_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','png')}", {}),
17
+ go_static_javascript_src_tag('png')
18
+ end
19
+
20
+ test 'go_static_include_tag should return many go_static_javascript_src_tags' do
21
+ assert_equal [go_static_javascript_src_tag('foo'), go_static_javascript_src_tag('bar')].join("\n"),
22
+ go_static_javascript_include_tag('foo', 'bar')
23
+ end
24
+ end
@@ -0,0 +1,82 @@
1
+ require 'test_helper'
2
+
3
+ GoStatic.config = { :exe_path => '/usr/local/bin/wkhtmltoimage' }
4
+ HTML_DOCUMENT = "<html><body>Hello World</body></html>"
5
+
6
+ # Provide a public accessor to the normally-private parse_options function
7
+ class GoStatic
8
+ def get_parsed_options(opts)
9
+ parse_options(opts)
10
+ end
11
+ end
12
+
13
+ class GoStaticTest < ActiveSupport::TestCase
14
+
15
+ test "should generate PDF from html document" do
16
+ wp = GoStatic.new
17
+ png = wp.png_from_string HTML_DOCUMENT
18
+ assert png.length > 100
19
+ end
20
+
21
+ test "should raise exception when no path to wkhtmltopng" do
22
+ assert_raise RuntimeError do
23
+ GoStatic.new " "
24
+ end
25
+ end
26
+
27
+ test "should raise exception when wkhtmltopng path is wrong" do
28
+ assert_raise RuntimeError do
29
+ GoStatic.new "/i/do/not/exist/notwkhtmltopng"
30
+ end
31
+ end
32
+
33
+ test "should raise exception when wkhtmltopng is not executable" do
34
+ begin
35
+ tmp = Tempfile.new('wkhtmltopng')
36
+ fp = tmp.path
37
+ File.chmod 0000, fp
38
+ assert_raise RuntimeError do
39
+ GoStatic.new fp
40
+ end
41
+ ensure
42
+ tmp.delete
43
+ end
44
+ end
45
+
46
+ test "should raise exception when png generation fails" do
47
+ begin
48
+ tmp = Tempfile.new('wkhtmltopng')
49
+ fp = tmp.path
50
+ File.chmod 0777, fp
51
+ wp = GoStatic.new fp
52
+ assert_raise RuntimeError do
53
+ wp.png_from_string HTML_DOCUMENT
54
+ end
55
+ ensure
56
+ tmp.delete
57
+ end
58
+ end
59
+
60
+ test "should parse other options" do
61
+ wp = GoStatic.new
62
+
63
+ =begin
64
+ [ :orientation, :page_size, :proxy, :username, :password, :cover, :dpi,
65
+ :encoding, :user_style_sheet
66
+ ].each do |o|
67
+ assert_equal "--#{o.to_s.gsub('_', '-')} \"opts\"", wp.get_parsed_options(o => "opts").strip
68
+ end
69
+
70
+ [:redirect_delay, :zoom, :page_offset].each do |o|
71
+ assert_equal "--#{o.to_s.gsub('_', '-')} 5", wp.get_parsed_options(o => 5).strip
72
+ end
73
+
74
+ [ :book, :default_header, :disable_javascript, :grayscale, :lowquality,
75
+ :enable_plugins, :disable_internal_links, :disable_external_links,
76
+ :print_media_type, :disable_smart_shrinking, :use_xserver, :no_background
77
+ ].each do |o|
78
+ assert_equal "--#{o.to_s.gsub('_', '-')}", wp.get_parsed_options(o => true).strip
79
+ end
80
+ =end
81
+ end
82
+ end
@@ -0,0 +1,19 @@
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 StaticHelperTest < ActionController::TestCase
12
+ def setup
13
+ @ac = ActionController::Base.new
14
+ end
15
+
16
+ def teardown
17
+ @ac=nil
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'rails'
4
+ require 'action_controller/test_case'
5
+ require 'go_static'
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: go_static
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Lleir Borras Metje
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-06-21 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: |
22
+ GoStatic uses the shell utility wkhtmltoimage to serve an image file to a user from HTML.
23
+ You simply write an HTML view as you would normally, and let GoStatic take care of the hard stuff.
24
+
25
+ email: lleir@llegeix.me
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - README.md
34
+ - Rakefile
35
+ - MIT-LICENSE
36
+ - lib/generators/go_static_generator.rb
37
+ - lib/go_static.rb
38
+ - lib/go_static_helper.rb
39
+ - lib/go_static_railtie.rb
40
+ - lib/go_static_tempfile.rb
41
+ - lib/static_helper.rb
42
+ - test/fixtures/static.css
43
+ - test/go_static_helper_test.rb
44
+ - test/go_static_test.rb
45
+ - test/static_helper_test.rb
46
+ - test/test_helper.rb
47
+ homepage: http://github.com/lleirborras/go_static
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.15
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: Render views in Ruby on Rails written in html to an image (png, ...)
80
+ test_files: []
81
+