require 'fileutils'
require 'rdoc/markup/to_html'
require 'webrick'
class WikiHtml < RDoc::Markup::ToHtml
def initialize
super
@markup.add_special(/\b(([A-Z][a-z]+){2,})\b/, :WIKIWORD)
end
def handle_special_WIKIWORD(special)
"#{special.text}"
end
end
class RDocWiki < WEBrick::HTTPServlet::AbstractServlet
TEMPLATE = "\n
\n%s\n\n\n%s\n"
REVISION = "%s\n\nMainPage"
DISPLAY = "#{REVISION} Edit %s\n"
def initialize(server, store)
super server
@store = File.expand_path store
@rcs = File.join @store, 'RCS'
@wiki_html = WikiHtml.new
FileUtils.mkdir_p @rcs
end
def add_history_links(body, page, peer, current, head = current)
body << " ←" if
current > 1
body << " Revision 1.#{current} by #{peer}"
if current != head then
body << <<-EOF
\n
EOF
end
if current + 1 == head then
body << " →"
elsif current != head
body << " →"
body << " ⇒"
end
end
def check_revision(page, revision)
revision =~ /\A1\.(\d+)\z/
current = $1.to_i
head, message = current_revision page, current
raise WEBrick::HTTPStatus::NotFound if current > head
raise WEBrick::HTTPStatus::TemporaryRedirect, "/#{page}" if current == head
return message, current, head
end
def current_revision(page, current = nil)
revision = current ? " -r1.#{current}" : ''
rlog = `rlog#{revision} #{File.join @store, page}`
return nil unless $?.success?
rlog =~ /^head: 1\.(\d+)$/
head = $1.to_i
rlog =~ /^date: .*\n(.*)/
message = $1
return head, message
end
def do_GET(request, response)
title = nil
body = nil
uri = request.request_uri
if uri.path == '/' then
response.set_redirect WEBrick::HTTPStatus::MovedPermanently, 'MainPage'
return
end
page = get_page uri
response['Content-Type'] = 'text/html'
case uri.query
when 'edit' then
title = "Editing #{page}"
content = get_content page, nil, false
body = <<-BODY
BODY
when /\Arevision/ then
message, current, head = check_revision page, request.query['revision']
title = "Revision #{current} of #{page}"
content = get_content page, current
body = REVISION % [content]
add_history_links body, page, message, current, head
when nil then
title = page
content = get_content page
if page == 'WikiCss' then
response['Content-Type'] = 'text/css'
response.body = content
return
elsif content then
body = DISPLAY % [content, page]
current, message = current_revision page
add_history_links body, page, message, current
else
response.set_redirect WEBrick::HTTPStatus::SeeOther, "/#{page}?edit"
return
end
else
raise WEBrick::HTTPStatus::NotFound
end
response.body = TEMPLATE % [title, body]
end
def do_POST(request, response)
uri = request.request_uri
page = get_page uri
peer = request.peeraddr[2]
case uri.query
when 'save' then
write_content page, request.query['content'], peer
when /\Arestore/ then
path = File.join @store, page
raise WEBrick::HTTPStatus::NotFound unless File.exist? path
_, current, head = check_revision page, request.query['revision']
system "co -q -p1.#{current} #{path} > #{path}"
system "ci -q -l -m#{peer} -t-#{peer} #{path}"
else
raise WEBrick::HTTPStatus::NotFound
end
response.set_redirect WEBrick::HTTPStatus::SeeOther, page
end
def get_content(page, current = nil, convert = true)
path = File.join @store, page
return nil unless File.exist? path
content = if current then
content = `co -q -p1.#{current} #{path}`
return nil unless $?.success?
content
else
File.read path
end
content = @wiki_html.convert content if convert and page != 'WikiCss'
content
end
def get_page(uri)
page = uri.path.sub '/', ''
raise WEBrick::HTTPStatus::NotFound, "#{uri.path} not found" unless
page =~ /\A([A-Z][a-z]+){2,}\z/
page
end
def write_content(page, content, peer)
path = File.join @store, page
File.open path, 'w' do |fp| fp.write content end
system "ci -q -l -m#{peer} -t-#{peer} #{path}"
end
end
server = WEBrick::HTTPServer.new :Port => 8000
server.mount '/', RDocWiki, '~/.rdocwiki'
trap 'INT' do server.shutdown end
server.start