Skip to content

Commit 014eb28

Browse files
authored
Merge pull request #43 from blocknotes/prawn-html-instance
Introduce PrawnHtml::Instance class to preserve the context
2 parents 0261e60 + de3a069 commit 014eb28

8 files changed

Lines changed: 119 additions & 8 deletions

File tree

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,23 @@ pdf.render_file('test.pdf')
3535

3636
To check some examples with the PDF output see [examples](examples/) folder.
3737

38+
Alternative form using _PrawnHtml::Instance_ to preserve the context:
39+
40+
```rb
41+
require 'prawn-html'
42+
pdf = Prawn::Document.new(page_size: 'A4')
43+
phtml = PrawnHtml::Instance.new(pdf)
44+
css = <<~CSS
45+
h1 { color: green }
46+
i { color: red }
47+
CSS
48+
phtml.append(css: css)
49+
phtml.append(html: '<h1>Some <i>HTML</i> before</h1>')
50+
pdf.text 'Some Prawn text'
51+
phtml.append(html: '<h1>Some <i>HTML</i> after</h1>')
52+
pdf.render_file('test.pdf')
53+
```
54+
3855
## Supported tags & attributes
3956

4057
HTML tags (using MDN definitions):

examples/instance.pdf

2.01 KB
Binary file not shown.

lib/prawn-html.rb

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,7 @@ module PrawnHtml
156156
}.freeze
157157

158158
def append_html(pdf, html)
159-
pdf_wrapper = PdfWrapper.new(pdf)
160-
renderer = DocumentRenderer.new(pdf_wrapper)
161-
html_parser = PrawnHtml::HtmlParser.new(renderer)
162-
html_parser.process(html)
159+
PrawnHtml::Instance.new(pdf).append(html: html)
163160
end
164161

165162
module_function :append_html
@@ -179,3 +176,4 @@ def append_html(pdf, html)
179176
require 'prawn_html/pdf_wrapper'
180177
require 'prawn_html/document_renderer'
181178
require 'prawn_html/html_parser'
179+
require 'prawn_html/instance'

lib/prawn_html/html_parser.rb

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,28 @@ def initialize(renderer, ignore_content_tags: %i[script style])
1515
@ignore = false
1616
@ignore_content_tags = ignore_content_tags
1717
@renderer = renderer
18-
@styles = {}
18+
@raw_styles = {}
1919
end
2020

2121
# Processes HTML and renders it
2222
#
2323
# @param html [String] The HTML content to process
2424
def process(html)
25+
@styles = {}
2526
@processing = !html.include?('<body')
2627
@document = Oga.parse_html(html)
28+
process_styles # apply previously loaded styles
2729
traverse_nodes(document.children)
2830
renderer.flush
2931
end
3032

33+
# Parses CSS styles
34+
#
35+
# @param text_styles [String] The CSS styles to evaluate
36+
def parse_styles(text_styles)
37+
@raw_styles = text_styles.scan(REGEXP_STYLES).to_h
38+
end
39+
3140
private
3241

3342
attr_reader :document, :ignore, :processing, :renderer, :styles
@@ -59,9 +68,9 @@ def init_element(node)
5968
end
6069
end
6170

62-
def process_styles(text_styles)
63-
hash_styles = text_styles.scan(REGEXP_STYLES).to_h
64-
hash_styles.each do |selector, rule|
71+
def process_styles(text_styles = nil)
72+
parse_styles(text_styles) if text_styles
73+
@raw_styles.each do |selector, rule|
6574
document.css(selector).each do |node|
6675
styles[node] = rule
6776
end

lib/prawn_html/instance.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
module PrawnHtml
4+
class Instance
5+
attr_reader :html_parser, :pdf_wrapper, :renderer
6+
7+
def initialize(pdf)
8+
@pdf_wrapper = PrawnHtml::PdfWrapper.new(pdf)
9+
@renderer = PrawnHtml::DocumentRenderer.new(@pdf_wrapper)
10+
@html_parser = PrawnHtml::HtmlParser.new(@renderer)
11+
end
12+
13+
def append(css: nil, html: nil)
14+
html_parser.parse_styles(css) if css
15+
html_parser.process(html) if html
16+
end
17+
end
18+
end

spec/features/instance_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe 'Instance' do
4+
it 'preserves the styles in the instance' do
5+
pdf = Prawn::Document.new(page_size: 'A4')
6+
phtml = PrawnHtml::Instance.new(pdf)
7+
css = <<~CSS
8+
h1 { color: green }
9+
i { color: red }
10+
CSS
11+
phtml.append(css: css)
12+
phtml.append(html: '<h1>Some <i>HTML</i> before</h1>')
13+
pdf.text 'Some Prawn text'
14+
phtml.append(html: '<h1>Some <i>HTML</i> after</h1>')
15+
16+
output_file = File.expand_path('../../examples/instance.pdf', __dir__)
17+
pdf.render_file(output_file) unless File.exist?(output_file)
18+
19+
expected_pdf = File.read(output_file)
20+
expect(Zlib.crc32(pdf.render)).to eq Zlib.crc32(expected_pdf)
21+
end
22+
end

spec/units/prawn_html/html_parser_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@
3838
end
3939
end
4040

41+
describe '#parse_styles' do
42+
subject(:parse_styles) { html_parser.parse_styles(css) }
43+
44+
let(:css) { 'h1 { color: red }' }
45+
46+
it { is_expected.to eq('h1' => 'color: red') }
47+
end
48+
4149
describe '#process' do
4250
subject(:process) { html_parser.process(html) }
4351

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe PrawnHtml::Instance do
4+
describe 'initialize' do
5+
subject(:instance) { described_class.new(pdf) }
6+
7+
let(:pdf) { instance_double(Prawn::Document) }
8+
9+
before do
10+
allow(PrawnHtml::PdfWrapper).to receive(:new)
11+
allow(PrawnHtml::DocumentRenderer).to receive(:new)
12+
allow(PrawnHtml::HtmlParser).to receive(:new)
13+
end
14+
15+
it 'initializes the required entities', :aggregate_failures do
16+
instance
17+
expect(PrawnHtml::PdfWrapper).to have_received(:new)
18+
expect(PrawnHtml::DocumentRenderer).to have_received(:new)
19+
expect(PrawnHtml::HtmlParser).to have_received(:new)
20+
end
21+
end
22+
23+
describe '#append' do
24+
subject(:append) { described_class.new(pdf).append(html: html) }
25+
26+
let(:html) { '<h1>Some HTML</h1>' }
27+
let(:html_parser) { instance_double(PrawnHtml::HtmlParser, process: nil) }
28+
let(:pdf) { instance_double(Prawn::Document) }
29+
30+
before do
31+
allow(PrawnHtml::HtmlParser).to receive(:new).and_return(html_parser)
32+
end
33+
34+
it 'sends a process message to the html parser' do
35+
append
36+
expect(html_parser).to have_received(:process).with(html)
37+
end
38+
end
39+
end

0 commit comments

Comments
 (0)