ruwiki 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Readme.rubygems +86 -0
- data/Readme.tarfile +65 -0
- data/bin/ruwiki +58 -0
- data/bin/ruwiki.cgi +87 -0
- data/bin/ruwiki_convert +56 -0
- data/bin/ruwiki_service.rb +82 -0
- data/bin/ruwiki_servlet +53 -0
- data/contrib/enscript-token.rb +55 -0
- data/contrib/rublog_integrator.rb +68 -0
- data/data/Default/ProjectIndex.ruwiki +49 -0
- data/data/Ruwiki/Antispam.ruwiki +65 -0
- data/data/Ruwiki/BugTracking.ruwiki +33 -0
- data/data/Ruwiki/ChangeLog.ruwiki +102 -0
- data/data/Ruwiki/Configuring_Ruwiki.ruwiki +151 -0
- data/data/Ruwiki/Extending_Ruwiki.ruwiki +317 -0
- data/data/Ruwiki/LicenseAndAuthorInfo.ruwiki +30 -0
- data/data/Ruwiki/ProjectIndex.ruwiki +84 -0
- data/data/Ruwiki/Roadmap.ruwiki +225 -0
- data/data/Ruwiki/RuwikiTemplatingLibrary.ruwiki +156 -0
- data/data/Ruwiki/RuwikiUtilities.ruwiki +157 -0
- data/data/Ruwiki/SandBox.ruwiki +9 -0
- data/data/Ruwiki/To_Do.ruwiki +51 -0
- data/data/Ruwiki/TroubleShooting.ruwiki +33 -0
- data/data/Ruwiki/WikiFeatures.ruwiki +17 -0
- data/data/Ruwiki/WikiMarkup.ruwiki +261 -0
- data/data/Tutorial/AddingPages.ruwiki +16 -0
- data/data/Tutorial/AddingProjects.ruwiki +16 -0
- data/data/Tutorial/ProjectIndex.ruwiki +11 -0
- data/data/Tutorial/SandBox.ruwiki +9 -0
- data/data/agents.banned +60 -0
- data/data/agents.readonly +321 -0
- data/data/hostip.banned +30 -0
- data/data/hostip.readonly +28 -0
- data/lib/ruwiki.rb +622 -0
- data/lib/ruwiki/auth.rb +56 -0
- data/lib/ruwiki/auth/gforge.rb +73 -0
- data/lib/ruwiki/backend.rb +318 -0
- data/lib/ruwiki/backend/flatfiles.rb +217 -0
- data/lib/ruwiki/config.rb +244 -0
- data/lib/ruwiki/exportable.rb +192 -0
- data/lib/ruwiki/handler.rb +342 -0
- data/lib/ruwiki/lang/de.rb +339 -0
- data/lib/ruwiki/lang/en.rb +334 -0
- data/lib/ruwiki/lang/es.rb +339 -0
- data/lib/ruwiki/page.rb +262 -0
- data/lib/ruwiki/servlet.rb +38 -0
- data/lib/ruwiki/template.rb +553 -0
- data/lib/ruwiki/utils.rb +24 -0
- data/lib/ruwiki/utils/command.rb +102 -0
- data/lib/ruwiki/utils/converter.rb +297 -0
- data/lib/ruwiki/utils/manager.rb +639 -0
- data/lib/ruwiki/utils/servletrunner.rb +295 -0
- data/lib/ruwiki/wiki.rb +147 -0
- data/lib/ruwiki/wiki/tokens.rb +136 -0
- data/lib/ruwiki/wiki/tokens/00default.rb +211 -0
- data/lib/ruwiki/wiki/tokens/01wikilinks.rb +166 -0
- data/lib/ruwiki/wiki/tokens/02actions.rb +63 -0
- data/lib/ruwiki/wiki/tokens/abbreviations.rb +40 -0
- data/lib/ruwiki/wiki/tokens/calendar.rb +147 -0
- data/lib/ruwiki/wiki/tokens/headings.rb +43 -0
- data/lib/ruwiki/wiki/tokens/lists.rb +112 -0
- data/lib/ruwiki/wiki/tokens/rubylists.rb +48 -0
- data/ruwiki.conf +22 -0
- data/ruwiki.pkg +0 -0
- data/templates/default/body.tmpl +19 -0
- data/templates/default/content.tmpl +7 -0
- data/templates/default/controls.tmpl +23 -0
- data/templates/default/edit.tmpl +27 -0
- data/templates/default/error.tmpl +14 -0
- data/templates/default/footer.tmpl +23 -0
- data/templates/default/ruwiki.css +297 -0
- data/templates/default/save.tmpl +8 -0
- data/templates/sidebar/body.tmpl +19 -0
- data/templates/sidebar/content.tmpl +8 -0
- data/templates/sidebar/controls.tmpl +8 -0
- data/templates/sidebar/edit.tmpl +27 -0
- data/templates/sidebar/error.tmpl +13 -0
- data/templates/sidebar/footer.tmpl +22 -0
- data/templates/sidebar/ruwiki.css +347 -0
- data/templates/sidebar/save.tmpl +10 -0
- data/templates/simple/body.tmpl +13 -0
- data/templates/simple/content.tmpl +7 -0
- data/templates/simple/controls.tmpl +8 -0
- data/templates/simple/edit.tmpl +25 -0
- data/templates/simple/error.tmpl +10 -0
- data/templates/simple/footer.tmpl +10 -0
- data/templates/simple/ruwiki.css +192 -0
- data/templates/simple/save.tmpl +8 -0
- data/tests/harness.rb +52 -0
- data/tests/tc_backend_flatfile.rb +103 -0
- data/tests/tc_bugs.rb +74 -0
- data/tests/tc_exportable.rb +64 -0
- data/tests/tc_template.rb +145 -0
- data/tests/tc_tokens.rb +335 -0
- data/tests/testall.rb +20 -0
- metadata +182 -0
@@ -0,0 +1,295 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#--
|
3
|
+
# Ruwiki
|
4
|
+
# Copyright � 2002 - 2004, Digikata and HaloStatue
|
5
|
+
# Alan Chen (alan@digikata.com)
|
6
|
+
# Austin Ziegler (ruwiki@halostatue.ca)
|
7
|
+
#
|
8
|
+
# Licensed under the same terms as Ruby.
|
9
|
+
#
|
10
|
+
# This file may be renamed to change the URI for the wiki.
|
11
|
+
#
|
12
|
+
# $Id: servletrunner.rb,v 1.8 2004/11/26 12:18:47 austin Exp $
|
13
|
+
#++
|
14
|
+
|
15
|
+
# Customize this if you put the RuWiki files in a different location.
|
16
|
+
require 'webrick'
|
17
|
+
|
18
|
+
require 'ruwiki/utils'
|
19
|
+
require 'ruwiki/exportable'
|
20
|
+
require 'ruwiki/servlet'
|
21
|
+
require 'ruwiki/lang/en'
|
22
|
+
require 'ruwiki/lang/de'
|
23
|
+
require 'ruwiki/lang/es'
|
24
|
+
|
25
|
+
require 'optparse'
|
26
|
+
require 'ostruct'
|
27
|
+
|
28
|
+
module Ruwiki::Utils::ServletRunner
|
29
|
+
COPYRIGHT = <<-"COPYRIGHT"
|
30
|
+
Ruwiki #{Ruwiki::VERSION}
|
31
|
+
Copyright � 2002 - 2004, Digikata and HaloStatue
|
32
|
+
|
33
|
+
http://rubyforge.org/projects/ruwiki/
|
34
|
+
|
35
|
+
Alan Chen (alan@digikata.com)
|
36
|
+
Austin Ziegler (ruwiki@halostatue.ca)
|
37
|
+
|
38
|
+
Licensed under the same terms as Ruby.
|
39
|
+
|
40
|
+
$Id: servletrunner.rb,v 1.8 2004/11/26 12:18:47 austin Exp $
|
41
|
+
COPYRIGHT
|
42
|
+
|
43
|
+
class WEBrickConfig
|
44
|
+
include Ruwiki::Exportable
|
45
|
+
|
46
|
+
exportable_group 'webrick-config'
|
47
|
+
attr_accessor :port
|
48
|
+
exportable :port
|
49
|
+
attr_accessor :addresses
|
50
|
+
exportable :addresses
|
51
|
+
attr_accessor :mount
|
52
|
+
exportable :mount
|
53
|
+
attr_accessor :do_log
|
54
|
+
exportable :do_log
|
55
|
+
attr_accessor :log_dest
|
56
|
+
exportable :log_dest
|
57
|
+
attr_accessor :threads
|
58
|
+
exportable :threads
|
59
|
+
|
60
|
+
def export
|
61
|
+
hash = super
|
62
|
+
sc = hash['webrick-config']
|
63
|
+
sc['addresses'] = sc['addresses'].join(";")
|
64
|
+
sc['do-log'] = (sc['do-log'] ? 'true' : 'false')
|
65
|
+
hash
|
66
|
+
end
|
67
|
+
|
68
|
+
# Because the servlet can be started from the command-line, provide
|
69
|
+
# defaults for all possible configuration options.
|
70
|
+
def initialize(exported = {})
|
71
|
+
sc = exported['webrick-config'] || {}
|
72
|
+
@port = sc['port'] || 8808
|
73
|
+
@mount = sc['mount'] || '/'
|
74
|
+
@addresses = sc['addresses']
|
75
|
+
@do_log = ((sc['do-log'] == 'false') ? false : true)
|
76
|
+
@log_dest = sc['log-dest']
|
77
|
+
@threads = sc['threads'] || 1
|
78
|
+
|
79
|
+
if @addresses.nil? or @addresses.empty?
|
80
|
+
@addresses = []
|
81
|
+
else
|
82
|
+
@addresses = @addresses.split(/;/)
|
83
|
+
end
|
84
|
+
|
85
|
+
if @log_dest.nil? or @log_dest.empty?
|
86
|
+
@log_dest = "<STDERR>"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.message=(lang)
|
92
|
+
if lang.kind_of?(Hash)
|
93
|
+
@message = lang
|
94
|
+
elsif "constant" == defined?(lang::Message)
|
95
|
+
@message = lang::Message
|
96
|
+
else
|
97
|
+
raise ArgumentError
|
98
|
+
end
|
99
|
+
end
|
100
|
+
def self.message(id)
|
101
|
+
@message[id]
|
102
|
+
end
|
103
|
+
|
104
|
+
class << self
|
105
|
+
# This is for the WEBrick version of Ruwiki. This has been abstracted to
|
106
|
+
# accept a Config global variable to reconfigure Ruwiki after initial
|
107
|
+
# creation.
|
108
|
+
def read_config(filename)
|
109
|
+
ch = {}
|
110
|
+
if File.exists?(filename)
|
111
|
+
File.open(filename, 'rb') { |ff| ch = Ruwiki::Exportable.load(ff.read) }
|
112
|
+
end
|
113
|
+
|
114
|
+
@sc = WEBrickConfig.new(ch)
|
115
|
+
@rc = Ruwiki::Config.new(ch)
|
116
|
+
|
117
|
+
if @rc.webmaster.nil? or @rc.webmaster.empty?
|
118
|
+
@rc.webmaster = "webmaster@domain.tld"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def run(argv, input = $stdin, output = $stdout, error = $stderr)
|
123
|
+
read_config(Ruwiki::Config::CONFIG_NAME)
|
124
|
+
|
125
|
+
save_config = nil
|
126
|
+
|
127
|
+
language = 'en'
|
128
|
+
find_lang = argv.grep(%r{^--language})
|
129
|
+
find_lang.each do |ee|
|
130
|
+
if ee =~ %r{^--language=}
|
131
|
+
language = ee.sub(%r{^--language=}, '')
|
132
|
+
else
|
133
|
+
language = argv[argv.index(ee).succ]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
require "ruwiki/lang/#{language.downcase}"
|
138
|
+
@rc.language = Ruwiki::Lang.const_get(language.upcase)
|
139
|
+
self.message = @rc.language
|
140
|
+
|
141
|
+
argv.options do |oo|
|
142
|
+
oo.banner = self.message(:runner_usage) % [ File.basename($0) ]
|
143
|
+
oo.separator self.message(:runner_general_options)
|
144
|
+
oo.on('--save-config [FILENAME]', *([ self.message(:runner_saveconfig_desc), Ruwiki::Config::CONFIG_NAME ].flatten)) { |fname|
|
145
|
+
save_config = fname || Ruwiki::Config::CONFIG_NAME
|
146
|
+
}
|
147
|
+
oo.on('--config FILENAME', *self.message(:runner_config_desc)) { |fn|
|
148
|
+
read_config(fn)
|
149
|
+
}
|
150
|
+
oo.separator ""
|
151
|
+
oo.separator self.message(:runner_webrick_options)
|
152
|
+
oo.on('-P', '--port PORT', Numeric, *self.message(:runner_port_desc)) { |port|
|
153
|
+
@sc.port = port
|
154
|
+
}
|
155
|
+
oo.on('-A', '--accept ADDRESS,ADDRESS,ADDRESS', Array, *self.message(:runner_address_desc)) { |address|
|
156
|
+
@sc.addresses += address
|
157
|
+
}
|
158
|
+
oo.on('-L', '--local', *self.message(:runner_local_desc)) {
|
159
|
+
@sc.addresses = ["127.0.0.1"]
|
160
|
+
}
|
161
|
+
oo.on('-M', '--mount MOUNT-POINT', *self.message(:runner_mountpoint_desc)) { |mp|
|
162
|
+
@sc.mount = mp
|
163
|
+
}
|
164
|
+
oo.on('--[no-]log', *self.message(:runner_log_desc)) { |log|
|
165
|
+
@sc.do_log = log
|
166
|
+
}
|
167
|
+
oo.on('--logfile LOGFILE', *self.message(:runner_logfile_desc)) { |lf|
|
168
|
+
@sc.log_dest = lf
|
169
|
+
}
|
170
|
+
oo.on('-T', '--threads THREADS', Integer, *self.message(:runner_threads_desc)) { |tc|
|
171
|
+
@sc.threads = tc
|
172
|
+
}
|
173
|
+
oo.separator ""
|
174
|
+
oo.separator self.message(:runner_ruwiki_options)
|
175
|
+
oo.on('--language=LANGUAGE', *self.message(:runner_language_desc)) { |lang|
|
176
|
+
nil
|
177
|
+
}
|
178
|
+
oo.on('--webmaster WEBMASTER', *self.message(:runner_webmaster_desc)) { |wm|
|
179
|
+
@rc.webmaster = wm
|
180
|
+
}
|
181
|
+
oo.on('--[no-]debug', *self.message(:runner_debug_desc)) { |dd|
|
182
|
+
@rc.debug = dd
|
183
|
+
}
|
184
|
+
oo.on('--title TITLE', *self.message(:runner_title_desc)) { |tt|
|
185
|
+
@rc.title = tt
|
186
|
+
}
|
187
|
+
oo.on('--default-page PAGENAME', *self.message(:runner_defaultpage_desc)) { |dp|
|
188
|
+
@rc.default_page = dp
|
189
|
+
}
|
190
|
+
oo.on('--default-project PAGENAME', *self.message(:runner_defaultproject_desc)) { |dp|
|
191
|
+
@rc.default_project = dp
|
192
|
+
}
|
193
|
+
oo.on('--template-path TEMPLATE_PATH', *self.message(:runner_templatepath_desc)) { |tp|
|
194
|
+
@rc.template_path = tp
|
195
|
+
}
|
196
|
+
oo.on('--templates TEMPLATES', *self.message(:runner_templatename_desc)) { |tp|
|
197
|
+
@rc.template_set = tp
|
198
|
+
}
|
199
|
+
oo.on('--css CSS_NAME', *self.message(:runner_cssname_desc)) { |css|
|
200
|
+
@rc.css = css
|
201
|
+
}
|
202
|
+
oo.on('--storage-type TYPE', Ruwiki::KNOWN_BACKENDS, *([self.message(:runner_storage_desc), Ruwiki::KNOWN_BACKENDS.join(", ")].flatten)) { |st|
|
203
|
+
@rc.storage_type = st
|
204
|
+
@rc.storage_options[@rc.storage_type]['data-path'] ||= "./data/"
|
205
|
+
@rc.storage_options[@rc.storage_type]['extension'] ||= "ruwiki"
|
206
|
+
}
|
207
|
+
oo.on('--data-path PATH', *self.message(:runner_datapath_desc)) { |fdp|
|
208
|
+
@rc.storage_options['flatfiles']['data-path'] = fdp
|
209
|
+
}
|
210
|
+
oo.on('--extension EXT', *self.message(:runner_extension_desc)) { |ext|
|
211
|
+
@rc.storage_options['flatfiles']['data-path'] = fdp
|
212
|
+
}
|
213
|
+
if defined?(Gem::Cache)
|
214
|
+
oo.separator ""
|
215
|
+
oo.on('--central', *self.message(:runner_central_desc)) {
|
216
|
+
gempath = Gem::Cache.from_installed_gems.search("ruwiki", "=#{Ruwiki::VERSION}").last.full_gem_path
|
217
|
+
@rc.storage_type = 'flatfiles'
|
218
|
+
@rc.storage_options['flatfiles']['data-path'] = "#{gempath}/data"
|
219
|
+
@rc.storage_options['flatfiles']['extension'] = "ruwiki"
|
220
|
+
@rc.storage_options['flatfiles']['format'] = "exportable"
|
221
|
+
@rc.template_path = "#{gempath}/templates"
|
222
|
+
@rc.template_set = "sidebar"
|
223
|
+
}
|
224
|
+
end
|
225
|
+
|
226
|
+
# TODO: Add options for time, date, and datetime formats.
|
227
|
+
oo.separator ""
|
228
|
+
oo.separator self.message(:runner_general_info)
|
229
|
+
oo.on_tail('--help', *self.message(:runner_help_desc)) {
|
230
|
+
error << oo << "\n"
|
231
|
+
return 0
|
232
|
+
}
|
233
|
+
oo.on_tail('--version', *self.message(:runner_version_desc)) {
|
234
|
+
error << COPYRIGHT << "\n"
|
235
|
+
return 0
|
236
|
+
}
|
237
|
+
oo.parse!
|
238
|
+
end
|
239
|
+
|
240
|
+
if save_config
|
241
|
+
sc = @sc.export
|
242
|
+
rc = @rc.export
|
243
|
+
cf = sc.merge(rc)
|
244
|
+
|
245
|
+
File.open(save_config, 'wb') { |ff| ff.puts Ruwiki::Exportable.dump(cf) }
|
246
|
+
return 0
|
247
|
+
end
|
248
|
+
|
249
|
+
# If the list of accepted addresses is not empty, provide IP-based
|
250
|
+
# restrictions.
|
251
|
+
if not @sc.addresses.empty?
|
252
|
+
localonly = lambda do |sock|
|
253
|
+
if not @sc.addresses.include?(sock.peeraddr[3])
|
254
|
+
raise WEBrick::ServerError, self.message(:runner_rejected_address) % [ sock.peeraddr[3], @sc.addresses.join(", ") ]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
else
|
258
|
+
localonly = nil
|
259
|
+
end
|
260
|
+
|
261
|
+
if @sc.do_log
|
262
|
+
if "<STDERR>" == @sc.log_dest
|
263
|
+
dest = $stderr
|
264
|
+
else
|
265
|
+
dest = File.open(@sc.log_dest, "wb+")
|
266
|
+
end
|
267
|
+
logger = WEBrick::Log.new(dest, WEBrick::Log::DEBUG)
|
268
|
+
else
|
269
|
+
logger = nil
|
270
|
+
end
|
271
|
+
|
272
|
+
banner = self.message(:runner_banner) %
|
273
|
+
[ Ruwiki::Utils::ServletRunner::COPYRIGHT, @sc.port,
|
274
|
+
@sc.addresses.join(", "), @sc.mount, @sc.do_log, @sc.log_dest,
|
275
|
+
@sc.threads, @rc.webmaster, @rc.debug, @rc.title,
|
276
|
+
@rc.default_project, @rc.default_page, @rc.template_path,
|
277
|
+
@rc.template_set, @rc.css, @rc.storage_type,
|
278
|
+
@rc.storage_options[@rc.storage_type]['data-path'],
|
279
|
+
@rc.storage_options[@rc.storage_type]['extension'] ]
|
280
|
+
|
281
|
+
banner.each { |bb| logger.info(bb) } unless logger.nil?
|
282
|
+
|
283
|
+
server = WEBrick::HTTPServer.new(:Port => @sc.port.to_i,
|
284
|
+
:StartThreads => @sc.threads.to_i,
|
285
|
+
:AcceptCallback => localonly,
|
286
|
+
:Logger => logger)
|
287
|
+
@rc.logger = logger
|
288
|
+
Ruwiki::Servlet.config = @rc
|
289
|
+
|
290
|
+
server.mount(@sc.mount, Ruwiki::Servlet)
|
291
|
+
trap("INT") { server.shutdown; return }
|
292
|
+
server.start
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
data/lib/ruwiki/wiki.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
#--
|
2
|
+
# Ruwiki
|
3
|
+
# Copyright � 2002 - 2004, Digikata and HaloStatue
|
4
|
+
# Alan Chen (alan@digikata.com)
|
5
|
+
# Austin Ziegler (ruwiki@halostatue.ca)
|
6
|
+
#
|
7
|
+
# Licensed under the same terms as Ruby.
|
8
|
+
#
|
9
|
+
# $Id: wiki.rb,v 1.14 2004/11/28 05:27:32 austin Exp $
|
10
|
+
#++
|
11
|
+
# Ruwiki's Wiki markup class. This will convert the Wiki markup known by
|
12
|
+
# Ruwiki (defined by Token classes). The algorithm is as follows:
|
13
|
+
#
|
14
|
+
# 1. For each known Token class, match each instance of it in the content
|
15
|
+
# stream. Replace each instance in the content stream with a Token
|
16
|
+
# marker: TOKEN_x or \TOKEN_x, where x is a digit representing the Token.
|
17
|
+
# (\TOKEN_x is a special case of token matching. See
|
18
|
+
# Ruwiki::Markup::Token for more information.) Store the Token for later
|
19
|
+
# processing.
|
20
|
+
# 2. Go back through the content, replacing each instance of \TOKEN_x with
|
21
|
+
# the Token's defined restore value (which should be the same value as was
|
22
|
+
# originally matched).
|
23
|
+
# 3. Go through the content, replacing each instance of TOKEN_x with the
|
24
|
+
# Token's defined replacement value.
|
25
|
+
# 4. Go through the tokens, in reverse, and execute the post replacement
|
26
|
+
# routine defined by the Token. (This may be necessary to collapse
|
27
|
+
# consecutive HTML structures.)
|
28
|
+
# 5. Return the parsed content and the collected metadata.
|
29
|
+
#
|
30
|
+
# == Tokens
|
31
|
+
# Look at Ruwiki::Markup::Token describes how to create Token objects.
|
32
|
+
class Ruwiki::Wiki
|
33
|
+
def parse(content, project)
|
34
|
+
content = clean(content)
|
35
|
+
tokens = []
|
36
|
+
project ||= @default_project
|
37
|
+
|
38
|
+
Token.tokenlist.each do |token|
|
39
|
+
content.gsub!(token.regexp) do |mm|
|
40
|
+
match = Regexp.last_match
|
41
|
+
tc = token.new(match, project, @backend, @script, @message, @title)
|
42
|
+
tokens << tc
|
43
|
+
if mm[0, 1] == '\\'
|
44
|
+
"\\TOKEN_#{tokens.size - 1}"
|
45
|
+
else
|
46
|
+
"TOKEN_#{tokens.size - 1}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
replaced = []
|
52
|
+
ss = true
|
53
|
+
loop do
|
54
|
+
break if replaced.size >= tokens.size
|
55
|
+
break if ss.nil?
|
56
|
+
ss = content.gsub!(/\\TOKEN_(\d+)/) { |mm|
|
57
|
+
match = Regexp.last_match
|
58
|
+
itoken = match[1].to_i
|
59
|
+
replaced << itoken
|
60
|
+
tokens[itoken].restore
|
61
|
+
}
|
62
|
+
|
63
|
+
ss = content.gsub!(/TOKEN_(\d+)/) { |mm|
|
64
|
+
match = Regexp.last_match
|
65
|
+
itoken = match[1].to_i
|
66
|
+
replaced << itoken
|
67
|
+
tokens[itoken].replace
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
token_classes = tokens.map { |token| token.class }.sort_by { |token| token.rank }
|
72
|
+
token_classes.uniq.each { |tc| tc.post_replace(content) }
|
73
|
+
|
74
|
+
content
|
75
|
+
end
|
76
|
+
|
77
|
+
attr_accessor :default_project
|
78
|
+
attr_accessor :script
|
79
|
+
attr_accessor :backend
|
80
|
+
attr_accessor :message
|
81
|
+
|
82
|
+
# Creates the markup class.
|
83
|
+
def initialize(default_project, script, title)
|
84
|
+
@default_project = default_project
|
85
|
+
@script = script
|
86
|
+
@title = title
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
# Find HTML tags
|
91
|
+
SIMPLE_TAG_RE = %r{<[^<>]+?>} # Ensure that only the tag is grabbed.
|
92
|
+
HTML_TAG_RE = %r{\A< # Tag must be at start of match.
|
93
|
+
(/)? # Closing tag?
|
94
|
+
([\w:]+) # Tag name
|
95
|
+
(?:\s+ # Space
|
96
|
+
([^>]+) # Attributes
|
97
|
+
(/)? # Singleton tag?
|
98
|
+
)? # The above three are optional
|
99
|
+
>}x
|
100
|
+
ATTRIBUTES_RE = %r{([\w:]+)(=(?:\w+|"[^"]+?"|'[^']+?'))?}x
|
101
|
+
STYLE_NOVD_RE = %r{(?:\s?(visibility|display):[^'";]+;?)}x
|
102
|
+
ALLOWED_ATTR = %w(style title type lang dir class id cite datetime abbr) +
|
103
|
+
%w(colspan rowspan compact start media)
|
104
|
+
ALLOWED_HTML = %w(abbr acronym address b big blockquote br caption cite) +
|
105
|
+
%w(code col colgroup dd del dfn dir div dl dt em h1 h2 h3) +
|
106
|
+
%w(h4 h5 h6 hr i ins kbd li menu ol p pre q s samp small) +
|
107
|
+
%w(span strike strong style sub sup table tbody td tfoot) +
|
108
|
+
%w(th thead tr tt u ul var)
|
109
|
+
|
110
|
+
# Clean the content of unsupported HTML and attributes. This includes
|
111
|
+
# XML namespaced HTML. Sorry, but there's too much possibility for
|
112
|
+
# abuse.
|
113
|
+
def clean(content)
|
114
|
+
content = content.gsub(SIMPLE_TAG_RE) do |tag|
|
115
|
+
tagset = HTML_TAG_RE.match(tag)
|
116
|
+
|
117
|
+
if tagset.nil?
|
118
|
+
tag = Ruwiki.clean_entities(tag)
|
119
|
+
else
|
120
|
+
closer, name, attributes, single = tagset.captures
|
121
|
+
|
122
|
+
if ALLOWED_HTML.include?(name.downcase)
|
123
|
+
unless closer or attributes.nil?
|
124
|
+
attributes = attributes.scan(ATTRIBUTES_RE).map do |set|
|
125
|
+
if ALLOWED_ATTR.include?(set[0].downcase)
|
126
|
+
if set[0] == 'style'
|
127
|
+
set[1].gsub!(STYLE_NOVD_RE, '')
|
128
|
+
end
|
129
|
+
set.join
|
130
|
+
else
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
end.compact.join(" ")
|
134
|
+
tag = "<#{closer}#{name} #{attributes}#{single}>"
|
135
|
+
else
|
136
|
+
tag = "<#{closer}#{name}>"
|
137
|
+
end
|
138
|
+
else
|
139
|
+
tag = Ruwiki.clean_entities(tag)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
tag.gsub(%r{((?:href|src)=["'])(#{Ruwiki::Wiki::RE_URI_SCHEME})}) { "#{$1}\\#{$2}" }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
require 'ruwiki/wiki/tokens'
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#--
|
2
|
+
# Ruwiki
|
3
|
+
# Copyright � 2002 - 2004, Digikata and HaloStatue
|
4
|
+
# Alan Chen (alan@digikata.com)
|
5
|
+
# Austin Ziegler (ruwiki@halostatue.ca)
|
6
|
+
#
|
7
|
+
# Licensed under the same terms as Ruby.
|
8
|
+
#
|
9
|
+
# $Id: tokens.rb,v 1.8 2004/11/26 12:18:47 austin Exp $
|
10
|
+
#++
|
11
|
+
class Ruwiki
|
12
|
+
class Wiki
|
13
|
+
# The base Token class. All Token classes must inherit from Token and
|
14
|
+
# *must* implement the following methods:
|
15
|
+
#
|
16
|
+
# [self.regexp] The regular expression that the Token will be
|
17
|
+
# replacing.
|
18
|
+
# [replace] The mechanism for replacing the Token with the desired
|
19
|
+
# results.
|
20
|
+
#
|
21
|
+
# Token classes <i>should</i> implement the following method:
|
22
|
+
# [self.rank] Default: <tt>5000</tt>. Affects the sort order.
|
23
|
+
# Must return an integer.
|
24
|
+
#
|
25
|
+
# Token classes <i>may</i> implement the following methods:
|
26
|
+
# [restore] Restores the token without replacement.
|
27
|
+
# Implements the results of the escape character.
|
28
|
+
# NOTE: each Token class is responsible for its own
|
29
|
+
# restore. Tokens that are anchored to the
|
30
|
+
# beginning of a line are the most likely to need
|
31
|
+
# to reimplement this.
|
32
|
+
# [self.post_replace] Performs any necessary massaging of the data. See
|
33
|
+
# the implementation of Ruwiki::Wiki::Lists for
|
34
|
+
# more information.
|
35
|
+
class Token
|
36
|
+
@@tokenlist = []
|
37
|
+
@@sorted = false
|
38
|
+
|
39
|
+
class << self
|
40
|
+
# Tokens should define rank if they must be first or last in
|
41
|
+
# processing. Otherwise, they are sorted in the order defined.
|
42
|
+
def rank
|
43
|
+
5000
|
44
|
+
end
|
45
|
+
|
46
|
+
# The Wiki parsing routine uses Token.tokenlist to determine the
|
47
|
+
# tokens that are processed, and the order in which they are
|
48
|
+
# processed. See Token.rank for more information.
|
49
|
+
def tokenlist
|
50
|
+
unless @@sorted
|
51
|
+
head = @@tokenlist.shift
|
52
|
+
@@tokenlist.sort! { |aa, bb| aa.rank <=> bb.rank }
|
53
|
+
@@tokenlist.unshift(head)
|
54
|
+
sorted = true
|
55
|
+
end
|
56
|
+
@@tokenlist
|
57
|
+
end
|
58
|
+
|
59
|
+
def inherited(child_class) #:nodoc:
|
60
|
+
@@tokenlist << Token if @@tokenlist.empty?
|
61
|
+
|
62
|
+
# Make the child class post_replace a blank function because we
|
63
|
+
# don't want to propogate the currently defined post_replace.
|
64
|
+
# The current post_replace is specific to Token_Base only.
|
65
|
+
class << child_class
|
66
|
+
def self.post_replace(content)
|
67
|
+
content
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
@@tokenlist << child_class
|
72
|
+
@@sorted = false
|
73
|
+
end
|
74
|
+
|
75
|
+
# The replacement regular expression.
|
76
|
+
def regexp
|
77
|
+
/TOKEN_(\d*)/
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# All Token classes must match this header signature if they define
|
82
|
+
# #initialize.
|
83
|
+
#
|
84
|
+
# [match] The MatchData object for this Token.
|
85
|
+
# [project] The project being processed.
|
86
|
+
# [backend] The backend for the wiki. This is used to determine if
|
87
|
+
# the page or project exists. The object passed must
|
88
|
+
# respond to #project_exists?(project) and
|
89
|
+
# #page_exists?(page, project).
|
90
|
+
# [script] The URI to the script.
|
91
|
+
# [message] The message hash for localized messages.
|
92
|
+
# [title] The title of the Wiki.
|
93
|
+
def initialize(match, project, backend, script, message, title)
|
94
|
+
@match = match
|
95
|
+
@project = project
|
96
|
+
@backend = backend
|
97
|
+
@script = script
|
98
|
+
@message = message
|
99
|
+
@title = title
|
100
|
+
end
|
101
|
+
|
102
|
+
# The replacement method. Uses @match to replace the token with the
|
103
|
+
# appropriate values.
|
104
|
+
def replace
|
105
|
+
"TOKEN_#{@match[1]}"
|
106
|
+
end
|
107
|
+
|
108
|
+
# Restores the token without replacement. By default, replaces
|
109
|
+
# "dangerous" HTML characters.
|
110
|
+
def restore
|
111
|
+
Ruwiki.clean_entities(@match[0])
|
112
|
+
end
|
113
|
+
|
114
|
+
# The content may need massaging after processing.
|
115
|
+
def self.post_replace(content)
|
116
|
+
content
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Load the tokens from the ruwiki/wiki/tokens directory.
|
123
|
+
tokens_dir = 'ruwiki/wiki/tokens'
|
124
|
+
|
125
|
+
$LOAD_PATH.each do |path|
|
126
|
+
target = "#{path}/#{tokens_dir}"
|
127
|
+
if File.exists?(target) and File.directory?(target)
|
128
|
+
Dir::glob("#{target}/*.rb") do |token|
|
129
|
+
begin
|
130
|
+
require token
|
131
|
+
rescue LoadError
|
132
|
+
nil
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|