pseudohikiparser 0.0.3 → 0.0.4.develop

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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