flyingsaucer4r 0.7

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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9fc5c40751267820b64eae3bc0edce1f8b7e69e8
4
+ data.tar.gz: c6f8848e36f4107e5f43476af2ba0a9f718a6dfd
5
+ SHA512:
6
+ metadata.gz: 13417560be87263d1bd60692a3733782546604cbba831a5d79bc3460dc4c733611e62d88bd0c3cbf54af1eea10235d7363591dc3befea703e13340994473f532
7
+ data.tar.gz: 1abd33645b6acd4696eade70eae6b44920323179c7dad979e26d3f6184c0a60fa2dd359b99db3b8d9731a56003e131e3ff9f67f00c08e7702ced6dfde12a5685
File without changes
@@ -0,0 +1,13 @@
1
+ === 0.6 / 2009-10-13
2
+
3
+ * Pull out PDF creation from filter
4
+
5
+ === 0.2.20081112 / 2008-12-05
6
+
7
+ * Add debug setting to log the XHTML Flying Saucer sees
8
+ * Treat absolute URIs as relative for better Rails compatibility
9
+
10
+ === 0.1.20081112 / 2008-12-03
11
+
12
+ * Initial version
13
+
@@ -0,0 +1,10 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/flying-saucer-core-9.0.2.jar
6
+ lib/flying-saucer-pdf-9.0.2.jar
7
+ lib/flyingsaucer4r.rb
8
+ lib/itext-2.1.7.02.jar
9
+ lib/pdffilter.rb
10
+ test/test_pdffilter.rb
@@ -0,0 +1,38 @@
1
+ = flyingsaucer4r
2
+
3
+ == DESCRIPTION:
4
+
5
+ The Flying Saucer gem gives JRuby access to the Flying Saucer XHTML renderer.
6
+ It also provides Rails integration to simplify sending PDFs generated from
7
+ XHTML to the browser.
8
+
9
+ == SYNOPSIS:
10
+
11
+ To add Flying Saucer to the JRuby classpath:
12
+
13
+ require 'flyingsaucer4r'
14
+
15
+ To use within Rails:
16
+
17
+ require 'pdffilter'
18
+
19
+ class ApplicationController < ActionController::Base
20
+ after_filter PDFFilter
21
+
22
+ ...
23
+ end
24
+
25
+ Now any request with a :format of 'pdf' will be turned into a PDF using Flying
26
+ Saucer on the way out to the browser.
27
+
28
+ == REQUIREMENTS:
29
+
30
+ * None (but the Rails integration only makes sense if you are using Rails)
31
+
32
+ == INSTALL:
33
+
34
+ jruby -S gem install pbrant-flyingsaucer4r
35
+
36
+ == LICENSE:
37
+
38
+ Copyright (c) 2008 Consolidated Court Automation Programs
@@ -0,0 +1,25 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require 'fileutils'
4
+
5
+ DEPENDENT_JARS = [ 'itext-2_0_8_02.jar' ]
6
+
7
+ STATIC_JAR_DIR = ENV['STATIC_JAR_DIR'] || "../StaticJars"
8
+
9
+ Hoe.spec('flyingsaucer4r') do |p|
10
+ developer 'CCAP Web Team', 'CCAP_Web_Team@wicourts.gov'
11
+ end
12
+
13
+ desc "Copies dependent JARs from StaticJars"
14
+ task :cp_dependent_jars do
15
+ rm_f 'lib/*.jar'
16
+ DEPENDENT_JARS.each do |jar|
17
+ cp "#{STATIC_JAR_DIR}/#{jar}", 'lib'
18
+ end
19
+ end
20
+
21
+ desc "Updates Flying Saucer JAR with the latest drop from StaticJars"
22
+ task :update_fs_jar => :cp_dependent_jars do
23
+ latest = Dir.glob("#{STATIC_JAR_DIR}/xhtmlrenderer*.jar").sort[-1]
24
+ cp latest, 'lib'
25
+ end
@@ -0,0 +1,90 @@
1
+ require 'java'
2
+ require 'enumerator'
3
+
4
+ Dir.glob(File.join(File.dirname(__FILE__), "*.jar")) { |jar| require File.basename(jar) }
5
+
6
+ module FlyingSaucer4R
7
+ VERSION = '0.7'
8
+
9
+ class UserAgent < org.xhtmlrenderer.pdf.ITextUserAgent
10
+ def initialize(output_device)
11
+ super
12
+ end
13
+
14
+ def resolveURI(uri)
15
+ if uri =~ /^\//
16
+ super(uri[1..uri.length])
17
+ else
18
+ super(uri)
19
+ end
20
+ end
21
+ alias :resolve_uri :resolveURI
22
+ end
23
+
24
+ def self.create_pdf(xhtml, base_path, logger = nil)
25
+ estimated_pdf_length = xhtml.length
26
+ output = java.io.ByteArrayOutputStream.new(estimated_pdf_length)
27
+
28
+ begin
29
+ dom = create_java_dom(xhtml, logger)
30
+ render_pdf(dom, base_path, output)
31
+ ensure
32
+ output.close
33
+ end
34
+ end
35
+
36
+ private
37
+ def self.provide_context(doc, line_no)
38
+ mark_selected = line_no != -1
39
+ line_no = 1 if line_no == -1
40
+ result = doc.enum_for(:each_line).enum_for(:each_with_index).inject([]) do |memo, pair|
41
+ line, current = pair
42
+ current += 1
43
+ diff = line_no - current
44
+ if diff.abs < 20
45
+ format_string = if line_no == current && mark_selected
46
+ "==> %4d %s"
47
+ else
48
+ " %4d %s"
49
+ end
50
+ memo << sprintf(format_string, current, line)
51
+ elsif current > line_no
52
+ break memo
53
+ end
54
+
55
+ memo
56
+ end
57
+
58
+ result.join('')
59
+ end
60
+
61
+ def self.create_java_dom(s, logger)
62
+ begin
63
+ builder = javax.xml.parsers.DocumentBuilderFactory.new_instance.new_document_builder
64
+ builder.parse(java.io.ByteArrayInputStream.new(s.to_java_bytes))
65
+ rescue NativeException => e
66
+ java_e = e.cause
67
+ if java_e.is_a?(org.xml.sax.SAXParseException)
68
+ context = provide_context(s, java_e.line_number)
69
+ logger.info("Unable to parse XHTML at line #{java_e.line_number}, column #{java_e.column_number}: #{java_e.message}\n#{context}") if logger
70
+ end
71
+ raise e
72
+ end
73
+ end
74
+
75
+ def self.render_pdf(dom, base_path, output)
76
+ renderer = org.xhtmlrenderer.pdf.ITextRenderer.new
77
+ agent = UserAgent.new(renderer.output_device)
78
+ agent.shared_context = renderer.shared_context
79
+ renderer.shared_context.user_agent_callback = agent
80
+ renderer.set_document(dom, path_to_url(base_path))
81
+ renderer.layout
82
+
83
+ renderer.create_pdf(output)
84
+ String.from_java_bytes(output.to_byte_array)
85
+ end
86
+
87
+ def self.path_to_url(path)
88
+ java.io.File.new(path).to_uri.to_url.to_string
89
+ end
90
+ end
Binary file
@@ -0,0 +1,37 @@
1
+ require 'flyingsaucer4r'
2
+ require 'java'
3
+ require 'enumerator'
4
+
5
+ class PDFFilter
6
+ class <<self
7
+ def debug=(b)
8
+ @debug = b
9
+ end
10
+
11
+ def debug?
12
+ @debug
13
+ end
14
+
15
+ def filter(controller)
16
+ format = controller.request.parameters[:format]
17
+ return unless format && format.to_sym == :pdf
18
+
19
+ controller.logger.debug("Rendering XHTML to PDF:\n" + controller.response.body) if debug?
20
+
21
+ pdf = FlyingSaucer4R.create_pdf(
22
+ controller.response.body,
23
+ File.join(Rails.public_path, 'placeholder.html'),
24
+ controller.logger)
25
+
26
+ controller.response.content_type = 'application/pdf'
27
+ add_ie6_pdf_over_ssl_headers(controller.response.headers)
28
+ controller.response.body = pdf
29
+ end
30
+
31
+ private
32
+ def add_ie6_pdf_over_ssl_headers(headers)
33
+ headers["Cache-Control"] ||= 'maxage=3600'
34
+ headers["Pragma"] ||= 'public'
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,167 @@
1
+ require 'rubygems'
2
+ require 'shoulda'
3
+ require 'test/unit'
4
+ require 'mocha'
5
+
6
+ lib_dir = "#{File.dirname(__FILE__)}/../lib"
7
+ $: << lib_dir unless $:.include?(lib_dir)
8
+ require 'pdffilter'
9
+
10
+ class Rails
11
+ def self.public_path
12
+ File.dirname(__FILE__) + "/public"
13
+ end
14
+ end
15
+
16
+ class LoggerStub
17
+ def debug(message)
18
+ @debug_message = message
19
+ end
20
+
21
+ def last_debug_message
22
+ @debug_message
23
+ end
24
+
25
+ def info(message)
26
+ @info_message = message
27
+ end
28
+
29
+ def last_info_message
30
+ @info_message
31
+ end
32
+ end
33
+
34
+ class PDFFilterTest < Test::Unit::TestCase
35
+ def setup
36
+ @controller = Struct.new(:request, :response, :logger).new
37
+ end
38
+
39
+ context "An HTML request" do
40
+ should "exit right away" do
41
+ @controller.request = stub(:parameters => { :format => "html" })
42
+ assert_nil PDFFilter.filter(@controller)
43
+ end
44
+ end
45
+
46
+ context "An request with no specified format" do
47
+ should "exit right away" do
48
+ @controller.request = stub(:parameters => {})
49
+ assert_nil PDFFilter.filter(@controller)
50
+ end
51
+ end
52
+
53
+ context "A PDF request with an image" do
54
+ setup do
55
+ standard_pdf("<html><body><h1><img src='images/apple.jpg' />Hello from Flying Saucer!</h1></body></html>")
56
+ end
57
+
58
+ should "render something" do
59
+ assert_not_nil PDFFilter.filter(@controller)
60
+ end
61
+ end
62
+
63
+ def standard_pdf(content)
64
+ @controller.request = stub(:parameters => { :format => "pdf" })
65
+ response_mock = mock()
66
+ @controller.response = response_mock
67
+ @controller.logger = LoggerStub.new
68
+ response_mock.expects(:body).returns(content).at_least_once
69
+ response_mock.expects(:content_type=).with('application/pdf').once
70
+ @headers = {}
71
+ response_mock.expects(:headers).returns(@headers).once
72
+ response_mock.expects(:body=).once
73
+ end
74
+
75
+ def invalid_xhtml(content)
76
+ @controller.request = stub(:parameters => { :format => "pdf" })
77
+ response_mock = mock()
78
+ @controller.response = response_mock
79
+ @controller.logger = LoggerStub.new
80
+ response_mock.expects(:body).returns(content).at_least_once
81
+ end
82
+
83
+ context "Malformed XHTML" do
84
+ should "report the line number of invalid XHTML with context" do
85
+ invalid_xhtml(<<-EOF)
86
+ <html>
87
+ <body>
88
+ <h1>Hello from Flying Saucer!
89
+ </body>
90
+ </html>
91
+ EOF
92
+ assert_raise NativeException do
93
+ PDFFilter.filter(@controller)
94
+ end
95
+ assert_match %r[Unable to parse XHTML at line 4], @controller.logger.last_info_message
96
+ assert_match %r[==>\s+4], @controller.logger.last_info_message
97
+ end
98
+
99
+ should "complain about XML that isn't" do
100
+ invalid_xhtml(<<-EOF)
101
+ some text
102
+ that
103
+ really
104
+ isn't XML
105
+ EOF
106
+ assert_raise NativeException do
107
+ PDFFilter.filter(@controller)
108
+ end
109
+ assert_match %r[==>\s+1 some text], @controller.logger.last_info_message
110
+ end
111
+ end
112
+
113
+ context "A PDF request" do
114
+ setup do
115
+ standard_pdf("<html><body><h1>Hello from Flying Saucer!</h1></body></html>")
116
+ end
117
+
118
+ should "render something" do
119
+ assert_not_nil PDFFilter.filter(@controller)
120
+ end
121
+
122
+ should("render something that looks like a PDF") do
123
+ assert_match(/%PDF/, PDFFilter.filter(@controller))
124
+ end
125
+
126
+ should "add headers for ie6" do
127
+ PDFFilter.filter(@controller)
128
+ assert_equal 'public', @headers["Pragma"]
129
+ assert_equal 'maxage=3600', @headers["Cache-Control"]
130
+ end
131
+
132
+ should "not overwrite existing ie6 header" do
133
+ @headers['Pragma'] = 'private'
134
+ PDFFilter.filter(@controller)
135
+ assert_equal 'private', @headers["Pragma"]
136
+ end
137
+
138
+ should "not log debug message if debug turned off" do
139
+ PDFFilter.filter(@controller)
140
+ assert_nil @controller.logger.last_debug_message
141
+ end
142
+
143
+ should "log XHTML content if debug turned on" do
144
+ old_debug = PDFFilter.debug?
145
+ PDFFilter.debug = true
146
+ begin
147
+ PDFFilter.filter(@controller)
148
+ assert_match(/<html>/, @controller.logger.last_debug_message)
149
+ ensure
150
+ PDFFilter.debug = old_debug
151
+ end
152
+ end
153
+ end
154
+
155
+ context FlyingSaucer4R::UserAgent do
156
+ setup { @user_agent = FlyingSaucer4R::UserAgent.new(org.xhtmlrenderer.pdf.ITextOutputDevice.new(1)) }
157
+
158
+ should "treat absolute URIs as relative (Java method name)" do
159
+ assert_equal @user_agent.resolveURI('stylesheets/aim.css'), @user_agent.resolveURI('/stylesheets/aim.css')
160
+ end
161
+
162
+ should "treat absolute URIs as relative (Ruby method name)" do
163
+ assert_equal @user_agent.resolve_uri('stylesheets/aim.css'), @user_agent.resolve_uri('/stylesheets/aim.css')
164
+ end
165
+ end
166
+
167
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flyingsaucer4r
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.7'
5
+ platform: ruby
6
+ authors:
7
+ - CCAP Web Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rdoc
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '4.0'
20
+ requirement: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: '4.0'
25
+ prerelease: false
26
+ type: :development
27
+ - !ruby/object:Gem::Dependency
28
+ name: hoe
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '3.13'
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: '3.13'
39
+ prerelease: false
40
+ type: :development
41
+ description: |-
42
+ The Flying Saucer gem gives JRuby access to the Flying Saucer XHTML renderer.
43
+ It also provides Rails integration to simplify sending PDFs generated from
44
+ XHTML to the browser.
45
+ email:
46
+ - CCAP_Web_Team@wicourts.gov
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files:
50
+ - History.txt
51
+ - Manifest.txt
52
+ - README.txt
53
+ files:
54
+ - History.txt
55
+ - Manifest.txt
56
+ - README.txt
57
+ - Rakefile
58
+ - lib/flying-saucer-core-9.0.2.jar
59
+ - lib/flying-saucer-pdf-9.0.2.jar
60
+ - lib/flyingsaucer4r.rb
61
+ - lib/itext-2.1.7.02.jar
62
+ - lib/pdffilter.rb
63
+ - test/test_pdffilter.rb
64
+ - .gemtest
65
+ homepage:
66
+ licenses:
67
+ - MIT
68
+ metadata: {}
69
+ post_install_message:
70
+ rdoc_options:
71
+ - --main
72
+ - README.txt
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ requirements: []
86
+ rubyforge_project:
87
+ rubygems_version: 2.1.9
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: The Flying Saucer gem gives JRuby access to the Flying Saucer XHTML renderer
91
+ test_files: []