htmldoc-rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,6 @@
1
+ .DS_Store
2
+ *.tmproj
3
+ .yardoc
4
+ doc
5
+ test/tmp
6
+ test/tmp/*
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Elliot Winkler
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.
@@ -0,0 +1,69 @@
1
+ # htmldoc-rails
2
+
3
+ ## Summary
4
+
5
+ Generate PDFs from your Rails views using [HTMLDoc](http://www.htmldoc.org).
6
+
7
+ ## Usage
8
+
9
+ Let's say we've got this setup:
10
+
11
+ # controller
12
+ class FooController < ApplicationController
13
+ def bar
14
+ # render bar.html.erb
15
+ end
16
+ end
17
+
18
+ # view - bar.html.erb
19
+ <p>Some content goes here</p>
20
+
21
+ Now let's say we want to give the user a regular HTML view when they go to `/foo/bar`, but a PDF file when they go to `/foo/bar.pdf`. We can use `respond_to` to differentiate between the two course of actions, but as for generating the PDF file itself, `htmldoc-rails` provides a special method called `render_pdf`. This method is responsible for piping a view through HTMLDoc and telling the action to return a PDF file. It also accepts options such as which view you want the PDF to be generated from, whether or not a download box should appear, and so on (you can find the possible options in the [documentation](http://mcmire.github.com/htmldoc-rails/HtmldocRails/Controller.html#render_pdf-instance_method)). Since we want to use the HTML view to generate the PDF, all we have to say is this:
22
+
23
+ # controller
24
+ class FooController < ApplicationController
25
+ def bar
26
+ respond_to do |wants|
27
+ wants.html
28
+ wants.pdf { render_pdf }
29
+ end
30
+ end
31
+ end
32
+
33
+ ## Prerequisites
34
+
35
+ * HTMLDoc 1.9.x
36
+ * htmldoc gem
37
+
38
+ ## Installation
39
+
40
+ First, you'll need to download, compile, and install the htmldoc executable. If you're on Mac or Linux, this is really easy. Just head on over to [the HTMLDoc website](http://www.htmldoc.org/software.php). You'll see a link to download 1.8, but don't even bother with that, since 1.8.27 was released way back in 2006 and doesn't support CSS or tables very well. These days new improvements are being done (however occasionally) on the 1.9.x branch, so you'll want to download the latest developer snapshot instead (it worked fine for us). Once you've done that, you should be able to just
41
+
42
+ ./configure
43
+ make
44
+ sudo make install
45
+
46
+ If you happen to be on Windows, well, you aren't so lucky. If you're fine with using 1.8, you can find a pre-compiled copy either from the HTMLDoc website or from Cygwin. If you really want a version of 1.9, you'll have to look around -- possibly someone has been generous enough to put one out there.
47
+
48
+ Once you've got the htmldoc executable installed, you'll need the htmldoc Ruby gem, which provides a thin wrapper around the executable. Just
49
+
50
+ gem install htmldoc
51
+
52
+ Finally, you can install this gem:
53
+
54
+ * `gem install htmldoc-rails` (probably as root)
55
+ * Add `config.gem 'htmldoc-rails'` to your environment.rb file
56
+
57
+ ## Compatibility
58
+
59
+ This gem has been tested successfully on Rails 2.1.2, 2.2.3, and 2.3.5 under Ruby 1.8.6, 1.8.7, and 1.9.1.
60
+
61
+ ## I found a bug!
62
+
63
+ Great! File a [Github issue](http://github.com/mcmire/htmldoc-rails/issues) so that I am aware of the problem and I will try to fix it as soon as I can. If you're able to figure out a solution on your own, feel free to write a patch and send it to me, or fork the [project on Github](http://github.com/mcmire/htmldoc-rails) and send me a pull request. Bonus points if you write tests -- that helps me out a lot.
64
+
65
+ If you need to get in contact with me, you can [find me on Twitter](http://twitter.com/mcmire) or [send me an email](mailto:elliot.winkler@gmail.com).
66
+
67
+ ## Author
68
+
69
+ (c) 2008-2010 Elliot Winkler. See LICENSE for details.
@@ -0,0 +1,95 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ require File.dirname(__FILE__) + "/lib/htmldoc_rails/version"
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.version = HtmldocRails::VERSION
10
+ gem.name = "htmldoc-rails"
11
+ gem.summary = %Q{Generate PDFs from your Rails views using HTMLDoc}
12
+ gem.description = %Q{Generate PDFs from your Rails views using HTMLDoc}
13
+ gem.email = "elliot.winkler@gmail.com"
14
+ gem.homepage = "http://github.com/mcmire/htmldoc-rails"
15
+ gem.authors = ["Elliot Winkler"]
16
+ gem.add_dependency "htmldoc"
17
+ unless ENV["AP_VERSION"]
18
+ gem.add_dependency "actionpack", "< 3.0"
19
+ end
20
+ gem.add_development_dependency "mcmire-protest"
21
+ gem.add_development_dependency "mcmire-matchy"
22
+ gem.add_development_dependency "mcmire-mocha"
23
+ gem.add_development_dependency "mocha-protest-integration"
24
+ gem.add_development_dependency "yard", ">= 0"
25
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
26
+ end
27
+ Jeweler::GemcutterTasks.new
28
+ rescue LoadError
29
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
30
+ end
31
+
32
+ require 'rake/testtask'
33
+ Rake::TestTask.new(:test) do |test|
34
+ test.libs << 'lib' << 'test'
35
+ test.pattern = 'test/**/test_*.rb'
36
+ test.verbose = true
37
+ end
38
+
39
+ namespace :test do
40
+ def run(*cmd)
41
+ cmd = cmd.flatten
42
+ options = Hash === cmd.last ? cmd.pop : {}
43
+ cmd.unshift("sudo") if options[:sudo]
44
+ puts cmd.join(" ")
45
+ system(*cmd)
46
+ exit if $? != 0
47
+ end
48
+ def run_gem(*cmd)
49
+ run "gem", cmd, :sudo => (ENV["GEM_PATH"] !~ /rvm/)
50
+ end
51
+
52
+ task :all do
53
+ require File.dirname(__FILE__) + '/test/all'
54
+ end
55
+
56
+ task :install_dependencies do
57
+ puts
58
+ puts "Installing dev test gems..."
59
+ puts
60
+ run_gem %w(install jeweler htmldoc mcmire-protest mcmire-matchy mcmire-mocha mocha-protest-integration)
61
+ for version in %w(2.1.2 2.2.3 2.3.5)
62
+ puts
63
+ puts "Installing rails v#{version}..."
64
+ puts
65
+ run_gem %w(install rails -v), version
66
+ end
67
+ puts
68
+ end
69
+ end
70
+
71
+ task :check_platform do
72
+ if RUBY_PLATFORM !~ /darwin|linux/
73
+ warn <<-EOT
74
+ Sorry, you can only run the tests if you're on Mac or Linux. This is because the
75
+ tests use the `file` command to detect file type, but to my knowledge this
76
+ command is only available on Mac or Linux.
77
+ EOT
78
+ exit 1
79
+ end
80
+ end
81
+
82
+ task :test => [:check_platform, :check_dependencies, :"check_dependencies:development"]
83
+
84
+ task :default => :test
85
+
86
+ begin
87
+ require 'yard'
88
+ YARD::Rake::YardocTask.new do |t|
89
+ t.options = ['--no-private']
90
+ end
91
+ rescue LoadError
92
+ task :yardoc do
93
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
94
+ end
95
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'mcmire/render_htmldoc_pdf'
@@ -0,0 +1 @@
1
+ require 'htmldoc_rails'
@@ -0,0 +1,20 @@
1
+ require 'htmldoc_rails/htmldoc_ext'
2
+ require 'htmldoc_rails/controller'
3
+
4
+ module HtmldocRails
5
+ class << self
6
+ # @private
7
+ def action_view
8
+ ActionPack::VERSION::MAJOR == 1 ? ActionView::Base : ActionView::Template
9
+ end
10
+ def debug=(mode)
11
+ @debug = mode
12
+ end
13
+ def debug?
14
+ @debug
15
+ end
16
+ end
17
+ end
18
+
19
+ ActionController::Base.send(:include, HtmldocRails::Controller)
20
+ Mime::Type.register('application/pdf', :pdf)
@@ -0,0 +1,97 @@
1
+ module HtmldocRails
2
+ module Controller
3
+ # Runs the given view through HTMLDoc and sends the generated PDF data back
4
+ # to the browser.
5
+ #
6
+ # @param [Hash] options Various options
7
+ # @option options [Hash, String] :url (nil) The hash/url that represents which
8
+ # view you want to render. Passed straight to <tt>render()</tt>.
9
+ # @option options [Symbol] :as (:inline) The disposition; <tt>:inline</tt>
10
+ # renders the PDF in the browser, <tt>:attachment</tt> pops up a download
11
+ # box when the page loads. You can also set the disposition at runtime
12
+ # by appending <tt>?as=attachment|inline</tt> to the URL.
13
+ # @option options [String] :filename (nil) The default filename for the file being
14
+ # downloaded, assuming <tt>:as => :attachment</tt>.
15
+ # @option options [Hash] :htmldoc ({}) Options that will be passed to HTMLDoc
16
+ # when the PDF is rendered.
17
+ #
18
+ # @example Rendering default view of action as PDF
19
+ # render_pdf
20
+ # @example Rendering a specific view as PDF
21
+ # render_pdf :action => 'bar'
22
+ # @example Set a top-margin of 50px in the PDF and force a download box when the page loads
23
+ # render_pdf :action => "bar", :as => :attachment, :htmldoc => { :top => 50 }
24
+ #
25
+ def render_pdf(options={})
26
+ filename = options.delete(:filename)
27
+ disposition = (options.delete(:as) || params[:as] || :inline).to_sym
28
+ htmldoc_options = options.delete(:htmldoc) || {}
29
+ render_options = options.merge(options.delete(:url) || {})
30
+ if !render_options.include?(:layout)
31
+ render_options[:layout] = false
32
+ end
33
+
34
+ send_data_options = { :type => content_type }
35
+ send_data_options[:filename] = filename if filename
36
+ send_data_options[:disposition] = (disposition == :attachment) ? 'attachment' : 'inline'
37
+
38
+ # Make sure that the rendered PDF isn't cached
39
+ if request.env['HTTP_USER_AGENT'] =~ /msie/i
40
+ headers['Pragma'] = ''
41
+ headers['Cache-Control'] = ''
42
+ else
43
+ headers['Pragma'] = 'no-cache'
44
+ headers['Cache-Control'] = 'no-cache, must-revalidate'
45
+ end
46
+
47
+ # Run view through PDF::HTMLDoc::View
48
+ html_content = render_to_string(render_options)
49
+ pdf_data = run_through_htmldoc(html_content, htmldoc_options)
50
+ unless pdf_data.blank?
51
+ send_data(pdf_data, send_data_options)
52
+ else
53
+ render :text => "HTMLDoc had trouble parsing the HTML to create the PDF."
54
+ end
55
+ end
56
+
57
+ # Runs the given view through HTMLDoc and writes the generated PDF data
58
+ # to the file of your choice.
59
+ #
60
+ # @param [String] filename The outfile
61
+ # @param [Hash, String] render_options The hash/url that represents which
62
+ # view you want to render. Passed straight to <tt>render()</tt>.
63
+ # @param [Hash] htmldoc_options Options that will be passed to HTMLDoc
64
+ # when the PDF is rendered.
65
+ #
66
+ # @example Render the 'blah' view to 'foo.pdf'
67
+ # render_pdf_to_file 'foo.pdf', :action => 'blah'
68
+ # @example Same thing, but set a top-margin of 50px in the PDF
69
+ # render_pdf_to_file 'foo.pdf', { :action => 'blah' }, { :top => 50 }
70
+ #
71
+ def render_pdf_to_file(filename, render_options={}, htmldoc_options={})
72
+ if !render_options.include?(:layout)
73
+ render_options[:layout] = false
74
+ end
75
+ headers["Content-Disposition"] = "inline"
76
+ html_content = render_to_string(render_options)
77
+ pdf_data = run_through_htmldoc(html_content, htmldoc_options)
78
+ File.open(filename, 'w') {|f| f.write(pdf_data) }
79
+ end
80
+
81
+ private
82
+ def run_through_htmldoc(content, htmldoc_options)
83
+ PDF::HTMLDoc.create do |pdf|
84
+ PDF::HTMLDoc::DEFAULT_OPTIONS.merge(htmldoc_options).each do |name, value|
85
+ pdf.set_option(name, value)
86
+ end
87
+ # don't know what this does??
88
+ pdf.set_option :path, Pathname.new(File.join(RAILS_ROOT, 'public')).realpath.to_s
89
+ pdf << content
90
+ end
91
+ end
92
+
93
+ def content_type
94
+ Mime::Type.lookup_by_extension('pdf')
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,24 @@
1
+ # Extend 'htmldoc' gem to support the edge releases of the htmldoc executable
2
+ # and to make usage a bit more intuitive
3
+ module PDF
4
+ class HTMLDoc
5
+ @@basic_options << :top unless @@basic_options.include?(:top)
6
+ @@basic_options << :bottom unless @@basic_options.include?(:bottom)
7
+ @@all_options = @@basic_options + @@extra_options
8
+
9
+ DEFAULT_OPTIONS = {
10
+ :bodycolor => 'white',
11
+ :toc => false,
12
+ :portrait => true,
13
+ :continuous => true,
14
+ :footer => '...',
15
+ :header => '...',
16
+ :links => false,
17
+ :webpage => true,
18
+ :left => '50',
19
+ :right => '50',
20
+ :top => '90',
21
+ :size => 'Letter'
22
+ }
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ module HtmldocRails
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,32 @@
1
+ require 'pathname'
2
+
3
+ proj_dir = File.expand_path(File.dirname(__FILE__) + '/..')
4
+ lib_dir = "#{proj_dir}/lib"
5
+ test_dir = "#{proj_dir}/test"
6
+
7
+ $:.unshift(lib_dir, test_dir)
8
+
9
+ files = Dir["#{test_dir}/test_*.rb"]
10
+
11
+ pids = []
12
+
13
+ %w(2.1.2 2.2.3 2.3.5).each do |version|
14
+ (class << $stdout; self; end).class_eval <<-EOT, __FILE__, __LINE__
15
+ def puts(*str)
16
+ str = str.flatten
17
+ str[0] = "#{version})) \#{str[0]}"
18
+ super(*str)
19
+ end
20
+ def print(*str)
21
+ str = str.flatten
22
+ str[0] = "#{version})) \#{str[0]}"
23
+ super(*str)
24
+ end
25
+ EOT
26
+
27
+ pids << fork do
28
+ ENV["AP_VERSION"] = version
29
+ files.each {|file| require file }
30
+ end
31
+ end
32
+ pids.each {|pid| Process.wait(pid) }
@@ -0,0 +1,136 @@
1
+ require 'rubygems'
2
+
3
+ require 'pp'
4
+
5
+ gem 'mcmire-protest'
6
+ require 'protest'
7
+ gem 'mcmire-mocha'
8
+ require 'mocha'
9
+ # This must be required before matchy since matchy patches
10
+ # the current test case's #run method, however mocha-protest-integration
11
+ # completely overrides it
12
+ require 'mocha-protest-integration'
13
+ #gem 'mcmire-matchy'
14
+ $:.unshift "/Users/elliot/code/github/forks/matchy/lib"
15
+ require 'matchy'
16
+
17
+ # Matchy/Protest integration
18
+ Matchy.adapter :protest, "Protest" do
19
+ def assertions_module; Test::Unit::Assertions; end
20
+ def test_case_class; Protest::TestCase; end
21
+ def assertion_failed_error; Protest::AssertionFailed; end
22
+ end
23
+ Matchy.use(:protest)
24
+
25
+ Protest.report_with :documentation
26
+ Protest::Utils::BacktraceFilter::ESCAPE_PATHS << %r|test/unit| << %r|matchy| << %r|mocha-protest-integration| << %r|actionpack|
27
+ #Protest::Utils::BacktraceFilter::ESCAPE_PATHS.clear
28
+
29
+ #----
30
+
31
+ if ENV["AP_VERSION"]
32
+ gem 'actionpack', "= #{ENV["AP_VERSION"]}"
33
+ end
34
+
35
+ require 'action_controller'
36
+
37
+ # Since ActionController::TestCase in 2.3.5 tries to require Mocha
38
+ # and replaces it with a stub on failure we have to save a reference
39
+ # to the current class and then replace the stub Mocha with the real Mocha
40
+ CurrentMocha = Mocha
41
+ require 'action_controller/test_case'
42
+ Object.const_set :Mocha, CurrentMocha
43
+
44
+ require 'action_controller/integration'
45
+ require 'action_view'
46
+ require 'action_pack/version'
47
+ require 'active_support/version'
48
+
49
+ puts
50
+ puts " -- Using ActionPack v#{ActionPack::VERSION::STRING}, on Ruby #{RUBY_VERSION}."
51
+ puts
52
+
53
+ RAILS_ROOT = File.expand_path(File.dirname(__FILE__))
54
+ RAILS_ENV = "test"
55
+
56
+ #logger = Logger.new(STDOUT)
57
+ #logger.level = Logger::DEBUG
58
+ #ActionController::Base.logger = logger
59
+
60
+ # Disable sessions so we don't get a 'key is required to write a cookie
61
+ # containing the session data' error
62
+ ActionController::Base.session_store = nil
63
+
64
+ module Protest
65
+ module Rails
66
+ # Copied from ActionController::TestCase
67
+ class FunctionalTestCase < ::Protest::TestCase
68
+ include ActionController::TestProcess
69
+
70
+ # When the request.remote_addr remains the default for testing, which is 0.0.0.0, the exception is simply raised inline
71
+ # (bystepping the regular exception handling from rescue_action). If the request.remote_addr is anything else, the regular
72
+ # rescue_action process takes place. This means you can test your rescue_action code by setting remote_addr to something else
73
+ # than 0.0.0.0.
74
+ #
75
+ # The exception is stored in the exception accessor for further inspection.
76
+ module RaiseActionExceptions
77
+ attr_accessor :exception
78
+
79
+ def rescue_action(e)
80
+ self.exception = e
81
+
82
+ if request.remote_addr == "0.0.0.0"
83
+ raise(e)
84
+ else
85
+ super(e)
86
+ end
87
+ end
88
+ end
89
+
90
+ @@controller_class = nil
91
+
92
+ class << self
93
+ def controller_class=(new_class)
94
+ prepare_controller_class(new_class)
95
+ write_inheritable_attribute(:controller_class, new_class)
96
+ end
97
+
98
+ def controller_class
99
+ if current_controller_class = read_inheritable_attribute(:controller_class)
100
+ current_controller_class
101
+ end
102
+ end
103
+
104
+ def prepare_controller_class(new_class)
105
+ new_class.send :include, RaiseActionExceptions
106
+ end
107
+ end
108
+
109
+ attr_reader :controller, :request, :response
110
+
111
+ setup do
112
+ @controller = self.class.controller_class.new
113
+ @controller.request = @request = ActionController::TestRequest.new
114
+ @response = ActionController::TestResponse.new
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ require 'htmldoc'
121
+
122
+ #----
123
+
124
+ # This is only here so our template handler won't complain
125
+ module ApplicationHelper; end
126
+
127
+ ActionController::Routing::Routes.draw do |map|
128
+ map.connect ':controller/:action'
129
+ end
130
+
131
+ require 'htmldoc-rails'
132
+
133
+ # This has to be set after we require htmldoc-rails and consequently
134
+ # after rpdf is added to the template handlers, that way the Template objects
135
+ # have rpdf stored as the extension
136
+ ActionController::Base.view_paths = File.expand_path(File.dirname(__FILE__) + '/views')
@@ -0,0 +1,21 @@
1
+ AV::Template#initialize("/full/path/to/render_pdf/doc.rpdf")
2
+ - AV::Template#split("/full/path/to/render_pdf/doc.rpdf")
3
+ - AV::Template#valid_extension?("rpdf") #=> [base_path = "/full/path/to/render_pdf/", name = "doc", format = nil, extension = "rpdf"]
4
+
5
+ AC::Base#render(options = {:action => 'doc.rpdf', :layout => false}, extra_options = {}):
6
+ - AC::Base#pick_layout(options = {:action => 'doc.rpdf', :layout => false}) #=> nil
7
+ - AC::Base#default_template_name(action_name = "doc.rpdf") #=> "render_pdf/doc.rpdf"
8
+ - AC::Base#render_for_file(action_name = "render_pdf/doc.rpdf", status = nil, layout = nil, locals = {})
9
+ - AV::Base#render(options = {:file => "render_pdf/doc.rpdf", :locals => {}, :layout => nil}, local_assigns = {})
10
+ - AV::Base#_pick_template(template_path = "render_pdf/doc.rpdf") #=> AV::Template.new("/full/path/to/render_pdf/doc.rpdf")
11
+ - AV::Template#render_template(view, locals = {})
12
+ - AV::Template#render(view, locals = {}) # in Renderable
13
+ - AV::Template#compile(locals = {}) # in Renderable
14
+ - AV::Template#recompile?(render_symbol) #=> true # in Renderable
15
+ - AV::PathSet::Path.eager_load_templates? #=> false since config.cache_classes is false
16
+ - AV::Template#compile!(render_symbol, local_assigns = {}) # in Renderable
17
+ - AV::Template#compiled_source #=> "the template" # Renderable
18
+ - AV::Template#handler
19
+ - AV::Template.handler_class_for_extension(extension = "rpdf") #=> should return PDF::HTMLDoc::View?? # in TemplateHandlers
20
+ - PDF::HTMLDoc::View#call #=> "PDF::HTMLDoc::View.new(self).render(template, local_assigns)"
21
+ - PDF::HTMLDoc::View.new(view).render(template, local_assigns = {})
@@ -0,0 +1,156 @@
1
+ require 'helper'
2
+
3
+ class RenderPdfController < ActionController::Base
4
+ def default
5
+ render_pdf :action => 'doc.html.erb'
6
+ end
7
+ def default_with_layout
8
+ render_pdf :action => 'doc.html.erb', :layout => "layout"
9
+ end
10
+ def download
11
+ render_pdf :url => {:action => 'doc.html.erb'}, :as => :attachment
12
+ end
13
+ def download_with_filename
14
+ render_pdf :url => {:action => 'doc.html.erb'}, :as => :attachment, :filename => "foo.pdf"
15
+ end
16
+ def with_just_filename
17
+ render_pdf :url => {:action => 'doc.html.erb'}, :filename => "foo.pdf"
18
+ end
19
+ def inline_with_filename
20
+ render_pdf :url => {:action => 'doc.html.erb'}, :as => :inline, :filename => "foo.pdf"
21
+ end
22
+ def with_htmldoc_options
23
+ render_pdf :action => 'doc.html.erb', :htmldoc => {:top => 10, :left => 10}
24
+ end
25
+ def with_no_url
26
+ render_pdf
27
+ end
28
+ def partial
29
+ render_pdf :action => 'doc_with_partial.html.erb'
30
+ end
31
+ def responder
32
+ respond_to do |wants|
33
+ wants.html { render :text => "HTML" }
34
+ wants.pdf { render_pdf :action => 'doc.html.erb' }
35
+ end
36
+ end
37
+ def no_arguments
38
+ render_pdf
39
+ end
40
+ def rpdf
41
+ render_pdf :action => 'doc.rpdf'
42
+ end
43
+ end
44
+
45
+ module RenderPdfHelper; end
46
+
47
+ Protest::Rails::FunctionalTestCase.describe("render_pdf") do
48
+ self.controller_class = RenderPdfController
49
+
50
+ def visit(url, options={})
51
+ get(url, options)
52
+ #puts "Headers:"
53
+ #pp :headers => response.headers
54
+ #puts "Response body:"
55
+ #puts response.body unless response.success?
56
+ end
57
+
58
+ def should_render_a_pdf
59
+ response.content_type.should == 'application/pdf'
60
+ tempfile = Tempfile.new("test_htmldoc_rails")
61
+ tempfile.write(response.body)
62
+ `file -Ib "#{tempfile.path}"`.chomp.should == "application/pdf"
63
+ end
64
+
65
+ test "converts a view into a PDF with the right content type" do
66
+ visit :default
67
+ should_render_a_pdf
68
+ end
69
+ test "returns an error if the PDF file couldn't be generated for some reason" do
70
+ PDF::HTMLDoc.stubs(:create).returns(nil)
71
+ visit :default
72
+ response.body.should =~ /HTMLDoc had trouble parsing the HTML to create the PDF/
73
+ end
74
+ test ":url option is required" do
75
+ lambda { visit :with_no_url }.should raise_error
76
+ end
77
+
78
+ test "the PDF file is rendered with no layout by default" do
79
+ controller.stubs(:render_to_string).returns("")
80
+ visit :default
81
+ controller.should have_received(:render_to_string).with(has_entry(:layout, false))
82
+ end
83
+ test "the PDF file is rendered with a layout if one was specified" do
84
+ controller.stubs(:render_to_string).returns("")
85
+ visit :default_with_layout
86
+ controller.should have_received(:render_to_string).with(has_entry(:layout, "layout"))
87
+ end
88
+
89
+ test "renders the PDF in the browser by default" do
90
+ visit :default
91
+ response.headers["Content-Disposition"].should == "inline"
92
+ end
93
+ test ":as => :attachment option gives the user a download box" do
94
+ visit :download
95
+ response.headers["Content-Disposition"].should == "attachment"
96
+ end
97
+ test ":filename option when disposition is attachment pre-sets the filename that the user will download the PDF as" do
98
+ visit :download_with_filename
99
+ response.headers["Content-Disposition"].should == 'attachment; filename="foo.pdf"'
100
+ end
101
+ test ":filename option without disposition does not auto-set disposition to attachment" do
102
+ visit :with_just_filename
103
+ response.headers["Content-Disposition"].should == 'inline; filename="foo.pdf"'
104
+ end
105
+ test ":filename option when disposition is inline sets filename" do
106
+ visit :inline_with_filename
107
+ response.headers["Content-Disposition"].should == 'inline; filename="foo.pdf"'
108
+ end
109
+ test "?as=attachment in the querystring gives the user a download box" do
110
+ visit :download, :as => "attachment"
111
+ response.headers["Content-Disposition"].should == "attachment"
112
+ end
113
+ test "?as=inline in the querystring renders the PDF in the browser" do
114
+ visit :default, :as => "inline"
115
+ #response.success?.should == true
116
+ response.headers["Content-Disposition"].should == "inline"
117
+ end
118
+
119
+ test "sends headers to ensure that the PDF file isn't cached" do
120
+ visit :default
121
+ response.headers["Pragma"].should == "no-cache"
122
+ response.headers["Cache-Control"].should == 'no-cache, must-revalidate'
123
+ end
124
+ test "doesn't ensure PDF file isn't cached on IE" do
125
+ request.env['HTTP_USER_AGENT'] = "msie"
126
+ visit :default
127
+ response.headers["Pragma"].should == ""
128
+ response.headers["Cache-Control"].should == ""
129
+ end
130
+
131
+ test "forwards :htmldoc options straight to HTMLDoc" do
132
+ pdf = PDF::HTMLDoc.new
133
+ pdf.stubs(:set_option)
134
+ PDF::HTMLDoc.stubs(:create).returns("").yields(pdf)
135
+ visit :with_htmldoc_options
136
+ pdf.should have_received(:set_option).with(:left, 10)
137
+ pdf.should have_received(:set_option).with(:top, 10)
138
+ end
139
+
140
+ test "rendering a partial within a view works" do
141
+ visit :partial
142
+ should_render_a_pdf
143
+ end
144
+
145
+ test "rendering a view in a responder works" do
146
+ request.accept = "application/pdf"
147
+ visit :responder
148
+ should_render_a_pdf
149
+ end
150
+
151
+ test "renders a file named after the action if passed no arguments" do
152
+ visit :no_arguments
153
+ should_render_a_pdf
154
+ end
155
+
156
+ end
@@ -0,0 +1,78 @@
1
+ require 'helper'
2
+
3
+ class RenderPdfToFileController < ActionController::Base
4
+ def default
5
+ render_pdf_to_file "/tmp/htmldoc-rails.test.pdf", :action => 'doc.html.erb'
6
+ render :nothing => true
7
+ end
8
+ def default_with_layout
9
+ render_pdf_to_file "/tmp/htmldoc-rails.test.pdf", :action => 'doc.html.erb', :layout => "layout"
10
+ render :nothing => true
11
+ end
12
+ def with_htmldoc_options
13
+ render_pdf_to_file "/tmp/htmldoc-rails.test.pdf", {:action => 'doc.html.erb'}, :top => 10, :left => 10
14
+ render :nothing => true
15
+ end
16
+ def partial
17
+ render_pdf_to_file "/tmp/htmldoc-rails.test.pdf", :action => 'doc_with_partial.html.erb'
18
+ render :nothing => true
19
+ end
20
+ def no_arguments
21
+ render_pdf_to_file "/tmp/htmldoc-rails.test.pdf"
22
+ render :nothing => true
23
+ end
24
+ end
25
+
26
+ module RenderPdfToFileHelper; end
27
+
28
+ Protest::Rails::FunctionalTestCase.describe("render_pdf_to_file") do
29
+ self.controller_class = RenderPdfToFileController
30
+
31
+ def visit(url, options={})
32
+ get(url, options)
33
+ #puts "Headers:"
34
+ #pp :headers => response.headers
35
+ #puts "Response body:"
36
+ #puts response.body unless response.success?
37
+ end
38
+
39
+ def should_render_a_pdf
40
+ File.exists?("/tmp/htmldoc-rails.test.pdf").should == true
41
+ `file -Ib "/tmp/htmldoc-rails.test.pdf"`.chomp.should == "application/pdf"
42
+ end
43
+
44
+ test "writes the rendered PDF to the given file" do
45
+ visit :default
46
+ should_render_a_pdf
47
+ end
48
+ test "sends the PDF straight to the browser" do
49
+ visit :default
50
+ response.headers["Content-Disposition"].should == "inline"
51
+ end
52
+ test "forwards :htmldoc options straight to HTMLDoc" do
53
+ pdf = PDF::HTMLDoc.new
54
+ pdf.stubs(:set_option)
55
+ PDF::HTMLDoc.stubs(:create).returns("").yields(pdf)
56
+ visit :with_htmldoc_options
57
+ pdf.should have_received(:set_option).with(:left, 10)
58
+ pdf.should have_received(:set_option).with(:top, 10)
59
+ end
60
+ test "renders the PDF in no layout by default" do
61
+ controller.stubs(:render_to_string).returns("")
62
+ visit :default
63
+ controller.should have_received(:render_to_string).with(has_entry(:layout, false))
64
+ end
65
+ test "renders the PDF in the layout that's specified" do
66
+ controller.stubs(:render_to_string).returns("")
67
+ visit :default_with_layout
68
+ controller.should have_received(:render_to_string).with(has_entry(:layout, "layout"))
69
+ end
70
+ test "rendering a partial within a view works" do
71
+ visit :partial
72
+ should_render_a_pdf
73
+ end
74
+ test "renders a file named after the action if passed no arguments" do
75
+ visit :no_arguments
76
+ should_render_a_pdf
77
+ end
78
+ end
@@ -0,0 +1 @@
1
+ <p>Some more stuff.</p>
@@ -0,0 +1 @@
1
+ <p>This is some <%= "text" %> and stuff</p>
@@ -0,0 +1 @@
1
+ <p>This is some <%= "text" %> and stuff</p>
@@ -0,0 +1,3 @@
1
+ <p>Here is some content.</p>
2
+
3
+ <%= render :partial => "foo" %>
@@ -0,0 +1 @@
1
+ Alright here we go
@@ -0,0 +1 @@
1
+ <p>Some more stuff.</p>
@@ -0,0 +1 @@
1
+ <p>This is some <%= "text" %> and stuff</p>
@@ -0,0 +1,3 @@
1
+ <p>Here is some content.</p>
2
+
3
+ <%= render :partial => "foo" %>
@@ -0,0 +1 @@
1
+ Alright here we go
metadata ADDED
@@ -0,0 +1,153 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: htmldoc-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Elliot Winkler
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-11 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: htmldoc
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: actionpack
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - <
32
+ - !ruby/object:Gem::Version
33
+ version: "3.0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: mcmire-protest
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: mcmire-matchy
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: mcmire-mocha
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: mocha-protest-integration
67
+ type: :development
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: yard
77
+ type: :development
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ description: Generate PDFs from your Rails views using HTMLDoc
86
+ email: elliot.winkler@gmail.com
87
+ executables: []
88
+
89
+ extensions: []
90
+
91
+ extra_rdoc_files:
92
+ - LICENSE
93
+ - README.md
94
+ files:
95
+ - .gitignore
96
+ - LICENSE
97
+ - README.md
98
+ - Rakefile
99
+ - init.rb
100
+ - lib/htmldoc-rails.rb
101
+ - lib/htmldoc_rails.rb
102
+ - lib/htmldoc_rails/controller.rb
103
+ - lib/htmldoc_rails/htmldoc_ext.rb
104
+ - lib/htmldoc_rails/version.rb
105
+ - test/all.rb
106
+ - test/helper.rb
107
+ - test/rails_template_process.txt
108
+ - test/test_render_pdf.rb
109
+ - test/test_render_pdf_to_file.rb
110
+ - test/tmp/out.html
111
+ - test/tmp/out.pdf
112
+ - test/views/render_pdf/_foo.html.erb
113
+ - test/views/render_pdf/doc.html.erb
114
+ - test/views/render_pdf/doc.rpdf
115
+ - test/views/render_pdf/doc_with_partial.html.erb
116
+ - test/views/render_pdf/no_arguments.html.erb
117
+ - test/views/render_pdf_to_file/_foo.html.erb
118
+ - test/views/render_pdf_to_file/doc.html.erb
119
+ - test/views/render_pdf_to_file/doc_with_partial.html.erb
120
+ - test/views/render_pdf_to_file/no_arguments.html.erb
121
+ has_rdoc: true
122
+ homepage: http://github.com/mcmire/htmldoc-rails
123
+ licenses: []
124
+
125
+ post_install_message:
126
+ rdoc_options:
127
+ - --charset=UTF-8
128
+ require_paths:
129
+ - lib
130
+ required_ruby_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: "0"
135
+ version:
136
+ required_rubygems_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: "0"
141
+ version:
142
+ requirements: []
143
+
144
+ rubyforge_project:
145
+ rubygems_version: 1.3.5
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: Generate PDFs from your Rails views using HTMLDoc
149
+ test_files:
150
+ - test/all.rb
151
+ - test/helper.rb
152
+ - test/test_render_pdf.rb
153
+ - test/test_render_pdf_to_file.rb