markdown_prawn 0.0.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +11 -0
- data/bin/md2pdf +12 -0
- data/lib/markdown_fragments/heading_fragment.rb +20 -0
- data/lib/markdown_fragments/horizontal_rule_fragment.rb +25 -0
- data/lib/markdown_fragments/image_fragment.rb +25 -0
- data/lib/markdown_fragments/links_reference_fragment.rb +17 -0
- data/lib/markdown_fragments/list_fragment.rb +40 -0
- data/lib/markdown_fragments/markdown_fragment.rb +13 -0
- data/lib/markdown_fragments/paragraph_fragment.rb +21 -0
- data/lib/markdown_fragments.rb +7 -0
- data/lib/markdown_parser/file_parser.rb +18 -0
- data/lib/markdown_parser/parser.rb +213 -0
- data/lib/markdown_parser/string_parser.rb +11 -0
- data/lib/markdown_parser.rb +5 -0
- data/lib/markdown_prawn_exceptions.rb +6 -0
- data/markdown_prawn.gemspec +21 -0
- data/test/fixtures/ordered_lists.mdown +3 -0
- data/test/fixtures/paragraphs.mdown +8 -0
- data/test/fixtures/unordered_lists.mdown +3 -0
- data/test/helper.rb +4 -0
- data/test/test_lists_handling.rb +24 -0
- data/test/test_paragraph_handling.rb +18 -0
- metadata +107 -0
data/Rakefile
ADDED
data/bin/md2pdf
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Markdown to PDF by Ryan Stenhouse <ryan@ryanstenhouse.eu>
|
4
|
+
# November 1st 2010
|
5
|
+
#
|
6
|
+
# Takes input from standard in, expected to be a markdown document
|
7
|
+
# and renders a PDF to standard out.
|
8
|
+
#
|
9
|
+
root = File.expand_path(File.dirname(__FILE__)+ '/../')
|
10
|
+
load root + '/markdown_prawn.rb'
|
11
|
+
content = $stdin.read
|
12
|
+
puts MarkdownPrawn::StringParser.new(content).to_pdf.render
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class HeadingFragment < MarkdownFragment
|
2
|
+
attr_accessor :level
|
3
|
+
|
4
|
+
def render_on(pdf_object, options = {})
|
5
|
+
arguments = _default_render_options.merge(options)
|
6
|
+
pdf_object.move_down(@level * 2)
|
7
|
+
pdf_object.text @content.join(' '), arguments
|
8
|
+
pdf_object.move_down(@level * 2)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def _default_render_options
|
14
|
+
options = { :size => (40 - (8*@level)), :align => :left, :leading => 2, :weight => :bold }
|
15
|
+
if Prawn::VERSION =~ /^0.1/ || Prawn::VERSION =~ /^1/
|
16
|
+
options.merge({:inline_format => true})
|
17
|
+
end
|
18
|
+
options
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class HorizontalRuleFragment < MarkdownFragment
|
2
|
+
|
3
|
+
def render_on(pdf_object, options = {})
|
4
|
+
pdf_object.move_down(3)
|
5
|
+
old_width = pdf_object.line_width
|
6
|
+
pdf_object.line_width = 3
|
7
|
+
pdf_object.horizontal_rule
|
8
|
+
pdf_object.stroke
|
9
|
+
pdf_object.line_width = old_width
|
10
|
+
pdf_object.move_down(3)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def _default_render_options
|
16
|
+
options = { :size => 12, :align => :left, :leading => 2 }
|
17
|
+
if Prawn::VERSION =~ /^0.1/ || Prawn::VERSION =~ /^1/
|
18
|
+
options = options.merge({:inline_format => true})
|
19
|
+
else
|
20
|
+
options = options.merge({:inline_format => false})
|
21
|
+
end
|
22
|
+
options
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
class ImageFragment < MarkdownFragment
|
5
|
+
def render_on(pdf_object)
|
6
|
+
if is_remote_uri?
|
7
|
+
filename = @content.first.split('/').last
|
8
|
+
file_path = "#{Dir.tmpdir}/#{filename}"
|
9
|
+
content = Net::HTTP.get(URI.parse(@content.first))
|
10
|
+
File.open(file_path, 'w') do |f|
|
11
|
+
f.puts content
|
12
|
+
end
|
13
|
+
else
|
14
|
+
file_path = File.expand_path(@content.first)
|
15
|
+
end
|
16
|
+
pdf_object.image file_path
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def is_remote_uri?
|
22
|
+
!/^(http:|https:)/.match(@content.first).nil?
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class LinksReferenceFragment < MarkdownFragment
|
2
|
+
|
3
|
+
def render_on(pdf_object)
|
4
|
+
|
5
|
+
pdf_object.move_down(10)
|
6
|
+
pdf_object.horizontal_rule
|
7
|
+
pdf_object.stroke
|
8
|
+
pdf_object.move_down(4)
|
9
|
+
pdf_object.text "Hyperlink References:"
|
10
|
+
pdf_object.move_down(4)
|
11
|
+
pdf_object.table @content do
|
12
|
+
cells.borders = []
|
13
|
+
end
|
14
|
+
pdf_object.move_down(4)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class ListFragment < MarkdownFragment
|
2
|
+
attr_accessor :ordered
|
3
|
+
|
4
|
+
def render_on(pdf_object, options = {})
|
5
|
+
bullet = '• '
|
6
|
+
arguments = _default_render_options.merge(options)
|
7
|
+
width = ((pdf_object.bounds.width / 100) * 90)
|
8
|
+
data = []
|
9
|
+
|
10
|
+
@content.each_with_index do |item, i|
|
11
|
+
# Strip any un-needed white space
|
12
|
+
#
|
13
|
+
item = item.gsub(/\s\s+/,' ')
|
14
|
+
if ordered?
|
15
|
+
bullet = "#{i+1}."
|
16
|
+
end
|
17
|
+
data << [bullet,item]
|
18
|
+
end
|
19
|
+
|
20
|
+
pdf_object.table data, arguments.merge({:width => width}) do
|
21
|
+
cells.borders = []
|
22
|
+
end
|
23
|
+
pdf_object.move_down(5)
|
24
|
+
end
|
25
|
+
|
26
|
+
def ordered?
|
27
|
+
@ordered == true
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def _default_render_options
|
33
|
+
options = {}
|
34
|
+
if Prawn::VERSION =~ /^0.1/ || Prawn::VERSION =~ /^1/
|
35
|
+
options = options.merge({:cell_style => { :inline_format => true}})
|
36
|
+
end
|
37
|
+
options
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class MarkdownFragment
|
2
|
+
attr_accessor :content
|
3
|
+
|
4
|
+
def initialize(content = [])
|
5
|
+
@content = content
|
6
|
+
end
|
7
|
+
|
8
|
+
# Renders the current fragment on the supplied prawn PDF Object. By Default,
|
9
|
+
# it will just join content and add it as text - not too useful.
|
10
|
+
def render_on(pdf_object)
|
11
|
+
pdf_object.text @content.join(' ')
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class ParagraphFragment < MarkdownFragment
|
2
|
+
|
3
|
+
def render_on(pdf_object, options = {})
|
4
|
+
arguments = _default_render_options.merge(options)
|
5
|
+
pdf_object.move_down(3)
|
6
|
+
pdf_object.text @content.join(' '), arguments
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def _default_render_options
|
12
|
+
options = { :size => 12, :align => :left, :leading => 2 }
|
13
|
+
if Prawn::VERSION =~ /^0.1/ || Prawn::VERSION =~ /^1/
|
14
|
+
options = options.merge({:inline_format => true})
|
15
|
+
else
|
16
|
+
options = options.merge({:inline_format => false})
|
17
|
+
end
|
18
|
+
options
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/markdown_fragments/markdown_fragment.rb'
|
2
|
+
require File.dirname(__FILE__) + '/markdown_fragments/paragraph_fragment.rb'
|
3
|
+
require File.dirname(__FILE__) + '/markdown_fragments/heading_fragment.rb'
|
4
|
+
require File.dirname(__FILE__) + '/markdown_fragments/list_fragment.rb'
|
5
|
+
require File.dirname(__FILE__) + '/markdown_fragments/image_fragment.rb'
|
6
|
+
require File.dirname(__FILE__) + '/markdown_fragments/horizontal_rule_fragment.rb'
|
7
|
+
require File.dirname(__FILE__) + '/markdown_fragments/links_reference_fragment.rb'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MarkdownPrawn
|
2
|
+
class FileParser < Parser
|
3
|
+
|
4
|
+
# Give this the path to a file and (if it exists), it'll generate
|
5
|
+
# a PDF version of the markdown there.
|
6
|
+
#
|
7
|
+
def initialize(file_path)
|
8
|
+
file_path = File.expand_path(file_path)
|
9
|
+
if !File.exist?(file_path)
|
10
|
+
raise Errno::ENOENT.new("#{file_path} could not be found") and return
|
11
|
+
else
|
12
|
+
@content = detab(IO.read(file_path).gsub(/\r\n?/, "\n")).split("\n")
|
13
|
+
end
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../markdown_fragments.rb'
|
2
|
+
|
3
|
+
module MarkdownPrawn
|
4
|
+
|
5
|
+
# Horribly bodgy and wrong markdown parser which should just about do
|
6
|
+
# for a proof of concept. Some of the code comes from mislav's original
|
7
|
+
# BlueCloth since I cant find the source of a newer versoin.
|
8
|
+
#
|
9
|
+
class Parser
|
10
|
+
attr_accessor :links_list, :images_list, :document_structure
|
11
|
+
|
12
|
+
def initialize(document_structure = [])
|
13
|
+
@links_list = { :urls_seen => [], :object => LinksReferenceFragment.new }
|
14
|
+
@document_structure = []
|
15
|
+
@images_list = []
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns a Prawn::Document, accepts the same options as Prawn does when creating
|
19
|
+
# a new document, but defaults to creating pages in Portrait and at A4 size.
|
20
|
+
#
|
21
|
+
# Uses parse! rather than parse to ensure that the slate is always clean when
|
22
|
+
# generating the PDF.
|
23
|
+
#
|
24
|
+
def to_pdf(options = {})
|
25
|
+
parse!
|
26
|
+
options = options.merge({ :page_layout => :portrait, :page_size => 'A4' })
|
27
|
+
pdf = Prawn::Document.new(options)
|
28
|
+
@document_structure.each { |markdown_fragment| markdown_fragment.render_on(pdf) }
|
29
|
+
pdf
|
30
|
+
end
|
31
|
+
|
32
|
+
# Clears out the current sate of +@document_structure+ and then parses +@content+ content
|
33
|
+
#
|
34
|
+
def parse!
|
35
|
+
@document_structure = []
|
36
|
+
parse
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse
|
40
|
+
paragraph = ParagraphFragment.new
|
41
|
+
list = ListFragment.new
|
42
|
+
in_list = false
|
43
|
+
@content.each_with_index do |line, index|
|
44
|
+
line = process_inline_formatting(line)
|
45
|
+
|
46
|
+
# Assume everything is part of a paragraph by default and
|
47
|
+
# add its content to the current in-scope paragraph object.
|
48
|
+
#
|
49
|
+
paragraph.content << line
|
50
|
+
if line == ""
|
51
|
+
unless paragraph.content.empty?
|
52
|
+
@document_structure << paragraph
|
53
|
+
paragraph = ParagraphFragment.new
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Deal with inline headings
|
58
|
+
#
|
59
|
+
unless /^(#+)(\s?)\S/.match(line).nil?
|
60
|
+
paragraph.content = paragraph.content.delete_if { |i| i == line }
|
61
|
+
hashes = $1.dup
|
62
|
+
heading = HeadingFragment.new([line.gsub(hashes,'')])
|
63
|
+
heading.level = hashes.length
|
64
|
+
@document_structure << heading
|
65
|
+
end
|
66
|
+
|
67
|
+
# Deal with Level 1 Headings
|
68
|
+
#
|
69
|
+
if !/^(=)+$/.match(line).nil?
|
70
|
+
paragraph.content = paragraph.content.delete_if do |item|
|
71
|
+
item == line || item == @content[index - 1]
|
72
|
+
end
|
73
|
+
heading = HeadingFragment.new([@content[index - 1]])
|
74
|
+
heading.level = 1
|
75
|
+
@document_structure << heading
|
76
|
+
end
|
77
|
+
|
78
|
+
# Deal with Level 2 Headings or horizontal rules.
|
79
|
+
#
|
80
|
+
if !/^(-)+$/.match(line).nil?
|
81
|
+
if @content[index - 1].strip == ''
|
82
|
+
# Assume it's a horizontal rule
|
83
|
+
#
|
84
|
+
paragraph.content = paragraph.content.delete_if { |i| i == line }
|
85
|
+
@document_structure << HorizontalRuleFragment.new
|
86
|
+
else
|
87
|
+
paragraph.content = paragraph.content.delete_if do |item|
|
88
|
+
item == line || item == @content[index - 1]
|
89
|
+
end
|
90
|
+
heading = HeadingFragment.new([@content[index - 1]])
|
91
|
+
heading.level = 2
|
92
|
+
@document_structure << heading
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Deal with all other kinds of horizontal rules
|
97
|
+
#
|
98
|
+
if !/^(\*+)(\s)?(\*+)(\s)?(\*+)/.match(line).nil? || !/^(-+)(\s)(-+)(\s)(-+)/.match(line).nil?
|
99
|
+
if @content[index - 1].strip == ''
|
100
|
+
paragraph.content = paragraph.content.delete_if { |i| i == line }
|
101
|
+
@document_structure << HorizontalRuleFragment.new
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Try to deal with lists.
|
106
|
+
#
|
107
|
+
if in_list
|
108
|
+
# We're in a list just now.
|
109
|
+
#
|
110
|
+
|
111
|
+
# Remove the content from the paragraph where it will have
|
112
|
+
# automatically been appended
|
113
|
+
#
|
114
|
+
paragraph.content = paragraph.content.delete_if { |i| i == line }
|
115
|
+
|
116
|
+
# Check to see if we've got a new list item.
|
117
|
+
#
|
118
|
+
if (!/^\s+\*\s/.match(line).nil? || !/^\s+\d+\.\s/.match(line).nil?)
|
119
|
+
|
120
|
+
# Find out if this new list item is for a different type of list
|
121
|
+
# and deal with that before adding the new list item.
|
122
|
+
#
|
123
|
+
if list.ordered? && !/^\s+\*\s/.match(line).nil?
|
124
|
+
@document_structure << list
|
125
|
+
list = ListFragment.new
|
126
|
+
elsif !list.ordered? && !/^\s+\d+\.\s/.match(line).nil?
|
127
|
+
@document_structure << list
|
128
|
+
list = ListFragment.new
|
129
|
+
list.ordered = true
|
130
|
+
end
|
131
|
+
|
132
|
+
# Remove the list style and add the new list item.
|
133
|
+
#
|
134
|
+
list.content << line.sub(/^\s+\*\s/,'').sub(/^\s+\d+\.\s/,'')
|
135
|
+
|
136
|
+
else
|
137
|
+
# If this line isn't a new list item, then it's a continuation for the current
|
138
|
+
# list item.
|
139
|
+
#
|
140
|
+
list.content[-1] += line
|
141
|
+
end
|
142
|
+
|
143
|
+
# If the current line is empty, then we're done with the list.
|
144
|
+
#
|
145
|
+
if line == ''
|
146
|
+
@document_structure << list
|
147
|
+
list = ListFragment.new
|
148
|
+
in_list = false
|
149
|
+
end
|
150
|
+
else
|
151
|
+
# Not currently in a list, but we've detected a list item
|
152
|
+
#
|
153
|
+
if (!/^\s+\*\s/.match(line).nil? || !/^\s+\d+\.\s/.match(line).nil?)
|
154
|
+
ordered = false
|
155
|
+
ordered = true if !/^\s+\d+\.\s/.match(line).nil?
|
156
|
+
list = ListFragment.new
|
157
|
+
list.ordered = ordered
|
158
|
+
list.content << line.sub(/^\s+\*\s/,'').sub(/^\s+\d+\.\s/,'')
|
159
|
+
paragraph.content = paragraph.content.delete_if { |i| i == line }
|
160
|
+
in_list = true
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
# Deal with a link reference by adding it ot the list of references
|
166
|
+
#
|
167
|
+
if !/^(\[\S+\]){1}:\s(\S+)\s?(.+)?/.match(line).nil?
|
168
|
+
reference, url, title = $1, $2, $3
|
169
|
+
paragraph.content = paragraph.content.delete_if { |i| i == line }
|
170
|
+
@links_list[:urls_seen] << url
|
171
|
+
@links_list[:object].content << [ reference, url, "#{title}" ]
|
172
|
+
end
|
173
|
+
|
174
|
+
# Deal with inline images
|
175
|
+
#
|
176
|
+
line.scan(/(?:^|\s)?(\!\[(?:.+?)\]\((.+?)\))/) do |val|
|
177
|
+
line.gsub(val[0],'')
|
178
|
+
@document_structure << ImageFragment.new([val[1]])
|
179
|
+
end
|
180
|
+
end
|
181
|
+
if !list.content.empty? && ! @document_structure.include?(list)
|
182
|
+
@document_structure << list
|
183
|
+
list = ListFragment.new
|
184
|
+
end
|
185
|
+
@document_structure << paragraph unless paragraph.content == ''
|
186
|
+
@document_structure << @links_list[:object] if !@links_list[:urls_seen].empty?
|
187
|
+
end
|
188
|
+
|
189
|
+
private
|
190
|
+
|
191
|
+
def detab(string, tabwidth = 2)
|
192
|
+
string.split("\n").collect { |line|
|
193
|
+
line.gsub(/(.*?)\t/) do
|
194
|
+
$1 + ' ' * (tabwidth - $1.length % tabwidth)
|
195
|
+
end
|
196
|
+
}.join("\n")
|
197
|
+
end
|
198
|
+
|
199
|
+
# Only do Inline formatting for versions of Prawn which support it.
|
200
|
+
#
|
201
|
+
def process_inline_formatting(str)
|
202
|
+
breg = [ %r{ \b(\_\_) (\S|\S.*?\S) \1\b }x, %r{ (\*\*) (\S|\S.*?\S) \1 }x ]
|
203
|
+
ireg = [ %r{ (\*) (\S|\S.*?\S) \1 }x, %r{ \b(_) (\S|\S.*?\S) \1\b }x ]
|
204
|
+
if Prawn::VERSION =~ /^0.1/ || Prawn::VERSION =~ /^1/
|
205
|
+
str.gsub(breg[0], %{<b>\\2</b>} ).gsub(breg[1], %{<b>\\2</b>} ).gsub(ireg[0], %{<i>\\2</i>} ).gsub(ireg[1], %{<i>\\2</i>} )
|
206
|
+
else
|
207
|
+
str.gsub(breg[0], %{\\2} ).gsub(breg[1], %{\\2} ).gsub(ireg[0], %{\\2} ).gsub(ireg[1], %{\\2} )
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module MarkdownPrawn
|
2
|
+
class StringParser < Parser
|
3
|
+
# Take a string or an object which responds to to_s and attemps to
|
4
|
+
# parse markdown in it.
|
5
|
+
def initialize(string_to_convert)
|
6
|
+
string_to_convert = string_to_convert.to_s
|
7
|
+
@content = detab(string_to_convert.gsub(/\r\n?/, "\n")).split("\n")
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
description = "Markdown Parawn is a library and an executable strip which allow you to generate a PDF from any valid Markdown."
|
2
|
+
Gem::Specification.new do |spec|
|
3
|
+
spec.name = "markdown_prawn"
|
4
|
+
spec.version = '0.0.1.pre'
|
5
|
+
spec.platform = Gem::Platform::RUBY
|
6
|
+
spec.files = Dir.glob("{bin,lib,test}/**/**/*") +
|
7
|
+
["Rakefile", "markdown_prawn.gemspec"]
|
8
|
+
spec.require_path = "lib"
|
9
|
+
spec.required_ruby_version = '>= 1.8.7'
|
10
|
+
spec.required_rubygems_version = ">= 1.3.6"
|
11
|
+
|
12
|
+
spec.test_files = Dir[ "test/*_test.rb" ]
|
13
|
+
spec.has_rdoc = false
|
14
|
+
spec.author = "Ryan Stenhouse"
|
15
|
+
spec.email = "ryan@ryanstenhouse.eu"
|
16
|
+
spec.rubyforge_project = "markdown_prawn"
|
17
|
+
spec.add_dependency('prawn', '~>0.10')
|
18
|
+
spec.homepage = "http://ryanstenhouse.eu"
|
19
|
+
spec.summary = description
|
20
|
+
spec.description = description
|
21
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper.rb'
|
2
|
+
|
3
|
+
class TestListsHandling < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@unordered = MarkdownPrawn::FileParser.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/unordered_lists.mdown'))
|
7
|
+
@ordered = MarkdownPrawn::FileParser.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/ordered_lists.mdown'))
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_document_structure_is_correct_for_unordered_lists
|
11
|
+
@unordered.parse
|
12
|
+
assert !@unordered.document_structure.empty?
|
13
|
+
assert_equal ListFragment, @unordered.document_structure[0].class
|
14
|
+
assert_equal false, @unordered.document_structure[0].ordered?
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_document_structure_is_correct_for_ordered_lists
|
18
|
+
@ordered.parse
|
19
|
+
assert !@ordered.document_structure.empty?
|
20
|
+
assert_equal ListFragment, @ordered.document_structure[0].class
|
21
|
+
assert_equal true, @ordered.document_structure[0].ordered?
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper.rb'
|
2
|
+
|
3
|
+
class TestParagraphHandling < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@paragraphs = MarkdownPrawn::FileParser.new(File.expand_path(File.dirname(__FILE__) + '/fixtures/paragraphs.mdown'))
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_document_structure_is_correct_for_paragraphs
|
10
|
+
@paragraphs.parse
|
11
|
+
assert !@paragraphs.document_structure.empty?
|
12
|
+
assert_equal 2, @paragraphs.document_structure.nitems
|
13
|
+
@paragraphs.document_structure.each do |fragment|
|
14
|
+
assert_equal ParagraphFragment, fragment.class
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: markdown_prawn
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 961915968
|
5
|
+
prerelease: true
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
- pre
|
11
|
+
version: 0.0.1.pre
|
12
|
+
platform: ruby
|
13
|
+
authors:
|
14
|
+
- Ryan Stenhouse
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-11-01 00:00:00 +00:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: prawn
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 31
|
31
|
+
segments:
|
32
|
+
- 0
|
33
|
+
- 10
|
34
|
+
version: "0.10"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
description: Markdown Parawn is a library and an executable strip which allow you to generate a PDF from any valid Markdown.
|
38
|
+
email: ryan@ryanstenhouse.eu
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- bin/md2pdf
|
47
|
+
- lib/markdown_fragments.rb
|
48
|
+
- lib/markdown_parser/parser.rb
|
49
|
+
- lib/markdown_parser/file_parser.rb
|
50
|
+
- lib/markdown_parser/string_parser.rb
|
51
|
+
- lib/markdown_parser.rb
|
52
|
+
- lib/markdown_fragments/paragraph_fragment.rb
|
53
|
+
- lib/markdown_fragments/markdown_fragment.rb
|
54
|
+
- lib/markdown_fragments/image_fragment.rb
|
55
|
+
- lib/markdown_fragments/heading_fragment.rb
|
56
|
+
- lib/markdown_fragments/links_reference_fragment.rb
|
57
|
+
- lib/markdown_fragments/list_fragment.rb
|
58
|
+
- lib/markdown_fragments/horizontal_rule_fragment.rb
|
59
|
+
- lib/markdown_prawn_exceptions.rb
|
60
|
+
- test/test_lists_handling.rb
|
61
|
+
- test/test_paragraph_handling.rb
|
62
|
+
- test/fixtures/ordered_lists.mdown
|
63
|
+
- test/fixtures/paragraphs.mdown
|
64
|
+
- test/fixtures/unordered_lists.mdown
|
65
|
+
- test/helper.rb
|
66
|
+
- Rakefile
|
67
|
+
- markdown_prawn.gemspec
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: http://ryanstenhouse.eu
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
hash: 57
|
83
|
+
segments:
|
84
|
+
- 1
|
85
|
+
- 8
|
86
|
+
- 7
|
87
|
+
version: 1.8.7
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 23
|
94
|
+
segments:
|
95
|
+
- 1
|
96
|
+
- 3
|
97
|
+
- 6
|
98
|
+
version: 1.3.6
|
99
|
+
requirements: []
|
100
|
+
|
101
|
+
rubyforge_project: markdown_prawn
|
102
|
+
rubygems_version: 1.3.7
|
103
|
+
signing_key:
|
104
|
+
specification_version: 3
|
105
|
+
summary: Markdown Parawn is a library and an executable strip which allow you to generate a PDF from any valid Markdown.
|
106
|
+
test_files: []
|
107
|
+
|