pseudohikiparser 0.0.3 → 0.0.4.develop
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.
- 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
|