thelinuxlich-pdfkit 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ .bundle
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :rubygems
2
+
3
+ group :development do
4
+ gem "rspec", "~> 2.0.0.beta.8"
5
+ gem "rspec-core", "~> 2.0.0.beta.8"
6
+ gem "mocha"
7
+ gem "jeweler"
8
+ gem "rack"
9
+ end
@@ -0,0 +1,35 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ gemcutter (0.6.1)
6
+ git (1.2.5)
7
+ jeweler (1.4.0)
8
+ gemcutter (>= 0.1.0)
9
+ git (>= 1.2.5)
10
+ rubyforge (>= 2.0.0)
11
+ json_pure (1.4.3)
12
+ mocha (0.9.8)
13
+ rake
14
+ rack (1.2.1)
15
+ rake (0.8.7)
16
+ rspec (2.0.0.beta.19)
17
+ rspec-core (= 2.0.0.beta.19)
18
+ rspec-expectations (= 2.0.0.beta.19)
19
+ rspec-mocks (= 2.0.0.beta.19)
20
+ rspec-core (2.0.0.beta.19)
21
+ rspec-expectations (2.0.0.beta.19)
22
+ diff-lcs (>= 1.1.2)
23
+ rspec-mocks (2.0.0.beta.19)
24
+ rubyforge (2.0.4)
25
+ json_pure (>= 1.1.7)
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ jeweler
32
+ mocha
33
+ rack
34
+ rspec (~> 2.0.0.beta.8)
35
+ rspec-core (~> 2.0.0.beta.8)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 jdpace
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,8 @@
1
+ ******************************************************************
2
+
3
+ Now install wkhtmltopdf binaries:
4
+ Global: sudo `which pdfkit` --install-wkhtmltopdf
5
+ or inside RVM folder: export TO=`which pdfkit | sed 's:/pdfkit:/wkhtmltopdf:'` && pdfkit --install-wkhtmltopdf
6
+ (run pdfkit --help to see more options)
7
+
8
+ ******************************************************************
@@ -0,0 +1,90 @@
1
+ # PDFKit
2
+
3
+ Create PDFs using plain old HTML+CSS. Uses [wkhtmltopdf](http://github.com/antialize/wkhtmltopdf) on the backend which renders HTML using Webkit.
4
+
5
+ ## Install
6
+
7
+ ### PDFKit
8
+
9
+ gem install pdfkit
10
+
11
+ ### wkhtmltopdf
12
+ * **Automatic**: `sudo pdfkit --install-wkhtmltopdf`
13
+ install latest version into /usr/local/bin
14
+ (overwrite defaults with e.g. ARCHITECTURE=amd64 TO=/home/foo/bin)
15
+ * By hand: http://code.google.com/p/wkhtmltopdf/downloads/list
16
+
17
+ ## Usage
18
+
19
+ # PDFKit.new takes the HTML and any options for wkhtmltopdf
20
+ # run `wkhtmltopdf --extended-help` for a full list of options
21
+ kit = PDFKit.new(html, :page_size => 'Letter')
22
+ kit.stylesheets << '/path/to/css/file'
23
+
24
+ # Git an inline PDF
25
+ pdf = kit.to_pdf
26
+
27
+ # Save the PDF to a file
28
+ file = kit.to_file('/path/to/save/pdf')
29
+
30
+ # PDFKit.new can optionally accept a URL or a File.
31
+ # Stylesheets can not be added when source is provided as a URL of File.
32
+ kit = PDFKit.new('http://google.com')
33
+ kit = PDFKit.new(File.new('/path/to/html'))
34
+
35
+ # Add any kind of option through meta tags
36
+ PDFKit.new('<html><head><meta name="pdfkit-page_size" content="Letter")
37
+
38
+ ## Configuration
39
+
40
+ If you're on Windows or you installed wkhtmltopdf by hand to a location other than /usr/local/bin you will need to tell PDFKit where the binary is. You can configure PDFKit like so:
41
+
42
+ # config/initializers/pdfkit.rb
43
+ PDFKit.configure do |config|
44
+ config.wkhtmltopdf = '/path/to/wkhtmltopdf'
45
+ config.default_options = {
46
+ :page_size => 'Legal',
47
+ :print_media_type => true
48
+ }
49
+ end
50
+
51
+ ## Middleware
52
+
53
+ PDFKit comes with a middleware that allows users to get a PDF view of any page on your site by appending .pdf to the URL.
54
+
55
+ ### Middleware Setup
56
+
57
+ **Non-Rails Rack apps**
58
+
59
+ # in config.ru
60
+ require 'pdfkit'
61
+ use PDFKit::Middleware
62
+
63
+ **Rails apps**
64
+
65
+ # in application.rb(Rails3) or environment.rb(Rails2)
66
+ require 'pdfkit'
67
+ config.middleware.use PDFKit::Middleware
68
+
69
+ **With PDFKit options**
70
+
71
+ # options will be passed to PDFKit.new
72
+ config.middleware.use PDFKit::Middleware, :print_media_type => true
73
+
74
+ ## TODO
75
+ - add amd64 support in --install-wkhtmltopdf
76
+
77
+ ## Note on Patches/Pull Requests
78
+
79
+ * Fork the project.
80
+ * Setup your development environment with: gem install bundler; bundle install
81
+ * Make your feature addition or bug fix.
82
+ * Add tests for it. This is important so I don't break it in a
83
+ future version unintentionally.
84
+ * Commit, do not mess with rakefile, version, or history.
85
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
86
+ * Send me a pull request. Bonus points for topic branches.
87
+
88
+ ## Copyright
89
+
90
+ Copyright (c) 2010 Jared Pace. See LICENSE for details.
@@ -0,0 +1,45 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'bundler'
4
+ Bundler.require(:development)
5
+
6
+ begin
7
+ require 'jeweler'
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = "thelinuxlich-pdfkit"
10
+ gem.summary = %Q{HTML+CSS -> PDF}
11
+ gem.description = %Q{Uses wkhtmltopdf to create PDFs using HTML(Windows-compatible)}
12
+ gem.email = "thelinuxlich@gmail.com"
13
+ gem.homepage = "http://github.com/thelinuxlich/PDFKit"
14
+ gem.authors = ["jdpace","thelinuxlich"]
15
+ gem.add_development_dependency "rspec"
16
+ gem.add_development_dependency "rspec-core"
17
+ gem.add_development_dependency 'mocha'
18
+ gem.post_install_message = File.read('POST_INSTALL')
19
+ end
20
+ Jeweler::GemcutterTasks.new
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
23
+ end
24
+
25
+ require 'rspec/core/rake_task'
26
+ RSpec::Core::RakeTask.new(:spec) do |spec|
27
+ end
28
+
29
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
30
+ spec.rcov = true
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+
35
+ task :default => :spec
36
+
37
+ require 'rake/rdoctask'
38
+ Rake::RDocTask.new do |rdoc|
39
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
40
+
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "PDFKit #{version}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.4.6
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'optparse'
4
+ require 'rbconfig'
5
+ require 'open-uri'
6
+ require 'pdfkit/configuration'
7
+
8
+ def detect_architecture
9
+ case Config::CONFIG['host_os']
10
+ when /x86_64-linux/i
11
+ 'amd64'
12
+ when /linux/i
13
+ 'i386'
14
+ when /darwin/i
15
+ 'OS-X.i368'
16
+ else
17
+ raise "No binaries found for your system. Please install wkhtmltopdf by hand."
18
+ end
19
+ end
20
+
21
+ def cleanup(install_to)
22
+ `rm -rf wkhtmltopdf*`
23
+ `rm #{install_to}`
24
+ end
25
+
26
+ def download_wkhtmltopdf(arch)
27
+ page = open("http://code.google.com/p/wkhtmltopdf/downloads/list").read
28
+ download = page.match(/href=".*name=(.*wkhtmltopdf-.*#{arch}.*?)&/) || raise("File not found..")
29
+ download = download[1]
30
+ url = "http://wkhtmltopdf.googlecode.com/files/#{download}"
31
+ puts "Downloading #{download} from #{url}"
32
+
33
+ `curl #{url} > #{download}`
34
+ download
35
+ end
36
+
37
+ def install(download, arch, install_to)
38
+ puts "Installing #{download} to #{install_to}"
39
+ if download =~ /.tar.bz2$/
40
+ `tar xjvf #{download}`
41
+ `mv wkhtmltopdf-#{arch} #{install_to}`
42
+ elsif download =~ /.tar.lzma$/
43
+ raise "couldn't extract archive: lzcat not found" unless system("which lzcat > /dev/null 2>/dev/null")
44
+ `lzcat #{download} | tar x`
45
+ `mv wkhtmltopdf-#{arch} #{install_to}`
46
+ else
47
+ `mv #{download} #{install_to}`
48
+ end
49
+ `sudo chmod +x #{install_to}`
50
+ end
51
+
52
+ OptionParser.new do |parser|
53
+ parser.banner = "PDFKit\n\nOptions are:"
54
+
55
+ parser.on("--install-wkhtmltopdf", "Install wkhtmltopdf binaries (TO=/usr/local/bin ARCHITECTURE=i386)") do
56
+ architecture = ENV['ARCHITECTURE'] || detect_architecture
57
+ install_to = ENV['TO'] || PDFKit.configuration.wkhtmltopdf
58
+
59
+ Dir.chdir '/tmp'
60
+
61
+ cleanup(install_to)
62
+ download = download_wkhtmltopdf(architecture)
63
+ install(download, architecture, install_to)
64
+ end
65
+
66
+ parser.on("--version", "Show Version.") do
67
+ root = File.dirname(File.dirname(__FILE__))
68
+ puts File.read(File.join(root, 'VERSION'))
69
+ end
70
+
71
+ parser.on("-h", "--help", "Show this.") { puts parser; exit }
72
+ end.parse!
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'pdfkit/source'
3
+ require 'pdfkit/pdfkit'
4
+ require 'pdfkit/middleware'
5
+ require 'pdfkit/configuration'
@@ -0,0 +1,41 @@
1
+ class PDFKit
2
+ class Configuration
3
+ attr_accessor :meta_tag_prefix, :wkhtmltopdf, :default_options
4
+
5
+ def initialize
6
+ @meta_tag_prefix = 'pdfkit-'
7
+ @wkhtmltopdf = '/usr/local/bin/wkhtmltopdf'
8
+ @default_options = {
9
+ :disable_smart_shrinking => true,
10
+ :page_size => 'Letter',
11
+ :margin_top => '0.75in',
12
+ :margin_right => '0.75in',
13
+ :margin_bottom => '0.75in',
14
+ :margin_left => '0.75in',
15
+ :encoding => "UTF-8"
16
+ }
17
+ end
18
+ end
19
+
20
+ class << self
21
+ attr_accessor :configuration
22
+ end
23
+
24
+ # Configure PDFKit someplace sensible,
25
+ # like config/initializers/pdfkit.rb
26
+ #
27
+ # @example
28
+ # PDFKit.configure do |config|
29
+ # config.wkhtmltopdf = '/usr/bin/wkhtmltopdf'
30
+ # end
31
+
32
+ def self.configuration
33
+ @configuration ||= Configuration.new
34
+ end
35
+
36
+
37
+ def self.configure
38
+ self.configuration
39
+ yield(configuration)
40
+ end
41
+ end
@@ -0,0 +1,61 @@
1
+ class PDFKit
2
+
3
+ class Middleware
4
+
5
+ def initialize(app, options = {})
6
+ @app = app
7
+ @options = options
8
+ end
9
+
10
+ def call(env)
11
+ @render_pdf = false
12
+ set_request_to_render_as_pdf(env) if env['PATH_INFO'].match(/\.pdf$/)
13
+
14
+ status, headers, response = @app.call(env)
15
+
16
+ request = Rack::Request.new(env)
17
+ if @render_pdf && headers['Content-Type'] =~ /text\/html|application\/xhtml\+xml/
18
+ body = response.body
19
+
20
+ body = translate_paths(body, env)
21
+
22
+ pdf = PDFKit.new(body, @options)
23
+ body = pdf.to_pdf
24
+
25
+ # Do not cache PDFs
26
+ headers.delete('ETag')
27
+ headers.delete('Cache-Control')
28
+
29
+ headers["Content-Length"] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
30
+ headers["Content-Type"] = "application/pdf"
31
+
32
+ response = [body]
33
+ end
34
+
35
+ [status, headers, response]
36
+ end
37
+
38
+ private
39
+
40
+ # Change relative paths to absolute
41
+ def translate_paths(body, env)
42
+ # Host with protocol
43
+ root = env['rack.url_scheme'] + "://" + env['HTTP_HOST'] + "/"
44
+
45
+ body.gsub(/(href|src)=(['"])\/([^\"']*|[^"']*)['"]/,'\1=\2'+root+'\3\2')
46
+ end
47
+
48
+ def set_request_to_render_as_pdf(env)
49
+ @render_pdf = true
50
+
51
+ path = Pathname(env['PATH_INFO'])
52
+ ['PATH_INFO','REQUEST_URI'].each { |e| env[e] = path.to_s.sub(/#{path.extname}$/,'') } if path.extname == '.pdf'
53
+ env['HTTP_ACCEPT'] = concat(env['HTTP_ACCEPT'], Rack::Mime.mime_type('.html'))
54
+ end
55
+
56
+ def concat(accepts, type)
57
+ (accepts || '').split(',').unshift(type).compact.join(',')
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,144 @@
1
+ class PDFKit
2
+
3
+ class NoExecutableError < StandardError
4
+ def initialize
5
+ msg = "No wkhtmltopdf executable found at #{PDFKit.configuration.wkhtmltopdf}\n"
6
+ msg << ">> Install wkhtmltopdf by hand or try running `pdfkit --install-wkhtmltopdf`"
7
+ super(msg)
8
+ end
9
+ end
10
+
11
+ class ImproperSourceError < StandardError
12
+ def initialize(msg)
13
+ super("Improper Source: #{msg}")
14
+ end
15
+ end
16
+
17
+ attr_accessor :source, :stylesheets,:fix_fonts_for_windows
18
+ attr_reader :options
19
+
20
+ def initialize(url_file_or_html, options = {})
21
+ @source = Source.new(url_file_or_html)
22
+
23
+ @stylesheets = []
24
+ @fix_fonts_for_windows = false
25
+
26
+ @options = PDFKit.configuration.default_options.merge(options)
27
+ @options.merge! find_options_in_meta(url_file_or_html) unless source.url?
28
+ @options = normalize_options(@options)
29
+
30
+ raise NoExecutableError.new unless File.exists?(PDFKit.configuration.wkhtmltopdf)
31
+ end
32
+
33
+ def command
34
+ args = [executable]
35
+ args += @options.to_a.flatten.compact
36
+ args << '--quiet'
37
+
38
+ if @source.html?
39
+ args << '-' # Get HTML from stdin
40
+ else
41
+ args << @source.to_s
42
+ end
43
+
44
+ args << '-' # Read PDF from stdout
45
+ args
46
+ end
47
+
48
+ def executable
49
+ default = PDFKit.configuration.wkhtmltopdf
50
+ return default if default !~ /^\// # its not a path, so nothing we can do
51
+ if File.exist?(default)
52
+ default
53
+ else
54
+ default.split('/').last
55
+ end
56
+ end
57
+
58
+ def to_pdf(path=nil)
59
+ append_stylesheets
60
+ fix_all_font_styles_for_windows if @fix_fonts_for_windows == true
61
+ args = command
62
+ args[-1] = path if path && args[-1] == "-"
63
+ invoke = args.map {|arg| %{"#{arg.gsub('"','\\"')}"}} * " "
64
+
65
+ result = IO.popen(invoke, "w+") do |pdf|
66
+ pdf.puts(@source.to_s) if @source.html?
67
+ pdf.close_write
68
+ pdf.gets(nil)
69
+ end
70
+ result = File.open(path, "rb") {|file| file.read} if path
71
+
72
+ raise "command failed: #{invoke}" if result.to_s.strip.empty?
73
+ return result
74
+ end
75
+
76
+ alias to_file to_pdf
77
+
78
+ protected
79
+
80
+ def find_options_in_meta(body)
81
+ pdfkit_meta_tags(body).inject({}) do |found, tag|
82
+ name = tag.attributes["name"].sub(/^#{PDFKit.configuration.meta_tag_prefix}/, '').to_sym
83
+ found.merge(name => tag.attributes["content"])
84
+ end
85
+ end
86
+
87
+ def pdfkit_meta_tags(body)
88
+ require 'rexml/document'
89
+ xml_body = REXML::Document.new(body)
90
+ found = []
91
+ xml_body.elements.each("html/head/meta") do |tag|
92
+ found << tag if tag.attributes['name'].to_s =~ /^#{PDFKit.configuration.meta_tag_prefix}/
93
+ end
94
+ found
95
+ rescue # rexml random crash on invalid xml
96
+ []
97
+ end
98
+
99
+ def style_tag_for(stylesheet)
100
+ "<style>#{File.read(stylesheet)}</style>"
101
+ end
102
+
103
+ def append_stylesheets
104
+ raise ImproperSourceError.new('Stylesheets may only be added to an HTML source') if stylesheets.any? && !@source.html?
105
+
106
+ stylesheets.each do |stylesheet|
107
+ if @source.to_s.match(/<\/head>/)
108
+ @source.to_s.gsub!(/(<\/head>)/, style_tag_for(stylesheet)+'\1')
109
+ else
110
+ @source.to_s.insert(0, style_tag_for(stylesheet))
111
+ end
112
+ end
113
+ end
114
+
115
+ def normalize_options(options)
116
+ normalized_options = {}
117
+
118
+ options.each do |key, value|
119
+ next if !value
120
+ normalized_key = "--#{normalize_arg key}"
121
+ normalized_options[normalized_key] = normalize_value(value)
122
+ end
123
+ normalized_options
124
+ end
125
+
126
+ def normalize_arg(arg)
127
+ arg.to_s.downcase.gsub(/[^a-z0-9]/,'-')
128
+ end
129
+
130
+ def normalize_value(value)
131
+ case value
132
+ when TrueClass
133
+ nil
134
+ else
135
+ value.to_s
136
+ end
137
+ end
138
+
139
+ def fix_all_font_styles_for_windows
140
+ @source.to_s.gsub!(/(font-family:[\s]?)([a-zA-Z,\s]+)[;]?["]?$/) do |s|
141
+ s = $1+$2.split(',').map{|font| font = "'#{font}'"}.join(',')
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,27 @@
1
+ class PDFKit
2
+
3
+ class Source
4
+
5
+ def initialize(url_file_or_html)
6
+ @source = url_file_or_html
7
+ end
8
+
9
+ def url?
10
+ @source.is_a?(String) && @source.match(/^http/)
11
+ end
12
+
13
+ def file?
14
+ @source.kind_of?(File)
15
+ end
16
+
17
+ def html?
18
+ !(url? || file?)
19
+ end
20
+
21
+ def to_s
22
+ file? ? @source.path : @source
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,85 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{pdfkit}
8
+ s.version = "0.4.6"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["jdpace"]
12
+ s.date = %q{2010-09-03}
13
+ s.default_executable = %q{pdfkit}
14
+ s.description = %q{Uses wkhtmltopdf to create PDFs using HTML}
15
+ s.email = %q{jared@codewordstudios.com}
16
+ s.executables = ["pdfkit"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".gitignore",
24
+ ".rspec",
25
+ "Gemfile",
26
+ "Gemfile.lock",
27
+ "LICENSE",
28
+ "POST_INSTALL",
29
+ "README.md",
30
+ "Rakefile",
31
+ "VERSION",
32
+ "bin/pdfkit",
33
+ "lib/pdfkit.rb",
34
+ "lib/pdfkit/configuration.rb",
35
+ "lib/pdfkit/middleware.rb",
36
+ "lib/pdfkit/pdfkit.rb",
37
+ "lib/pdfkit/source.rb",
38
+ "pdfkit.gemspec",
39
+ "spec/fixtures/example.css",
40
+ "spec/fixtures/example.html",
41
+ "spec/middleware_spec.rb",
42
+ "spec/pdfkit_spec.rb",
43
+ "spec/source_spec.rb",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+ s.homepage = %q{http://github.com/jdpace/PDFKit}
47
+ s.post_install_message = %q{******************************************************************
48
+
49
+ Now install wkhtmltopdf binaries:
50
+ Global: sudo `which pdfkit` --install-wkhtmltopdf
51
+ or inside RVM folder: export TO=`which pdfkit | sed 's:/pdfkit:/wkhtmltopdf:'` && pdfkit --install-wkhtmltopdf
52
+ (run pdfkit --help to see more options)
53
+
54
+ ******************************************************************}
55
+ s.rdoc_options = ["--charset=UTF-8"]
56
+ s.require_paths = ["lib"]
57
+ s.rubygems_version = %q{1.3.7}
58
+ s.summary = %q{HTML+CSS -> PDF}
59
+ s.test_files = [
60
+ "spec/middleware_spec.rb",
61
+ "spec/pdfkit_spec.rb",
62
+ "spec/source_spec.rb",
63
+ "spec/spec_helper.rb"
64
+ ]
65
+
66
+ if s.respond_to? :specification_version then
67
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
68
+ s.specification_version = 3
69
+
70
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
71
+ s.add_development_dependency(%q<rspec>, ["~> 2.0.0.beta.8"])
72
+ s.add_development_dependency(%q<rspec-core>, ["~> 2.0.0.beta.8"])
73
+ s.add_development_dependency(%q<mocha>, [">= 0"])
74
+ else
75
+ s.add_dependency(%q<rspec>, ["~> 2.0.0.beta.8"])
76
+ s.add_dependency(%q<rspec-core>, ["~> 2.0.0.beta.8"])
77
+ s.add_dependency(%q<mocha>, [">= 0"])
78
+ end
79
+ else
80
+ s.add_dependency(%q<rspec>, ["~> 2.0.0.beta.8"])
81
+ s.add_dependency(%q<rspec-core>, ["~> 2.0.0.beta.8"])
82
+ s.add_dependency(%q<mocha>, [">= 0"])
83
+ end
84
+ end
85
+
@@ -0,0 +1 @@
1
+ body { font-size: 20px; }
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <body>
3
+ <h1>Oh Hai!</h1>
4
+ </body>
5
+ </html>
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe PDFKit::Middleware do
4
+ describe "#translate_paths" do
5
+
6
+ before do
7
+ @pdf = PDFKit::Middleware.new({})
8
+ @env = {'REQUEST_URI' => 'http://example.com/document.pdf', 'rack.url_scheme' => 'http', 'HTTP_HOST' => 'example.com'}
9
+ end
10
+
11
+ it "should correctly parse relative url with single quotes" do
12
+ @body = %{<html><head><link href='/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="/test.png" /></body></html>}
13
+ body = @pdf.send :translate_paths, @body, @env
14
+ body.should == "<html><head><link href='http://example.com/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src=\"http://example.com/test.png\" /></body></html>"
15
+ end
16
+
17
+ it "should correctly parse relative url with double quotes" do
18
+ @body = %{<link href="/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />}
19
+ body = @pdf.send :translate_paths, @body, @env
20
+ body.should == "<link href=\"http://example.com/stylesheets/application.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
21
+ end
22
+
23
+ it "should return the body even if there are no valid substitutions found" do
24
+ @body = "NO MATCH"
25
+ body = @pdf.send :translate_paths, @body, @env
26
+ body.should == "NO MATCH"
27
+ end
28
+ end
29
+
30
+ describe "#set_request_to_render_as_pdf" do
31
+
32
+ before do
33
+ @pdf = PDFKit::Middleware.new({})
34
+
35
+ @pdf_env = {'PATH_INFO' => Pathname.new("file.pdf"), 'REQUEST_URI' => Pathname.new("file.pdf")}
36
+ @non_pdf_env = {'PATH_INFO' => Pathname.new("file.txt"), 'REQUEST_URI' => Pathname.new("file.txt")}
37
+ end
38
+
39
+ it "should replace .pdf in PATH_INFO when the extname is .pdf" do
40
+ @pdf.send :set_request_to_render_as_pdf, @pdf_env
41
+ @pdf_env['PATH_INFO'].should == "file"
42
+ end
43
+
44
+ it "should replace .pdf in REQUEST_URI when the extname is .pdf" do
45
+ @pdf.send :set_request_to_render_as_pdf, @pdf_env
46
+ @pdf_env['REQUEST_URI'].should == "file"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,178 @@
1
+ require 'spec_helper'
2
+
3
+ describe PDFKit do
4
+
5
+ context "initialization" do
6
+ it "should accept HTML as the source" do
7
+ pdfkit = PDFKit.new('<h1>Oh Hai</h1>')
8
+ pdfkit.source.should be_html
9
+ pdfkit.source.to_s.should == '<h1>Oh Hai</h1>'
10
+ end
11
+
12
+ it "should accept a URL as the source" do
13
+ pdfkit = PDFKit.new('http://google.com')
14
+ pdfkit.source.should be_url
15
+ pdfkit.source.to_s.should == 'http://google.com'
16
+ end
17
+
18
+ it "should accept a File as the source" do
19
+ file_path = File.join(SPEC_ROOT,'fixtures','example.html')
20
+ pdfkit = PDFKit.new(File.new(file_path))
21
+ pdfkit.source.should be_file
22
+ pdfkit.source.to_s.should == file_path
23
+ end
24
+
25
+ it "should parse the options into a cmd line friedly format" do
26
+ pdfkit = PDFKit.new('html', :page_size => 'Letter')
27
+ pdfkit.options.should have_key('--page-size')
28
+ end
29
+
30
+ it "should provide default options" do
31
+ pdfkit = PDFKit.new('<h1>Oh Hai</h1>')
32
+ ['--disable-smart-shrinking', '--margin-top', '--margin-right', '--margin-bottom', '--margin-left'].each do |option|
33
+ pdfkit.options.should have_key(option)
34
+ end
35
+ end
36
+
37
+ it "should default to 'UTF-8' encoding" do
38
+ pdfkit = PDFKit.new('Captación')
39
+ pdfkit.options['--encoding'].should == 'UTF-8'
40
+ end
41
+
42
+ it "should not have any stylesheedt by default" do
43
+ pdfkit = PDFKit.new('<h1>Oh Hai</h1>')
44
+ pdfkit.stylesheets.should be_empty
45
+ end
46
+ end
47
+
48
+ context "command" do
49
+ it "should contstruct the correct command" do
50
+ pdfkit = PDFKit.new('html', :page_size => 'Letter', :toc_l1_font_size => 12)
51
+ pdfkit.command[0].should include('wkhtmltopdf')
52
+ pdfkit.command[pdfkit.command.index('--page-size') + 1].should == 'Letter'
53
+ pdfkit.command[pdfkit.command.index('--toc-l1-font-size') + 1].should == '12'
54
+ end
55
+
56
+ it "will not include default options it is told to omit" do
57
+ pdfkit = PDFKit.new('html')
58
+ pdfkit.command.should include('--disable-smart-shrinking')
59
+ pdfkit = PDFKit.new('html', :disable_smart_shrinking => false)
60
+ pdfkit.command.should_not include('--disable-smart-shrinking')
61
+ end
62
+
63
+ it "should encapsulate string arguments in quotes" do
64
+ pdfkit = PDFKit.new('html', :header_center => "foo [page]")
65
+ pdfkit.command[pdfkit.command.index('--header-center') + 1].should == 'foo [page]'
66
+ end
67
+
68
+ it "read the source from stdin if it is html" do
69
+ pdfkit = PDFKit.new('html')
70
+ pdfkit.command[-2..-1].should == ['-', '-']
71
+ end
72
+
73
+ it "specify the URL to the source if it is a url" do
74
+ pdfkit = PDFKit.new('http://google.com')
75
+ pdfkit.command[-2..-1].should == ['http://google.com', '-']
76
+ end
77
+
78
+ it "should specify the path to the source if it is a file" do
79
+ file_path = File.join(SPEC_ROOT,'fixtures','example.html')
80
+ pdfkit = PDFKit.new(File.new(file_path))
81
+ pdfkit.command[-2..-1].should == [file_path, '-']
82
+ end
83
+
84
+ it "should detect special pdfkit meta tags" do
85
+ body = %{
86
+ <html>
87
+ <head>
88
+ <meta name="pdfkit-page_size" content="Legal"/>
89
+ <meta name="pdfkit-orientation" content="Landscape"/>
90
+ </head>
91
+ </html>
92
+ }
93
+ pdfkit = PDFKit.new(body)
94
+ pdfkit.command[pdfkit.command.index('--page-size') + 1].should == 'Legal'
95
+ pdfkit.command[pdfkit.command.index('--orientation') + 1].should == 'Landscape'
96
+ end
97
+ end
98
+
99
+ context "#to_pdf" do
100
+ it "should generate a PDF of the HTML" do
101
+ pdfkit = PDFKit.new('html', :page_size => 'Letter')
102
+ pdf = pdfkit.to_pdf
103
+ pdf[0...4].should == "%PDF" # PDF Signature at beginning of file
104
+ end
105
+
106
+ it "should generate a PDF with a numerical parameter" do
107
+ pdfkit = PDFKit.new('html', :header_spacing => 1)
108
+ pdf = pdfkit.to_pdf
109
+ pdf[0...4].should == "%PDF" # PDF Signature at beginning of file
110
+ end
111
+
112
+ it "should generate a PDF with a symbol parameter" do
113
+ pdfkit = PDFKit.new('html', :page_size => :Letter)
114
+ pdf = pdfkit.to_pdf
115
+ pdf[0...4].should == "%PDF" # PDF Signature at beginning of file
116
+ end
117
+
118
+ it "should have the stylesheet added to the head if it has one" do
119
+ pdfkit = PDFKit.new("<html><head></head><body>Hai!</body></html>")
120
+ css = File.join(SPEC_ROOT,'fixtures','example.css')
121
+ pdfkit.stylesheets << css
122
+ pdfkit.to_pdf
123
+ pdfkit.source.to_s.should include("<style>#{File.read(css)}</style>")
124
+ end
125
+
126
+ it "should prepend style tags if the HTML doesn't have a head tag" do
127
+ pdfkit = PDFKit.new("<html><body>Hai!</body></html>")
128
+ css = File.join(SPEC_ROOT,'fixtures','example.css')
129
+ pdfkit.stylesheets << css
130
+ pdfkit.to_pdf
131
+ pdfkit.source.to_s.should include("<style>#{File.read(css)}</style><html>")
132
+ end
133
+
134
+ it "should throw an error if the source is not html and stylesheets have been added" do
135
+ pdfkit = PDFKit.new('http://google.com')
136
+ css = File.join(SPEC_ROOT,'fixtures','example.css')
137
+ pdfkit.stylesheets << css
138
+ lambda { pdfkit.to_pdf }.should raise_error(PDFKit::ImproperSourceError)
139
+ end
140
+ end
141
+
142
+ context "#to_file" do
143
+ before do
144
+ @file_path = File.join(SPEC_ROOT,'fixtures','test.pdf')
145
+ File.delete(@file_path) if File.exist?(@file_path)
146
+ end
147
+
148
+ after do
149
+ File.delete(@file_path)
150
+ end
151
+
152
+ it "should create a file with the PDF as content" do
153
+ pdfkit = PDFKit.new('html', :page_size => 'Letter')
154
+ pdfkit.expects(:to_pdf).returns('PDF')
155
+ file = pdfkit.to_file(@file_path)
156
+ file.should be_instance_of(File)
157
+ File.read(file.path).should == 'PDF'
158
+ end
159
+ end
160
+
161
+ context "security" do
162
+ before do
163
+ @test_path = File.join(SPEC_ROOT,'fixtures','security-oops')
164
+ File.delete(@test_path) if File.exist?(@test_path)
165
+ end
166
+
167
+ after do
168
+ File.delete(@test_path) if File.exist?(@test_path)
169
+ end
170
+
171
+ it "should not allow shell injection in options" do
172
+ pdfkit = PDFKit.new('html', :header_center => "a title\"; touch #{@test_path} #")
173
+ pdfkit.to_pdf
174
+ File.exist?(@test_path).should be_false
175
+ end
176
+ end
177
+
178
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe PDFKit::Source do
4
+
5
+ describe "#url?" do
6
+ it "should return true if passed a url like string" do
7
+ source = PDFKit::Source.new('http://google.com')
8
+ source.should be_url
9
+ end
10
+
11
+ it "should return false if passed a file" do
12
+ source = PDFKit::Source.new(File.new(__FILE__))
13
+ source.should_not be_url
14
+ end
15
+
16
+ it "should return false if passed HTML" do
17
+ source = PDFKit::Source.new('<blink>Oh Hai!</blink>')
18
+ source.should_not be_url
19
+ end
20
+ end
21
+
22
+ describe "#file?" do
23
+ it "should return true if passed a file" do
24
+ source = PDFKit::Source.new(File.new(__FILE__))
25
+ source.should be_file
26
+ end
27
+
28
+ it "should return false if passed a url like string" do
29
+ source = PDFKit::Source.new('http://google.com')
30
+ source.should_not be_file
31
+ end
32
+
33
+ it "should return false if passed HTML" do
34
+ source = PDFKit::Source.new('<blink>Oh Hai!</blink>')
35
+ source.should_not be_file
36
+ end
37
+ end
38
+
39
+ describe "#html?" do
40
+ it "should return true if passed HTML" do
41
+ source = PDFKit::Source.new('<blink>Oh Hai!</blink>')
42
+ source.should be_html
43
+ end
44
+
45
+ it "should return false if passed a file" do
46
+ source = PDFKit::Source.new(File.new(__FILE__))
47
+ source.should_not be_html
48
+ end
49
+
50
+ it "should return false if passed a url like string" do
51
+ source = PDFKit::Source.new('http://google.com')
52
+ source.should_not be_html
53
+ end
54
+ end
55
+
56
+ describe "#to_s" do
57
+ it "should return the HTML if passed HTML" do
58
+ source = PDFKit::Source.new('<blink>Oh Hai!</blink>')
59
+ source.to_s.should == '<blink>Oh Hai!</blink>'
60
+ end
61
+
62
+ it "should return a path if passed a file" do
63
+ source = PDFKit::Source.new(File.new(__FILE__))
64
+ source.to_s.should == __FILE__
65
+ end
66
+
67
+ it "should return the url if passed a url like string" do
68
+ source = PDFKit::Source.new('http://google.com')
69
+ source.to_s.should == 'http://google.com'
70
+ end
71
+ end
72
+
73
+ end
@@ -0,0 +1,18 @@
1
+ SPEC_ROOT = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(SPEC_ROOT)
3
+ $LOAD_PATH.unshift(File.join(SPEC_ROOT, '..', 'lib'))
4
+ require 'pdfkit'
5
+ require 'rspec'
6
+ require 'rspec/autorun'
7
+ require 'mocha'
8
+ require 'rack'
9
+
10
+ RSpec.configure do |config|
11
+
12
+ config.before do
13
+ PDFKit.any_instance.stubs(:wkhtmltopdf).returns(
14
+ File.join(SPEC_ROOT,'..','bin','wkhtmltopdf-proxy')
15
+ )
16
+ end
17
+
18
+ end
metadata ADDED
@@ -0,0 +1,138 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thelinuxlich-pdfkit
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 4
8
+ - 6
9
+ version: 0.4.6
10
+ platform: ruby
11
+ authors:
12
+ - jdpace
13
+ - thelinuxlich
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-20 00:00:00 -02:00
19
+ default_executable: pdfkit
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ prerelease: false
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec-core
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *id002
47
+ - !ruby/object:Gem::Dependency
48
+ name: mocha
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ type: :development
58
+ prerelease: false
59
+ version_requirements: *id003
60
+ description: Uses wkhtmltopdf to create PDFs using HTML(Windows-compatible)
61
+ email: thelinuxlich@gmail.com
62
+ executables:
63
+ - pdfkit
64
+ extensions: []
65
+
66
+ extra_rdoc_files:
67
+ - LICENSE
68
+ - README.md
69
+ files:
70
+ - .document
71
+ - .gitignore
72
+ - .rspec
73
+ - Gemfile
74
+ - Gemfile.lock
75
+ - LICENSE
76
+ - POST_INSTALL
77
+ - README.md
78
+ - Rakefile
79
+ - VERSION
80
+ - bin/pdfkit
81
+ - lib/pdfkit.rb
82
+ - lib/pdfkit/configuration.rb
83
+ - lib/pdfkit/middleware.rb
84
+ - lib/pdfkit/pdfkit.rb
85
+ - lib/pdfkit/source.rb
86
+ - pdfkit.gemspec
87
+ - spec/fixtures/example.css
88
+ - spec/fixtures/example.html
89
+ - spec/middleware_spec.rb
90
+ - spec/pdfkit_spec.rb
91
+ - spec/source_spec.rb
92
+ - spec/spec_helper.rb
93
+ has_rdoc: true
94
+ homepage: http://github.com/thelinuxlich/PDFKit
95
+ licenses: []
96
+
97
+ post_install_message: |-
98
+ ******************************************************************
99
+
100
+ Now install wkhtmltopdf binaries:
101
+ Global: sudo `which pdfkit` --install-wkhtmltopdf
102
+ or inside RVM folder: export TO=`which pdfkit | sed 's:/pdfkit:/wkhtmltopdf:'` && pdfkit --install-wkhtmltopdf
103
+ (run pdfkit --help to see more options)
104
+
105
+ ******************************************************************
106
+ rdoc_options:
107
+ - --charset=UTF-8
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ none: false
112
+ requirements:
113
+ - - ">="
114
+ - !ruby/object:Gem::Version
115
+ hash: 1989877863628538783
116
+ segments:
117
+ - 0
118
+ version: "0"
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ segments:
125
+ - 0
126
+ version: "0"
127
+ requirements: []
128
+
129
+ rubyforge_project:
130
+ rubygems_version: 1.3.7
131
+ signing_key:
132
+ specification_version: 3
133
+ summary: HTML+CSS -> PDF
134
+ test_files:
135
+ - spec/source_spec.rb
136
+ - spec/middleware_spec.rb
137
+ - spec/pdfkit_spec.rb
138
+ - spec/spec_helper.rb