pseudohikiparser 0.0.3 → 0.0.4.develop

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,24 +10,31 @@ module PseudoHiki
10
10
  include BlockParser::BlockElement
11
11
  include TableRowParser::InlineElement
12
12
 
13
- #for InlineParser
13
+ # for InlineParser
14
14
  LINK, LITERAL, PLUGIN = %w(a code span)
15
15
  BLANK, SPACE = "", " "
16
16
  HREF, SRC, ALT, ID, CLASS, ROWSPAN, COLSPAN = %w(href src alt id class rowspan colspan)
17
- #for BlockParser
17
+ # for BlockParser
18
18
  DT, DD, LI = %w(dt dd li)
19
- DescSep = [InlineParser::DescSep]
19
+ DescSep, LinkSep = [InlineParser::DescSep], [InlineParser::LinkSep]
20
20
 
21
21
  Formatter = {}
22
22
 
23
+ class << self
24
+ attr_accessor :auto_link_in_verbatim
25
+ end
26
+
27
+ @auto_link_in_verbatim = true
28
+
23
29
  attr_reader :element_name
24
- attr_writer :generator, :formatter
30
+ attr_writer :generator, :formatter, :format_class
25
31
 
26
32
  def self.setup_new_formatter(new_formatter, generator)
27
33
  new_formatter.each do |node_class, formatter|
28
34
  new_formatter[node_class] = formatter.clone
29
35
  new_formatter[node_class].generator = generator
30
36
  new_formatter[node_class].formatter = new_formatter
37
+ new_formatter[node_class].format_class = self
31
38
  end
32
39
  end
33
40
 
@@ -39,19 +46,29 @@ module PseudoHiki
39
46
  self
40
47
  end
41
48
 
42
- def self.format(tree)
43
- formatter = self.get_plain
49
+ def self.default_options
50
+ { :auto_link_in_verbatim => @auto_link_in_verbatim }
51
+ end
52
+
53
+ def self.format(tree, options=nil)
54
+ cur_auto_link_setting = @auto_link_in_verbatim
55
+ options = default_options unless options
56
+ @auto_link_in_verbatim = options[:auto_link_in_verbatim]
57
+ formatter = get_plain
44
58
  tree.accept(formatter)
59
+ ensure
60
+ @auto_link_in_verbatim = cur_auto_link_setting
45
61
  end
46
62
 
47
63
  def initialize(element_name, generator=HtmlElement)
48
64
  @element_name = element_name
49
65
  @generator = generator
50
66
  @formatter = Formatter
67
+ @format_class = self.class
51
68
  end
52
69
 
53
70
  def visited_result(element)
54
- visitor = @formatter[element.class]||@formatter[PlainNode]
71
+ visitor = @formatter[element.class] || @formatter[PlainNode]
55
72
  element.accept(visitor)
56
73
  end
57
74
 
@@ -60,17 +77,19 @@ module PseudoHiki
60
77
  end
61
78
 
62
79
  def visit(tree)
63
- htmlelement = create_self_element(tree)
80
+ htmlelement = create_element(tree)
81
+ decorate(htmlelement, tree)
64
82
  push_visited_results(htmlelement, tree)
65
83
  htmlelement
66
84
  end
67
85
 
68
- def create_self_element(tree=nil)
86
+ def create_element(tree=nil)
69
87
  @generator.create(@element_name)
70
88
  end
71
89
 
72
90
  def split_into_parts(tree, separator)
73
91
  chunks = []
92
+ tree = tree.dup
74
93
  while sep_index = tree.index(separator)
75
94
  chunks.push tree.shift(sep_index)
76
95
  tree.shift
@@ -78,45 +97,61 @@ module PseudoHiki
78
97
  chunks.push tree
79
98
  end
80
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
+
81
115
  class ListLeafNodeFormatter < self
82
- def create_self_element(tree)
83
- super(tree).tap do |element|
84
- element[ID] = tree.node_id.upcase if tree.node_id
116
+ def create_element(tree)
117
+ super(tree).tap do |elm|
118
+ elm[ID] = tree.node_id.upcase if tree.node_id
85
119
  end
86
120
  end
87
121
  end
88
122
 
89
- [ [EmNode, "em"],
90
- [StrongNode, "strong"],
91
- [DelNode, "del"],
92
- [LiteralNode, LITERAL],
93
- [PluginNode, PLUGIN],
94
- [LinkNode, LINK],
95
- [InlineLeaf, nil],
96
- [PlainNode, nil], #Until here is for InlineParser
97
- [DescNode, "dl"],
98
- [QuoteNode, "blockquote"],
99
- [TableNode, "table"],
100
- [ParagraphNode, "p"],
101
- [HrNode, "hr"],
102
- [ListNode, "ul"],
103
- [EnumNode, "ol"],
104
- [TableLeaf, "tr"],
105
- [VerbatimNode, "pre"],
106
- [CommentOutNode, nil],
107
- [HeadingNode, "section"],
108
- [DescLeaf, DT],
109
- [TableCellNode, nil],
110
- [HeadingLeaf, "h"], #Until here is for BlockParser
111
- ].each {|node_class, element| Formatter[node_class] = self.new(element) }
112
-
113
- #for InlineParser
114
- ImgFormat = self.new("img")
115
- #for BlockParser
123
+ [[EmNode, "em"],
124
+ [StrongNode, "strong"],
125
+ [DelNode, "del"],
126
+ [LiteralNode, LITERAL],
127
+ [PluginNode, PLUGIN],
128
+ [LinkNode, LINK],
129
+ [InlineLeaf, nil],
130
+ [PlainNode, nil], # Until here is for InlineParser
131
+ [DescNode, "dl"],
132
+ [QuoteNode, "blockquote"],
133
+ [TableNode, "table"],
134
+ [ParagraphNode, "p"],
135
+ [HrNode, "hr"],
136
+ [ListNode, "ul"],
137
+ [EnumNode, "ol"],
138
+ [TableLeaf, "tr"],
139
+ [VerbatimNode, "pre"],
140
+ [SectioningNode, "section"],
141
+ [CommentOutNode, nil],
142
+ [HeadingNode, "section"],
143
+ [DescLeaf, DT],
144
+ [TableCellNode, nil],
145
+ [HeadingLeaf, "h"], # Until here is for BlockParser
146
+ ].each {|node_class, elm| Formatter[node_class] = new(elm) }
147
+
148
+ # for InlineParser
149
+ ImgFormat = new("img")
150
+ # for BlockParser
116
151
  Formatter[ListWrapNode] = ListLeafNodeFormatter.new(LI)
117
152
  Formatter[EnumWrapNode] = ListLeafNodeFormatter.new(LI)
118
153
 
119
- #for InlineParser
154
+ # for InlineParser
120
155
 
121
156
  class << Formatter[PluginNode]
122
157
  def visit(tree)
@@ -134,31 +169,26 @@ module PseudoHiki
134
169
  class << Formatter[LinkNode]
135
170
  def visit(tree)
136
171
  not_from_thumbnail = tree.first.class != LinkNode
137
- tree = tree.dup
138
- caption = get_caption(tree)
139
- begin
140
- ref = tree.last.join
141
- rescue NoMethodError
142
- raise NoMethodError unless tree.empty?
143
- STDERR.puts "No uri is specified for #{caption}"
144
- end
145
- if ImageSuffix =~ ref and not_from_thumbnail
146
- htmlelement = ImgFormat.create_self_element
147
- htmlelement[SRC] = tree.join
172
+ caption, ref = caption_and_ref(tree)
173
+ if IMAGE_SUFFIX_RE =~ ref and not_from_thumbnail
174
+ htmlelement = ImgFormat.create_element
175
+ htmlelement[SRC] = ref
148
176
  htmlelement[ALT] = caption.join if caption
149
177
  else
150
- htmlelement = create_self_element
151
- url = tree.join
152
- htmlelement[HREF] = url.start_with?("#".freeze) ? url.upcase : url
153
- htmlelement.push caption||url
178
+ htmlelement = create_element
179
+ htmlelement[HREF] = ref.start_with?("#".freeze) ? ref.upcase : ref
180
+ htmlelement.push caption || ref
154
181
  end
155
182
  htmlelement
156
183
  end
157
184
 
158
- def get_caption(tree)
159
- first_part, second_part = split_into_parts(tree, [LinkSep])
160
- return nil unless second_part
161
- first_part.map {|token| visited_result(token) }
185
+ def caption_and_ref(tree)
186
+ caption, ref = split_into_parts(tree, LinkSep)
187
+ caption = ref ? caption.map {|token| visited_result(token) } : nil
188
+ return caption, (ref || tree).join
189
+ rescue NoMethodError
190
+ raise NoMethodError unless (ref || tree).empty?
191
+ STDERR.puts "No uri is specified for #{caption}"
162
192
  end
163
193
  end
164
194
 
@@ -169,20 +199,63 @@ module PseudoHiki
169
199
  end
170
200
 
171
201
  class << Formatter[PlainNode]
172
- def create_self_element(tree=nil)
202
+ def create_element(tree=nil)
173
203
  @generator::Children.new
174
204
  end
175
205
  end
176
206
 
177
- #for BlockParser
207
+ # for BlockParser
208
+
209
+ class << Formatter[TableNode]
210
+ def decorate(htmlelement, tree)
211
+ each_decorator(htmlelement, tree) do |elm, decorator|
212
+ summary = decorator["summary"] && decorator["summary"].value.join
213
+ htmlelement["summary"] = HtmlElement.escape(summary) if summary
214
+ end
215
+ end
216
+ end
178
217
 
179
218
  class << Formatter[VerbatimNode]
180
219
  def visit(tree)
181
- create_self_element.tap do |element|
182
- contents = @generator.escape(tree.join).gsub(BlockParser::URI_RE) do |url|
183
- @generator.create(LINK, url, HREF => url).to_s
220
+ contents = add_link(@generator.escape(tree.join))
221
+ create_element.tap {|elm| elm.push contents }
222
+ end
223
+
224
+ def add_link(verbatim)
225
+ return verbatim unless @format_class.auto_link_in_verbatim
226
+ verbatim.gsub(AutoLink::URI_RE) do |url|
227
+ @generator.create(LINK, url, HREF => url).to_s
228
+ end
229
+ end
230
+ end
231
+
232
+ class << Formatter[SectioningNode]
233
+ ID_MARK = "#"
234
+
235
+ alias :orig_create_element :create_element
236
+
237
+ def section_with_id(tree, node_id)
238
+ orig_create_element(tree).tap do |elm|
239
+ elm[ID] = node_id[1..-1] # remove the first charactor from node_id
240
+ end
241
+ end
242
+
243
+ def section_for_class(tree, node_id)
244
+ if HtmlElement::HTML5_TAGS.include? node_id
245
+ @generator.create(node_id)
246
+ else
247
+ orig_create_element(tree).tap do |elm|
248
+ elm[CLASS] = elm[CLASS] ? "#{elm[CLASS]} #{node_id}" : node_id
184
249
  end
185
- element.push contents
250
+ end
251
+ end
252
+
253
+ def create_element(tree)
254
+ node_id = tree.node_id
255
+ if node_id.start_with? ID_MARK
256
+ section_with_id(tree, node_id)
257
+ else
258
+ section_for_class(tree, node_id)
186
259
  end
187
260
  end
188
261
  end
@@ -192,46 +265,45 @@ module PseudoHiki
192
265
  end
193
266
 
194
267
  class << Formatter[HeadingNode]
195
- def create_self_element(tree)
196
- super(tree).tap do |element|
197
- heading_level = "h#{tree.first.nominal_level}"
198
- element[CLASS] ||= heading_level
199
- element[CLASS] += SPACE + heading_level unless element[CLASS] == heading_level
268
+ def create_element(tree)
269
+ super(tree).tap do |elm|
270
+ heading_level = "h#{tree.first.level}"
271
+ elm[CLASS] ||= heading_level
272
+ elm[CLASS] += SPACE + heading_level unless elm[CLASS] == heading_level
200
273
  end
201
274
  end
202
275
  end
203
276
 
204
277
  class << Formatter[DescLeaf]
205
278
  def visit(tree)
206
- tree = tree.dup
207
- element = @generator::Children.new
279
+ elm = @generator::Children.new
208
280
  dt_part, dd_part = split_into_parts(tree, DescSep)
209
281
  dt = super(dt_part)
210
- element.push dt
282
+ elm.push dt
211
283
  unless dd_part.nil? or dd_part.empty?
212
284
  dd = @generator.create(DD)
213
285
  push_visited_results(dd, dd_part)
214
- element.push dd
286
+ elm.push dd
215
287
  end
216
- element
288
+ elm
217
289
  end
218
290
  end
219
291
 
220
292
  class << Formatter[TableCellNode]
221
293
  def visit(tree)
222
294
  @element_name = tree.cell_type
223
- super(tree).tap do |element|
224
- element[ROWSPAN] = tree.rowspan if tree.rowspan > 1
225
- element[COLSPAN] = tree.colspan if tree.colspan > 1
226
- # element.push "&#160;" if element.empty? # &#160; = &nbsp; this line would be necessary for HTML 4 or XHTML 1.0
295
+ super(tree).tap do |elm|
296
+ elm[ROWSPAN] = tree.rowspan if tree.rowspan > 1
297
+ elm[COLSPAN] = tree.colspan if tree.colspan > 1
298
+ # elm.push "&#160;" if elm.empty? # &#160; = &nbsp; this line would be necessary for HTML 4 or XHTML 1.0
227
299
  end
228
300
  end
229
301
  end
230
302
 
231
303
  class << Formatter[HeadingLeaf]
232
- def create_self_element(tree)
233
- @generator.create(@element_name+tree.nominal_level.to_s).tap do |element|
234
- element[ID] = tree.node_id.upcase if tree.node_id
304
+ def create_element(tree)
305
+ @generator.create(@element_name + tree.level.to_s).tap do |elm|
306
+ elm[ID] = tree.node_id.upcase if tree.node_id
235
307
  end
236
308
  end
237
309
  end
@@ -240,10 +312,12 @@ module PseudoHiki
240
312
  class XhtmlFormat < HtmlFormat
241
313
  Formatter = HtmlFormat::Formatter.dup
242
314
  setup_new_formatter(Formatter, XhtmlElement)
315
+ @auto_link_in_verbatim = true
243
316
  end
244
317
 
245
318
  class Xhtml5Format < XhtmlFormat
246
319
  Formatter = HtmlFormat::Formatter.dup
247
320
  setup_new_formatter(Formatter, Xhtml5Element)
321
+ @auto_link_in_verbatim = true
248
322
  end
249
323
  end
@@ -9,7 +9,7 @@ module PseudoHiki
9
9
  class HtmlFormat
10
10
  class << Formatter[PluginNode]
11
11
  def visit(leaf)
12
- escape_inline_tags(leaf) { HtmlPlugin.new(@element_name,leaf.join).apply }
12
+ escape_inline_tags(leaf) { HtmlPlugin.new(@element_name, leaf.join).apply }
13
13
  end
14
14
  end
15
15
  end
@@ -30,20 +30,19 @@ module PseudoHiki
30
30
  NUMBER_RE = /(\d+)/
31
31
 
32
32
  def parse(data)
33
- result = nil
33
+ result = "".freeze
34
34
  if PLUGIN_PAT =~ data
35
35
  @plugin_name = $1
36
36
  @with_paren = true if $2.chomp == "("
37
- result = data.chomp.sub(PLUGIN_PAT,"")
38
- result[-1,1] = "" if @with_paren
37
+ result = data.chomp.sub(PLUGIN_PAT, "")
38
+ result[-1, 1] = "" if @with_paren
39
39
  else
40
40
  @plugin_name = data.chomp
41
- result = ""
42
41
  end
43
42
  result
44
43
  end
45
44
 
46
- def initialize(tag_type,parsed_data)
45
+ def initialize(tag_type, parsed_data)
47
46
  @tag_type = tag_type
48
47
  @plugin_name = nil
49
48
  @with_paren = nil
@@ -66,14 +65,14 @@ module PseudoHiki
66
65
  # end
67
66
 
68
67
  def anchor
69
- name, anchor_mark = @data.split(/,\s*/o,2)
68
+ name, anchor_mark = @data.split(/,\s*/o, 2)
70
69
  anchor_mark = "_" if (anchor_mark.nil? or anchor_mark.empty?)
71
70
  HtmlElement.create("a", anchor_mark,
72
71
  "name" => name,
73
- "href" => "#"+name)
72
+ "href" => "#" + name)
74
73
  end
75
74
 
76
- def HtmlPlugin.add_chemical_formula(chemical_formula="CO2",en_word="carbon dioxide")
75
+ def HtmlPlugin.add_chemical_formula(chemical_formula="CO2", en_word="carbon dioxide")
77
76
  eval(<<-End)
78
77
  def #{chemical_formula.downcase}
79
78
  #(display=":cf",second_display=nil)
@@ -130,7 +129,7 @@ module PseudoHiki
130
129
  @data.scan(/\A(\d+)([^\d].*)/o) do |data|
131
130
  weight, molecule = data
132
131
  if self.respond_to? molecule
133
- return "<sup>#{weight}</sup>" + HtmlPlugin.new("",molecule).apply
132
+ return "<sup>#{weight}</sup>" + HtmlPlugin.new("", molecule).apply
134
133
  else
135
134
  return "<sup>#{weight}</sup>" + molecule
136
135
  end
@@ -145,21 +144,3 @@ module PseudoHiki
145
144
  end
146
145
  end
147
146
  end
148
-
149
- if $0 == __FILE__
150
- p HtmlPlugin.new("div","html(
151
- <ul>
152
- <li>list
153
- <li>list
154
- </ul>)").apply
155
- p HtmlPlugin.new("div","inline(
156
- *list
157
- *list
158
- )").apply
159
-
160
- p HtmlPlugin.new("div","co2").apply
161
- p HtmlPlugin.new("div","co2 :en").apply
162
- p HtmlPlugin.new("div","cb(3km)").apply
163
- p HtmlPlugin.new("div","per m").apply
164
- p HtmlPlugin.new("div","iso 18co2").apply
165
- end
@@ -7,11 +7,7 @@ module PseudoHiki
7
7
  RELATIVE_PATH = /^\./o
8
8
  ROOT_PATH = /^(\/|\\\\|[A-Za-z]:\\)/o
9
9
  FILE_MARK = "file:///"
10
- ImageSuffix = /\.(jpg|jpeg|gif|png|bmp)$/io
11
-
12
- def self.subclass_of(parent_class, bound_env, subclass_names)
13
- subclass_names. each {|name| eval "class #{name} < #{parent_class}; end", bound_env }
14
- end
10
+ IMAGE_SUFFIX_RE = /\.(jpg|jpeg|gif|png|bmp)$/io
15
11
 
16
12
  def self.compile_token_pat(*token_sets)
17
13
  tokens = token_sets.flatten.uniq.sort do |x, y|
@@ -35,10 +31,11 @@ module PseudoHiki
35
31
  module InlineElement
36
32
  class InlineNode < InlineParser::Node; end
37
33
  class InlineLeaf < InlineParser::Leaf; end
38
- # class LinkSepLeaf < InlineLeaf; end
34
+ # class LinkSepLeaf < InlineLeaf; end
39
35
 
40
- PseudoHiki.subclass_of(InlineNode, binding,
41
- %w(LinkNode EmNode StrongNode DelNode PlainNode LiteralNode PluginNode))
36
+ %w(LinkNode EmNode StrongNode DelNode PlainNode LiteralNode PluginNode).each do |subclass|
37
+ const_set(subclass, Class.new(InlineNode))
38
+ end
42
39
 
43
40
  LinkSep, TableSep, DescSep = %w(| || :)
44
41
  end
@@ -48,7 +45,7 @@ module PseudoHiki
48
45
  TAIL = {}
49
46
  NodeTypeToHead = {}
50
47
  TokenPat = {}
51
-
48
+
52
49
  [[LinkNode, "[[", "]]"],
53
50
  [EmNode, "''", "''"],
54
51
  [StrongNode, "'''", "'''"],
@@ -60,7 +57,7 @@ module PseudoHiki
60
57
  NodeTypeToHead[type] = head
61
58
  end
62
59
 
63
- TokenPat[self] = PseudoHiki.compile_token_pat(HEAD.keys,TAIL.keys,[LinkSep, TableSep, DescSep])
60
+ TokenPat[self] = PseudoHiki.compile_token_pat(HEAD.keys, TAIL.keys, [LinkSep, TableSep, DescSep])
64
61
 
65
62
  def initialize(str)
66
63
  @tokens = PseudoHiki.split_into_tokens(str, TokenPat[self.class])
@@ -70,8 +67,8 @@ module PseudoHiki
70
67
  def convert_last_node_into_leaf
71
68
  last_node = remove_current_node
72
69
  tag_head = NodeTypeToHead[last_node.class]
73
- self.push InlineLeaf.create(tag_head)
74
- last_node.each {|leaf| self.push_as_leaf leaf }
70
+ push InlineLeaf.create(tag_head)
71
+ last_node.each {|leaf| push_as_leaf leaf }
75
72
  end
76
73
 
77
74
  def node_in_ancestors?(node_class)
@@ -79,23 +76,23 @@ module PseudoHiki
79
76
  end
80
77
 
81
78
  def treated_as_node_end(token)
82
- return self.pop if current_node.class == TAIL[token]
79
+ return pop if current_node.class == TAIL[token]
83
80
  return nil unless node_in_ancestors?(TAIL[token])
84
81
  convert_last_node_into_leaf until current_node.class == TAIL[token]
85
- self.pop
82
+ pop
86
83
  end
87
84
 
88
85
  def parse
89
86
  while token = @tokens.shift
90
87
  next if TAIL[token] and treated_as_node_end(token)
91
- next if HEAD[token] and self.push HEAD[token].new
92
- self.push InlineLeaf.create(token)
88
+ next if HEAD[token] and push HEAD[token].new
89
+ push InlineLeaf.create(token)
93
90
  end
94
91
  self
95
92
  end
96
93
 
97
94
  def self.parse(str)
98
- new(str).parse.tree #parser = new(str)
95
+ new(str).parse.tree # parser = new(str)
99
96
  end
100
97
  end
101
98
 
@@ -120,9 +117,9 @@ module PseudoHiki
120
117
 
121
118
  class InlineElement::TableCellNode
122
119
  def parse_cellspan(token_str)
123
- return token_str if m = MODIFIED_CELL_PAT.match(token_str) and m[0].empty? #if token.kind_of? String
124
- cell_modifiers = m[0]
125
- @cell_type = TH if cell_modifiers[0].chr == TH_PAT
120
+ m = MODIFIED_CELL_PAT.match(token_str) and cell_modifiers = m[0]
121
+ return token_str if cell_modifiers.empty?
122
+ @cell_type = TH if cell_modifiers.start_with? TH_PAT
126
123
  @rowspan = cell_modifiers.count(ROW_EXPANDER) + 1
127
124
  @colspan = cell_modifiers.count(COL_EXPANDER) + 1
128
125
  m.post_match
@@ -134,19 +131,19 @@ module PseudoHiki
134
131
  end
135
132
 
136
133
  def push(token)
137
- return super(token) unless self.empty?
134
+ return super(token) unless empty?
138
135
  super(parse_first_token(token))
139
136
  end
140
137
  end
141
138
 
142
139
  def treated_as_node_end(token)
143
140
  return super(token) unless token == TableSep
144
- self.pop
145
- self.push TableCellNode.new
141
+ pop
142
+ push TableCellNode.new
146
143
  end
147
144
 
148
145
  def parse
149
- self.push TableCellNode.new
146
+ push TableCellNode.new
150
147
  super
151
148
  end
152
149
  end