wikicloth 0.1.3

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.
@@ -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
+