wikicloth 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,77 @@
1
+ module WikiCloth
2
+
3
+ class WikiBuffer::Var < WikiBuffer
4
+
5
+ def initialize(data="",options={})
6
+ super(data,options)
7
+ self.buffer_type = "var"
8
+ @in_quotes = false
9
+ end
10
+
11
+ def skip_html?
12
+ true
13
+ end
14
+
15
+ def function_name
16
+ @fname
17
+ end
18
+
19
+ def to_s
20
+ if self.is_function?
21
+ ret = "#{buffer_type}"
22
+ ret += " function #{function_name}"
23
+ ret += "(#{params.inspect})"
24
+ ret += " [#{data}]"
25
+ else
26
+ ret = @options[:link_handler].include_resource("#{params[0]}".strip,params[1..-1])
27
+ end
28
+ ret ||= "<!-- TEMPLATE[#{params[0]}] NOT FOUND -->"
29
+ ret
30
+ end
31
+
32
+ def is_function?
33
+ self.function_name.nil? || self.function_name.blank? ? false : true
34
+ end
35
+
36
+ protected
37
+ def function_name=(val)
38
+ @fname = val
39
+ end
40
+
41
+ def new_char()
42
+ case
43
+ when current_char == '|' && @in_quotes == false
44
+ self.current_param = self.data
45
+ self.data = ""
46
+ self.params << ""
47
+
48
+ # Start of either a function or a namespace change
49
+ when current_char == ':' && @in_quotes == false && self.params.size <= 1
50
+ self.function_name = self.data
51
+ self.data = ""
52
+ puts "[found var function (#{function_name})"
53
+
54
+ # Dealing with variable names within functions
55
+ # and variables
56
+ when current_char == '=' && @in_quotes == false
57
+ self.current_param = self.data
58
+ self.data = ""
59
+ self.name_current_param()
60
+
61
+ # End of a template, variable, or function
62
+ when current_char == '}' && previous_char == '}'
63
+ self.data.chop!
64
+ self.current_param = self.data
65
+ self.data = ""
66
+ return false
67
+
68
+ else
69
+ self.data += current_char
70
+ end
71
+
72
+ return true
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,279 @@
1
+ module WikiCloth
2
+ class WikiBuffer
3
+
4
+ def initialize(data="",options={})
5
+ @options = options
6
+ self.data = data
7
+ self.buffer_type = nil
8
+ @section_count = 0
9
+ @buffers ||= [ ]
10
+ @buffers << self
11
+ @list_data = []
12
+ end
13
+
14
+ def run_globals?
15
+ true
16
+ end
17
+
18
+ def skip_html?
19
+ false
20
+ end
21
+
22
+ def data
23
+ @data ||= ""
24
+ end
25
+
26
+ def params
27
+ @params ||= [ "" ]
28
+ end
29
+
30
+ def buffer_type
31
+ @buffer_type
32
+ end
33
+
34
+ def to_s
35
+ "<p>" + self.params.join("\n") + "</p>"
36
+ end
37
+
38
+ def check_globals()
39
+ return false if self.class != WikiBuffer
40
+
41
+ if previous_char == "\n"
42
+ if @indent == @buffers[-1].object_id && current_char != " " && current_char != "\n"
43
+ # close pre tag
44
+ cc_temp = current_char
45
+ "</pre>\n".each_char { |c| self.add_char(c) }
46
+ # get the parser back on the right track
47
+ "\n#{cc_temp}".each_char { |c| @buffers[-1].add_char(c) }
48
+ @indent = nil
49
+ return true
50
+ end
51
+ if current_char == " " && @indent.nil? && @buffers[-1].class != WikiBuffer::HTMLElement
52
+ "\n<pre> ".each_char { |c| @buffers[-1].add_char(c) }
53
+ @indent = @buffers[-1].object_id
54
+ return true
55
+ end
56
+ end
57
+
58
+ if @buffers[-1].run_globals?
59
+ # new html tag
60
+ if @check_new_tag == true && current_char =~ /([a-z])/ && !@buffers[-1].skip_html?
61
+ @buffers[-1].data.chop!
62
+ parent = @buffers[-1].element_name if @buffers[-1].class == WikiBuffer::HTMLElement
63
+ @buffers << WikiBuffer::HTMLElement.new("",@options,parent)
64
+ end
65
+ @check_new_tag = current_char == '<' ? true : false
66
+
67
+ # global
68
+ case
69
+ # start variable
70
+ when previous_char == '{' && current_char == '{'
71
+ @buffers[-1].data.chop!
72
+ @buffers << WikiBuffer::Var.new("",@options)
73
+ return true
74
+
75
+ # start link
76
+ when current_char == '[' && previous_char != '['
77
+ @buffers << WikiBuffer::Link.new("",@options)
78
+ return true
79
+
80
+ # start table
81
+ when previous_char == '{' && current_char == "|"
82
+ @buffers[-1].data.chop!
83
+ @buffers << WikiBuffer::Table.new("",@options)
84
+ return true
85
+
86
+ end
87
+ end
88
+
89
+ return false
90
+ end
91
+
92
+ def add_char(c)
93
+ self.previous_char = self.current_char
94
+ self.current_char = c
95
+
96
+ if self.check_globals() == false
97
+ case
98
+ when @buffers.size == 1
99
+ return self.new_char()
100
+ when @buffers[-1].add_char(c) == false && self.class == WikiBuffer
101
+ tmp = @buffers.pop
102
+ @buffers[-1].data += tmp.to_s
103
+ # any data left in the buffer we feed into the parent
104
+ unless tmp.data.blank?
105
+ tmp.data.each_char { |c| self.add_char(c) }
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ protected
112
+ # only executed in the default state
113
+ def new_char()
114
+ case
115
+ when current_char == "\n"
116
+ if @options[:extended_markup] == true
117
+ self.data.gsub!(/---([^-]+)---/,"<strike>\\1</strike>")
118
+ self.data.gsub!(/_([^_]+)_/,"<u>\\1</u>")
119
+ end
120
+ self.data.gsub!(/__([a-zA-Z0-9]+)__/) { |r|
121
+ case $1
122
+ when "NOEDITSECTION"
123
+ @noeditsection = true
124
+ end
125
+ ""
126
+ }
127
+ self.data.gsub!(/^([-]{4,})/) { |r| "<hr />" }
128
+ self.data.gsub!(/^([=]{1,6})\s*(.*?)\s*(\1)/) { |r|
129
+ @section_count += 1
130
+ "<h#{$1.length}>" + (@noeditsection == true ? "" :
131
+ "<span class=\"editsection\">[<a href=\"" + @options[:link_handler].section_link(@section_count) +
132
+ "\" title=\"Edit section: #{$2}\">edit</a>]</span>") +
133
+ " <span class=\"mw-headline\">#{$2}</span></h#{$1.length}>"
134
+ }
135
+ self.data.gsub!(/([\']{2,5})(.*?)(\1)/) { |r|
136
+ tmp = "<i>#{$2}</i>" if $1.length == 2
137
+ tmp = "<b>#{$2}</b>" if $1.length == 3
138
+ tmp = "<b>'#{$2}'</b>" if $1.length == 4
139
+ tmp = "<b><i>#{$2}</i></b>" if $1.length == 5
140
+ tmp
141
+ }
142
+ lines = self.data.split("\n")
143
+ self.data = ""
144
+ for line in lines
145
+ if !@list_data.empty? && (line.blank? || line =~ /^([^#\*:;]+)/)
146
+ tmp = ""
147
+ @list_data.reverse!
148
+ @list_data.each { |x| tmp += "</" + list_inner_tag_for(x) + "></#{list_tag_for(x)}>" }
149
+ line = "#{tmp} #{line}"
150
+ @list_data = []
151
+ end
152
+ line.gsub!(/^([#\*:;]+)(.*)$/) { |r|
153
+ cdata = []
154
+ tmp = ""
155
+ $1.each_char { |c| cdata << c }
156
+ if @list_data.empty?
157
+ tmp += "<#{list_tag_for(cdata[0])}>"
158
+ cdata[1..-1].each { |x| tmp += "<" + list_inner_tag_for(cdata[0]) + "><#{list_tag_for(x)}>" } if cdata.size > 1
159
+ else
160
+ case
161
+ when cdata.size > @list_data.size
162
+ i = cdata.size-@list_data.size
163
+ cdata[-i,i].each { |x| tmp += "<#{list_tag_for(x)}>" }
164
+ when cdata.size < @list_data.size
165
+ i = @list_data.size-cdata.size
166
+ nlist = @list_data[-i,i].reverse
167
+ nlist.each { |x| tmp += "</" + list_inner_tag_for(x) + "></#{list_tag_for(x)}>" }
168
+ tmp += "</#{list_inner_tag_for(cdata.last)}>"
169
+ else
170
+ if cdata != @list_data
171
+ # FIXME: this will only work if the change depth is one level
172
+ unless (@list_data.last == ';' || @list_data.last == ':') && (cdata.last == ';' || cdata.last == ':')
173
+ tmp += "</#{list_tag_for(@list_data.pop)}>"
174
+ tmp += "<#{list_tag_for(cdata.last)}>"
175
+ end
176
+ else
177
+ tmp += "</" + list_inner_tag_for(@list_data.last) + ">"
178
+ end
179
+ end
180
+ end
181
+ # FIXME: still probably does not detect the : properly
182
+ peices = cdata.last == ";" ? $2.smart_split(":") : [ $2 ]
183
+ if peices.size > 1
184
+ tmp += "<#{list_inner_tag_for(cdata.last)}>#{peices[0]}</#{list_inner_tag_for(cdata.last)}>"
185
+ tmp += "<dd>#{peices[1..-1].join(":")}</dd>"
186
+ cdata[-1] = ":"
187
+ else
188
+ tmp += "<#{list_inner_tag_for(cdata.last)}>#{peices[0]}"
189
+ end
190
+ @list_data = cdata
191
+ tmp
192
+ }
193
+ self.data += line + "\n"
194
+ end
195
+
196
+ self.data = "</p><p>" if self.data.blank?
197
+
198
+ self.params << self.data.auto_link
199
+ self.data = ""
200
+ else
201
+ self.data += current_char
202
+ end
203
+ return true
204
+ end
205
+
206
+ def name_current_param()
207
+ params[-1] = { :value => "", :name => params[-1] } unless params[-1].kind_of?(Hash) || params[-1].nil?
208
+ end
209
+
210
+ def current_param=(val)
211
+ unless self.params[-1].nil? || self.params[-1].kind_of?(String)
212
+ self.params[-1][:value] = val
213
+ else
214
+ self.params[-1] = val
215
+ end
216
+ end
217
+
218
+ def params=(val)
219
+ @params = val
220
+ end
221
+
222
+ def buffer_type=(val)
223
+ @buffer_type = val
224
+ end
225
+
226
+ def data=(val)
227
+ @data = val
228
+ end
229
+
230
+ def current_char=(val)
231
+ @current_char = val
232
+ end
233
+
234
+ def current_char
235
+ @current_char ||= ""
236
+ end
237
+
238
+ def previous_char=(val)
239
+ @previous_char = val
240
+ end
241
+
242
+ def previous_char
243
+ @previous_char
244
+ end
245
+
246
+ def current_line=(val)
247
+ @current_line = val
248
+ end
249
+
250
+ def current_line
251
+ @current_line ||= ""
252
+ end
253
+
254
+ def list_tag_for(tag)
255
+ case tag
256
+ when "#" then "ol"
257
+ when "*" then "ul"
258
+ when ";" then "dl"
259
+ when ":" then "dl"
260
+ end
261
+ end
262
+
263
+ def list_inner_tag_for(tag)
264
+ case tag
265
+ when "#" then "li"
266
+ when "*" then "li"
267
+ when ";" then "dt"
268
+ when ":" then "dd"
269
+ end
270
+ end
271
+
272
+ end
273
+
274
+ end
275
+
276
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "html_element")
277
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "table")
278
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "var")
279
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "link")
data/lib/wiki_cloth.rb ADDED
@@ -0,0 +1,61 @@
1
+ require 'jcode'
2
+
3
+ module WikiCloth
4
+
5
+ class WikiCloth
6
+
7
+ def initialize(opt={})
8
+ self.load(opt[:data],opt[:params]) unless opt[:data].nil? || opt[:data].blank?
9
+ self.options[:link_handler] = opt[:link_handler] unless opt[:link_handler].nil?
10
+ end
11
+
12
+ def load(data,p={})
13
+ data.gsub!(/<!--(.|\s)*?-->/,"")
14
+ self.params = p
15
+ self.html = data
16
+ end
17
+
18
+ def render(opt={})
19
+ self.options = { :output => :html, :link_handler => self.link_handler, :params => self.params }.merge(opt)
20
+ self.options[:link_handler].params = options[:params]
21
+ buffer = WikiBuffer.new("",options)
22
+ self.html.each_char { |c| buffer.add_char(c) }
23
+ buffer.to_s
24
+ end
25
+
26
+ def to_html(opt={})
27
+ self.render(opt)
28
+ end
29
+
30
+ def link_handler
31
+ self.options[:link_handler] ||= WikiLinkHandler.new
32
+ end
33
+
34
+ def html
35
+ @page_data + (@page_data[-1,1] == "\n" ? "" : "\n")
36
+ end
37
+
38
+ def params
39
+ @page_params ||= {}
40
+ end
41
+
42
+ protected
43
+ def options=(val)
44
+ @options = val
45
+ end
46
+
47
+ def options
48
+ @options ||= {}
49
+ end
50
+
51
+ def html=(val)
52
+ @page_data = val
53
+ end
54
+
55
+ def params=(val)
56
+ @page_params = val
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,138 @@
1
+ require 'rubygems'
2
+ require 'builder'
3
+
4
+ module WikiCloth
5
+
6
+ class WikiLinkHandler
7
+
8
+ def references
9
+ @references ||= []
10
+ end
11
+
12
+ def section_link(section)
13
+ ""
14
+ end
15
+
16
+ def params
17
+ @params ||= {}
18
+ end
19
+
20
+ def external_links
21
+ @external_links ||= []
22
+ end
23
+
24
+ def find_reference_by_name(n)
25
+ references.each { |r| return r if !r[:name].nil? && r[:name].strip == n }
26
+ return nil
27
+ end
28
+
29
+ def reference_index(h)
30
+ references.each_index { |r| return r+1 if references[r] == h }
31
+ return nil
32
+ end
33
+
34
+ def references=(val)
35
+ @references = val
36
+ end
37
+
38
+ def params=(val)
39
+ @params = val
40
+ end
41
+
42
+ def external_link(url,text)
43
+ self.external_links << url
44
+ elem.a({ :href => url }) { |x| x << (text.blank? ? url : text) }
45
+ end
46
+
47
+ def external_links=(val)
48
+ @external_links = val
49
+ end
50
+
51
+ def url_for(page)
52
+ "javascript:void(0)"
53
+ end
54
+
55
+ def link_attributes_for(page)
56
+ { :href => url_for(page) }
57
+ end
58
+
59
+ def link_for(page, text)
60
+ ltitle = !text.nil? && text.blank? ? self.pipe_trick(page) : text
61
+ ltitle = page if text.nil?
62
+ elem.a(link_attributes_for(page)) { |x| x << ltitle.strip }
63
+ end
64
+
65
+ def include_resource(resource, options=[])
66
+ return self.params[resource] unless self.params[resource].nil?
67
+ end
68
+
69
+ def link_for_resource(prefix, resource, options=[])
70
+ ret = ""
71
+ prefix.downcase!
72
+ case
73
+ when ["image","file","media"].include?(prefix)
74
+ ret += wiki_image(resource,options)
75
+ else
76
+ title = options[0] ? options[0] : "#{prefix}:#{resource}"
77
+ ret += link_for("#{prefix}:#{resource}",title)
78
+ end
79
+ ret
80
+ end
81
+
82
+ protected
83
+ def pipe_trick(page)
84
+ t = page.split(":")
85
+ t = t[1..-1] if t.size > 1
86
+ return t.join("").split(/[,(]/)[0]
87
+ end
88
+
89
+ # this code needs some work... lots of work
90
+ def wiki_image(resource,options)
91
+ pre_img = ''
92
+ post_img = ''
93
+ css = []
94
+ loc = "right"
95
+ type = nil
96
+ w = 180
97
+ h = nil
98
+ title = nil
99
+ ffloat = false
100
+
101
+ options.each do |x|
102
+ case
103
+ when ["thumb","thumbnail","frame","border"].include?(x.strip)
104
+ type = x.strip
105
+ when ["left","right","center","none"].include?(x.strip)
106
+ ffloat = true
107
+ loc = x.strip
108
+ when x.strip =~ /^([0-9]+)\s*px$/
109
+ w = $1
110
+ css << "width:#{w}px"
111
+ when x.strip =~ /^([0-9]+)\s*x\s*([0-9]+)\s*px$/
112
+ w = $1
113
+ css << "width:#{w}px"
114
+ h = $2
115
+ css << "height:#{h}px"
116
+ else
117
+ title = x.strip
118
+ end
119
+ end
120
+ css << "float:#{loc}" if ffloat == true
121
+ css << "border:1px solid #000" if type == "border"
122
+
123
+ sane_title = title.nil? ? "" : title.gsub(/<\/?[^>]*>/, "")
124
+ if type == "thumb" || type == "thumbnail" || type == "frame"
125
+ pre_img = '<div class="thumb t' + loc + '"><div class="thumbinner" style="width: ' + w.to_s +
126
+ 'px;"><a href="" class="image" title="' + sane_title + '">'
127
+ post_img = '</a><div class="thumbcaption">' + title + '</div></div></div>'
128
+ end
129
+ "#{pre_img}<img src=\"#{resource}\" alt=\"#{sane_title}\" title=\"#{sane_title}\" style=\"#{css.join(";")}\" />#{post_img}"
130
+ end
131
+
132
+ def elem
133
+ Builder::XmlMarkup.new
134
+ end
135
+
136
+ end
137
+
138
+ end
data/lib/wikicloth.rb ADDED
@@ -0,0 +1,5 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), "core_ext")
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_cloth")
3
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer")
4
+ require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_link_handler")
5
+ String.send(:include, ExtendedString)
data/run_tests.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'init'
2
+ include WikiCloth
3
+
4
+ class CustomLinkHandler < WikiLinkHandler
5
+ def include_resource(resource,options=[])
6
+ case resource
7
+ when "date"
8
+ Time.now.to_s
9
+ else
10
+ # default behavior
11
+ super(resource,options)
12
+ end
13
+ end
14
+ def url_for(page)
15
+ "javascript:alert('You clicked on: #{page}');"
16
+ end
17
+ def link_attributes_for(page)
18
+ { :href => url_for(page) }
19
+ end
20
+ end
21
+ @wiki = WikiCloth::WikiCloth.new({
22
+ :data => "<nowiki>{{test}}</nowiki> ''Hello {{test}}!''\n",
23
+ :params => { "test" => "World" } })
24
+ puts @wiki.to_html
25
+ @wiki = WikiCloth::WikiCloth.new({
26
+ :params => { "PAGENAME" => "Testing123" },
27
+ :link_handler => CustomLinkHandler.new,
28
+ :data => "\n[[Hello World]] From {{ PAGENAME }} on {{ date }}\n"
29
+ })
30
+ puts @wiki.to_html
31
+
32
+ Dir.glob("sample_documents/*.wiki").each do |x|
33
+
34
+ start_time = Time.now
35
+ out_name = "#{x}.html"
36
+ data = File.open(x) { |x| x.read }
37
+
38
+ tmp = WikiCloth::WikiCloth.new()
39
+ tmp.load(data, { "PAGENAME" => "HelloWorld" })
40
+ out = tmp.render({ :output => :html })
41
+ out = "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\" dir=\"ltr\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /><link rel=\"stylesheet\" href=\"default.css\" type=\"text/css\" /></head><body>#{out}</body></html>"
42
+
43
+ File.open(out_name, "w") { |x| x.write(out) }
44
+ end_time = Time.now
45
+ puts "#{out_name}: Completed (#{end_time - start_time} sec) | External Links: #{tmp.link_handler.external_links.size} -- References: #{tmp.link_handler.references.size}"
46
+
47
+ end
48
+