diff --git a/README.mdown b/README.mdown index 244dabf..23d6c98 100644 --- a/README.mdown +++ b/README.mdown @@ -1,97 +1,19 @@ -# Tilt::PDF +# Tilt::PDF::Rails -Integrates PDF generation into a Tilt flow for maxxed out ease of use. +Integrates Tilt::PDF into Rails ActionView -Contrary to other solutions, all files will be rendered locally without relying -on a web server. It follows that even if used in a web server, no concurrent -requests are being made to render assets. +See [Tilt::PDF](https://github.com/lloeki/tilt-pdf) for details about the templates themselves. -## Dependencies - -This gem depends on PDFKit, which in turn requires `wkhtmltopdf`. It is -recommended to use the statically compiled version of the latter, as it is -built against a patched QT that supports more features. - -## Usage as a Tilt template - -Add `tilt-pdf` to your Gemfile. Also add any template engine you may optionally -want, such as `less` or `slim`. - -A `foo` template is currently threefold: - -- `foo.rpdf`: this file is a YAML file containing options pertaining to the PDF - generation process, such as page size, orientation, metadata, support files, - headers and footers. Some options are passed as is to PDFKit, and - subsequently to `wkhtmltopdf`. -- `foo.html`: this document can be written in any template language you need - (such as ERB or Slim), and the Tilt template resolution system via extension - chaining will apply. Tilt will pass the render block to be yielded to this - document. -- `foo.css`: this stylesheet can be written in any template language you need - (such as Sass or Less), and the Tilt template resolution system via extension - chaining will apply. Tilt will *not* pass the block to be yielded to this - template. - -The three files must currently be stored in the *same* directory. - -Rendering is done the usual Tilt way: +## Usage ```ruby -require 'tilt-pdf' - -pdf = Tilt.new('foo.rpdf').render() +gem 'tilt-pdf-rails' ``` -## The rpdf file +Have a `FooController` `respond_to :pdf` and `render some_view` as usual. -This file contains options. If empty, it is made to 'just work' as -summplemental files will be looked up according to its basename. +Put your `some_view` template files either *together* in the relevant +`app/views/foo` view directory, or use absolute paths using application/engine +root. -- `main`: document body, overriding the default derived from the basename. -- `footer` and `header`: html that will get used for (surprise!) header and - footers. -- `stylesheets`: list of stylesheets to include (used for all html, incl. - headers/footers). Defaults to one file from the basename. -- `javascripts`: list of javascripts to include (used for all html, incl. - headers/footers). Defaults to one file from the basename. -- `pdfkit`: While a few PDFKit options are made available at the toplevel for - convenience, this key passes all options as-is to PDFKit. - -Example: - -``` -title: Foorever young -page-size: A4 -orientation: landscape -grayscale: true -margin-left: 0 -margin-right: 0 -margin-top: 0 -margin-bottom: 0 -pdfkit: - print-media-type: true -main: foorever_young.html.slim -stylesheets: - - novel.css.less - - common.css -javascripts: - - page_numbering.js.coffee -footer: footer.html.slim -``` - -Filenames can be relative or absolute. When relative, they will be evaluated -as based from the rpdf file. - -## Rails and ActionView integration - -Require `tilt/pdf/rails` if you want to set up and register `tilt-pdf` as an -ActionView template handler. You can do it in an initializer, or straight from -the Gemfile: - -```ruby -gem 'tilt-pdf', require: 'tilt/pdf/rails' -``` - -Put your three template files *together* in the relevant `app/views/foo` view -directory, or use absolute paths using application/engine root. Work is in -progress to enable better integration with Rails file layout. +Work is in progress to enable better integration with Rails file layout (notably assets). diff --git a/lib/tilt-pdf-rails.rb b/lib/tilt-pdf-rails.rb new file mode 100644 index 0000000..4432e02 --- /dev/null +++ b/lib/tilt-pdf-rails.rb @@ -0,0 +1 @@ +require 'tilt/pdf/rails' diff --git a/lib/tilt-pdf.rb b/lib/tilt-pdf.rb deleted file mode 100644 index 4f638a3..0000000 --- a/lib/tilt-pdf.rb +++ /dev/null @@ -1 +0,0 @@ -require 'tilt/pdf' diff --git a/lib/tilt/pdf.rb b/lib/tilt/pdf.rb deleted file mode 100644 index d580869..0000000 --- a/lib/tilt/pdf.rb +++ /dev/null @@ -1,211 +0,0 @@ -require 'pdfkit' -require 'tilt' -require 'tilt/template' -require 'yaml' -require 'tempfile' -require 'pry' - -module Tilt - class PDFTemplate < Template - self.default_mime_type = 'application/pdf' - - def prepare; end - - def evaluate(scope, locals, &block) - files = aux_files - files << main_html_file - render_to_tmp(*files, scope, locals, block) do |tmp| - opts = pdfkit_options - - if header - htmp = tmp.select { |_, f, _| f == header }.first[2] - opts.merge!('header-html' => htmp) if header - end - - if footer - ftmp = tmp.select { |_, f, _| f == footer }.first[2] - opts.merge!('footer-html' => ftmp) if footer - end - - main = tmp.select { |_, f, _| f == main_html_file }.first[2] - kit = PDFKit.new(File.read(main), opts) - - @output = kit.to_pdf - end - - @output - end - - private - - def absolutize(path) - Pathname.new(path).absolute? ? path : File.join(dirname, path) - end - - def config - @config = (YAML.load(data) || {}) - end - - def aux_files - files = [] - files.concat css_files - files.concat js_files - files << header if header - files << footer if footer - - files - end - - def header - if (f = config['header']) - absolutize(f) - end - end - - def footer - if (f = config['footer']) - absolutize(f) - end - end - - def main_html_file - main_html_from_config || find_html - end - - def main_html_from_config - if (f = config['main']) - absolutize(f) - end - end - - def css_files - css_from_config || find_css - end - - def css_from_config - return unless config.key?('stylesheets') - - config.fetch('stylesheets', []).map { |f| absolutize(f) } - end - - def js_files - js_from_config || find_js - end - - def js_from_config - return unless config.key?('javascripts') - - config.fetch('javascripts', []).map { |f| absolutize(f) } - end - - def pdfkit_options - toplevel_options = %w[title - orientation - grayscale - page-size - margin-left - margin-right - margin-top - margin-bottom] - - options = config.select { |k, _| toplevel_options.include?(k) } - - options.merge config.fetch('pdfkit', {}) - end - - def dirname - File.dirname(eval_file) - end - - def find_html - Dir.glob(File.join(dirname, name + '.html*')).first - end - - def find_css - Dir.glob(File.join(dirname, name + '.css*')) - end - - def find_js - Dir.glob(File.join(dirname, name + '.js*')) - end - - def render_html(file, scope, locals, &block) - Tilt.new(file).render(scope, locals, &block) - end - - def inject_css!(document, stylesheet) - append_to_head!(document, "") - end - - def inject_js!(document, script) - append_to_head!(document, "") - end - - def append_to_head!(document, tag) - if document.match(/<\/head>/) - document.gsub!(/(<\/head>)/) { |s| tag + s } - else - document.insert(0, tag) - end - end - - def render_to_tmp(*files, scope, locals, block) - tmps = [] - no_tilt = %w[html css js] - - result = files.map do |file| - ext = File.extname(file).sub(/^\./, '') - if no_tilt.include?(ext) - mime = case ext - when 'js', 'javascript' then 'application/javascript' - else "text/#{ext}" - end - rendered = File.read(file) - else - template = Tilt.new(file) - mime = template.class.default_mime_type - ext = mime.split('/').last - rendered = template.render(scope, locals, &block) - end - - [ext, mime, file, rendered] - end - - result.sort! do |a, b| - a[1] <=> b[1] # css < html - end - - styles = result.select { |_, mime, _, _| mime == 'text/css' } - scripts = result.select { |_, mime, _, _| mime == 'application/javascript' } - result.map! do |ext, mime, file, rendered| - if mime == 'text/html' - styles.each do |_, _, _, style| - inject_css!(rendered, style) - end - scripts.each do |_, _, _, script| - inject_js!(rendered, script) - end - end - - [ext, mime, file, rendered] - end - - result.map! do |ext, mime, file, rendered| - tmp = Tempfile.new([File.basename(file), '.' + ext]) - tmps << tmp - tmp.write(rendered) - tmp.close - - path = tmp.path - - [mime, file, path] - end - - yield result - ensure - tmps.each { |tmp| tmp.close! } - end - end -end - -Tilt.register Tilt::PDFTemplate, 'rpdf' diff --git a/lib/tilt/pdf/rails/version.rb b/lib/tilt/pdf/rails/version.rb new file mode 100644 index 0000000..8607c22 --- /dev/null +++ b/lib/tilt/pdf/rails/version.rb @@ -0,0 +1,7 @@ +module Tilt + module PDF + module Rails + VERSION = '0.10.0' + end + end +end diff --git a/lib/tilt/pdf/version.rb b/lib/tilt/pdf/version.rb deleted file mode 100644 index 05c0a13..0000000 --- a/lib/tilt/pdf/version.rb +++ /dev/null @@ -1,5 +0,0 @@ -module Tilt - module PDF - VERSION = '0.9.0' - end -end diff --git a/tilt-pdf-rails.gemspec b/tilt-pdf-rails.gemspec new file mode 100644 index 0000000..9bf7900 --- /dev/null +++ b/tilt-pdf-rails.gemspec @@ -0,0 +1,21 @@ +# -*- encoding: utf-8 -*- +$LOAD_PATH.push File.expand_path('../lib', __FILE__) +require 'tilt/pdf/rails/version' + +Gem::Specification.new do |s| + s.name = 'tilt-pdf-rails' + s.version = Tilt::PDF::Rails::VERSION + s.authors = ['Loic Nageleisen'] + s.email = ['loic.nageleisen@gmail.com'] + s.homepage = 'http://github.com/lloeki/tilt-pdf-rails' + s.summary = %q{PDF files in Rails via Tilt} + s.description = %q{Integrates PDF generation with Tilt::PDF into ActionView} + s.license = 'MIT' + s.files = `git ls-files`.split("\n") + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") + s.executables = `git ls-files -- bin/*`.split("\n") + .map { |f| File.basename(f) } + s.require_paths = ['lib'] + + s.add_dependency 'tilt-pdf', '~> 0.10.0' +end diff --git a/tilt-pdf.gemspec b/tilt-pdf.gemspec deleted file mode 100644 index be402c3..0000000 --- a/tilt-pdf.gemspec +++ /dev/null @@ -1,31 +0,0 @@ -# -*- encoding: utf-8 -*- -$LOAD_PATH.push File.expand_path('../lib', __FILE__) -require 'tilt/pdf/version' - -Gem::Specification.new do |s| - s.name = 'tilt-pdf' - s.version = Tilt::PDF::VERSION - s.authors = ['Loic Nageleisen'] - s.email = ['loic.nageleisen@gmail.com'] - s.homepage = 'http://github.com/lloeki/tilt-pdf' - s.summary = %q{PDF files via Tilt} - s.description = %q{Integrates PDF generation into a Tilt flow} - s.license = 'MIT' - s.files = `git ls-files`.split("\n") - s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") - s.executables = `git ls-files -- bin/*`.split("\n") - .map { |f| File.basename(f) } - s.require_paths = ['lib'] - - s.add_dependency 'tilt', '~> 1.4.1' - s.add_dependency 'pdfkit', '~> 0.5.4' - - s.add_development_dependency 'therubyracer' - s.add_development_dependency 'less' - s.add_development_dependency 'coffee-script' - s.add_development_dependency 'slim' - s.add_development_dependency 'rspec', '~> 2.14' - s.add_development_dependency 'rake' - s.add_development_dependency 'guard-rspec' - s.add_development_dependency 'pry' -end