pseudohikiparser 0.0.2 → 0.0.3.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 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.'