pseudohikiparser 0.0.3 → 0.0.4.develop
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.ja.md +132 -8
- data/README.md +134 -10
- data/lib/htmlelement.rb +42 -42
- data/lib/pseudohiki/autolink.rb +60 -0
- data/lib/pseudohiki/blockparser.rb +233 -125
- data/lib/pseudohiki/converter.rb +140 -81
- data/lib/pseudohiki/htmlformat.rb +156 -82
- data/lib/pseudohiki/htmlplugin.rb +9 -28
- data/lib/pseudohiki/inlineparser.rb +21 -24
- data/lib/pseudohiki/markdownformat.rb +94 -98
- data/lib/pseudohiki/plaintextformat.rb +67 -57
- data/lib/pseudohiki/sinatra_helpers.rb +23 -0
- data/lib/pseudohiki/treestack.rb +4 -4
- data/lib/pseudohiki/utils.rb +1 -2
- data/lib/pseudohiki/version.rb +1 -1
- data/lib/pseudohikiparser.rb +49 -28
- data/test/test_autolink.rb +104 -0
- data/test/test_blockparser.rb +78 -11
- data/test/test_htmlformat.rb +436 -0
- data/test/test_htmlplugin.rb +43 -0
- data/test/test_markdownformat.rb +156 -3
- data/test/test_plaintextformat.rb +85 -0
- data/test/test_pseudohiki2html.rb +82 -0
- data/test/test_pseudohikiparser.rb +286 -0
- data/test/test_utils.rb +1 -1
- metadata +22 -4
data/lib/pseudohikiparser.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "pseudohiki/htmlformat"
|
4
4
|
require "pseudohiki/plaintextformat"
|
5
5
|
require "pseudohiki/markdownformat"
|
6
|
+
require 'pseudohiki/autolink'
|
6
7
|
require "pseudohiki/version"
|
7
8
|
|
8
9
|
# = PseudoHikiParser -- A converter of texts written in a Hiki-like notation into HTML or other formats.
|
@@ -13,25 +14,41 @@ module PseudoHiki
|
|
13
14
|
# This class provides class methods for converting texts written in a Hiki-like notation into HTML or other formats.
|
14
15
|
#
|
15
16
|
class Format
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
@formatter = {}
|
18
|
+
@preset_options = {}
|
19
|
+
@type_to_formatter = {}
|
20
|
+
@html_types = [:html, :xhtml, :html5]
|
19
21
|
|
20
22
|
[
|
21
23
|
[:html, HtmlFormat, nil],
|
22
24
|
[:xhtml, XhtmlFormat, nil],
|
23
25
|
[:html5, Xhtml5Format, nil],
|
24
|
-
[:plain, PlainTextFormat, {:verbose_mode => false }],
|
25
|
-
[:plain_verbose, PlainTextFormat, {:verbose_mode => true }],
|
26
|
-
[:markdown, MarkDownFormat, { :strict_mode=> false, :gfm_style => false }],
|
27
|
-
[:gfm, MarkDownFormat, { :strict_mode=> false, :gfm_style => true }]
|
26
|
+
[:plain, PlainTextFormat, { :verbose_mode => false }],
|
27
|
+
[:plain_verbose, PlainTextFormat, { :verbose_mode => true }],
|
28
|
+
[:markdown, MarkDownFormat, { :strict_mode => false, :gfm_style => false }],
|
29
|
+
[:gfm, MarkDownFormat, { :strict_mode => false, :gfm_style => true }]
|
28
30
|
].each do |type, formatter, options|
|
29
31
|
preset_options = [type, nil]
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
@formatter[preset_options] = formatter.create(options)
|
33
|
+
@preset_options[type] = preset_options
|
34
|
+
@type_to_formatter[type] = formatter
|
33
35
|
end
|
34
36
|
|
37
|
+
def self.select_formatter(format_type, options)
|
38
|
+
if options
|
39
|
+
@formatter[[format_type, options]] ||= @type_to_formatter[format_type].create(options)
|
40
|
+
else
|
41
|
+
@formatter[@preset_options[format_type]]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.auto_link_url?(auto_linker)
|
46
|
+
return true if auto_linker.nil?
|
47
|
+
auto_linker.auto_link_url?
|
48
|
+
end
|
49
|
+
|
50
|
+
private_class_method :select_formatter, :auto_link_url?
|
51
|
+
|
35
52
|
# Converts <hiki_data> into a format specified by <format_type>
|
36
53
|
#
|
37
54
|
# <hiki_data> should be a string or an array of strings
|
@@ -45,14 +62,16 @@ module PseudoHiki
|
|
45
62
|
# [:markdown] Markdown
|
46
63
|
# [:gfm] GitHub Flavored Markdown
|
47
64
|
#
|
48
|
-
def self.format(hiki_data, format_type, options=nil,
|
49
|
-
|
65
|
+
def self.format(hiki_data, format_type, options=nil,
|
66
|
+
auto_linker=BlockParser.auto_linker, &block)
|
67
|
+
tree = BlockParser.parse(hiki_data, auto_linker)
|
68
|
+
formatter = select_formatter(format_type, options)
|
50
69
|
|
51
|
-
if
|
52
|
-
|
70
|
+
if @html_types.include? format_type
|
71
|
+
formatter.format(tree, { :auto_link_in_verbatim => auto_link_url?(auto_linker) })
|
53
72
|
else
|
54
|
-
|
55
|
-
end.
|
73
|
+
formatter.format(tree)
|
74
|
+
end.tap do |formatted|
|
56
75
|
block.call(formatted) if block
|
57
76
|
end.to_s
|
58
77
|
end
|
@@ -92,42 +111,44 @@ module PseudoHiki
|
|
92
111
|
# <!-- end of section h2 -->
|
93
112
|
# </div>
|
94
113
|
#
|
95
|
-
def self.to_html(hiki_data, &block)
|
96
|
-
format(hiki_data, :html,
|
114
|
+
def self.to_html(hiki_data, auto_linker=BlockParser.auto_linker, &block)
|
115
|
+
format(hiki_data, :html, nil, auto_linker, &block)
|
97
116
|
end
|
98
117
|
|
99
118
|
# Converts <hiki_data> into XHTML1.0
|
100
119
|
#
|
101
120
|
# You can give a block to this method as in the case of ::to_html, but the parameter to the block is a tree of XhtmlElement objects
|
102
121
|
#
|
103
|
-
def self.to_xhtml(hiki_data, &block)
|
104
|
-
format(hiki_data, :xhtml,
|
122
|
+
def self.to_xhtml(hiki_data, auto_linker=BlockParser.auto_linker, &block)
|
123
|
+
format(hiki_data, :xhtml, nil, auto_linker, &block)
|
105
124
|
end
|
106
125
|
|
107
126
|
# Converts <hiki_data> into HTML5
|
108
127
|
#
|
109
128
|
# You can give a block to this method as in the case of ::to_html, but the parameter to the block is a tree of Xhtml5Element objects
|
110
129
|
#
|
111
|
-
def self.to_html5(hiki_data, &block)
|
112
|
-
format(hiki_data, :html5,
|
130
|
+
def self.to_html5(hiki_data, auto_linker=BlockParser.auto_linker, &block)
|
131
|
+
format(hiki_data, :html5, nil, auto_linker, &block)
|
113
132
|
end
|
114
133
|
|
115
134
|
# Converts <hiki_data> into plain texts without tags
|
116
135
|
#
|
117
|
-
def self.to_plain(hiki_data, &block)
|
118
|
-
format(hiki_data, :plain,
|
136
|
+
def self.to_plain(hiki_data, auto_linker=BlockParser.auto_linker, &block)
|
137
|
+
format(hiki_data, :plain, nil, auto_linker, &block)
|
119
138
|
end
|
120
139
|
|
121
140
|
# Converts <hiki_data> into Markdown
|
122
141
|
#
|
123
|
-
def self.to_markdown(hiki_data, &block)
|
124
|
-
format(hiki_data, :markdown,
|
142
|
+
def self.to_markdown(hiki_data, auto_linker=BlockParser.auto_linker, &block)
|
143
|
+
format(hiki_data, :markdown, nil, auto_linker, &block)
|
125
144
|
end
|
126
145
|
|
127
146
|
# Converts <hiki_data> into GitHub Flavored Markdown
|
128
147
|
#
|
129
|
-
def self.to_gfm(hiki_data, &block)
|
130
|
-
format(hiki_data, :gfm,
|
148
|
+
def self.to_gfm(hiki_data, auto_linker=BlockParser.auto_linker, &block)
|
149
|
+
format(hiki_data, :gfm, nil, auto_linker, &block)
|
131
150
|
end
|
132
151
|
end
|
133
152
|
end
|
153
|
+
|
154
|
+
require 'pseudohiki/sinatra_helpers' if defined? Sinatra
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'lib/pseudohiki/blockparser'
|
5
|
+
require 'lib/pseudohiki/htmlformat'
|
6
|
+
require 'lib/pseudohiki/autolink'
|
7
|
+
|
8
|
+
class TC_WikiName < MiniTest::Unit::TestCase
|
9
|
+
include PseudoHiki
|
10
|
+
|
11
|
+
|
12
|
+
def test_link_only_url
|
13
|
+
text = <<TEXT
|
14
|
+
a line with a url http://www.example.org/ and a WikiName.
|
15
|
+
TEXT
|
16
|
+
|
17
|
+
xhtml = <<HTML
|
18
|
+
<p>
|
19
|
+
a line with a url <a href="http://www.example.org/">http://www.example.org/</a> and a WikiName.
|
20
|
+
</p>
|
21
|
+
HTML
|
22
|
+
auto_linker = AutoLink::WikiName.new({:wiki_name => false})
|
23
|
+
tree = BlockParser.parse(text.lines.to_a, auto_linker)
|
24
|
+
assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_link_wiki_name
|
28
|
+
text = <<TEXT
|
29
|
+
a line with a url http://www.example.org/ , an ^EscapedWikiName and a WikiName.
|
30
|
+
TEXT
|
31
|
+
|
32
|
+
xhtml = <<HTML
|
33
|
+
<p>
|
34
|
+
a line with a url <a href="http://www.example.org/">http://www.example.org/</a> , an EscapedWikiName and a <a href="WikiName">WikiName</a>.
|
35
|
+
</p>
|
36
|
+
HTML
|
37
|
+
auto_linker = AutoLink::WikiName.new
|
38
|
+
tree = BlockParser.parse(text.lines.to_a, auto_linker)
|
39
|
+
assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_not_escape_wiki_name
|
43
|
+
text = <<TEXT
|
44
|
+
a line with a url http://www.example.org/ , an ^EscapedWikiName and a WikiName.
|
45
|
+
TEXT
|
46
|
+
|
47
|
+
xhtml = <<HTML
|
48
|
+
<p>
|
49
|
+
a line with a url <a href="http://www.example.org/">http://www.example.org/</a> , an ^<a href="EscapedWikiName">EscapedWikiName</a> and a <a href="WikiName">WikiName</a>.
|
50
|
+
</p>
|
51
|
+
HTML
|
52
|
+
auto_linker = AutoLink::WikiName.new({:wiki_name => true, :escape_wiki_name => false})
|
53
|
+
tree = BlockParser.parse(text.lines.to_a, auto_linker)
|
54
|
+
assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_link_only_wiki_name
|
58
|
+
text = <<TEXT
|
59
|
+
a line with a url http://www.example.org/ , an ^EscapedWikiName and a WikiName.
|
60
|
+
TEXT
|
61
|
+
|
62
|
+
xhtml = <<HTML
|
63
|
+
<p>
|
64
|
+
a line with a url http://www.example.org/ , an EscapedWikiName and a <a href="WikiName">WikiName</a>.
|
65
|
+
</p>
|
66
|
+
HTML
|
67
|
+
auto_linker = AutoLink::WikiName.new({:url => false, :wiki_name => true, :escape_wiki_name => true})
|
68
|
+
tree = BlockParser.parse(text.lines.to_a, auto_linker)
|
69
|
+
assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_link_wiki_name_in_quote
|
73
|
+
text = <<TEXT
|
74
|
+
""a line with a url http://www.example.org/ , an ^EscapedWikiName and a WikiName.
|
75
|
+
TEXT
|
76
|
+
|
77
|
+
xhtml = <<HTML
|
78
|
+
<blockquote>
|
79
|
+
<p>
|
80
|
+
a line with a url <a href="http://www.example.org/">http://www.example.org/</a> , an EscapedWikiName and a <a href="WikiName">WikiName</a>.
|
81
|
+
</p>
|
82
|
+
</blockquote>
|
83
|
+
HTML
|
84
|
+
|
85
|
+
wikiname_off_xhtml = <<HTML
|
86
|
+
<blockquote>
|
87
|
+
<p>
|
88
|
+
a line with a url <a href="http://www.example.org/">http://www.example.org/</a> , an ^EscapedWikiName and a WikiName.
|
89
|
+
</p>
|
90
|
+
</blockquote>
|
91
|
+
HTML
|
92
|
+
auto_linker = AutoLink::WikiName.new({:wiki_name => true, :escape_wiki_name => true})
|
93
|
+
tree = BlockParser.parse(text.lines.to_a, auto_linker)
|
94
|
+
assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
|
95
|
+
|
96
|
+
BlockParser.auto_linker = AutoLink::WikiName.new({:wiki_name => true, :escape_wiki_name => true})
|
97
|
+
tree = BlockParser.parse(text.lines.to_a)
|
98
|
+
assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
|
99
|
+
|
100
|
+
BlockParser.auto_linker = nil
|
101
|
+
tree = BlockParser.parse(text.lines.to_a)
|
102
|
+
assert_equal(wikiname_off_xhtml, XhtmlFormat.format(tree).to_s)
|
103
|
+
end
|
104
|
+
end
|
data/test/test_blockparser.rb
CHANGED
@@ -39,7 +39,7 @@ class TC_BlockLeaf < MiniTest::Unit::TestCase
|
|
39
39
|
paragraph_line = "This is a paragraph."
|
40
40
|
paragraph = parser.select_leaf_type(paragraph_line).create(paragraph_line)
|
41
41
|
assert_equal([paragraph_line], paragraph)
|
42
|
-
assert_equal(nil, paragraph.
|
42
|
+
assert_equal(nil, paragraph.level)
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_nestedleaf_create
|
@@ -47,12 +47,12 @@ class TC_BlockLeaf < MiniTest::Unit::TestCase
|
|
47
47
|
level1_heading_line = "!This is a level1 heading."
|
48
48
|
heading1 = parser.select_leaf_type(level1_heading_line).create(level1_heading_line)
|
49
49
|
assert_equal([["This is a level1 heading."]], heading1)
|
50
|
-
assert_equal(1, heading1.
|
50
|
+
assert_equal(1, heading1.level)
|
51
51
|
|
52
52
|
level2_heading_line = "!!This is a level2 heading."
|
53
53
|
heading2 = parser.select_leaf_type(level2_heading_line).create(level2_heading_line)
|
54
54
|
assert_equal([["This is a level2 heading."]], heading2)
|
55
|
-
assert_equal(2, heading2.
|
55
|
+
assert_equal(2, heading2.level)
|
56
56
|
end
|
57
57
|
|
58
58
|
def test_select_leaf_type
|
@@ -85,7 +85,7 @@ class TC_BlockLeaf < MiniTest::Unit::TestCase
|
|
85
85
|
stack.push create_leaf(paragraph_str)
|
86
86
|
paragraph_tree = stack.tree
|
87
87
|
assert_equal([[[paragraph_str]]],paragraph_tree)
|
88
|
-
assert_equal(nil,paragraph_tree.first.
|
88
|
+
assert_equal(nil,paragraph_tree.first.level)
|
89
89
|
another_paragraph = create_leaf(another_paragraph_str)
|
90
90
|
stack.push another_paragraph
|
91
91
|
assert_equal([[[paragraph_str,
|
@@ -96,7 +96,7 @@ class TC_BlockLeaf < MiniTest::Unit::TestCase
|
|
96
96
|
stack.push create_leaf("!"+heading_str)
|
97
97
|
heading_tree = stack.tree
|
98
98
|
# heading_tree = push_leaf_on_stack("!"+heading_str).tree
|
99
|
-
assert_equal(1,heading_tree.first.
|
99
|
+
assert_equal(1,heading_tree.first.level)
|
100
100
|
assert_equal(HeadingNode, heading_tree.first.class)
|
101
101
|
assert_equal(HeadingLeaf, heading_tree.first.first.class)
|
102
102
|
stack.push create_leaf("!!"+heading_str)
|
@@ -107,7 +107,7 @@ class TC_BlockLeaf < MiniTest::Unit::TestCase
|
|
107
107
|
stack.push create_leaf("!!"+heading_str)
|
108
108
|
heading2_tree = stack.tree
|
109
109
|
assert_equal([[[[heading_str]]]], heading2_tree)
|
110
|
-
assert_equal(2,heading2_tree.first.
|
110
|
+
assert_equal(2,heading2_tree.first.level)
|
111
111
|
|
112
112
|
stack = PseudoHiki::BlockParser.new.stack
|
113
113
|
stack.push create_leaf("!"+heading_str)
|
@@ -180,11 +180,11 @@ class TC_BlockLeaf < MiniTest::Unit::TestCase
|
|
180
180
|
parser.stack.push list2_leaf
|
181
181
|
current_node_superclass = parser.stack.current_node.class.superclass
|
182
182
|
leaf_superclass = list1_leaf.block.superclass
|
183
|
-
assert_equal(2, parser.stack.current_node.
|
183
|
+
assert_equal(2, parser.stack.current_node.level)
|
184
184
|
assert_equal(ListNode, list1_leaf.block)
|
185
|
-
assert_equal(1, list1_leaf.
|
185
|
+
assert_equal(1, list1_leaf.level)
|
186
186
|
assert_equal(ListNode, list2_leaf.block)
|
187
|
-
assert_equal(2, list2_leaf.
|
187
|
+
assert_equal(2, list2_leaf.level)
|
188
188
|
assert_equal(ListWrapNode, parser.stack.current_node.class)
|
189
189
|
# assert_equal(true, parser.stack.current_node.class.kind_of?(PseudoHiki::BlockParser::ListTypeBlockNode))
|
190
190
|
assert_equal(PseudoHiki::BlockParser::ListLeafNode, current_node_superclass)
|
@@ -192,8 +192,8 @@ class TC_BlockLeaf < MiniTest::Unit::TestCase
|
|
192
192
|
assert_equal(false, current_node_superclass == leaf_superclass)
|
193
193
|
assert_equal(true, PseudoHiki::BlockParser::ListTypeBlockNode == leaf_superclass)
|
194
194
|
assert_equal(true, parser.breakable?(blocknode_end))
|
195
|
-
assert_equal(false, parser.stack.current_node.
|
196
|
-
assert_equal(true, parser.stack.current_node.
|
195
|
+
assert_equal(false, parser.stack.current_node.level <= list1_leaf.level)
|
196
|
+
assert_equal(true, parser.stack.current_node.level <= list2_leaf.level)
|
197
197
|
assert_equal(true, parser.breakable?(list1_leaf))
|
198
198
|
assert_equal(true, parser.breakable?(list2_leaf))
|
199
199
|
parser.stack.pop
|
@@ -311,6 +311,73 @@ TEXT
|
|
311
311
|
assert_equal([[[["heading"]]]],parsed)
|
312
312
|
end
|
313
313
|
|
314
|
+
|
315
|
+
def test_decorator
|
316
|
+
text = <<TEXT
|
317
|
+
//@class[section_name]
|
318
|
+
!!title of section
|
319
|
+
|
320
|
+
//@summary: Summary of the table
|
321
|
+
||!header 1||! header 2
|
322
|
+
||cell 1||cell 2
|
323
|
+
|
324
|
+
a paragraph.
|
325
|
+
|
326
|
+
//@class[class_name]
|
327
|
+
//@[id_name]
|
328
|
+
another paragraph.
|
329
|
+
TEXT
|
330
|
+
|
331
|
+
tree = PseudoHiki::BlockParser.parse(text.lines.to_a.map {|line| line.chomp })
|
332
|
+
assert_equal(PseudoHiki::BlockParser::BlockNode, tree.class)
|
333
|
+
assert_equal("section_name", tree[0].decorator["class"].id)
|
334
|
+
assert_equal(PseudoHiki::BlockParser::BlockElement::HeadingNode, tree[0].class)
|
335
|
+
assert_equal([[["title of section"]], [[[["header 1"]], [[" header 2"]]], [[["cell 1"]], [["cell 2"]]]], [[["a paragraph."]]], [[["another paragraph."]]]], tree[0])
|
336
|
+
assert_equal([["Summary of the table"]], tree[0][1].decorator["summary"].value)
|
337
|
+
assert_equal(PseudoHiki::BlockParser::BlockElement::TableNode, tree[0][1].class)
|
338
|
+
assert_equal(nil, tree[0][2].decorator)
|
339
|
+
assert_equal('id_name', tree[0][3].decorator[:id].id)
|
340
|
+
assert_equal('class_name', tree[0][3].decorator["class"].id)
|
341
|
+
end
|
342
|
+
|
343
|
+
def test_sectioning_node
|
344
|
+
text = <<TEXT
|
345
|
+
! Main title
|
346
|
+
|
347
|
+
//@begin[header]
|
348
|
+
!! first title in header
|
349
|
+
|
350
|
+
paragraph
|
351
|
+
|
352
|
+
!! second title in header
|
353
|
+
|
354
|
+
paragraph2
|
355
|
+
|
356
|
+
//@end[header]
|
357
|
+
|
358
|
+
!! first subtitle in main part
|
359
|
+
|
360
|
+
paragraph3
|
361
|
+
|
362
|
+
TEXT
|
363
|
+
|
364
|
+
expected_tree = [[[[" Main title\n"]],
|
365
|
+
[
|
366
|
+
[[[" first title in header\n"]],
|
367
|
+
[[["paragraph\n"]]]],
|
368
|
+
[[[" second title in header\n"]],
|
369
|
+
[[["paragraph2\n"]]]]
|
370
|
+
],
|
371
|
+
[[[" first subtitle in main part\n"]],
|
372
|
+
[[["paragraph3\n"]]]]]]
|
373
|
+
|
374
|
+
|
375
|
+
tree = PseudoHiki::BlockParser.parse(text)
|
376
|
+
assert_equal(expected_tree, tree)
|
377
|
+
assert_kind_of(PseudoHiki::BlockParser::BlockElement::SectioningNode, tree[0][1])
|
378
|
+
assert_equal("header", tree[0][1].node_id)
|
379
|
+
end
|
380
|
+
|
314
381
|
def test_comment_out_followed_by_a_verbatim_block
|
315
382
|
text = <<TEXT
|
316
383
|
the first paragraph
|