pseudohikiparser 0.0.2 → 0.0.3.develop

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b6aeacee81ab200ae29767f62343c2c8c3b6383b
4
- data.tar.gz: 29c8d6ef7d5546530c0836173b503346c1270f97
3
+ metadata.gz: 4194b79f711194dc48b8b09a13302ec50dd9f20d
4
+ data.tar.gz: 1b91b097c191eb63711aae1f62bf92788943310e
5
5
  SHA512:
6
- metadata.gz: b9e0df31b3ca4d2e347f9ef841f0c86c13bb8398f477f2d2b85fc6185ab9ce54c7ba0420bfa09ebb7e30d12baa26da76f3d8557e90c0df2fda7ed62114efd53c
7
- data.tar.gz: abf97289e38d87b669af8ee08a7076fd72f684bab2115be9aef9dbf7512b076fe90c95d0392408cf255c3e1482abe08bc952b8d6ce7af96da21fc4557e97dc23
6
+ metadata.gz: 7bc7d683db890fc147c1149480481af8df86ac9738e39958f251c9aee2eb5a6792ac2fe3e6465b7af798d31f1eccedda273a47ecba99608eda344772eb04548b
7
+ data.tar.gz: a0b647bc3512f1ca38a3fadec0a2a77560c7d7b457a564a49cc40b901f00754d6eaa82c37c7f0a01e8234d341252d5e4ee9502adfc53f0a024feabad60bbcbf2
data/README.ja.md CHANGED
@@ -353,7 +353,7 @@ Hiki記法のマークアップを除去するためのVisitorクラスで、使
353
353
  :fax:03-xxxx-xxxx
354
354
  ```
355
355
 
356
- will be rendered as
356
+ は次のように変換されます。
357
357
 
358
358
  ```
359
359
  tel: 03-xxxx-xxxx
@@ -37,18 +37,17 @@ module PseudoHiki
37
37
  end
38
38
 
39
39
  class BlockStack < TreeStack
40
- def pop
41
- self.current_node.parse_leafs
42
- super
40
+ def pop_with_breaker(breaker=nil)
41
+ self.current_node.parse_leafs(breaker)
42
+ pop
43
43
  end
44
44
  end
45
45
 
46
46
  class BlockLeaf < BlockStack::Leaf
47
- @@head_re = {}
48
- attr_accessor :nominal_level, :node_id
47
+ attr_accessor :nominal_level, :node_id, :decorator
49
48
 
50
49
  def self.head_re=(head_regex)
51
- @self_head_re = @@head_re[self] = head_regex
50
+ @self_head_re = head_regex
52
51
  end
53
52
 
54
53
  def self.head_re
@@ -65,7 +64,7 @@ module PseudoHiki
65
64
  end
66
65
 
67
66
  def head_re
68
- @head_re ||= @@head_re[self.class]
67
+ @head_re ||= self.class.head_re
69
68
  end
70
69
 
71
70
  def block
@@ -85,7 +84,7 @@ module PseudoHiki
85
84
  super(stack)
86
85
  end
87
86
 
88
- def parse_leafs
87
+ def parse_leafs(breaker)
89
88
  parsed = InlineParser.parse(self.join)
90
89
  self.clear
91
90
  self.concat(parsed)
@@ -135,6 +134,10 @@ module PseudoHiki
135
134
  first.nominal_level if first # @cached_nominal_level ||= (first.nominal_level if first)
136
135
  end
137
136
 
137
+ def decorator
138
+ first.decorator if first
139
+ end
140
+
138
141
  def push_self(stack)
139
142
  @stack = stack
140
143
  super(stack)
@@ -144,7 +147,7 @@ module PseudoHiki
144
147
  not (kind_of?(breaker.block) and nominal_level == breaker.nominal_level)
145
148
  end
146
149
 
147
- def parse_leafs; end
150
+ def parse_leafs(breaker); end
148
151
 
149
152
  def in_link_tag?(preceding_str)
150
153
  preceding_str[-2, 2] == "[[".freeze or preceding_str[-1, 1] == "|".freeze
@@ -156,7 +159,7 @@ module PseudoHiki
156
159
 
157
160
  def add_leaf(line, blockparser)
158
161
  leaf = create_leaf(line, blockparser)
159
- blockparser.stack.pop while blockparser.breakable?(leaf)
162
+ blockparser.stack.pop_with_breaker(leaf) while blockparser.breakable?(leaf)
160
163
  blockparser.stack.push leaf
161
164
  end
162
165
 
@@ -168,8 +171,8 @@ module PseudoHiki
168
171
  end
169
172
 
170
173
  class NonNestedBlockNode < BlockNode
171
- def parse_leafs
172
- self.each {|leaf| leaf.parse_leafs }
174
+ def parse_leafs(breaker)
175
+ self.each {|leaf| leaf.parse_leafs(breaker) }
173
176
  end
174
177
  end
175
178
 
@@ -189,11 +192,11 @@ module PseudoHiki
189
192
 
190
193
  module BlockElement
191
194
  {
192
- BlockLeaf => %w(DescLeaf VerbatimLeaf TableLeaf CommentOutLeaf BlockNodeEnd HrLeaf),
195
+ BlockLeaf => %w(DescLeaf VerbatimLeaf TableLeaf CommentOutLeaf BlockNodeEnd HrLeaf DecoratorLeaf),
193
196
  NonNestedBlockLeaf => %w(QuoteLeaf ParagraphLeaf),
194
197
  NestedBlockLeaf => %w(HeadingLeaf),
195
198
  ListTypeLeaf => %w(ListLeaf EnumLeaf),
196
- BlockNode => %w(DescNode VerbatimNode TableNode CommentOutNode HrNode),
199
+ BlockNode => %w(DescNode VerbatimNode TableNode CommentOutNode HrNode DecoratorNode),
197
200
  NonNestedBlockNode => %w(QuoteNode ParagraphNode),
198
201
  NestedBlockNode => %w(HeadingNode),
199
202
  ListTypeBlockNode => %w(ListNode EnumNode),
@@ -218,15 +221,43 @@ module PseudoHiki
218
221
  attr_accessor :in_block_tag
219
222
 
220
223
  def add_leaf(line, blockparser)
221
- return @stack.pop if LINE_PAT::VERBATIM_END =~ line
224
+ return @stack.pop_with_breaker if LINE_PAT::VERBATIM_END =~ line
222
225
  return super(line, blockparser) unless @in_block_tag
223
226
  line = " ".concat(line) if BlockElement::BlockNodeEnd.head_re =~ line and not @in_block_tag
224
227
  @stack.push BlockElement::VerbatimLeaf.create(line, @in_block_tag)
225
228
  end
226
229
  end
227
230
 
231
+ class BlockElement::DecoratorNode
232
+ DECORATOR_PAT = /\A(?:([^\[\]:]+))?(?:\[([^\[\]]+)\])?(?::\s*(\S.*))?/o
233
+
234
+ class DecoratorItem < Struct.new(:string, :type, :id, :value)
235
+ def initialize(*args)
236
+ super
237
+ self.value = InlineParser.parse(self.value) if self.value
238
+ end
239
+ end
240
+
241
+ def parse_leafs(breaker)
242
+ decorator = {}
243
+ breaker.decorator = decorator
244
+ @stack.remove_current_node.each do |leaf|
245
+ m = DECORATOR_PAT.match(leaf.join)
246
+ return nil unless m
247
+ item = DecoratorItem.new(*(m.to_a))
248
+ decorator[item.type||:id] = item
249
+ end
250
+ end
251
+
252
+ def breakable?(breaker)
253
+ return super if breaker.kind_of?(BlockElement::DecoratorLeaf)
254
+ parse_leafs(breaker)
255
+ @stack.current_node.breakable?(breaker)
256
+ end
257
+ end
258
+
228
259
  class BlockElement::QuoteNode
229
- def parse_leafs
260
+ def parse_leafs(breaker)
230
261
  self[0] = BlockParser.parse(self[0])
231
262
  end
232
263
  end
@@ -284,7 +315,8 @@ module PseudoHiki
284
315
  [ParagraphLeaf, ParagraphNode],
285
316
  [HrLeaf, HrNode],
286
317
  [ListLeaf, ListNode],
287
- [EnumLeaf, EnumNode]
318
+ [EnumLeaf, EnumNode],
319
+ [DecoratorLeaf, DecoratorNode]
288
320
  ].each do |leaf, node|
289
321
  ParentNode[leaf] = node
290
322
  end
@@ -302,6 +334,7 @@ module PseudoHiki
302
334
  ['!', HeadingLeaf],
303
335
  ['""', QuoteLeaf],
304
336
  ['||', TableLeaf],
337
+ ['//@', DecoratorLeaf],
305
338
  ['//', CommentOutLeaf],
306
339
  ['----\s*$', HrLeaf]
307
340
  ].each do |head, leaf|
@@ -340,7 +373,7 @@ module PseudoHiki
340
373
  def read_lines(lines)
341
374
  each_line = lines.respond_to?(:each_line) ? :each_line : :each
342
375
  lines.send(each_line) {|line| @stack.current_node.add_leaf(line, self) }
343
- @stack.pop
376
+ @stack.pop_with_breaker
344
377
  end
345
378
  end
346
379
  end
@@ -60,8 +60,21 @@ module PseudoHiki
60
60
  end
61
61
  end
62
62
 
63
+ def gfm_id(heading_node)
64
+ MarkDownFormat.convert_to_gfm_id_format(to_plain(heading_node).strip)
65
+ end
66
+
67
+ def create_gfm_table_of_contents(tree)
68
+ toc_lines = collect_nodes_for_table_of_contents(tree).map do |toc_node|
69
+ "%s[[%s|#%s]]#{$/}"%['*'*toc_node.nominal_level, to_plain(toc_node).strip, gfm_id(toc_node)]
70
+ end
71
+
72
+ @options.formatter.format(BlockParser.parse(toc_lines))
73
+ end
74
+
63
75
  def create_table_of_contents(tree)
64
76
  return "" unless @options[:toc]
77
+ return create_gfm_table_of_contents(tree) if @options[:html_version].version == "gfm"
65
78
  return create_plain_table_of_contents(tree) unless @options.html_template
66
79
  create_html_table_of_contents(tree)
67
80
  end
@@ -275,9 +288,9 @@ module PseudoHiki
275
288
 
276
289
  def set_encoding(given_opt)
277
290
  return nil unless String.new.respond_to? :encoding
278
- external, internal = given_opt.split(/:/o)
279
- Encoding.default_external = external if external
280
- Encoding.default_internal = internal if internal
291
+ external, internal = given_opt.split(/:/o, 2)
292
+ Encoding.default_external = external if external and not external.empty?
293
+ Encoding.default_internal = internal if internal and not internal.empty?
281
294
  end
282
295
 
283
296
  def parse_command_line_options
@@ -61,6 +61,7 @@ module PseudoHiki
61
61
 
62
62
  def visit(tree)
63
63
  htmlelement = create_self_element(tree)
64
+ decorate(htmlelement, tree)
64
65
  push_visited_results(htmlelement, tree)
65
66
  htmlelement
66
67
  end
@@ -78,6 +79,21 @@ module PseudoHiki
78
79
  chunks.push tree
79
80
  end
80
81
 
82
+ def decorate(htmlelement, tree)
83
+ each_decorator(htmlelement, tree) do |element, decorator|
84
+ element[CLASS] = HtmlElement.escape(decorator[CLASS].id) if decorator[CLASS]
85
+ if id_item = decorator[ID]||decorator[:id]
86
+ element[ID] = HtmlElement.escape(id_item.id).upcase
87
+ end
88
+ end
89
+ end
90
+
91
+ def each_decorator(element, tree)
92
+ return unless element.kind_of? HtmlElement
93
+ return unless tree.kind_of? BlockParser::BlockNode and tree.decorator
94
+ tree.decorator.tap {|decorator| yield element, decorator }
95
+ end
96
+
81
97
  class ListLeafNodeFormatter < self
82
98
  def create_self_element(tree)
83
99
  super(tree).tap do |element|
@@ -148,8 +164,9 @@ module PseudoHiki
148
164
  htmlelement[ALT] = caption.join if caption
149
165
  else
150
166
  htmlelement = create_self_element
151
- htmlelement[HREF] = tree.join
152
- htmlelement.push caption||tree.join
167
+ url = tree.join
168
+ htmlelement[HREF] = url.start_with?("#".freeze) ? url.upcase : url
169
+ htmlelement.push caption||url
153
170
  end
154
171
  htmlelement
155
172
  end
@@ -175,6 +192,14 @@ module PseudoHiki
175
192
 
176
193
  #for BlockParser
177
194
 
195
+ class << Formatter[TableNode]
196
+ def decorate(htmlelement, tree)
197
+ each_decorator(htmlelement, tree) do |element, decorator|
198
+ htmlelement["summary"] = HtmlElement.escape(decorator["summary"].value.join) if decorator["summary"]
199
+ end
200
+ end
201
+ end
202
+
178
203
  class << Formatter[VerbatimNode]
179
204
  def visit(tree)
180
205
  create_self_element.tap do |element|
@@ -20,6 +20,17 @@ module PseudoHiki
20
20
  Regexp.new(tokens.join("|"))
21
21
  end
22
22
 
23
+ def self.split_into_tokens(str, token_pat)
24
+ tokens = []
25
+ while m = token_pat.match(str)
26
+ tokens.push m.pre_match unless m.pre_match.empty?
27
+ tokens.push m[0]
28
+ str = m.post_match
29
+ end
30
+ tokens.push str unless str.empty?
31
+ tokens
32
+ end
33
+
23
34
  class InlineParser < TreeStack
24
35
  module InlineElement
25
36
  class InlineNode < InlineParser::Node; end
@@ -43,7 +54,7 @@ module PseudoHiki
43
54
  [StrongNode, "'''", "'''"],
44
55
  [DelNode, "==", "=="],
45
56
  [LiteralNode, "``", "``"],
46
- [PluginNode, "{{","}}"]].each do |type, head, tail|
57
+ [PluginNode, "{{", "}}"]].each do |type, head, tail|
47
58
  HEAD[head] = type
48
59
  TAIL[tail] = type
49
60
  NodeTypeToHead[type] = head
@@ -52,8 +63,7 @@ module PseudoHiki
52
63
  TokenPat[self] = PseudoHiki.compile_token_pat(HEAD.keys,TAIL.keys,[LinkSep, TableSep, DescSep])
53
64
 
54
65
  def initialize(str)
55
- @token_pat = TokenPat[self.class]
56
- @tokens = split_into_tokens(str)
66
+ @tokens = PseudoHiki.split_into_tokens(str, TokenPat[self.class])
57
67
  super()
58
68
  end
59
69
 
@@ -75,17 +85,6 @@ module PseudoHiki
75
85
  self.pop
76
86
  end
77
87
 
78
- def split_into_tokens(str)
79
- tokens = []
80
- while m = @token_pat.match(str)
81
- tokens.push m.pre_match unless m.pre_match.empty?
82
- tokens.push m[0]
83
- str = m.post_match
84
- end
85
- tokens.push str unless str.empty?
86
- tokens
87
- end
88
-
89
88
  def parse
90
89
  while token = @tokens.shift
91
90
  next if TAIL[token] and treated_as_node_end(token)
@@ -4,6 +4,7 @@ require 'pseudohiki/inlineparser'
4
4
  require 'pseudohiki/blockparser'
5
5
  require 'pseudohiki/htmlformat'
6
6
  require 'pseudohiki/plaintextformat'
7
+ require 'pseudohiki/utils'
7
8
  require 'htmlelement'
8
9
  require 'ostruct'
9
10
 
@@ -14,6 +15,8 @@ module PseudoHiki
14
15
  include BlockParser::BlockElement
15
16
 
16
17
  Formatters = {}
18
+ GFM_STRIPPED_CHARS = " -&+$,/:;=?@\"{}#|^~[]`\\*()%.!'"
19
+ GFM_STRIPPED_CHARS_PAT = Regexp.union(/\s+/o, /[#{Regexp.escape(GFM_STRIPPED_CHARS)}]/o)
17
20
 
18
21
  def self.format(tree, options={ :strict_mode=> false, :gfm_style => false })
19
22
  if Formatters.empty?
@@ -25,6 +28,12 @@ module PseudoHiki
25
28
  Formatters[options].format(tree)
26
29
  end
27
30
 
31
+ def self.convert_to_gfm_id_format(heading)
32
+ heading.gsub(GFM_STRIPPED_CHARS_PAT) do |char|
33
+ /\A\s+\Z/o =~ char ? '-'.freeze : ''.freeze
34
+ end.downcase
35
+ end
36
+
28
37
  def initialize(formatter={}, options={ :strict_mode=> false, :gfm_style => false })
29
38
  @formatter = formatter
30
39
  options_given_via_block = nil
@@ -60,6 +69,7 @@ module PseudoHiki
60
69
 
61
70
  def format(tree)
62
71
  formatter = get_plain
72
+ @formatter[LinkNode].id_conv_table = prepare_id_conv_table(tree) if @options.gfm_style
63
73
  tree.accept(formatter).join
64
74
  end
65
75
 
@@ -78,6 +88,23 @@ module PseudoHiki
78
88
  element.to_s.gsub(/([^>])\r?\n/, "\\1") << $/
79
89
  end
80
90
 
91
+ def collect_headings(tree)
92
+ PseudoHiki::Utils::NodeCollector.select(tree) do |node|
93
+ node.kind_of? PseudoHiki::BlockParser::HeadingLeaf
94
+ end
95
+ end
96
+
97
+ def prepare_id_conv_table(tree)
98
+ {}.tap do |table|
99
+ collect_headings(tree).each do |heading|
100
+ if node_id = heading.node_id
101
+ heading_text = PlainTextFormat.format(heading).strip
102
+ table[node_id] = MarkDownFormat.convert_to_gfm_id_format(heading_text)
103
+ end
104
+ end
105
+ end
106
+ end
107
+
81
108
  def self.create(options={ :strict_mode => false })
82
109
  formatter = {}
83
110
  main_formatter = self.new(formatter, options)
@@ -139,6 +166,8 @@ module PseudoHiki
139
166
  end
140
167
 
141
168
  class LinkNodeFormatter < self
169
+ attr_writer :id_conv_table
170
+
142
171
  def visit(tree)
143
172
  not_from_thumbnail = tree.first.class != LinkNode
144
173
  tree = tree.dup
@@ -151,7 +180,8 @@ module PseudoHiki
151
180
  STDERR.puts "No uri is specified for #{caption}"
152
181
  end
153
182
  element.push "!" if ImageSuffix =~ ref and not_from_thumbnail
154
- element.push "[#{(caption||tree).join}](#{tree.join})"
183
+ link = format_link(tree)
184
+ element.push "[#{(caption||tree).join}](#{link})"
155
185
  element
156
186
  end
157
187
 
@@ -162,6 +192,16 @@ module PseudoHiki
162
192
  tree.shift
163
193
  caption_part.map {|element| visited_result(element) }
164
194
  end
195
+
196
+ def format_link(tree)
197
+ link = tree.join
198
+ return link unless @id_conv_table
199
+ if /\A#/o =~ link and gfm_link = @id_conv_table[link[1..-1]]
200
+ "#".concat gfm_link
201
+ else
202
+ link
203
+ end
204
+ end
165
205
  end
166
206
 
167
207
  class EmNodeFormatter < self
@@ -244,13 +284,14 @@ module PseudoHiki
244
284
  class VerbatimNodeFormatter < self
245
285
  def visit(tree)
246
286
  element = super(tree)
287
+ @language_name = language_name(tree)
247
288
  return gfm_verbatim(element) if @options.gfm_style
248
289
  md_verbatim(element)
249
290
  end
250
291
 
251
292
  def gfm_verbatim(element)
252
293
  element.tap do |lines|
253
- lines.unshift "```#{$/}"
294
+ lines.unshift "```#{@language_name + $/}"
254
295
  lines.push "```#{$/ * 2}"
255
296
  end
256
297
  end
@@ -258,6 +299,12 @@ module PseudoHiki
258
299
  def md_verbatim(element)
259
300
  element.join.gsub(/^/o, " ").sub(/ \Z/o, "").concat $/
260
301
  end
302
+
303
+ def language_name(tree)
304
+ tree.decorator.tap do |decorator|
305
+ return decorator ? decorator["code"].id : ""
306
+ end
307
+ end
261
308
  end
262
309
 
263
310
  class QuoteNodeFormatter < self
@@ -329,11 +376,9 @@ module PseudoHiki
329
376
  rows.each_with_index do |row, i|
330
377
  row.each do |cell|
331
378
  return false if cell.rowspan > 1 or cell.colspan > 1
332
- if i == 0
333
- return false unless cell.cell_type == "th"
334
- else
335
- return false if cell.cell_type == "th"
336
- end
379
+ #A table head row should be at the beginning and composed of <th> elements,
380
+ #and other rows should not include <th> elements
381
+ return false unless (i == 0) == (cell.cell_type == "th")
337
382
  end
338
383
  end
339
384
  true
@@ -159,25 +159,31 @@ ERROR_TEXT
159
159
 
160
160
  def visit(tree)
161
161
  table = create_self_element(tree)
162
- rows = deep_copy_tree(tree)
163
- rows.length.times { table.push create_self_element(tree) }
162
+ tree.length.times { table.push create_self_element(tree) }
164
163
  max_col = tree.map{|row| row.reduce(0) {|sum, cell| sum + cell.colspan }}.max - 1
165
- max_row = rows.length - 1
164
+ max_row = tree.length - 1
165
+ each_empty_cell_index(max_row, max_col, tree, table) do |r, c, cur_row|
166
+ table[r][c] = cur_row.shift
167
+ fill_expand(table, r, c, table[r][c])
168
+ end
169
+ format_table(table, tree)
170
+ end
171
+
172
+ def each_empty_cell_index(max_row, max_col, tree, table)
173
+ rows = deep_copy_tree(tree)
166
174
  cur_row = nil
167
175
  each_cell_index(max_row, max_col) do |r, c|
168
176
  cur_row = rows.shift if c == 0
169
177
  next if table[r][c]
170
178
  begin
171
179
  raise MalFormedTableError.new(ERROR_MESSAGE%[table[r].inspect]) if cur_row.empty?
172
- table[r][c] = cur_row.shift
173
- fill_expand(table, r, c, table[r][c])
180
+ yield r, c, cur_row
174
181
  rescue
175
182
  raise if @options.strict_mode
176
183
  STDERR.puts ERROR_MESSAGE%[table[r].inspect]
177
184
  next
178
185
  end
179
186
  end
180
- format_table(table, tree)
181
187
  end
182
188
 
183
189
  def deep_copy_tree(tree)
@@ -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
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pseudohiki/inlineparser'
4
+ require 'pseudohiki/blockparser'
5
+
6
+ module PseudoHiki
7
+ module Utils
8
+
9
+ class NodeCollector
10
+ attr_reader :nodes
11
+
12
+ def self.select(tree, &condition)
13
+ collector = new(&condition)
14
+ collector.visit(tree)
15
+ collector.nodes
16
+ end
17
+
18
+ def initialize (&condition)
19
+ @nodes = []
20
+ @condition = condition
21
+ end
22
+
23
+ def visit(tree)
24
+ if @condition.call(tree)
25
+ @nodes.push tree
26
+ else
27
+ tree.each do |node|
28
+ node.accept(self) if node.respond_to? :accept
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,3 +1,3 @@
1
1
  module PseudoHiki
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3.develop"
3
3
  end
@@ -131,3 +131,5 @@ module PseudoHiki
131
131
  end
132
132
  end
133
133
  end
134
+
135
+ require 'pseudohiki/sinatra_helpers'if defined? Sinatra
@@ -311,6 +311,35 @@ 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
+
314
343
  def test_comment_out_followed_by_a_verbatim_block
315
344
  text = <<TEXT
316
345
  the first paragraph
@@ -696,6 +696,69 @@ HTML
696
696
  assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
697
697
  end
698
698
 
699
+ def test_decorator
700
+ text = <<TEXT
701
+ //@class[section_type]
702
+ !!title of section
703
+
704
+ a paragraph.
705
+
706
+ //@class[class_name]
707
+ //@id[id_name]
708
+ another paragraph.
709
+ TEXT
710
+
711
+ xhtml = <<HTML
712
+ <div class="section_type">
713
+ <h2>title of section</h2>
714
+ <p>
715
+ a paragraph.</p>
716
+ <p class="class_name" id="ID_NAME">
717
+ another paragraph.</p>
718
+ <!-- end of section_type -->
719
+ </div>
720
+ HTML
721
+ tree = BlockParser.parse(text.lines.to_a.map {|line| line.chomp })
722
+ assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
723
+ end
724
+
725
+ def test_decorator_for_table
726
+ text = <<TEXT
727
+ //@summary: Summary of the table
728
+ ||!header 1||! header 2
729
+ ||cell 1||cell 2
730
+ TEXT
731
+
732
+ xhtml = <<HTML
733
+ <table summary="Summary of the table">
734
+ <tr><th>header 1</th><th> header 2</th></tr>
735
+ <tr><td>cell 1</td><td>cell 2</td></tr>
736
+ </table>
737
+ HTML
738
+ tree = BlockParser.parse(text.lines.to_a.map {|line| line.chomp })
739
+ assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
740
+ end
741
+
742
+ def test_decorator_for_verbatim
743
+ text = <<TEXT
744
+ //@code[ruby]
745
+ def bonjour!
746
+ puts "Bonjour!"
747
+ end
748
+ TEXT
749
+
750
+ xhtml = <<HTML
751
+ <pre>
752
+ def bonjour!
753
+ puts &quot;Bonjour!&quot;
754
+ end
755
+ </pre>
756
+ HTML
757
+
758
+ tree = BlockParser.parse(text.lines.to_a)
759
+ assert_equal(xhtml, XhtmlFormat.format(tree).to_s)
760
+ end
761
+
699
762
  def test_comment_out_followed_by_a_verbatim_block
700
763
  text = <<TEXT
701
764
  the first paragraph
@@ -10,16 +10,19 @@ class TC_InlineParser < MiniTest::Unit::TestCase
10
10
 
11
11
  def test_inlineparser_compile_token_pat
12
12
  parser = InlineParser.new("")
13
- assert_equal(/'''|\}\}|\|\||\{\{|``|\]\]|\[\[|==|''|\||:/, parser.instance_variable_get(:@token_pat))
13
+ assert_equal(/'''|\}\}|\|\||\{\{|``|\]\]|\[\[|==|''|\||:/, InlineParser::TokenPat[parser.class])
14
14
  end
15
15
 
16
16
  def test_inlineparser_split_into_tokens
17
17
  parser = InlineParser.new("")
18
- tokens = parser.split_into_tokens("As a test case, '''this part''' must be in <strong>.")
18
+ tokens = PseudoHiki.split_into_tokens("As a test case, '''this part''' must be in <strong>.",
19
+ InlineParser::TokenPat[parser.class])
19
20
  assert_equal(["As a test case, ","'''","this part","'''"," must be in <strong>."],tokens)
20
- tokens = parser.split_into_tokens("As another {{test case}}, '''this part''' must be in <strong>.")
21
+ tokens = PseudoHiki.split_into_tokens("As another {{test case}}, '''this part''' must be in <strong>.",
22
+ InlineParser::TokenPat[parser.class])
21
23
  assert_equal(["As another ","{{","test case","}}", ", ","'''","this part","'''"," must be in <strong>."],tokens)
22
- tokens = parser.split_into_tokens("As another ''test case'', '''this part''' must be in <strong>.")
24
+ tokens = PseudoHiki.split_into_tokens("As another ''test case'', '''this part''' must be in <strong>.",
25
+ InlineParser::TokenPat[parser.class])
23
26
  assert_equal(["As another ","''","test case","''", ", ","'''","this part","'''"," must be in <strong>."],tokens)
24
27
  end
25
28
 
@@ -44,6 +44,15 @@ TEXT
44
44
  assert_equal(gfm_text, MarkDownFormat.format(tree, :gfm_style => true))
45
45
  end
46
46
 
47
+ def test_self_convert_to_gfm_id_format
48
+ heading_with_non_ascii_chars = "class PseudoHiki::BlockParser"
49
+ heading_with_multiple_spaces = "Development status of features from the original Hiki notation"
50
+ gfm_id_with_non_ascii_chars = MarkDownFormat.convert_to_gfm_id_format(heading_with_non_ascii_chars)
51
+ gfm_id_with_multiple_spaces = MarkDownFormat.convert_to_gfm_id_format(heading_with_multiple_spaces)
52
+ assert_equal("class-pseudohikiblockparser", gfm_id_with_non_ascii_chars)
53
+ assert_equal("development-status-of-features-from-the-original-hiki-notation", gfm_id_with_multiple_spaces)
54
+ end
55
+
47
56
  def test_plain
48
57
  text = <<TEXT
49
58
  test string
@@ -508,5 +517,132 @@ TEXT
508
517
  tree = BlockParser.parse(text.lines.to_a)
509
518
  assert_equal(md_text, @formatter.format(tree).to_s)
510
519
  end
520
+
521
+ def test_decorator_for_verbatim
522
+ text = <<TEXT
523
+ //@code[ruby]
524
+ def bonjour!
525
+ puts "Bonjour!"
526
+ end
527
+ TEXT
528
+
529
+ gfm_text =<<TEXT
530
+ ```ruby
531
+ def bonjour!
532
+ puts "Bonjour!"
533
+ end
534
+ ```
535
+
536
+ TEXT
537
+
538
+ md_text = <<TEXT
539
+ def bonjour!
540
+ puts "Bonjour!"
541
+ end
542
+
543
+ TEXT
544
+
545
+ tree = BlockParser.parse(text.lines.to_a)
546
+ assert_equal(gfm_text, @gfm_formatter.format(tree).to_s)
547
+ assert_equal(md_text, @formatter.format(tree).to_s)
548
+ end
549
+
550
+ def test_decorator_for_verbatim_block
551
+ text = <<TEXT
552
+ //@code[ruby]
553
+ <<<
554
+ def bonjour!
555
+ puts "Bonjour!"
556
+ end
557
+ >>>
558
+ TEXT
559
+
560
+ gfm_text =<<TEXT
561
+ ```ruby
562
+ def bonjour!
563
+ puts "Bonjour!"
564
+ end
565
+ ```
566
+
567
+ TEXT
568
+
569
+ md_text = <<TEXT
570
+ def bonjour!
571
+ puts "Bonjour!"
572
+ end
573
+
574
+ TEXT
575
+
576
+ tree = BlockParser.parse(text.lines.to_a)
577
+ assert_equal(gfm_text, @gfm_formatter.format(tree).to_s)
578
+ assert_equal(md_text, @formatter.format(tree).to_s)
579
+ end
580
+
581
+ def test_collect_headings
582
+ text = <<TEXT
583
+ !![main-heading] heading
584
+
585
+ paragraph
586
+
587
+ !!![sub-heading] subheading
588
+
589
+ another paragraph
590
+ TEXT
591
+
592
+ tree = BlockParser.parse(text)
593
+ headings = @gfm_formatter.collect_headings(tree)
594
+
595
+ assert_equal([[[" heading\n"]], [[" subheading\n"]]], headings)
596
+ end
597
+
598
+ def test_prepare_id_conv_table
599
+ text = <<TEXT
600
+ !![main-heading] heading
601
+
602
+ paragraph
603
+
604
+ !!![sub-heading] subheading
605
+
606
+ another paragraph
607
+ TEXT
608
+
609
+ expected_table = {
610
+ "main-heading" => "heading",
611
+ "sub-heading" => "subheading"
612
+ }
613
+
614
+ tree = BlockParser.parse(text)
615
+ id_conv_table = @gfm_formatter.prepare_id_conv_table(tree)
616
+
617
+ assert_equal(expected_table, id_conv_table)
618
+ end
619
+
620
+ def test_gfm_style_in_page_anchor
621
+ text = <<TEXT
622
+ !![main_heading] Main Heading
623
+
624
+ a paragraph
625
+
626
+ !!![sub-heading] SubHeading
627
+
628
+ a link to [[main heading|#main_heading]]
629
+ TEXT
630
+
631
+ expected_text = <<TEXT
632
+ ## Main Heading
633
+
634
+ a paragraph
635
+
636
+ ### SubHeading
637
+
638
+ a link to [main heading](#main-heading)
639
+
640
+ TEXT
641
+
642
+ tree = BlockParser.parse(text)
643
+ gfm_text = @gfm_formatter.format(tree)
644
+
645
+ assert_equal(expected_text, gfm_text)
646
+ end
511
647
  end
512
648
 
@@ -194,17 +194,17 @@ TEXT
194
194
  toc = PageComposer.new(options).create_table_of_contents(@parsed_tree)
195
195
  assert_equal("", toc)
196
196
 
197
- toc_in_plain_text = <<TEXT
198
- * Heading1
199
- * Heading2
200
- * Heading2-1
197
+ toc_in_gfm_text = <<TEXT
198
+ * [Heading1](#heading1)
199
+ * [Heading2](#heading2)
200
+ * [Heading2-1](#heading21)
201
201
  TEXT
202
202
 
203
203
  set_argv("-fg -m 'table of contents' -c css/with_toc.css wikipage.txt")
204
204
  options = OptionManager.new
205
205
  options.set_options_from_command_line
206
206
  toc = PageComposer.new(options).create_table_of_contents(@parsed_tree)
207
- assert_equal(toc_in_plain_text, toc)
207
+ assert_equal(toc_in_gfm_text, toc)
208
208
 
209
209
  toc_in_html = <<TEXT
210
210
  <ul>
@@ -293,12 +293,12 @@ paragraph
293
293
  </html>
294
294
  HTML
295
295
 
296
- expected_plain_text = <<TEXT
296
+ expected_gfm_text = <<TEXT
297
297
  ## table of contents
298
298
 
299
- * Heading1
300
- * Heading2
301
- * Heading2-1
299
+ * [Heading1](#heading1)
300
+ * [Heading2](#heading2)
301
+ * [Heading2-1](#heading21)
302
302
 
303
303
  # Title
304
304
 
@@ -329,8 +329,8 @@ TEXT
329
329
  options = OptionManager.new
330
330
  options.set_options_from_command_line
331
331
 
332
- composed_plain_text = PageComposer.new(options).compose_html(@input_lines).join
333
- assert_equal(expected_plain_text, composed_plain_text)
332
+ composed_gfm_text = PageComposer.new(options).compose_html(@input_lines).join
333
+ assert_equal(expected_gfm_text, composed_gfm_text)
334
334
  end
335
335
 
336
336
  def test_output_in_gfm_with_toc
@@ -355,8 +355,8 @@ output = <<GFM
355
355
 
356
356
  ## Table of Contents
357
357
 
358
- * The first heading
359
- * The second heading
358
+ * [The first heading](#the-first-heading)
359
+ * [The second heading](#the-second-heading)
360
360
 
361
361
  ## The first heading
362
362
 
@@ -33,7 +33,7 @@ TEXT
33
33
  the first paragraph with <em>inline</em> <code>tags</code>
34
34
  </p>
35
35
  <p>
36
- the second paragraph with <del>block</del> <a href="#id">inline</a> tags
36
+ the second paragraph with <del>block</del> <a href="#ID">inline</a> tags
37
37
  </p>
38
38
  <!-- end of section h2 -->
39
39
  </div>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pseudohikiparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3.develop
5
5
  platform: ruby
6
6
  authors:
7
7
  - HASHIMOTO, Naoki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-30 00:00:00.000000000 Z
11
+ date: 2015-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -74,7 +74,9 @@ files:
74
74
  - lib/pseudohiki/inlineparser.rb
75
75
  - lib/pseudohiki/markdownformat.rb
76
76
  - lib/pseudohiki/plaintextformat.rb
77
+ - lib/pseudohiki/sinatra_helpers.rb
77
78
  - lib/pseudohiki/treestack.rb
79
+ - lib/pseudohiki/utils.rb
78
80
  - lib/pseudohiki/version.rb
79
81
  - lib/pseudohikiparser.rb
80
82
  - test/test_blockparser.rb
@@ -105,12 +107,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
105
107
  version: 1.8.7
106
108
  required_rubygems_version: !ruby/object:Gem::Requirement
107
109
  requirements:
108
- - - ">="
110
+ - - ">"
109
111
  - !ruby/object:Gem::Version
110
- version: '0'
112
+ version: 1.3.1
111
113
  requirements: []
112
114
  rubyforge_project:
113
- rubygems_version: 2.2.2
115
+ rubygems_version: 2.2.3
114
116
  signing_key:
115
117
  specification_version: 4
116
118
  summary: 'PseudoHikiParser: a parser of texts in a Hiki like notation.'