kron4eg-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,20 @@
1
+ Copyright (c) 2009.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
File without changes
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the wikicloth plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the wikicloth plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'WikiCloth'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
@@ -0,0 +1,43 @@
1
+ module ExtendedString
2
+
3
+ def blank?
4
+ respond_to?(:empty?) ? empty? : !self
5
+ end
6
+
7
+ def to_slug
8
+ self.gsub(/\W+/, '-').gsub(/^-+/,'').gsub(/-+$/,'').downcase
9
+ end
10
+
11
+ def auto_link
12
+ url_check = Regexp.new( '(^|[\n ])([\w]+?://[\w]+[^ \"\r\n\t<]*)', Regexp::MULTILINE | Regexp::IGNORECASE )
13
+ www_check = Regexp.new( '(^|[\n ])((www)\.[^ \"\t\n\r<]*)', Regexp::MULTILINE | Regexp::IGNORECASE )
14
+ self.gsub!(url_check, '\1<a href="\2">\2</a>')
15
+ self.gsub!(www_check, '\1<a href="http://\2">\2</a>')
16
+ to_s
17
+ end
18
+
19
+ def dump()
20
+ ret = to_s
21
+ delete!(to_s)
22
+ ret
23
+ end
24
+
25
+ def smart_split(char)
26
+ ret = []
27
+ tmp = ""
28
+ inside = 0
29
+ to_s.each_char do |x|
30
+ if x == char && inside == 0
31
+ ret << tmp
32
+ tmp = ""
33
+ else
34
+ inside += 1 if x == "[" || x == "{" || x == "<"
35
+ inside -= 1 if x == "]" || x == "}" || x == ">"
36
+ tmp += x
37
+ end
38
+ end
39
+ ret << tmp unless tmp.empty?
40
+ ret
41
+ end
42
+
43
+ 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 != " "
43
+ # close pre tag
44
+ cc_temp = current_char
45
+ "</pre>".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
+ "<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")
@@ -0,0 +1,237 @@
1
+ require 'rubygems'
2
+ require 'builder'
3
+
4
+ module WikiCloth
5
+
6
+ class WikiBuffer::HTMLElement < WikiBuffer
7
+
8
+ ALLOWED_ELEMENTS = ['a','b','i','div','span','sup','sub','strike','s','u','font','big','ref','tt','del',
9
+ 'small','blockquote','strong','pre','code','references','ol','li','ul','dd','dt','dl','center',
10
+ 'h2','h3','h4','h5','h6']
11
+ ALLOWED_ATTRIBUTES = ['id','name','style','class','href','start','value']
12
+ ESCAPED_TAGS = [ 'nowiki', 'pre', 'code' ]
13
+ SHORT_TAGS = [ 'meta','br','hr','img' ]
14
+ NO_NEED_TO_CLOSE = ['li','p'] + SHORT_TAGS
15
+
16
+ def initialize(d="",options={},check=nil)
17
+ super("",options)
18
+ self.buffer_type = "Element"
19
+ @in_quotes = false
20
+ @in_single_quotes = false
21
+ @start_tag = 1
22
+ @tag_check = check unless check.nil?
23
+ end
24
+
25
+ def run_globals?
26
+ return ESCAPED_TAGS.include?(self.element_name) ? false : true
27
+ end
28
+
29
+ def to_s
30
+ if NO_NEED_TO_CLOSE.include?(self.element_name)
31
+ return "<#{self.element_name} />" if SHORT_TAGS.include?(self.element_name)
32
+ return "</#{self.element_name}><#{self.element_name}>" if @tag_check == self.element_name
33
+ end
34
+
35
+ if ESCAPED_TAGS.include?(self.element_name)
36
+ # escape all html inside this element
37
+ self.element_content = self.element_content.gsub('<','&lt;').gsub('>','&gt;')
38
+ # hack to fix <code><nowiki> nested mess
39
+ self.element_content = self.element_content.gsub(/&lt;[\/]*\s*nowiki\s*&gt;/,'')
40
+ end
41
+
42
+ lhandler = @options[:link_handler]
43
+ case self.element_name
44
+ when "ref"
45
+ self.element_name = "sup"
46
+ named_ref = self.name_attribute
47
+ ref = lhandler.find_reference_by_name(named_ref) unless named_ref.nil?
48
+ if ref.nil?
49
+ lhandler.references << { :name => named_ref, :value => self.element_content, :count => 0 }
50
+ ref = lhandler.references.last
51
+ end
52
+ ref_id = (named_ref.nil? ? "" : "#{named_ref}_") + "#{lhandler.reference_index(ref)}-#{ref[:count]}"
53
+ self.params << { :name => "id", :value => "cite_ref-#{ref_id}" }
54
+ self.params << { :name => "class", :value => "reference" }
55
+ self.element_content = "[<a href=\"#cite_note-" + (named_ref.nil? ? "" : "#{named_ref}_") +
56
+ "#{lhandler.reference_index(ref)}\">#{lhandler.reference_index(ref)}</a>]"
57
+ ref[:count] += 1
58
+ when "references"
59
+ ref_count = 0
60
+ self.element_name = "ol"
61
+ self.element_content = lhandler.references.collect { |r|
62
+ ref_count += 1
63
+ ref_name = (r[:name].nil? ? "" : r[:name].to_slug + "_")
64
+ ret = "<li id=\"cite_note-#{ref_name}#{ref_count}\"><b>"
65
+ 1.upto(r[:count]) { |x| ret += "<a href=\"#cite_ref-#{ref_name}#{ref_count}-#{x-1}\">" +
66
+ (r[:count] == 1 ? "^" : (x-1).to_s(26).tr('0-9a-p', 'a-z')) + "</a> " }
67
+ ret += "</b> #{r[:value]}</li>"
68
+ }.to_s
69
+ when "nowiki"
70
+ return self.element_content
71
+ end
72
+
73
+ tmp = elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content }
74
+ unless ALLOWED_ELEMENTS.include?(self.element_name)
75
+ tmp.gsub!(/[\-!\|&"\{\}\[\]]/) { |r| self.escape_char(r) }
76
+ return tmp.gsub('<', '&lt;').gsub('>', '&gt;')
77
+ end
78
+ tmp
79
+ end
80
+
81
+ def name_attribute
82
+ params.each { |p| return p[:value].to_slug if p.kind_of?(Hash) && p[:name] == "name" }
83
+ return nil
84
+ end
85
+
86
+ def element_attributes
87
+ attr = {}
88
+ params.each { |p| attr[p[:name]] = p[:value] if p.kind_of?(Hash) }
89
+ if ALLOWED_ELEMENTS.include?(self.element_name.strip.downcase)
90
+ attr.delete_if { |key,value| !ALLOWED_ATTRIBUTES.include?(key.strip) }
91
+ end
92
+ return attr
93
+ end
94
+
95
+ def element_name
96
+ @ename ||= ""
97
+ end
98
+
99
+ def element_content
100
+ @econtent ||= ""
101
+ end
102
+
103
+ protected
104
+
105
+ def escape_char(c)
106
+ c = case c
107
+ when '-' then '&#45;'
108
+ when '!' then '&#33;'
109
+ when '|' then '&#124;'
110
+ when '&' then '&amp;'
111
+ when '"' then '&quot;'
112
+ when '{' then '&#123;'
113
+ when '}' then '&#125;'
114
+ when '[' then '&#91;'
115
+ when ']' then '&#93;'
116
+ when '*' then '&#42;'
117
+ when '#' then '&#35;'
118
+ when ':' then '&#58;'
119
+ when ';' then '&#59;'
120
+ when "'" then '&#39;'
121
+ when '=' then '&#61;'
122
+ else
123
+ c
124
+ end
125
+ return c
126
+ end
127
+
128
+ def elem
129
+ Builder::XmlMarkup.new
130
+ end
131
+
132
+ def element_name=(val)
133
+ @ename = val
134
+ end
135
+
136
+ def element_content=(val)
137
+ @econtent = val
138
+ end
139
+
140
+ def in_quotes?
141
+ @in_quotes || @in_single_quotes ? true : false
142
+ end
143
+
144
+ def new_char()
145
+ case
146
+ # tag name
147
+ when @start_tag == 1 && current_char == ' '
148
+ self.element_name = self.data.strip.downcase
149
+ self.data = ""
150
+ @start_tag = 2
151
+
152
+ # tag is closed <tag/> no attributes
153
+ when @start_tag == 1 && previous_char == '/' && current_char == '>'
154
+ self.data.chop!
155
+ self.element_name = self.data.strip.downcase
156
+ self.data = ""
157
+ @start_tag = 0
158
+ return false
159
+
160
+ # open tag
161
+ when @start_tag == 1 && previous_char != '/' && current_char == '>'
162
+ self.element_name = self.data.strip.downcase
163
+ self.data = ""
164
+ @start_tag = 0
165
+ return false if SHORT_TAGS.include?(self.element_name)
166
+ return false if self.element_name == @tag_check && NO_NEED_TO_CLOSE.include?(self.element_name)
167
+
168
+ # new tag attr
169
+ when @start_tag == 2 && current_char == ' ' && self.in_quotes? == false
170
+ self.current_param = self.data
171
+ self.data = ""
172
+ self.params << ""
173
+
174
+ # tag attribute name
175
+ when @start_tag == 2 && current_char == '=' && self.in_quotes? == false
176
+ self.current_param = self.data
177
+ self.data = ""
178
+ self.name_current_param()
179
+
180
+ # tag is now open
181
+ when @start_tag == 2 && previous_char != '/' && current_char == '>'
182
+ self.current_param = self.data
183
+ self.data = ""
184
+ @start_tag = 0
185
+ return false if SHORT_TAGS.include?(self.element_name)
186
+ return false if self.element_name == @tag_check && NO_NEED_TO_CLOSE.include?(self.element_name)
187
+
188
+ # tag is closed <example/>
189
+ when @start_tag == 2 && previous_char == '/' && current_char == '>'
190
+ self.current_param = self.data.chop
191
+ self.data = ""
192
+ @start_tag = 0
193
+ return false
194
+
195
+ # in quotes
196
+ when @start_tag == 2 && current_char == "'" && previous_char != '\\' && !@in_quotes
197
+ @in_single_quotes = !@in_single_quotes
198
+
199
+ # in quotes
200
+ when @start_tag == 2 && current_char == '"' && previous_char != '\\' && !@in_single_quotes
201
+ @in_quotes = !@in_quotes
202
+
203
+ # start of a closing tag
204
+ when @start_tag == 0 && previous_char == '<' && current_char == '/'
205
+ self.element_content += self.data.chop
206
+ self.data = ""
207
+ @start_tag = 5
208
+
209
+ when @start_tag == 5 && (current_char == '>' || current_char == ' ') && !self.data.blank?
210
+ self.data = self.data.strip.downcase
211
+ if self.data == self.element_name
212
+ self.data = ""
213
+ return false
214
+ else
215
+ if @tag_check == self.data && NO_NEED_TO_CLOSE.include?(self.element_name)
216
+ self.data = "</#{self.data}>"
217
+ return false
218
+ else
219
+ self.element_content += "&lt;/#{self.data}&gt;"
220
+ @start_tag = 0
221
+ self.data = ""
222
+ end
223
+ end
224
+
225
+ else
226
+ if @start_tag == 0 && ESCAPED_TAGS.include?(self.element_name)
227
+ self.data += self.escape_char(current_char)
228
+ else
229
+ self.data += current_char
230
+ end
231
+ end
232
+ return true
233
+ end
234
+
235
+ end
236
+
237
+ end