ruwiki 0.9.0

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.
Files changed (96) hide show
  1. data/Readme.rubygems +86 -0
  2. data/Readme.tarfile +65 -0
  3. data/bin/ruwiki +58 -0
  4. data/bin/ruwiki.cgi +87 -0
  5. data/bin/ruwiki_convert +56 -0
  6. data/bin/ruwiki_service.rb +82 -0
  7. data/bin/ruwiki_servlet +53 -0
  8. data/contrib/enscript-token.rb +55 -0
  9. data/contrib/rublog_integrator.rb +68 -0
  10. data/data/Default/ProjectIndex.ruwiki +49 -0
  11. data/data/Ruwiki/Antispam.ruwiki +65 -0
  12. data/data/Ruwiki/BugTracking.ruwiki +33 -0
  13. data/data/Ruwiki/ChangeLog.ruwiki +102 -0
  14. data/data/Ruwiki/Configuring_Ruwiki.ruwiki +151 -0
  15. data/data/Ruwiki/Extending_Ruwiki.ruwiki +317 -0
  16. data/data/Ruwiki/LicenseAndAuthorInfo.ruwiki +30 -0
  17. data/data/Ruwiki/ProjectIndex.ruwiki +84 -0
  18. data/data/Ruwiki/Roadmap.ruwiki +225 -0
  19. data/data/Ruwiki/RuwikiTemplatingLibrary.ruwiki +156 -0
  20. data/data/Ruwiki/RuwikiUtilities.ruwiki +157 -0
  21. data/data/Ruwiki/SandBox.ruwiki +9 -0
  22. data/data/Ruwiki/To_Do.ruwiki +51 -0
  23. data/data/Ruwiki/TroubleShooting.ruwiki +33 -0
  24. data/data/Ruwiki/WikiFeatures.ruwiki +17 -0
  25. data/data/Ruwiki/WikiMarkup.ruwiki +261 -0
  26. data/data/Tutorial/AddingPages.ruwiki +16 -0
  27. data/data/Tutorial/AddingProjects.ruwiki +16 -0
  28. data/data/Tutorial/ProjectIndex.ruwiki +11 -0
  29. data/data/Tutorial/SandBox.ruwiki +9 -0
  30. data/data/agents.banned +60 -0
  31. data/data/agents.readonly +321 -0
  32. data/data/hostip.banned +30 -0
  33. data/data/hostip.readonly +28 -0
  34. data/lib/ruwiki.rb +622 -0
  35. data/lib/ruwiki/auth.rb +56 -0
  36. data/lib/ruwiki/auth/gforge.rb +73 -0
  37. data/lib/ruwiki/backend.rb +318 -0
  38. data/lib/ruwiki/backend/flatfiles.rb +217 -0
  39. data/lib/ruwiki/config.rb +244 -0
  40. data/lib/ruwiki/exportable.rb +192 -0
  41. data/lib/ruwiki/handler.rb +342 -0
  42. data/lib/ruwiki/lang/de.rb +339 -0
  43. data/lib/ruwiki/lang/en.rb +334 -0
  44. data/lib/ruwiki/lang/es.rb +339 -0
  45. data/lib/ruwiki/page.rb +262 -0
  46. data/lib/ruwiki/servlet.rb +38 -0
  47. data/lib/ruwiki/template.rb +553 -0
  48. data/lib/ruwiki/utils.rb +24 -0
  49. data/lib/ruwiki/utils/command.rb +102 -0
  50. data/lib/ruwiki/utils/converter.rb +297 -0
  51. data/lib/ruwiki/utils/manager.rb +639 -0
  52. data/lib/ruwiki/utils/servletrunner.rb +295 -0
  53. data/lib/ruwiki/wiki.rb +147 -0
  54. data/lib/ruwiki/wiki/tokens.rb +136 -0
  55. data/lib/ruwiki/wiki/tokens/00default.rb +211 -0
  56. data/lib/ruwiki/wiki/tokens/01wikilinks.rb +166 -0
  57. data/lib/ruwiki/wiki/tokens/02actions.rb +63 -0
  58. data/lib/ruwiki/wiki/tokens/abbreviations.rb +40 -0
  59. data/lib/ruwiki/wiki/tokens/calendar.rb +147 -0
  60. data/lib/ruwiki/wiki/tokens/headings.rb +43 -0
  61. data/lib/ruwiki/wiki/tokens/lists.rb +112 -0
  62. data/lib/ruwiki/wiki/tokens/rubylists.rb +48 -0
  63. data/ruwiki.conf +22 -0
  64. data/ruwiki.pkg +0 -0
  65. data/templates/default/body.tmpl +19 -0
  66. data/templates/default/content.tmpl +7 -0
  67. data/templates/default/controls.tmpl +23 -0
  68. data/templates/default/edit.tmpl +27 -0
  69. data/templates/default/error.tmpl +14 -0
  70. data/templates/default/footer.tmpl +23 -0
  71. data/templates/default/ruwiki.css +297 -0
  72. data/templates/default/save.tmpl +8 -0
  73. data/templates/sidebar/body.tmpl +19 -0
  74. data/templates/sidebar/content.tmpl +8 -0
  75. data/templates/sidebar/controls.tmpl +8 -0
  76. data/templates/sidebar/edit.tmpl +27 -0
  77. data/templates/sidebar/error.tmpl +13 -0
  78. data/templates/sidebar/footer.tmpl +22 -0
  79. data/templates/sidebar/ruwiki.css +347 -0
  80. data/templates/sidebar/save.tmpl +10 -0
  81. data/templates/simple/body.tmpl +13 -0
  82. data/templates/simple/content.tmpl +7 -0
  83. data/templates/simple/controls.tmpl +8 -0
  84. data/templates/simple/edit.tmpl +25 -0
  85. data/templates/simple/error.tmpl +10 -0
  86. data/templates/simple/footer.tmpl +10 -0
  87. data/templates/simple/ruwiki.css +192 -0
  88. data/templates/simple/save.tmpl +8 -0
  89. data/tests/harness.rb +52 -0
  90. data/tests/tc_backend_flatfile.rb +103 -0
  91. data/tests/tc_bugs.rb +74 -0
  92. data/tests/tc_exportable.rb +64 -0
  93. data/tests/tc_template.rb +145 -0
  94. data/tests/tc_tokens.rb +335 -0
  95. data/tests/testall.rb +20 -0
  96. 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
@@ -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