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
@@ -18,9 +18,15 @@ module PseudoHiki
|
|
18
18
|
GFM_STRIPPED_CHARS = " -&+$,/:;=?@\"{}#|^~[]`\\*()%.!'"
|
19
19
|
GFM_STRIPPED_CHARS_PAT = Regexp.union(/\s+/o, /[#{Regexp.escape(GFM_STRIPPED_CHARS)}]/o)
|
20
20
|
|
21
|
-
|
21
|
+
@default_options = { :strict_mode => false, :gfm_style => false }
|
22
|
+
|
23
|
+
def self.default_options
|
24
|
+
@default_options
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.format(tree, options=MarkDownFormat.default_options)
|
22
28
|
if Formatters.empty?
|
23
|
-
default_options =
|
29
|
+
default_options = MarkDownFormat.default_options
|
24
30
|
Formatters[default_options] = create(default_options)
|
25
31
|
end
|
26
32
|
|
@@ -28,15 +34,14 @@ module PseudoHiki
|
|
28
34
|
Formatters[options].format(tree)
|
29
35
|
end
|
30
36
|
|
31
|
-
def self.
|
37
|
+
def self.convert_into_gfm_id_format(heading)
|
32
38
|
heading.gsub(GFM_STRIPPED_CHARS_PAT) do |char|
|
33
39
|
/\A\s+\Z/o =~ char ? '-'.freeze : ''.freeze
|
34
40
|
end.downcase
|
35
41
|
end
|
36
42
|
|
37
|
-
def initialize(formatter={}, options=
|
43
|
+
def initialize(formatter={}, options=MarkDownFormat.default_options)
|
38
44
|
@formatter = formatter
|
39
|
-
options_given_via_block = nil
|
40
45
|
if block_given?
|
41
46
|
options_given_via_block = yield
|
42
47
|
options.merge!(options_given_via_block)
|
@@ -49,7 +54,7 @@ module PseudoHiki
|
|
49
54
|
end
|
50
55
|
|
51
56
|
def visited_result(node)
|
52
|
-
visitor = @formatter[node.class]
|
57
|
+
visitor = @formatter[node.class] || @formatter[PlainNode]
|
53
58
|
node.accept(visitor)
|
54
59
|
end
|
55
60
|
|
@@ -69,14 +74,14 @@ module PseudoHiki
|
|
69
74
|
|
70
75
|
def format(tree)
|
71
76
|
formatter = get_plain
|
72
|
-
|
77
|
+
prepare_id_conv_table(tree) if @options.gfm_style
|
73
78
|
tree.accept(formatter).join
|
74
79
|
end
|
75
80
|
|
76
81
|
def list_mark(tree, mark)
|
77
82
|
mark = mark.dup
|
78
83
|
mark << " " if /^ /o !~ tree.join
|
79
|
-
" " * (tree.
|
84
|
+
" " * (tree.level - 1) * 2 + mark
|
80
85
|
end
|
81
86
|
|
82
87
|
def enclose_in(element, mark)
|
@@ -94,63 +99,56 @@ module PseudoHiki
|
|
94
99
|
end
|
95
100
|
end
|
96
101
|
|
102
|
+
def heading_to_gfm_id(heading)
|
103
|
+
heading_text = PlainTextFormat.format(heading).strip
|
104
|
+
MarkDownFormat.convert_into_gfm_id_format(heading_text)
|
105
|
+
end
|
106
|
+
|
97
107
|
def prepare_id_conv_table(tree)
|
98
108
|
{}.tap do |table|
|
99
109
|
collect_headings(tree).each do |heading|
|
100
110
|
if node_id = heading.node_id
|
101
|
-
|
102
|
-
table[node_id] = MarkDownFormat.convert_to_gfm_id_format(heading_text)
|
111
|
+
table[node_id] = heading_to_gfm_id(heading)
|
103
112
|
end
|
104
113
|
end
|
114
|
+
@formatter[LinkNode].id_conv_table = table
|
105
115
|
end
|
106
116
|
end
|
107
117
|
|
108
118
|
def self.create(options={ :strict_mode => false })
|
109
119
|
formatter = {}
|
110
|
-
|
111
|
-
formatter.
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
formatter[ListNode] = ListNodeFormatter.new(formatter, options)
|
143
|
-
formatter[EnumNode] = EnumNodeFormatter.new(formatter, options)
|
144
|
-
formatter[ListWrapNode] = ListWrapNodeFormatter.new(formatter, options)
|
145
|
-
formatter[EnumWrapNode] = EnumWrapNodeFormatter.new(formatter, options)
|
146
|
-
|
147
|
-
main_formatter
|
148
|
-
end
|
149
|
-
|
150
|
-
## Definitions of subclasses of MarkDownFormat begins here.
|
151
|
-
|
152
|
-
# class PlainNodeFormatter < self; end
|
153
|
-
# class InlineNodeFormatter < self; end
|
120
|
+
|
121
|
+
new(formatter, options).tap do |main_formatter|
|
122
|
+
formatter.default = main_formatter
|
123
|
+
|
124
|
+
[[InlineLeaf, InlineLeafFormatter],
|
125
|
+
[LinkNode, LinkNodeFormatter],
|
126
|
+
[EmNode, EmNodeFormatter],
|
127
|
+
[StrongNode, StrongNodeFormatter],
|
128
|
+
[DelNode, DelNodeFormatter],
|
129
|
+
[LiteralNode, LiteralNodeFormatter],
|
130
|
+
[PluginNode, PluginNodeFormatter],
|
131
|
+
[VerbatimLeaf, VerbatimLeafFormatter],
|
132
|
+
[CommentOutLeaf, CommentOutLeafFormatter],
|
133
|
+
[HeadingLeaf, HeadingLeafFormatter],
|
134
|
+
[HrLeaf, HrLeafFormatter],
|
135
|
+
[DescNode, DescNodeFormatter],
|
136
|
+
[VerbatimNode, VerbatimNodeFormatter],
|
137
|
+
[QuoteNode, QuoteNodeFormatter],
|
138
|
+
[TableNode, TableNodeFormatter],
|
139
|
+
[HeadingNode, HeadingNodeFormatter],
|
140
|
+
[ParagraphNode, ParagraphNodeFormatter],
|
141
|
+
[ListNode, ListNodeFormatter],
|
142
|
+
[EnumNode, EnumNodeFormatter],
|
143
|
+
[ListWrapNode, ListWrapNodeFormatter],
|
144
|
+
[EnumWrapNode, EnumWrapNodeFormatter]
|
145
|
+
].each do |node, formatter_class|
|
146
|
+
formatter[node] = formatter_class.new(formatter, options)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
## Definitions of subclasses of MarkDownFormat begins here.
|
154
152
|
|
155
153
|
class InlineLeafFormatter < self
|
156
154
|
def visit(leaf)
|
@@ -173,15 +171,11 @@ module PseudoHiki
|
|
173
171
|
tree = tree.dup
|
174
172
|
element = create_self_element
|
175
173
|
caption = get_caption(tree)
|
176
|
-
|
177
|
-
|
178
|
-
rescue NoMethodError
|
179
|
-
raise NoMethodError unless tree.empty?
|
180
|
-
STDERR.puts "No uri is specified for #{caption}"
|
174
|
+
if IMAGE_SUFFIX_RE =~ ref_tail(tree, caption) and not_from_thumbnail
|
175
|
+
element.push "!"
|
181
176
|
end
|
182
|
-
element.push "!" if ImageSuffix =~ ref and not_from_thumbnail
|
183
177
|
link = format_link(tree)
|
184
|
-
element.push "[#{(caption||tree).join}](#{link})"
|
178
|
+
element.push "[#{(caption || tree).join}](#{link})"
|
185
179
|
element
|
186
180
|
end
|
187
181
|
|
@@ -202,6 +196,13 @@ module PseudoHiki
|
|
202
196
|
link
|
203
197
|
end
|
204
198
|
end
|
199
|
+
|
200
|
+
def ref_tail(tree, caption)
|
201
|
+
tree.last.join
|
202
|
+
rescue NoMethodError
|
203
|
+
raise NoMethodError unless tree.empty?
|
204
|
+
STDERR.puts "No uri is specified for #{caption}"
|
205
|
+
end
|
205
206
|
end
|
206
207
|
|
207
208
|
class EmNodeFormatter < self
|
@@ -234,24 +235,18 @@ module PseudoHiki
|
|
234
235
|
|
235
236
|
class PluginNodeFormatter < self
|
236
237
|
def visit(tree)
|
237
|
-
str =tree.join
|
238
|
+
str = tree.join
|
238
239
|
return str.strip * 2 if str == " {" or str == "} "
|
239
240
|
super(tree)
|
240
241
|
end
|
241
242
|
end
|
242
243
|
|
243
|
-
# class DescLeafFormatter < self; end
|
244
|
-
# class TableCellNodeFormatter < self; end
|
245
|
-
|
246
244
|
class VerbatimLeafFormatter < InlineLeafFormatter
|
247
245
|
def visit(leaf)
|
248
246
|
leaf.join
|
249
247
|
end
|
250
248
|
end
|
251
249
|
|
252
|
-
# class QuoteLeafFormatter < self; end
|
253
|
-
# class TableLeafFormatter < self; end
|
254
|
-
|
255
250
|
class CommentOutLeafFormatter < self
|
256
251
|
def visit(tree); ""; end
|
257
252
|
end
|
@@ -261,7 +256,6 @@ module PseudoHiki
|
|
261
256
|
super(tree).tap {|element| element.push $/ }
|
262
257
|
end
|
263
258
|
end
|
264
|
-
# class ParagraphLeafFormatter < self; end
|
265
259
|
|
266
260
|
class HrLeafFormatter < self
|
267
261
|
def visit(tree)
|
@@ -269,9 +263,6 @@ module PseudoHiki
|
|
269
263
|
end
|
270
264
|
end
|
271
265
|
|
272
|
-
# class BlockNodeEndFormatter < self; end
|
273
|
-
# class ListLeafFormatter < self; end
|
274
|
-
# class EnumLeafFormatter < self; end
|
275
266
|
class DescNodeFormatter < self
|
276
267
|
def visit(tree)
|
277
268
|
desc_list = HtmlElement.create("dl").tap do |element|
|
@@ -284,13 +275,14 @@ module PseudoHiki
|
|
284
275
|
class VerbatimNodeFormatter < self
|
285
276
|
def visit(tree)
|
286
277
|
element = super(tree)
|
278
|
+
@language_name = language_name(tree)
|
287
279
|
return gfm_verbatim(element) if @options.gfm_style
|
288
280
|
md_verbatim(element)
|
289
281
|
end
|
290
282
|
|
291
283
|
def gfm_verbatim(element)
|
292
284
|
element.tap do |lines|
|
293
|
-
lines.unshift "```#{$/}"
|
285
|
+
lines.unshift "```#{@language_name + $/}"
|
294
286
|
lines.push "```#{$/ * 2}"
|
295
287
|
end
|
296
288
|
end
|
@@ -298,6 +290,12 @@ module PseudoHiki
|
|
298
290
|
def md_verbatim(element)
|
299
291
|
element.join.gsub(/^/o, " ").sub(/ \Z/o, "").concat $/
|
300
292
|
end
|
293
|
+
|
294
|
+
def language_name(tree)
|
295
|
+
tree.decorator.tap do |decorator|
|
296
|
+
return decorator ? decorator["code"].id : ""
|
297
|
+
end
|
298
|
+
end
|
301
299
|
end
|
302
300
|
|
303
301
|
class QuoteNodeFormatter < self
|
@@ -323,13 +321,13 @@ module PseudoHiki
|
|
323
321
|
cell_width = calculate_cell_width(table)
|
324
322
|
header_delimiter = cell_width.map {|width| "-" * width }
|
325
323
|
cell_formats = cell_width.map {|width| "%-#{width}s" }
|
326
|
-
table[1,0] = [header_delimiter]
|
324
|
+
table[1, 0] = [header_delimiter]
|
327
325
|
table.map do |row|
|
328
|
-
formatted_row = row.zip(cell_formats).map do |cell,
|
329
|
-
|
326
|
+
formatted_row = row.zip(cell_formats).map do |cell, format_str|
|
327
|
+
sprintf(format_str, cell)
|
330
328
|
end
|
331
329
|
"|#{formatted_row.join("|") }|#{$/}"
|
332
|
-
end.join
|
330
|
+
end.join + $/
|
333
331
|
end
|
334
332
|
|
335
333
|
def format_html_table(tree)
|
@@ -344,15 +342,21 @@ module PseudoHiki
|
|
344
342
|
return format_gfm_table(table) if @options.gfm_conformant
|
345
343
|
|
346
344
|
if @options.gfm_style == :force
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
end
|
352
|
-
return format_gfm_table(table)
|
345
|
+
warning_for_non_comformant_style
|
346
|
+
format_gfm_table(table)
|
347
|
+
else
|
348
|
+
format_html_table(tree)
|
353
349
|
end
|
350
|
+
end
|
354
351
|
|
355
|
-
|
352
|
+
def warning_for_non_comformant_style
|
353
|
+
warning_message = <<ERROR
|
354
|
+
The table is not conformant to GFM style.
|
355
|
+
The first row will be treated as a header row.
|
356
|
+
ERROR
|
357
|
+
raise NotConformantStyleError.new(warning_message)
|
358
|
+
rescue
|
359
|
+
STDERR.puts warning_message
|
356
360
|
end
|
357
361
|
|
358
362
|
def calculate_cell_width(table)
|
@@ -369,8 +373,8 @@ module PseudoHiki
|
|
369
373
|
rows.each_with_index do |row, i|
|
370
374
|
row.each do |cell|
|
371
375
|
return false if cell.rowspan > 1 or cell.colspan > 1
|
372
|
-
#A table head row should be at the beginning and composed of <th>
|
373
|
-
#and other rows should not include <th> elements
|
376
|
+
# A table head row should be at the beginning and composed of <th>
|
377
|
+
# elements, and other rows should not include <th> elements
|
374
378
|
return false unless (i == 0) == (cell.cell_type == "th")
|
375
379
|
end
|
376
380
|
end
|
@@ -378,12 +382,10 @@ module PseudoHiki
|
|
378
382
|
end
|
379
383
|
end
|
380
384
|
|
381
|
-
# class CommentOutNodeFormatter < self; end
|
382
|
-
|
383
385
|
class HeadingNodeFormatter < self
|
384
386
|
def visit(tree)
|
385
387
|
super(tree).tap do |element|
|
386
|
-
heading_mark = "#" * tree.first.
|
388
|
+
heading_mark = "#" * tree.first.level
|
387
389
|
heading_mark << " " if /^ /o !~ tree.join
|
388
390
|
element.unshift heading_mark
|
389
391
|
end
|
@@ -396,14 +398,10 @@ module PseudoHiki
|
|
396
398
|
end
|
397
399
|
end
|
398
400
|
|
399
|
-
# class HrNodeFormatter < self; end
|
400
|
-
|
401
401
|
class ListNodeFormatter < self
|
402
402
|
def visit(tree)
|
403
403
|
super(tree).tap do |element|
|
404
|
-
if /\A\*/o =~ element.first.join
|
405
|
-
element.push $/
|
406
|
-
end
|
404
|
+
element.push $/ if /\A\*/o =~ element.first.join
|
407
405
|
end
|
408
406
|
end
|
409
407
|
end
|
@@ -411,9 +409,7 @@ module PseudoHiki
|
|
411
409
|
class EnumNodeFormatter < self
|
412
410
|
def visit(tree)
|
413
411
|
super(tree).tap do |element|
|
414
|
-
if /\A\d/o =~ element.first.join
|
415
|
-
element.push $/
|
416
|
-
end
|
412
|
+
element.push $/ if /\A\d/o =~ element.first.join
|
417
413
|
end
|
418
414
|
end
|
419
415
|
end
|
@@ -429,7 +425,7 @@ module PseudoHiki
|
|
429
425
|
class EnumWrapNodeFormatter < self
|
430
426
|
def visit(tree)
|
431
427
|
super(tree).tap do |element|
|
432
|
-
element.unshift list_mark(tree, "#{tree.
|
428
|
+
element.unshift list_mark(tree, "#{tree.level}.")
|
433
429
|
end
|
434
430
|
end
|
435
431
|
end
|
@@ -27,9 +27,8 @@ module PseudoHiki
|
|
27
27
|
Formatters[options].format(tree)
|
28
28
|
end
|
29
29
|
|
30
|
-
def initialize(formatter={}, options
|
30
|
+
def initialize(formatter={}, options={ :verbose_mode => false })
|
31
31
|
@formatter = formatter
|
32
|
-
options_given_via_block = nil
|
33
32
|
if block_given?
|
34
33
|
options_given_via_block = yield
|
35
34
|
options.merge!(options_given_via_block)
|
@@ -42,7 +41,7 @@ module PseudoHiki
|
|
42
41
|
end
|
43
42
|
|
44
43
|
def visited_result(node)
|
45
|
-
visitor = @formatter[node.class]
|
44
|
+
visitor = @formatter[node.class] || @formatter[PlainNode]
|
46
45
|
node.accept(visitor)
|
47
46
|
end
|
48
47
|
|
@@ -65,24 +64,39 @@ module PseudoHiki
|
|
65
64
|
tree.accept(formatter).join
|
66
65
|
end
|
67
66
|
|
68
|
-
def
|
67
|
+
def split_into_parts(tree, separator)
|
68
|
+
tree = tree.dup
|
69
|
+
first_part = nil
|
70
|
+
sep_index = tree.index(separator)
|
71
|
+
if sep_index
|
72
|
+
first_part = tree.shift(sep_index)
|
73
|
+
tree.shift
|
74
|
+
end
|
75
|
+
return first_part, tree
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.create(options={ :verbose_mode => false })
|
69
79
|
formatter = {}
|
70
|
-
main_formatter = self.new(formatter, options)
|
71
|
-
formatter.default = main_formatter
|
72
80
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
81
|
+
new(formatter, options).tap do |main_formatter|
|
82
|
+
formatter.default = main_formatter
|
83
|
+
|
84
|
+
[[InlineLeaf, InlineLeafFormatter],
|
85
|
+
[LinkNode, LinkNodeFormatter],
|
86
|
+
[DelNode, DelNodeFormatter],
|
87
|
+
[DescLeaf, DescLeafFormatter],
|
88
|
+
[VerbatimNode, VerbatimNodeFormatter],
|
89
|
+
[TableNode, TableNodeFormatter],
|
90
|
+
[CommentOutNode, CommentOutNodeFormatter],
|
91
|
+
[ParagraphNode, ParagraphNodeFormatter],
|
92
|
+
[PluginNode, PluginNodeFormatter]
|
93
|
+
].each do |node, formatter_class|
|
94
|
+
formatter[node] = formatter_class.new(formatter, options)
|
95
|
+
end
|
96
|
+
end
|
83
97
|
end
|
84
98
|
|
85
|
-
## Definitions of subclasses of PlainTextFormat begins here.
|
99
|
+
## Definitions of subclasses of PlainTextFormat begins here.
|
86
100
|
|
87
101
|
class InlineLeafFormatter < self
|
88
102
|
def visit(leaf)
|
@@ -92,30 +106,28 @@ module PseudoHiki
|
|
92
106
|
|
93
107
|
class LinkNodeFormatter < self
|
94
108
|
def visit(tree)
|
95
|
-
tree = tree.dup
|
96
109
|
element = Node.new
|
97
|
-
caption = get_caption(tree)
|
98
|
-
|
99
|
-
|
100
|
-
rescue NoMethodError
|
101
|
-
raise NoMethodError unless tree.empty?
|
102
|
-
STDERR.puts "No uri is specified for #{caption}"
|
103
|
-
end
|
104
|
-
if ImageSuffix =~ ref
|
105
|
-
element.push (caption||tree).join
|
110
|
+
caption, ref = get_caption(tree)
|
111
|
+
if IMAGE_SUFFIX_RE =~ ref_tail(ref, caption)
|
112
|
+
element.push (caption || ref).join
|
106
113
|
else
|
107
|
-
element.push caption||
|
108
|
-
element.push " (#{
|
114
|
+
element.push caption || ref.join
|
115
|
+
element.push " (#{ref.join})" if @options.verbose_mode and caption
|
109
116
|
end
|
110
117
|
element
|
111
118
|
end
|
112
119
|
|
113
120
|
def get_caption(tree)
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
121
|
+
caption, ref_part = split_into_parts(tree, [LinkSep])
|
122
|
+
caption = caption.map {|element| visited_result(element) } if caption
|
123
|
+
return caption, ref_part
|
124
|
+
end
|
125
|
+
|
126
|
+
def ref_tail(tree, caption)
|
127
|
+
tree.last.join
|
128
|
+
rescue NoMethodError
|
129
|
+
raise NoMethodError unless tree.empty?
|
130
|
+
STDERR.puts "No uri is specified for #{caption}"
|
119
131
|
end
|
120
132
|
end
|
121
133
|
|
@@ -128,14 +140,10 @@ module PseudoHiki
|
|
128
140
|
|
129
141
|
class DescLeafFormatter < self
|
130
142
|
def visit(tree)
|
131
|
-
tree = tree.dup
|
132
143
|
element = create_self_element(tree)
|
133
|
-
|
134
|
-
if
|
135
|
-
|
136
|
-
tree.shift
|
137
|
-
end
|
138
|
-
dd = tree.map {|token| visited_result(token) }.join.lstrip
|
144
|
+
dt_part, dd_part = split_into_parts(tree, DescSep)
|
145
|
+
push_visited_results(element, dt_part) if dt_part
|
146
|
+
dd = dd_part.map {|token| visited_result(token) }.join.lstrip
|
139
147
|
unless dd.empty?
|
140
148
|
element.push element.empty? ? "\t" : ":\t"
|
141
149
|
element.push dd
|
@@ -160,11 +168,12 @@ ERROR_TEXT
|
|
160
168
|
def visit(tree)
|
161
169
|
table = create_self_element(tree)
|
162
170
|
tree.length.times { table.push create_self_element(tree) }
|
163
|
-
max_col = tree.map{|row| row.reduce(0) {|sum, cell| sum + cell.colspan }}.max - 1
|
171
|
+
max_col = tree.map {|row| row.reduce(0) {|sum, cell| sum + cell.colspan }}.max - 1
|
164
172
|
max_row = tree.length - 1
|
165
173
|
each_empty_cell_index(max_row, max_col, tree, table) do |r, c, cur_row|
|
166
|
-
|
167
|
-
|
174
|
+
cur_cell = cur_row.shift
|
175
|
+
table[r][c] = visited_result(cur_cell).join.lstrip.chomp
|
176
|
+
fill_expand(table, r, c, cur_cell)
|
168
177
|
end
|
169
178
|
format_table(table, tree)
|
170
179
|
end
|
@@ -175,17 +184,20 @@ ERROR_TEXT
|
|
175
184
|
each_cell_index(max_row, max_col) do |r, c|
|
176
185
|
cur_row = rows.shift if c == 0
|
177
186
|
next if table[r][c]
|
178
|
-
|
179
|
-
|
187
|
+
if cur_row.empty?
|
188
|
+
warning_for_malformed_row(table[r])
|
189
|
+
else
|
180
190
|
yield r, c, cur_row
|
181
|
-
rescue
|
182
|
-
raise if @options.strict_mode
|
183
|
-
STDERR.puts ERROR_MESSAGE%[table[r].inspect]
|
184
|
-
next
|
185
191
|
end
|
186
192
|
end
|
187
193
|
end
|
188
194
|
|
195
|
+
def warning_for_malformed_row(row)
|
196
|
+
message = sprintf(ERROR_MESSAGE, row.inspect)
|
197
|
+
raise MalFormedTableError.new(message) if @options.strict_mode
|
198
|
+
STDERR.puts message
|
199
|
+
end
|
200
|
+
|
189
201
|
def deep_copy_tree(tree)
|
190
202
|
tree.dup.clear.tap do |new_tree|
|
191
203
|
new_tree.concat tree.map {|node| node.dup }
|
@@ -206,11 +218,9 @@ ERROR_TEXT
|
|
206
218
|
max_col = initial_col + cur_cell.colspan - 1
|
207
219
|
each_cell_index(max_row, max_col,
|
208
220
|
initial_row, initial_col) do |r, c|
|
209
|
-
|
210
|
-
table[r][c] =
|
211
|
-
next
|
221
|
+
unless initial_row == r and initial_col == c
|
222
|
+
table[r][c] = initial_row == r ? col_expand : row_expand
|
212
223
|
end
|
213
|
-
table[r][c] = initial_row == r ? col_expand : row_expand
|
214
224
|
end
|
215
225
|
end
|
216
226
|
end
|
@@ -220,7 +230,7 @@ ERROR_TEXT
|
|
220
230
|
end
|
221
231
|
|
222
232
|
def format_table(table, tree)
|
223
|
-
table.map {|row| row.join("\t")
|
233
|
+
table.map {|row| row.join("\t") + $/ }.join
|
224
234
|
end
|
225
235
|
|
226
236
|
class CommentOutNodeFormatter < self
|
@@ -229,13 +239,13 @@ ERROR_TEXT
|
|
229
239
|
|
230
240
|
class ParagraphNodeFormatter < self
|
231
241
|
def visit(tree)
|
232
|
-
super(tree).join
|
242
|
+
super(tree).join + $/
|
233
243
|
end
|
234
244
|
end
|
235
245
|
|
236
246
|
class PluginNodeFormatter < self
|
237
247
|
def visit(tree)
|
238
|
-
str =tree.join
|
248
|
+
str = tree.join
|
239
249
|
return str.strip * 2 if str == " {" or str == "} "
|
240
250
|
super(tree)
|
241
251
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
module Sinatra
|
5
|
+
module PseudoHikiParserHelpers
|
6
|
+
XHTML5_CONTENT_TYPE = 'application/xhtml+xml'
|
7
|
+
def phiki(hiki_data, &block)
|
8
|
+
case content_type
|
9
|
+
when XHTML5_CONTENT_TYPE
|
10
|
+
PseudoHiki::Format.to_html5(hiki_data, &block)
|
11
|
+
else
|
12
|
+
PseudoHiki::Format.to_xhtml(hiki_data, &block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Base
|
18
|
+
helpers PseudoHikiParserHelpers
|
19
|
+
end
|
20
|
+
end
|
21
|
+
rescue
|
22
|
+
#Sinatra is not available
|
23
|
+
end
|
data/lib/pseudohiki/treestack.rb
CHANGED
@@ -34,7 +34,7 @@ class TreeStack
|
|
34
34
|
def merge(leaf)
|
35
35
|
raise NotLeafError unless leaf.kind_of? Leaf
|
36
36
|
return nil unless leaf.kind_of? Mergeable
|
37
|
-
|
37
|
+
concat(leaf)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -48,7 +48,7 @@ class TreeStack
|
|
48
48
|
include LeafType
|
49
49
|
|
50
50
|
def self.create(content=nil)
|
51
|
-
|
51
|
+
new.tap {|leaf| leaf.push content if content }
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -89,7 +89,7 @@ class TreeStack
|
|
89
89
|
@current_node = node
|
90
90
|
@stack.push node
|
91
91
|
end
|
92
|
-
|
92
|
+
|
93
93
|
def push_as_leaf(node)
|
94
94
|
@current_node.push node
|
95
95
|
end
|
@@ -102,7 +102,7 @@ class TreeStack
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def remove_current_node
|
105
|
-
removed_node =
|
105
|
+
removed_node = pop
|
106
106
|
@current_node.pop
|
107
107
|
removed_node
|
108
108
|
end
|
data/lib/pseudohiki/utils.rb
CHANGED
@@ -5,7 +5,6 @@ require 'pseudohiki/blockparser'
|
|
5
5
|
|
6
6
|
module PseudoHiki
|
7
7
|
module Utils
|
8
|
-
|
9
8
|
class NodeCollector
|
10
9
|
attr_reader :nodes
|
11
10
|
|
@@ -15,7 +14,7 @@ module PseudoHiki
|
|
15
14
|
collector.nodes
|
16
15
|
end
|
17
16
|
|
18
|
-
def initialize
|
17
|
+
def initialize(&condition)
|
19
18
|
@nodes = []
|
20
19
|
@condition = condition
|
21
20
|
end
|
data/lib/pseudohiki/version.rb
CHANGED