srdperu-prawn-format 0.1.1.2 → 0.1.2
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.
- metadata +11 -31
- data/Manifest +0 -37
- data/Rakefile +0 -30
- data/examples/basic-formatting.rb +0 -37
- data/examples/christmas-carol.txt +0 -717
- data/examples/document.rb +0 -61
- data/examples/flowing.rb +0 -24
- data/examples/style-classes.rb +0 -12
- data/examples/syntax-highlighting.rb +0 -31
- data/examples/tags.rb +0 -24
- data/manual/html.rb +0 -187
- data/manual/include/basics.rb +0 -6
- data/manual/include/breaks.rb +0 -13
- data/manual/include/custom-tags.rb +0 -10
- data/manual/include/custom-tags2.rb +0 -2
- data/manual/include/indent.rb +0 -4
- data/manual/include/options.rb +0 -15
- data/manual/include/style-classes.rb +0 -5
- data/manual/manual.txt +0 -101
- data/manual/pdf.rb +0 -204
- data/spec/layout_builder_spec.rb +0 -27
- data/spec/lexer_spec.rb +0 -91
- data/spec/parser_spec.rb +0 -103
- data/spec/spec_helper.rb +0 -24
data/manual/pdf.rb
DELETED
@@ -1,204 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
|
2
|
-
require 'prawn'
|
3
|
-
require 'prawn/format'
|
4
|
-
require 'prawn/format/version'
|
5
|
-
require 'coderay'
|
6
|
-
|
7
|
-
def process_style(document, style, content, line_number)
|
8
|
-
content = process_substitutions(content)
|
9
|
-
|
10
|
-
case style
|
11
|
-
when "h1" then h1(document, content)
|
12
|
-
when "h2" then h2(document, content)
|
13
|
-
when "p" then paragraph(document, content)
|
14
|
-
when "fp" then paragraph(document, content, false)
|
15
|
-
when "ul" then start_list(document)
|
16
|
-
when "li" then list_item(document, content)
|
17
|
-
when "/ul" then end_list(document)
|
18
|
-
when "page" then new_page(document)
|
19
|
-
when "highlight" then highlight(document, content)
|
20
|
-
when "hr" then horiz_rule(document)
|
21
|
-
when "center" then center(document, content)
|
22
|
-
else warn "unknown style #{style.inspect}"
|
23
|
-
end
|
24
|
-
|
25
|
-
rescue Exception => err
|
26
|
-
puts "[error occurred while processing line ##{line_number}]"
|
27
|
-
raise
|
28
|
-
end
|
29
|
-
|
30
|
-
def process_substitutions(content)
|
31
|
-
content.
|
32
|
-
gsub(/%FORMAT:VERSION%/, Prawn::Format::Version::STRING).
|
33
|
-
gsub(/%NOW%/, Time.now.utc.strftime("%e %B %Y at %H:%M UTC")).
|
34
|
-
gsub(/%PDF\{(.*?)\}HTML\{(.*?)\}END%/, '\\1')
|
35
|
-
end
|
36
|
-
|
37
|
-
def center(document, content)
|
38
|
-
padding(document, :clear => true)
|
39
|
-
document.text(content, :plain => false, :align => :center)
|
40
|
-
padding(document)
|
41
|
-
end
|
42
|
-
|
43
|
-
def horiz_rule(document)
|
44
|
-
padding(document, :clear => true)
|
45
|
-
document.stroke_color "000000"
|
46
|
-
document.stroke_horizontal_rule
|
47
|
-
padding(document)
|
48
|
-
end
|
49
|
-
|
50
|
-
def h1(document, content)
|
51
|
-
clear_padding!
|
52
|
-
document.text "<h1>#{content}</h1>"
|
53
|
-
document.stroke_color "000080"
|
54
|
-
document.stroke_horizontal_rule
|
55
|
-
padding(document, :size => document.font_size * 2)
|
56
|
-
end
|
57
|
-
|
58
|
-
def h2(document, content)
|
59
|
-
clear_padding!
|
60
|
-
document.text "<h2>#{content}</h2>"
|
61
|
-
document.stroke_color "000080"
|
62
|
-
document.stroke_horizontal_rule
|
63
|
-
padding(document, :size => document.font_size * 2)
|
64
|
-
end
|
65
|
-
|
66
|
-
def paragraph(document, content, indent=true)
|
67
|
-
return unless content.strip.length > 0
|
68
|
-
clear_padding!
|
69
|
-
document.text "#{content}", :align => :justify
|
70
|
-
padding(document, :size => document.font_size / 2)
|
71
|
-
end
|
72
|
-
|
73
|
-
def start_list(document)
|
74
|
-
padding(document)
|
75
|
-
end
|
76
|
-
|
77
|
-
def list_item(document, content)
|
78
|
-
clear_padding!
|
79
|
-
|
80
|
-
indent_b = document.font_size * 3
|
81
|
-
indent = document.font_size * 4
|
82
|
-
|
83
|
-
document.start_new_page if document.y < document.font_size
|
84
|
-
y = document.y - document.bounds.absolute_bottom
|
85
|
-
document.text "•", :at => [indent_b, y - document.font.ascender]
|
86
|
-
document.layout(content, :align => :justify) do |helper|
|
87
|
-
while !helper.done?
|
88
|
-
y = helper.fill(indent, y, document.bounds.width-indent, :height => document.y)
|
89
|
-
if helper.done?
|
90
|
-
document.y = y + document.bounds.absolute_bottom
|
91
|
-
else
|
92
|
-
document.start_new_page
|
93
|
-
y = document.y - document.bounds.absolute_bottom
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
padding(document, :size => document.font_size / 4)
|
99
|
-
end
|
100
|
-
|
101
|
-
def end_list(document)
|
102
|
-
padding(document)
|
103
|
-
end
|
104
|
-
|
105
|
-
def new_page(document)
|
106
|
-
document.start_new_page
|
107
|
-
clear_padding!
|
108
|
-
end
|
109
|
-
|
110
|
-
def highlight(document, content)
|
111
|
-
file, syntax = content.split(/,/)
|
112
|
-
analyzed = CodeRay.scan(File.read(File.join(File.dirname(__FILE__), file)), syntax.to_sym)
|
113
|
-
html = "<pre>" + analyzed.html + "</pre>"
|
114
|
-
|
115
|
-
padding(document, :size => document.font_size * 2, :clear => true)
|
116
|
-
y = document.y - document.bounds.absolute_bottom
|
117
|
-
start_y = y + document.font_size
|
118
|
-
|
119
|
-
indent = document.font_size * 2
|
120
|
-
|
121
|
-
document.layout(html) do |helper|
|
122
|
-
while !helper.done?
|
123
|
-
y = helper.fill(indent, y, document.bounds.width-indent*2, :height => document.y)
|
124
|
-
if helper.done?
|
125
|
-
document.y = y + document.bounds.absolute_bottom
|
126
|
-
else
|
127
|
-
document.start_new_page
|
128
|
-
y = document.y - document.bounds.absolute_bottom
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
document.stroke_color "a0a0a0"
|
134
|
-
document.rectangle [document.font_size, start_y], bounds.width - document.font_size*2, (start_y - y)
|
135
|
-
document.stroke
|
136
|
-
|
137
|
-
padding(document, :size => document.font_size)
|
138
|
-
end
|
139
|
-
|
140
|
-
def clear_padding!
|
141
|
-
@last_padding = nil
|
142
|
-
end
|
143
|
-
|
144
|
-
# This padding stuff is mostly here just so that adjacent vertical spaces
|
145
|
-
# will collapse.
|
146
|
-
def padding(document, options={})
|
147
|
-
size = options[:size] || document.font_size
|
148
|
-
|
149
|
-
if @last_padding
|
150
|
-
full_size = [@last_padding, size].max
|
151
|
-
size = full_size - @last_padding
|
152
|
-
@last_padding = full_size
|
153
|
-
else
|
154
|
-
@last_padding = size
|
155
|
-
end
|
156
|
-
|
157
|
-
document.y -= size
|
158
|
-
clear_padding! if options[:clear]
|
159
|
-
end
|
160
|
-
|
161
|
-
SERIF_FONT = "/Library/Fonts/Baskerville.dfont"
|
162
|
-
|
163
|
-
Prawn::Document.generate("prawn-format.pdf", :compress => true) do
|
164
|
-
if File.exists?(SERIF_FONT)
|
165
|
-
font_families["Baskerville"] = {
|
166
|
-
:normal => { :file => SERIF_FONT, :font => 1 },
|
167
|
-
:italic => { :file => SERIF_FONT, :font => 2 },
|
168
|
-
:bold => { :file => SERIF_FONT, :font => 4 }, # semi-bold, not bold
|
169
|
-
:bold_italic => { :file => SERIF_FONT, :font => 3 }
|
170
|
-
}
|
171
|
-
font "Baskerville", :size => 14
|
172
|
-
else
|
173
|
-
warn "Baskerville font is preferred for the manual, but could not be found. Using Times-Roman."
|
174
|
-
font "Times-Roman", :size => 14
|
175
|
-
end
|
176
|
-
|
177
|
-
tags :h1 => { :font_size => "2em", :font_weight => :bold, :color => "navy" },
|
178
|
-
:h2 => { :font_size => "1.5em", :font_weight => :bold, :color => "navy" },
|
179
|
-
:about => { :font_size => "80%", :color => "808080", :font_style => :italic }
|
180
|
-
|
181
|
-
styles :no => { :color => "gray" },
|
182
|
-
:c => { :color => "#666" },
|
183
|
-
:s => { :color => "#d20" },
|
184
|
-
:dl => { :color => "black" },
|
185
|
-
:co => { :color => "#036", :font_weight => :bold },
|
186
|
-
:pc => { :color => "#038", :font_weight => :bold },
|
187
|
-
:sy => { :color => "#A60" },
|
188
|
-
:r => { :color => "#080" },
|
189
|
-
:i => { :color => "#00D", :font_weight => :bold },
|
190
|
-
:idl => { :color => "#888", :font_weight => :bold },
|
191
|
-
:dl => { :color => "#840", :font_weight => :bold }
|
192
|
-
|
193
|
-
File.open("#{File.dirname(__FILE__)}/manual.txt") do |source|
|
194
|
-
number = 0
|
195
|
-
source.each_line do |line|
|
196
|
-
number += 1
|
197
|
-
line.chomp!
|
198
|
-
next if line.length == 0
|
199
|
-
|
200
|
-
style, content = line.match(/^(\S+)\.\s*(.*)/)[1,2]
|
201
|
-
process_style(self, style, content, number)
|
202
|
-
end
|
203
|
-
end
|
204
|
-
end
|
data/spec/layout_builder_spec.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
4
|
-
|
5
|
-
describe "when building a text layout" do
|
6
|
-
|
7
|
-
before(:each) { create_pdf }
|
8
|
-
|
9
|
-
it "should understand common tags by default" do
|
10
|
-
layout = new_layout("<b>hi</b> <i>there</i>")
|
11
|
-
assert_nothing_raised { lines(layout) }
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def new_layout(text, opts={})
|
17
|
-
Prawn::Format::LayoutBuilder.new(@pdf, text, opts)
|
18
|
-
end
|
19
|
-
|
20
|
-
def lines(layout)
|
21
|
-
lines = []
|
22
|
-
while (line = layout.next)
|
23
|
-
lines << line
|
24
|
-
end
|
25
|
-
return lines
|
26
|
-
end
|
27
|
-
end
|
data/spec/lexer_spec.rb
DELETED
@@ -1,91 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
4
|
-
|
5
|
-
def lexer_for(text)
|
6
|
-
Prawn::Format::Lexer.new(text)
|
7
|
-
end
|
8
|
-
|
9
|
-
describe "when scanning text" do
|
10
|
-
|
11
|
-
it "should scan a single text word as a chunk" do
|
12
|
-
lexer = lexer_for("christmas")
|
13
|
-
assert_equal({ :type => :text, :text => ["christmas"] }, lexer.next)
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should delimit multiple words by spaces" do
|
17
|
-
lexer = lexer_for("a christmas carol by charles dickens")
|
18
|
-
assert_equal({ :type => :text, :text => ["a", " ", "christmas", " ", "carol", " ", "by", " ", "charles", " ", "dickens"] }, lexer.next)
|
19
|
-
end
|
20
|
-
|
21
|
-
it "should delimit multiple words by hyphens" do
|
22
|
-
lexer = lexer_for("christmas-carol-thingy")
|
23
|
-
assert_equal({ :type => :text, :text => ["christmas", "-", "carol", "-", "thingy"] }, lexer.next)
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should delimit multiple words by em-dashes" do
|
27
|
-
lexer = lexer_for("christmas—carol—thingy")
|
28
|
-
assert_equal({ :type => :text, :text => ["christmas", "—", "carol", "—", "thingy"] }, lexer.next)
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should report nil as end-of-stream after scanning" do
|
32
|
-
lexer = lexer_for("a christmas carol by charles dickens")
|
33
|
-
assert_not_nil lexer.next
|
34
|
-
assert_nil lexer.next
|
35
|
-
assert_nil lexer.next
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "when scanning XML entities" do
|
41
|
-
|
42
|
-
Prawn::Format::Lexer::ENTITY_MAP.each do |key, value|
|
43
|
-
it "should map #{key} to #{value}" do
|
44
|
-
lexer = lexer_for("&#{key};")
|
45
|
-
assert_equal({ :type => :text, :text => [value] }, lexer.next)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should convert decimal entities to utf-8" do
|
50
|
-
lexer = lexer_for('—')
|
51
|
-
assert_equal({ :type => :text, :text => ["\xe2\x80\x94"] }, lexer.next)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should convert hexadecimal entities to utf-8" do
|
55
|
-
lexer = lexer_for('—')
|
56
|
-
assert_equal({ :type => :text, :text => ["\xe2\x80\x94"] }, lexer.next)
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should raise InvalidFormat on unrecognized entities" do
|
60
|
-
lexer = lexer_for('&bogus;')
|
61
|
-
assert_raises(Prawn::Format::Lexer::InvalidFormat) do
|
62
|
-
lexer.next
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
describe "when scanning tags" do
|
69
|
-
|
70
|
-
it "should return tag with empty options for a tag with no options" do
|
71
|
-
lexer = lexer_for("<test>")
|
72
|
-
assert_equal({ :type => :open, :tag => :test, :options => {} }, lexer.next)
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should scan tags with different delimiters consistently" do
|
76
|
-
lexer = lexer_for("<test first=january second=\"february\" third='march'>")
|
77
|
-
assert_equal({ :type => :open, :tag => :test, :options => { :first => "january", :second => "february", :third => "march" } }, lexer.next)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should scan closing tag" do
|
81
|
-
lexer = lexer_for("</test>")
|
82
|
-
assert_equal({ :type => :close, :tag => :test }, lexer.next)
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should scan self-closing tag as two tokens" do
|
86
|
-
lexer = lexer_for("<test/>")
|
87
|
-
assert_equal({ :type => :open, :tag => :test, :options => {} }, lexer.next)
|
88
|
-
assert_equal({ :type => :close, :tag => :test }, lexer.next)
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
data/spec/parser_spec.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
4
|
-
|
5
|
-
describe "when parsing formatted text" do
|
6
|
-
|
7
|
-
before(:each) { create_pdf }
|
8
|
-
|
9
|
-
it "should raise TagError when it does not recognize a tag" do
|
10
|
-
parser = parser_for("<hello>")
|
11
|
-
assert_raises(Prawn::Format::Parser::TagError) { parser.next }
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should raise TagError when it encounters an unmatched closing tag" do
|
15
|
-
parser = parser_for("</b>")
|
16
|
-
assert_raises(Prawn::Format::Parser::TagError) { parser.next }
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should raise TagError when it a tag is closed with the wrong type" do
|
20
|
-
parser = parser_for("<b></i>")
|
21
|
-
assert_raises(Prawn::Format::Parser::TagError) { parse(parser) }
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should apply styles defined for tag" do
|
25
|
-
parser = parser_for("a<b>c</b>d")
|
26
|
-
weights = [:normal, :bold, :bold, :bold, :normal]
|
27
|
-
assert_equal weights, parse(parser).map { |i| i.state.font_weight }
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should honor custom tag styles" do
|
31
|
-
parser = parser_for("a<k>c</k>d", :tags => { :k => { :text_decoration => :underline } })
|
32
|
-
decorations = [:none, :underline, :underline, :underline, :none]
|
33
|
-
assert_equal decorations, parse(parser).map { |i| i.state.text_decoration }
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should honor custom style classes" do
|
37
|
-
parser = parser_for("a<j class='test'>c</j>d", :tags => { :j => {} }, :styles => { :test => { :text_decoration => :underline } })
|
38
|
-
decorations = [:none, :underline, :underline, :underline, :none]
|
39
|
-
assert_equal decorations, parse(parser).map { |i| i.state.text_decoration }
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should parse delimited text as separate instructions" do
|
43
|
-
parser = parser_for("a b-cd")
|
44
|
-
bits = ["a", " ", "b", "-", "cd"]
|
45
|
-
assert_equal bits, parse(parser).map { |i| i.text }
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should return nil after last token is parsed" do
|
49
|
-
parser = parser_for("a")
|
50
|
-
assert_not_nil parser.next
|
51
|
-
assert_nil parser.next
|
52
|
-
assert_nil parser.next
|
53
|
-
end
|
54
|
-
|
55
|
-
it "should report eos? at end of stream" do
|
56
|
-
parser = parser_for("a")
|
57
|
-
assert !parser.eos?
|
58
|
-
parser.next
|
59
|
-
assert parser.eos?
|
60
|
-
end
|
61
|
-
|
62
|
-
it "should return next instruction without consuming it when peek is called" do
|
63
|
-
parser = parser_for("a")
|
64
|
-
assert_equal "a", parser.peek.text
|
65
|
-
assert !parser.eos?
|
66
|
-
assert_equal "a", parser.next.text
|
67
|
-
assert parser.eos?
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should save instruction for next call when push is called" do
|
71
|
-
parser = parser_for("a")
|
72
|
-
k = parser.next
|
73
|
-
assert parser.eos?
|
74
|
-
parser.push(k)
|
75
|
-
assert !parser.eos?
|
76
|
-
assert_equal k, parser.next
|
77
|
-
assert parser.eos?
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should map meta styles to styles on the tag" do
|
81
|
-
parser = parser_for("<k name='bob'>a</k>", :tags => { :k => { :meta => { :name => :__name__ } } })
|
82
|
-
i = parser.next
|
83
|
-
assert_equal "bob", i.tag[:style][:__name__]
|
84
|
-
end
|
85
|
-
|
86
|
-
private
|
87
|
-
|
88
|
-
def parser_for(text, opts={})
|
89
|
-
tags = @pdf.tags.merge(opts[:tags] || {})
|
90
|
-
styles = @pdf.styles.merge(opts[:styles] || {})
|
91
|
-
@parser = Prawn::Format::Parser.new(@pdf, text, opts.merge(:styles => styles, :tags => tags))
|
92
|
-
end
|
93
|
-
|
94
|
-
def parse(parser)
|
95
|
-
instructions = []
|
96
|
-
|
97
|
-
while instr = parser.next
|
98
|
-
instructions << instr
|
99
|
-
end
|
100
|
-
|
101
|
-
return instructions
|
102
|
-
end
|
103
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
puts "Prawn-Format specs: Running on Ruby Version: #{RUBY_VERSION}"
|
4
|
-
|
5
|
-
require "rubygems"
|
6
|
-
require "test/spec"
|
7
|
-
require "mocha"
|
8
|
-
require "prawn"
|
9
|
-
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
10
|
-
$LOAD_PATH << File.join(Prawn::BASEDIR, 'vendor','pdf-inspector','lib')
|
11
|
-
require "prawn/format"
|
12
|
-
|
13
|
-
Prawn.debug = true
|
14
|
-
|
15
|
-
gem 'pdf-reader', ">=0.7.3"
|
16
|
-
require "pdf/reader"
|
17
|
-
require "pdf/inspector"
|
18
|
-
|
19
|
-
def create_pdf(klass=Prawn::Document)
|
20
|
-
@pdf = klass.new(:left_margin => 0,
|
21
|
-
:right_margin => 0,
|
22
|
-
:top_margin => 0,
|
23
|
-
:bottom_margin => 0)
|
24
|
-
end
|