pseudohikiparser 0.0.5 → 0.0.6.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: 5ebc8c1ea077d8299c8d99b805fbed3ddc4f45e4
4
- data.tar.gz: 02fc8e556784f1bbbe63c6e2a0bcf369c4b0ec04
3
+ metadata.gz: 98aa9c74058bd6a6da9f43b9f2c7d73872db41c9
4
+ data.tar.gz: d921304c72c05629e616d47899b28e09c7fc91ab
5
5
  SHA512:
6
- metadata.gz: c48347a4e2cd673bbc426c0623255d8a64088d393730a5bdbba4962ca626b5ab8dad09bdb48abc64fd0fd307551d69dac7ae99a053ac7d230406ff9dc94ccc94
7
- data.tar.gz: ca8187e15865fd7bd5e9d5def177dcf11f4ce843af06412f79e14b44cfdc649eece0487c7ab3f6397057afa1a2c45165b91153198697b79fceb9c4128f791c63
6
+ metadata.gz: 4f1a030cee17f773f7f9489270874d462c4d1da7c6fa57b86830910a13018e5ee0757155d97e8e07de503cd2f22237bd515151de3583d187ac62aaf703120d37
7
+ data.tar.gz: 793b3d2c14b5b36fc6ee964c838f9f630a017c3a78cc7e35ab2457fed631c405487ecf0c489da88fd2a5f3342ebb9425831eebd8bb28293682bfdf2834df8481
data/bin/pseudohiki2html CHANGED
@@ -7,29 +7,10 @@ options.parse_command_line_options
7
7
 
8
8
  if $KCODE
9
9
  PseudoHiki::OptionManager::ENCODING_REGEXP.each do |pat, encoding|
10
- options[:encoding] = encoding if pat =~ $KCODE and not options[:force]
10
+ options[:encoding] = encoding if pat.match? $KCODE and not options[:force]
11
11
  end
12
12
  end
13
13
 
14
- unless String.new.respond_to? :encode
15
- require 'iconv'
16
-
17
- def choose_input_encoding_using_kcode
18
- PseudoHiki::OptionManager::ENCODING_REGEXP.each do |pat, encoding|
19
- return PseudoHiki::OptionManager::ENCODING_TO_CHARSET[encoding] if pat =~ $KCODE
20
- end
21
- HtmlElement::CHARSET::UTF8
22
- end
23
- private :choose_input_encoding_using_kcode
24
-
25
- def encode(to, from=choose_input_encoding_using_kcode)
26
- iconv = Iconv.new(to, from)
27
- str = iconv.iconv(self)
28
- str << iconv.iconv(nil)
29
- end
30
- public :encode
31
- end
32
-
33
14
  PseudoHiki::OptionManager.remove_bom
34
15
  input_lines = ARGF.readlines.map {|line| line.encode(options.charset) }
35
16
  options.set_options_from_input_file(input_lines)
@@ -23,6 +23,11 @@ class HtmlTemplate
23
23
  @title = nil
24
24
  @title_element = create_element("title")
25
25
  @body = create_element("body")
26
+ @default_skip_link_labels = {
27
+ "en" => "Skip to Content",
28
+ "ja" => "\u{672c}\u{6587}\u{3078}", # honbun he
29
+ "fr" => "Aller au contenu"
30
+ }
26
31
  @html.push @head
27
32
  @html.push @body
28
33
  [ @content_language,
@@ -36,7 +41,7 @@ class HtmlTemplate
36
41
  @head.push element
37
42
  end
38
43
  end
39
- attr_reader :title, :head
44
+ attr_reader :title, :head, :body
40
45
 
41
46
  def create_element(*params)
42
47
  ELEMENT[self.class].create(*params)
@@ -70,6 +75,12 @@ class HtmlTemplate
70
75
  @default_css_link["href"] = file_path
71
76
  end
72
77
 
78
+ def embed_style(css)
79
+ style = create_element("style", nil, "type" => "text/css")
80
+ @head.push style
81
+ style.push format_css(css)
82
+ end
83
+
73
84
  def title=(title)
74
85
  @title_element.pop until @title_element.empty?
75
86
  @title = title
@@ -103,6 +114,10 @@ class HtmlTemplate
103
114
  @html].join("")
104
115
  end
105
116
 
117
+ def add_skip_link(to="contents", from=@body,label=default_skip_link_label)
118
+ skip_link_container(from).unshift create_element("a", label, "href" => "##{to}")
119
+ end
120
+
106
121
  private
107
122
 
108
123
  def create_meta(type, content)
@@ -126,6 +141,23 @@ class HtmlTemplate
126
141
  return "" unless base_uri
127
142
  create_element("base", nil, "href" => base_uri)
128
143
  end
144
+
145
+ def format_css(css)
146
+ ["<!--", css.rstrip, "-->", ""].join($/)
147
+ end
148
+
149
+ def skip_link_container(from)
150
+ return from unless from == @body
151
+ create_element("div").tap do |div|
152
+ div["class"] = "skip-link"
153
+ @body.unshift div
154
+ end
155
+ end
156
+
157
+ def default_skip_link_label
158
+ @default_skip_link_labels[@html["lang"]] ||
159
+ @default_skip_link_labels["en"]
160
+ end
129
161
  end
130
162
 
131
163
  class XhtmlTemplate < HtmlTemplate
@@ -141,6 +173,12 @@ class XhtmlTemplate < HtmlTemplate
141
173
  super(language)
142
174
  @html["xml:lang"] = language
143
175
  end
176
+
177
+ private
178
+
179
+ def format_css(css)
180
+ css.rstrip + $/
181
+ end
144
182
  end
145
183
 
146
184
  class Xhtml5Template < XhtmlTemplate
data/lib/htmlelement.rb CHANGED
@@ -123,7 +123,21 @@ class HtmlElement
123
123
  end
124
124
 
125
125
  def pop
126
- @children.pop
126
+ last_child = @children.pop
127
+ last_child.parent = nil if last_child.kind_of? HtmlElement
128
+ last_child
129
+ end
130
+
131
+ def unshift(child)
132
+ @children.unshift child
133
+ child.parent = self if child.kind_of? HtmlElement
134
+ self
135
+ end
136
+
137
+ def shift
138
+ first_child = @children.shift
139
+ first_child.parent = nil if first_child.kind_of? HtmlElement
140
+ first_child
127
141
  end
128
142
 
129
143
  def []=(attribute, value)
@@ -47,7 +47,7 @@ module PseudoHiki
47
47
  end
48
48
 
49
49
  def link_wiki_name(line)
50
- return line if WIKI_NAME_RE !~ line or VERBATIM_LEAF_HEAD_RE =~ line
50
+ return line if not WIKI_NAME_RE.match? line or VERBATIM_LEAF_HEAD_RE.match? line
51
51
  line.gsub(WIKI_NAME_RE) {|url| in_link_tag?($`) ? url : add_tag(url) }
52
52
  end
53
53
 
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'pseudohiki/shim'
3
4
  require 'pseudohiki/treestack'
4
5
  require 'pseudohiki/inlineparser'
5
6
 
@@ -38,14 +39,21 @@ module PseudoHiki
38
39
  end
39
40
 
40
41
  class BlockStack < TreeStack
41
- def pop
42
- current_node.parse_leafs
43
- super
42
+ attr_reader :stack
43
+
44
+ def pop_with_breaker(breaker=nil)
45
+ current_node.parse_leafs(breaker)
46
+ pop
47
+ end
48
+
49
+ def current_heading_level
50
+ i = @stack.rindex {|node| node.kind_of? BlockElement::HeadingNode }
51
+ @stack[i].level || 0
44
52
  end
45
53
  end
46
54
 
47
55
  class BlockLeaf < BlockStack::Leaf
48
- attr_accessor :level, :node_id
56
+ attr_accessor :level, :node_id, :decorator
49
57
 
50
58
  class << self
51
59
  attr_accessor :head_re
@@ -81,7 +89,7 @@ module PseudoHiki
81
89
  super(stack)
82
90
  end
83
91
 
84
- def parse_leafs
92
+ def parse_leafs(breaker)
85
93
  parsed = InlineParser.parse(join)
86
94
  clear
87
95
  concat(parsed)
@@ -131,6 +139,10 @@ module PseudoHiki
131
139
  first.level if first # @cached_level ||= (first.level if first)
132
140
  end
133
141
 
142
+ def decorator
143
+ first.decorator if first
144
+ end
145
+
134
146
  def push_self(stack)
135
147
  @stack = stack
136
148
  super(stack)
@@ -140,24 +152,24 @@ module PseudoHiki
140
152
  not (kind_of? breaker.block and level == breaker.level)
141
153
  end
142
154
 
143
- def parse_leafs; end
155
+ def parse_leafs(breaker); end
144
156
 
145
157
  def add_leaf(line, blockparser)
146
158
  leaf = create_leaf(line, blockparser)
147
- blockparser.stack.pop while blockparser.breakable?(leaf)
159
+ blockparser.stack.pop_with_breaker(leaf) while blockparser.breakable?(leaf)
148
160
  blockparser.stack.push leaf
149
161
  end
150
162
 
151
163
  def create_leaf(line, blockparser)
152
- return BlockElement::VerbatimLeaf.create("".freeze, true) if VERBATIM_BEGIN =~ line
164
+ return BlockElement::VerbatimLeaf.create("".freeze, true) if VERBATIM_BEGIN.match? line
153
165
  line = blockparser.auto_linker.link(line)
154
166
  blockparser.select_leaf_type(line).create(line)
155
167
  end
156
168
  end
157
169
 
158
170
  class NonNestedBlockNode < BlockNode
159
- def parse_leafs
160
- each {|leaf| leaf.parse_leafs }
171
+ def parse_leafs(breaker)
172
+ each {|leaf| leaf.parse_leafs(breaker) }
161
173
  end
162
174
  end
163
175
 
@@ -175,13 +187,15 @@ module PseudoHiki
175
187
  end
176
188
  end
177
189
 
190
+ class UnmatchedSectioningTagError < StandardError; end
191
+
178
192
  module BlockElement
179
193
  {
180
- BlockLeaf => %w(DescLeaf VerbatimLeaf TableLeaf CommentOutLeaf BlockNodeEnd HrLeaf),
194
+ BlockLeaf => %w(DescLeaf VerbatimLeaf TableLeaf CommentOutLeaf BlockNodeEnd HrLeaf DecoratorLeaf SectioningNodeEnd),
181
195
  NonNestedBlockLeaf => %w(QuoteLeaf ParagraphLeaf),
182
196
  NestedBlockLeaf => %w(HeadingLeaf),
183
197
  ListTypeLeaf => %w(ListLeaf EnumLeaf),
184
- BlockNode => %w(DescNode VerbatimNode TableNode CommentOutNode HrNode),
198
+ BlockNode => %w(DescNode VerbatimNode TableNode CommentOutNode HrNode DecoratorNode SectioningNode),
185
199
  NonNestedBlockNode => %w(QuoteNode ParagraphNode),
186
200
  NestedBlockNode => %w(HeadingNode),
187
201
  ListTypeBlockNode => %w(ListNode EnumNode),
@@ -204,15 +218,100 @@ module PseudoHiki
204
218
  attr_accessor :in_block_tag
205
219
 
206
220
  def add_leaf(line, blockparser)
207
- return @stack.pop if VERBATIM_END =~ line
221
+ return @stack.pop_with_breaker if VERBATIM_END.match? line
208
222
  return super(line, blockparser) unless @in_block_tag
209
- line = " #{line}" if BlockNodeEnd.head_re =~ line and not @in_block_tag
223
+ line = " #{line}" if BlockNodeEnd.head_re.match? line and not @in_block_tag
210
224
  @stack.push VerbatimLeaf.create(line, @in_block_tag)
211
225
  end
212
226
  end
213
227
 
228
+ class DecoratorNode
229
+ DECORATOR_PAT = /\A(?:([^\[\]:]+))?(?:\[([^\[\]]+)\])?(?::\s*(\S.*))?/o
230
+ LABEL_SEP = [":"]
231
+
232
+ class DecoratorItem < Struct.new(:string, :type, :id, :value)
233
+ def self.create(leaf)
234
+ m = DECORATOR_PAT.match(leaf.join)
235
+ return nil unless m
236
+ args = m.to_a
237
+ if i = leaf.index(LABEL_SEP)
238
+ value = leaf.dup
239
+ value.shift(i + 1)
240
+ args[-1] = lstrip_value!(value)
241
+ end
242
+ self.new(*args)
243
+ end
244
+
245
+ def self.lstrip_value!(value)
246
+ head_val = value[0][0]
247
+ if head_val.kind_of? String and head_val.start_with? " ".freeze
248
+ value[0][0] = head_val.lstrip
249
+ end
250
+ value
251
+ end
252
+ end
253
+
254
+ def parse_leafs(breaker)
255
+ decorator = {}
256
+ breaker.decorator = decorator
257
+ @stack.remove_current_node.each do |leaf|
258
+ if item = DecoratorItem.create(leaf)
259
+ decorator[item.type || :id] = item
260
+ end
261
+ end
262
+ end
263
+
264
+ def breakable?(breaker)
265
+ return super if breaker.kind_of? DecoratorLeaf
266
+ parse_leafs(breaker)
267
+ @stack.current_node.breakable?(breaker)
268
+ end
269
+ end
270
+
271
+ class DecoratorLeaf
272
+ def push_sectioning_node(stack, node_class)
273
+ node = node_class.new
274
+ m = DecoratorNode::DECORATOR_PAT.match(join)
275
+ node.node_id = m[2]
276
+ node.section_level = stack.current_heading_level if node.kind_of? SectioningNode
277
+ stack.push(node)
278
+ end
279
+
280
+ def push_self(stack)
281
+ decorator_type = self[0][0]
282
+ if decorator_type.start_with? "begin[".freeze
283
+ push_sectioning_node(stack, SectioningNode)
284
+ elsif decorator_type.start_with? "end[".freeze
285
+ push_sectioning_node(stack, SectioningNodeEnd)
286
+ else
287
+ super
288
+ end
289
+ end
290
+ end
291
+
292
+ class SectioningNode
293
+ attr_accessor :section_level
294
+
295
+ def breakable?(breaker)
296
+ breaker.kind_of? HeadingLeaf and @section_level >= breaker.level
297
+ end
298
+ end
299
+
300
+ class SectioningNodeEnd
301
+ def push_self(stack)
302
+ n = stack.stack.rindex do |node|
303
+ node.kind_of? SectioningNode and node.node_id == node_id
304
+ end
305
+ raise UnmatchedSectioningTagError unless n
306
+ stack.pop until stack.stack.length == n
307
+ rescue UnmatchedSectioningTagError => e
308
+ STDERR.puts "#{e}: The start tag for '#{node_id}' is not found."
309
+ # FIXME: The handling of this error should be changed appropriately.
310
+ end
311
+ end
312
+
214
313
  class QuoteNode
215
- def parse_leafs
314
+ def parse_leafs(breaker)
216
315
  self[0] = BlockParser.parse(self[0], AutoLink::Off)
217
316
  end
218
317
  end
@@ -273,7 +372,8 @@ module PseudoHiki
273
372
  [HrLeaf, HrNode],
274
373
  [ListLeaf, ListNode],
275
374
  [EnumLeaf, EnumNode],
276
- [BlockNodeEnd, BlockNodeEnd] # special case
375
+ [BlockNodeEnd, BlockNodeEnd], # special case
376
+ [DecoratorLeaf, DecoratorNode]
277
377
  ].each do |leaf, node|
278
378
  PARENT_NODE[leaf] = node
279
379
  end
@@ -286,6 +386,7 @@ module PseudoHiki
286
386
  ['!', HeadingLeaf],
287
387
  ['""', QuoteLeaf],
288
388
  ['||', TableLeaf],
389
+ ['//@', DecoratorLeaf],
289
390
  ['//', CommentOutLeaf],
290
391
  ['----\s*$', HrLeaf]]
291
392
 
@@ -331,7 +432,7 @@ module PseudoHiki
331
432
  def read_lines(lines)
332
433
  each_line = lines.respond_to?(:each_line) ? :each_line : :each
333
434
  lines.send(each_line) {|line| @stack.current_node.add_leaf(line, self) }
334
- @stack.pop
435
+ @stack.pop_with_breaker
335
436
  end
336
437
  end
337
438
 
@@ -356,7 +457,7 @@ module PseudoHiki
356
457
  end
357
458
 
358
459
  def self.link(line)
359
- return line unless URI_RE =~ line and VERBATIM_LEAF_HEAD_RE !~ line
460
+ return line unless URI_RE.match? line and not VERBATIM_LEAF_HEAD_RE.match? line
360
461
  line.gsub(URI_RE) {|url| in_link_tag?($`) ? url : "[[#{url}]]" }
361
462
  end
362
463
 
@@ -29,8 +29,6 @@ module PseudoHiki
29
29
  @options.formatter.format(tree)
30
30
  end
31
31
 
32
- def create_style(path_to_css_file); "".freeze; end
33
-
34
32
  private
35
33
 
36
34
  def toc_item_pat?(node)
@@ -87,15 +85,6 @@ module PseudoHiki
87
85
  end
88
86
  end
89
87
 
90
- def create_style(path_to_css_file)
91
- style = formatter.create_element("style").tap do |element|
92
- element["type"] = "text/css"
93
- open(File.expand_path(path_to_css_file)) do |css_file|
94
- element.push css_file.read
95
- end
96
- end
97
- end
98
-
99
88
  private
100
89
 
101
90
  def setup_link_manager(options)
@@ -200,7 +189,7 @@ module PseudoHiki
200
189
 
201
190
  def split_main_heading(input_lines)
202
191
  return "" unless @options[:split_main_heading]
203
- h1_pos = input_lines.find_index {|line| /^![^!]/o =~ line }
192
+ h1_pos = input_lines.find_index {|line| /^![^!]/o.match? line }
204
193
  return "" unless h1_pos
205
194
  tree = BlockParser.parse([input_lines.delete_at(h1_pos)])
206
195
  @options.formatter.format(tree)
@@ -223,8 +212,9 @@ module PseudoHiki
223
212
  else
224
213
  html = @options.create_html_template_with_current_options
225
214
  embed_css = @options[:embed_css]
226
- html.head.push @composer.create_style(embed_css) if embed_css
215
+ html.embed_style(File.read(File.expand_path(embed_css))) if embed_css
227
216
  html.push main || body
217
+ html.add_skip_link if html.kind_of?(HtmlTemplate) and main
228
218
  end
229
219
 
230
220
  html
@@ -313,7 +303,7 @@ module PseudoHiki
313
303
  end
314
304
 
315
305
  def win32?
316
- true if RUBY_PLATFORM =~ /win/i
306
+ true if RUBY_PLATFORM.match? /win/i
317
307
  end
318
308
 
319
309
  def value_given?(value)
@@ -334,9 +324,9 @@ module PseudoHiki
334
324
 
335
325
  def base
336
326
  base_dir = self[:base]
337
- if base_dir and base_dir !~ /[\/\\]\.*$/o
327
+ if base_dir and not /[\/\\]\.*$/o.match? base_dir
338
328
  base_dir = File.join(base_dir, ".")
339
- base_dir = "file:///" + base_dir if base_dir !~ /^\./o and win32?
329
+ base_dir = "file:///" + base_dir if not /^\./o.match? base_dir and win32?
340
330
  end
341
331
  base_dir
342
332
  end
@@ -354,7 +344,7 @@ module PseudoHiki
354
344
  if v.version == version
355
345
  return self[:html_version] = v
356
346
  else
357
- self[:html_version] = v if v.opt_pat =~ version
347
+ self[:html_version] = v if v.opt_pat.match? version
358
348
  end
359
349
  end
360
350
  STDERR.puts "\"#{version}\" is an invalid option for --format-version. \
@@ -366,7 +356,7 @@ module PseudoHiki
366
356
  self[:encoding] = given_opt
367
357
  else
368
358
  ENCODING_REGEXP.each do |pat, encoding|
369
- self[:encoding] = encoding if pat =~ given_opt
359
+ self[:encoding] = encoding if pat.match? given_opt
370
360
  end
371
361
  STDERR.puts "\"#{self[:encoding]}\" is chosen as an encoding system, \
372
362
  instead of \"#{given_opt}\"."
@@ -513,7 +503,7 @@ inside (default: not specified)") do |template|
513
503
 
514
504
  def set_options_from_input_file(input_lines)
515
505
  input_lines.each do |line|
516
- break if FILE_HEADER_PAT !~ line
506
+ break unless FILE_HEADER_PAT.match? line
517
507
  line = line.chomp
518
508
  @options.keys.each do |opt|
519
509
  next if self[opt] and self[:force]
@@ -50,12 +50,12 @@ module PseudoHiki
50
50
  { :auto_link_in_verbatim => @auto_link_in_verbatim }
51
51
  end
52
52
 
53
- def self.format(tree, options=nil)
53
+ def self.format(tree, options=nil, memo=nil)
54
54
  cur_auto_link_setting = @auto_link_in_verbatim
55
55
  options = default_options unless options
56
56
  @auto_link_in_verbatim = options[:auto_link_in_verbatim]
57
57
  formatter = get_plain
58
- tree.accept(formatter)
58
+ tree.accept(formatter, memo)
59
59
  ensure
60
60
  @auto_link_in_verbatim = cur_auto_link_setting
61
61
  end
@@ -67,18 +67,19 @@ module PseudoHiki
67
67
  @format_class = self.class
68
68
  end
69
69
 
70
- def visited_result(element)
70
+ def visited_result(element, memo)
71
71
  visitor = @formatter[element.class] || @formatter[PlainNode]
72
- element.accept(visitor)
72
+ element.accept(visitor, memo)
73
73
  end
74
74
 
75
- def push_visited_results(element, tree)
76
- tree.each {|token| element.push visited_result(token) }
75
+ def push_visited_results(element, tree, memo)
76
+ tree.each {|token| element.push visited_result(token, memo) }
77
77
  end
78
78
 
79
- def visit(tree)
79
+ def visit(tree, memo)
80
80
  htmlelement = create_element(tree)
81
- push_visited_results(htmlelement, tree)
81
+ decorate(htmlelement, tree)
82
+ push_visited_results(htmlelement, tree, memo)
82
83
  htmlelement
83
84
  end
84
85
 
@@ -96,6 +97,21 @@ module PseudoHiki
96
97
  chunks.push tree
97
98
  end
98
99
 
100
+ def decorate(htmlelement, tree)
101
+ each_decorator(htmlelement, tree) do |elm, decorator|
102
+ elm[CLASS] = HtmlElement.escape(decorator[CLASS].id) if decorator[CLASS]
103
+ if id_item = decorator[ID] || decorator[:id]
104
+ elm[ID] = HtmlElement.escape(id_item.id).upcase
105
+ end
106
+ end
107
+ end
108
+
109
+ def each_decorator(element, tree)
110
+ return unless element.kind_of? HtmlElement
111
+ return unless tree.kind_of? BlockParser::BlockNode and tree.decorator
112
+ tree.decorator.tap {|decorator| yield element, decorator }
113
+ end
114
+
99
115
  class ListLeafNodeFormatter < self
100
116
  def create_element(tree)
101
117
  super(tree).tap do |elm|
@@ -121,6 +137,7 @@ module PseudoHiki
121
137
  [EnumNode, "ol"],
122
138
  [TableLeaf, "tr"],
123
139
  [VerbatimNode, "pre"],
140
+ [SectioningNode, "section"],
124
141
  [CommentOutNode, nil],
125
142
  [HeadingNode, "section"],
126
143
  [DescLeaf, DT],
@@ -137,8 +154,8 @@ module PseudoHiki
137
154
  # for InlineParser
138
155
 
139
156
  class << Formatter[PluginNode]
140
- def visit(tree)
141
- escape_inline_tags(tree) { super(tree) }
157
+ def visit(tree, memo)
158
+ escape_inline_tags(tree) { super(tree, memo) }
142
159
  end
143
160
 
144
161
  def escape_inline_tags(tree)
@@ -150,10 +167,10 @@ module PseudoHiki
150
167
  end
151
168
 
152
169
  class << Formatter[LinkNode]
153
- def visit(tree)
170
+ def visit(tree, memo)
154
171
  not_from_thumbnail = tree.first.class != LinkNode
155
- caption, ref = caption_and_ref(tree)
156
- if IMAGE_SUFFIX_RE =~ ref and not_from_thumbnail
172
+ caption, ref = caption_and_ref(tree, memo)
173
+ if IMAGE_SUFFIX_RE.match? ref and not_from_thumbnail
157
174
  htmlelement = ImgFormat.create_element
158
175
  htmlelement[SRC] = ref
159
176
  htmlelement[ALT] = caption.join if caption
@@ -165,9 +182,9 @@ module PseudoHiki
165
182
  htmlelement
166
183
  end
167
184
 
168
- def caption_and_ref(tree)
185
+ def caption_and_ref(tree, memo)
169
186
  caption, ref = split_into_parts(tree, LinkSep)
170
- caption = ref ? caption.map {|token| visited_result(token) } : nil
187
+ caption = ref ? caption.map {|token| visited_result(token, memo) } : nil
171
188
  return caption, (ref || tree).join
172
189
  rescue NoMethodError
173
190
  raise NoMethodError unless (ref || tree).empty?
@@ -176,7 +193,7 @@ module PseudoHiki
176
193
  end
177
194
 
178
195
  class << Formatter[InlineLeaf]
179
- def visit(leaf)
196
+ def visit(leaf, memo)
180
197
  @generator.escape(leaf.first)
181
198
  end
182
199
  end
@@ -189,8 +206,25 @@ module PseudoHiki
189
206
 
190
207
  # for BlockParser
191
208
 
209
+ class << Formatter[TableNode]
210
+ def decorate(htmlelement, tree, memo=nil)
211
+ each_decorator(htmlelement, tree) do |elm, decorator|
212
+ visited_value(decorator["summary"], memo) do |summary|
213
+ htmlelement["summary"] = HtmlElement.escape(summary.join.chomp)
214
+ end
215
+ visited_value(decorator["caption"], memo) do |caption|
216
+ htmlelement.push @generator.create("caption", caption)
217
+ end
218
+ end
219
+ end
220
+
221
+ def visited_value(decorator_item, memo)
222
+ yield visited_result(decorator_item.value, memo) if decorator_item
223
+ end
224
+ end
225
+
192
226
  class << Formatter[VerbatimNode]
193
- def visit(tree)
227
+ def visit(tree, memo)
194
228
  contents = add_link(@generator.escape(tree.join))
195
229
  create_element.tap {|elm| elm.push contents }
196
230
  end
@@ -203,8 +237,39 @@ module PseudoHiki
203
237
  end
204
238
  end
205
239
 
240
+ class << Formatter[SectioningNode]
241
+ ID_MARK = "#"
242
+
243
+ alias :orig_create_element :create_element
244
+
245
+ def section_with_id(tree, node_id)
246
+ orig_create_element(tree).tap do |elm|
247
+ elm[ID] = node_id[1..-1] # remove the first charactor from node_id
248
+ end
249
+ end
250
+
251
+ def section_for_class(tree, node_id)
252
+ if HtmlElement::HTML5_TAGS.include? node_id
253
+ @generator.create(node_id)
254
+ else
255
+ orig_create_element(tree).tap do |elm|
256
+ elm[CLASS] = elm[CLASS] ? "#{elm[CLASS]} #{node_id}" : node_id
257
+ end
258
+ end
259
+ end
260
+
261
+ def create_element(tree)
262
+ node_id = tree.node_id
263
+ if node_id.start_with? ID_MARK
264
+ section_with_id(tree, node_id)
265
+ else
266
+ section_for_class(tree, node_id)
267
+ end
268
+ end
269
+ end
270
+
206
271
  class << Formatter[CommentOutNode]
207
- def visit(tree); BLANK; end
272
+ def visit(tree, memo); BLANK; end
208
273
  end
209
274
 
210
275
  class << Formatter[HeadingNode]
@@ -218,14 +283,14 @@ module PseudoHiki
218
283
  end
219
284
 
220
285
  class << Formatter[DescLeaf]
221
- def visit(tree)
286
+ def visit(tree, memo)
222
287
  elm = @generator::Children.new
223
288
  dt_part, dd_part = split_into_parts(tree, DescSep)
224
- dt = super(dt_part)
289
+ dt = super(dt_part, memo)
225
290
  elm.push dt
226
291
  unless dd_part.nil? or dd_part.empty?
227
292
  dd = @generator.create(DD)
228
- push_visited_results(dd, dd_part)
293
+ push_visited_results(dd, dd_part, memo)
229
294
  elm.push dd
230
295
  end
231
296
  elm
@@ -233,9 +298,9 @@ module PseudoHiki
233
298
  end
234
299
 
235
300
  class << Formatter[TableCellNode]
236
- def visit(tree)
301
+ def visit(tree, memo)
237
302
  @element_name = tree.cell_type
238
- super(tree).tap do |elm|
303
+ super(tree, memo).tap do |elm|
239
304
  elm[ROWSPAN] = tree.rowspan if tree.rowspan > 1
240
305
  elm[COLSPAN] = tree.colspan if tree.colspan > 1
241
306
  # elm.push "&#160;" if elm.empty? # &#160; = &nbsp; this line would be necessary for HTML 4 or XHTML 1.0