Massive change of SVN properties to deal with EOL style problem

This commit is contained in:
Alexey Verkhovsky 2005-01-24 18:52:04 +00:00
parent b747b611b3
commit 3b6566577c
108 changed files with 12417 additions and 12417 deletions

View file

@ -1,71 +1,71 @@
require 'fileutils'
require 'application'
require 'instiki_errors'
class FileController < ApplicationController
layout 'default'
before_filter :check_allow_uploads
def file
check_path
if @params['file']
# form supplied
file_yard.upload_file(@file_name, @params['file'])
flash[:info] = "File '#{@file_name}' successfully uploaded"
@web.refresh_pages_with_references(@file_name)
return_to_last_remembered
elsif file_yard.has_file?(@file_name)
send_file(file_yard.file_path(@file_name))
else
logger.debug("File not found: #{file_yard.files_path}/#{@file_name}")
# go to the template, which is a file upload form
end
end
def cancel_upload
return_to_last_remembered
end
def pic
check_path
if @params['file']
# form supplied
file_yard.upload_file(@file_name, @params['file'])
flash[:info] = "Image '#{@file_name}' successfully uploaded"
@web.refresh_pages_with_references(@file_name)
return_to_last_remembered
elsif file_yard.has_file?(@file_name)
send_file(file_yard.file_path(@file_name))
else
logger.debug("Image not found: #{file_yard.files_path}/#{@file_name}")
render_action 'file'
end
end
protected
def check_allow_uploads
unless @web.allow_uploads
render_text 'File uploads are blocked by the webmaster', '403 Forbidden'
return false
end
end
private
def check_path
raise Instiki::ValidationError.new("Invalid path: no file name") unless @file_name
raise Instiki::ValidationError.new("Invalid path: no web name") unless @web_name
raise Instiki::ValidationError.new("Invalid path: unknown web name") unless @web
end
def file_yard
@wiki.file_yard(@web)
end
end
require 'fileutils'
require 'application'
require 'instiki_errors'
class FileController < ApplicationController
layout 'default'
before_filter :check_allow_uploads
def file
check_path
if @params['file']
# form supplied
file_yard.upload_file(@file_name, @params['file'])
flash[:info] = "File '#{@file_name}' successfully uploaded"
@web.refresh_pages_with_references(@file_name)
return_to_last_remembered
elsif file_yard.has_file?(@file_name)
send_file(file_yard.file_path(@file_name))
else
logger.debug("File not found: #{file_yard.files_path}/#{@file_name}")
# go to the template, which is a file upload form
end
end
def cancel_upload
return_to_last_remembered
end
def pic
check_path
if @params['file']
# form supplied
file_yard.upload_file(@file_name, @params['file'])
flash[:info] = "Image '#{@file_name}' successfully uploaded"
@web.refresh_pages_with_references(@file_name)
return_to_last_remembered
elsif file_yard.has_file?(@file_name)
send_file(file_yard.file_path(@file_name))
else
logger.debug("Image not found: #{file_yard.files_path}/#{@file_name}")
render_action 'file'
end
end
protected
def check_allow_uploads
unless @web.allow_uploads
render_text 'File uploads are blocked by the webmaster', '403 Forbidden'
return false
end
end
private
def check_path
raise Instiki::ValidationError.new("Invalid path: no file name") unless @file_name
raise Instiki::ValidationError.new("Invalid path: no web name") unless @web_name
raise Instiki::ValidationError.new("Invalid path: unknown web name") unless @web
end
def file_yard
@wiki.file_yard(@web)
end
end

766
app/controllers/wiki_controller.rb Executable file → Normal file
View file

@ -1,383 +1,383 @@
require 'application'
require 'fileutils'
require 'redcloth_for_tex'
class WikiController < ApplicationController
layout 'default', :except => [:rss_feed, :rss_with_headlines, :tex, :export_tex, :export_html]
def index
if @web_name
redirect_show 'HomePage'
elsif not @wiki.setup?
redirect_to :action => 'new_system'
elsif @wiki.webs.length == 1
redirect_show 'HomePage', @wiki.webs.values.first.address
else
redirect_to :action => 'web_list'
end
end
# Administrating the Instiki setup --------------------------------------------
def create_system
@wiki.setup(@params['password'], @params['web_name'], @params['web_address']) unless @wiki.setup?
redirect_show('HomePage', @params['web_address'])
end
def create_web
if @wiki.authenticate(@params['system_password'])
@wiki.create_web(@params['name'], @params['address'])
redirect_show('HomePage', @params['address'])
else
redirect_to :action => 'index'
end
end
def edit_web
# to template
end
def new_system
redirect_to(:action => 'index') if wiki.setup?
# otherwise, to template
end
def new_web
redirect_to :action => 'index' if wiki.system['password'].nil?
# otherwise, to template
end
# Outside a single web --------------------------------------------------------
def authenticate
if password_check(@params['password'])
redirect_show('HomePage')
else
redirect_to :action => 'login'
end
end
def login
# to template
end
def web_list
@webs = wiki.webs.values.sort_by { |web| web.name }
end
# Within a single web ---------------------------------------------------------
def authors
@authors = @web.select.authors
end
def export_html
export_pages_as_zip('html') { |page| @page = page; render_to_string 'wiki/print' }
end
def export_markup
export_pages_as_zip(@web.markup) { |page| page.content }
end
def export_pdf
file_name = "#{@web.address}-tex-#{@web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')}"
file_path = @wiki.storage_path + file_name
export_web_to_tex "#{file_path}.tex" unless FileTest.exists? "#{file_path}.tex"
convert_tex_to_pdf "#{file_path}.tex"
send_file "#{file_path}.pdf"
end
def export_tex
file_name = "#{@web.address}-tex-#{@web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')}.tex"
file_path = @wiki.storage_path + file_name
export_web_to_tex(file_path) unless FileTest.exists?(file_path)
send_file file_path
end
def feeds
# to template
end
def list
parse_category
@pages_by_name = @pages_in_category.by_name
@page_names_that_are_wanted = @pages_in_category.wanted_pages
@pages_that_are_orphaned = @pages_in_category.orphaned_pages
end
def recently_revised
parse_category
@pages_by_revision = @pages_in_category.by_revision
end
def remove_orphaned_pages
if wiki.authenticate(@params['system_password'])
wiki.remove_orphaned_pages(@web_name)
redirect_to :action => 'list'
else
redirect_show 'HomePage'
end
end
def rss_with_content
render_rss
end
def rss_with_headlines
render_rss(hide_description = true)
end
def search
@query = @params['query']
@results = @web.select { |page| page.content =~ /#{@query}/i }.sort
redirect_show(@results.first.name) if @results.length == 1
end
def update_web
if wiki.authenticate(@params['system_password'])
wiki.update_web(
@web.address, @params['address'], @params['name'],
@params['markup'].intern,
@params['color'], @params['additional_style'],
@params['safe_mode'] ? true : false,
@params['password'].empty? ? nil : @params['password'],
@params['published'] ? true : false,
@params['brackets_only'] ? true : false,
@params['count_pages'] ? true : false,
@params['allow_uploads'] ? true : false
)
redirect_show('HomePage', @params['address'])
else
redirect_show('HomePage')
end
end
# Within a single page --------------------------------------------------------
def cancel_edit
@page.unlock
redirect_show
end
def edit
if @page.nil?
redirect_to :action => 'index'
elsif @page.locked?(Time.now) and not @params['break_lock']
redirect_to :web => @web_name, :action => 'locked', :id => @page_name
else
@page.lock(Time.now, @author)
end
end
def locked
# to template
end
def new
# to template
end
def pdf
page = wiki.read_page(@web_name, @page_name)
safe_page_name = @page.name.gsub(/\W/, '')
file_name = "#{safe_page_name}-#{@web.address}-#{@page.created_at.strftime('%Y-%m-%d-%H-%M-%S')}"
file_path = @wiki.storage_path + file_name
export_page_to_tex("#{file_path}.tex") unless FileTest.exists?("#{file_path}.tex")
# NB: this is _very_ slow
convert_tex_to_pdf("#{file_path}.tex")
send_file "#{file_path}.pdf"
end
def print
# to template
end
def published
if @web.published
@page = wiki.read_page(@web_name, @page_name || 'HomePage')
else
redirect_show('HomePage')
end
end
def revision
get_page_and_revision
end
def rollback
get_page_and_revision
end
def save
redirect_to :action => 'index' if @page_name.nil?
cookies['author'] = @params['author']
begin
page = @web.pages[@page_name]
if @web.pages[@page_name]
wiki.revise_page(
@web_name, @page_name, @params['content'], Time.now,
Author.new(@params['author'], remote_ip)
)
page.unlock
else
wiki.write_page(
@web_name, @page_name, @params['content'], Time.now,
Author.new(@params['author'], remote_ip)
)
end
redirect_show(@page_name)
rescue Instiki::ValidationError => e
page.unlock if defined? page
flash[:error] = e
return_to_last_remembered
end
end
def show
if @page
begin
render_action 'page'
# TODO this rescue should differentiate between errors due to rendering and errors in
# the application itself (for application errors, it's better not to rescue the error at all)
rescue => e
logger.error e
if in_a_web?
redirect_to :web => @web_name, :action => 'edit',
:action_suffix => "#{CGI.escape(@page_name)}?msg=#{CGI.escape(e.message)}"
else
raise e
end
end
else
redirect_to :web => @web_name, :action => 'new', :id => CGI.escape(@page_name)
end
end
def tex
@tex_content = RedClothForTex.new(@page.content).to_tex
end
private
def convert_tex_to_pdf(tex_path)
# TODO remove earlier PDF files with the same prefix
# TODO handle gracefully situation where pdflatex is not available
logger.info `pdflatex --interaction=nonstopmode --output-directory #{File.dirname(tex_path)} #{File.basename(tex_path)}`
end
def export_page_to_tex(file_path)
tex
File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex')) }
end
def export_pages_as_zip(file_type, &block)
file_prefix = "#{@web.address}-#{file_type}-"
timestamp = @web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')
file_path = @wiki.storage_path + file_prefix + timestamp + '.zip'
tmp_path = "#{file_path}.tmp"
Zip::ZipOutputStream.open(tmp_path) do |zip_out|
@web.select.by_name.each do |page|
zip_out.put_next_entry("#{page.name}.#{file_type}")
zip_out.puts(block.call(page))
end
# add an index file, if exporting to HTML
if file_type.to_s.downcase == 'html'
zip_out.put_next_entry 'index.html'
zip_out.puts <<-EOL
<html>
<head>
<META HTTP-EQUIV="Refresh" CONTENT="0;URL=HomePage.#{file_type}">
</head>
</html>
EOL
end
end
FileUtils.rm_rf(Dir[@wiki.storage_path + file_prefix + '*.zip'])
FileUtils.mv(tmp_path, file_path)
send_file file_path
end
def export_web_to_tex(file_path)
@tex_content = table_of_contents(@web.pages['HomePage'].content.dup, render_tex_web)
File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex_web')) }
end
def get_page_and_revision
@revision = @page.revisions[@params['rev'].to_i]
end
def parse_category
@categories = @web.categories
@category = @params['category']
if @categories.include?(@category)
@pages_in_category = @web.select { |page| page.in_category?(@category) }
@set_name = "category '#{@category}'"
else
@pages_in_category = PageSet.new(@web).by_name
@set_name = 'the web'
end
@category_links = @categories.map { |c|
if @category == c
%{<span class="selected">#{c}</span>}
else
%{<a href="?category=#{c}">#{c}</a>}
end
}
end
def password_check(password)
if password == @web.password
cookies['web_address'] = password
true
else
false
end
end
def redirect_show(page_name = @page_name, web = @web_name)
redirect_to :web => web, :action => 'show', :id => CGI.escape(page_name)
end
def remote_ip
ip = @request.remote_ip
logger.info(ip)
ip
end
def render_rss(hide_description = false)
@pages_by_revision = @web.select.by_revision.first(15)
@hide_description = hide_description
@response.headers['Content-Type'] = 'text/xml'
render 'wiki/rss_feed'
end
def render_tex_web
@web.select.by_name.inject({}) do |tex_web, page|
tex_web[page.name] = RedClothForTex.new(page.content).to_tex
tex_web
end
end
def render_to_string(template_name)
add_variables_to_assigns
render template_name
@performed_render = false
@template.render_file(template_name)
end
def truncate(text, length = 30, truncate_string = '...')
if text.length > length then text[0..(length - 3)] + truncate_string else text end
end
end
require 'application'
require 'fileutils'
require 'redcloth_for_tex'
class WikiController < ApplicationController
layout 'default', :except => [:rss_feed, :rss_with_headlines, :tex, :export_tex, :export_html]
def index
if @web_name
redirect_show 'HomePage'
elsif not @wiki.setup?
redirect_to :action => 'new_system'
elsif @wiki.webs.length == 1
redirect_show 'HomePage', @wiki.webs.values.first.address
else
redirect_to :action => 'web_list'
end
end
# Administrating the Instiki setup --------------------------------------------
def create_system
@wiki.setup(@params['password'], @params['web_name'], @params['web_address']) unless @wiki.setup?
redirect_show('HomePage', @params['web_address'])
end
def create_web
if @wiki.authenticate(@params['system_password'])
@wiki.create_web(@params['name'], @params['address'])
redirect_show('HomePage', @params['address'])
else
redirect_to :action => 'index'
end
end
def edit_web
# to template
end
def new_system
redirect_to(:action => 'index') if wiki.setup?
# otherwise, to template
end
def new_web
redirect_to :action => 'index' if wiki.system['password'].nil?
# otherwise, to template
end
# Outside a single web --------------------------------------------------------
def authenticate
if password_check(@params['password'])
redirect_show('HomePage')
else
redirect_to :action => 'login'
end
end
def login
# to template
end
def web_list
@webs = wiki.webs.values.sort_by { |web| web.name }
end
# Within a single web ---------------------------------------------------------
def authors
@authors = @web.select.authors
end
def export_html
export_pages_as_zip('html') { |page| @page = page; render_to_string 'wiki/print' }
end
def export_markup
export_pages_as_zip(@web.markup) { |page| page.content }
end
def export_pdf
file_name = "#{@web.address}-tex-#{@web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')}"
file_path = @wiki.storage_path + file_name
export_web_to_tex "#{file_path}.tex" unless FileTest.exists? "#{file_path}.tex"
convert_tex_to_pdf "#{file_path}.tex"
send_file "#{file_path}.pdf"
end
def export_tex
file_name = "#{@web.address}-tex-#{@web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')}.tex"
file_path = @wiki.storage_path + file_name
export_web_to_tex(file_path) unless FileTest.exists?(file_path)
send_file file_path
end
def feeds
# to template
end
def list
parse_category
@pages_by_name = @pages_in_category.by_name
@page_names_that_are_wanted = @pages_in_category.wanted_pages
@pages_that_are_orphaned = @pages_in_category.orphaned_pages
end
def recently_revised
parse_category
@pages_by_revision = @pages_in_category.by_revision
end
def remove_orphaned_pages
if wiki.authenticate(@params['system_password'])
wiki.remove_orphaned_pages(@web_name)
redirect_to :action => 'list'
else
redirect_show 'HomePage'
end
end
def rss_with_content
render_rss
end
def rss_with_headlines
render_rss(hide_description = true)
end
def search
@query = @params['query']
@results = @web.select { |page| page.content =~ /#{@query}/i }.sort
redirect_show(@results.first.name) if @results.length == 1
end
def update_web
if wiki.authenticate(@params['system_password'])
wiki.update_web(
@web.address, @params['address'], @params['name'],
@params['markup'].intern,
@params['color'], @params['additional_style'],
@params['safe_mode'] ? true : false,
@params['password'].empty? ? nil : @params['password'],
@params['published'] ? true : false,
@params['brackets_only'] ? true : false,
@params['count_pages'] ? true : false,
@params['allow_uploads'] ? true : false
)
redirect_show('HomePage', @params['address'])
else
redirect_show('HomePage')
end
end
# Within a single page --------------------------------------------------------
def cancel_edit
@page.unlock
redirect_show
end
def edit
if @page.nil?
redirect_to :action => 'index'
elsif @page.locked?(Time.now) and not @params['break_lock']
redirect_to :web => @web_name, :action => 'locked', :id => @page_name
else
@page.lock(Time.now, @author)
end
end
def locked
# to template
end
def new
# to template
end
def pdf
page = wiki.read_page(@web_name, @page_name)
safe_page_name = @page.name.gsub(/\W/, '')
file_name = "#{safe_page_name}-#{@web.address}-#{@page.created_at.strftime('%Y-%m-%d-%H-%M-%S')}"
file_path = @wiki.storage_path + file_name
export_page_to_tex("#{file_path}.tex") unless FileTest.exists?("#{file_path}.tex")
# NB: this is _very_ slow
convert_tex_to_pdf("#{file_path}.tex")
send_file "#{file_path}.pdf"
end
def print
# to template
end
def published
if @web.published
@page = wiki.read_page(@web_name, @page_name || 'HomePage')
else
redirect_show('HomePage')
end
end
def revision
get_page_and_revision
end
def rollback
get_page_and_revision
end
def save
redirect_to :action => 'index' if @page_name.nil?
cookies['author'] = @params['author']
begin
page = @web.pages[@page_name]
if @web.pages[@page_name]
wiki.revise_page(
@web_name, @page_name, @params['content'], Time.now,
Author.new(@params['author'], remote_ip)
)
page.unlock
else
wiki.write_page(
@web_name, @page_name, @params['content'], Time.now,
Author.new(@params['author'], remote_ip)
)
end
redirect_show(@page_name)
rescue Instiki::ValidationError => e
page.unlock if defined? page
flash[:error] = e
return_to_last_remembered
end
end
def show
if @page
begin
render_action 'page'
# TODO this rescue should differentiate between errors due to rendering and errors in
# the application itself (for application errors, it's better not to rescue the error at all)
rescue => e
logger.error e
if in_a_web?
redirect_to :web => @web_name, :action => 'edit',
:action_suffix => "#{CGI.escape(@page_name)}?msg=#{CGI.escape(e.message)}"
else
raise e
end
end
else
redirect_to :web => @web_name, :action => 'new', :id => CGI.escape(@page_name)
end
end
def tex
@tex_content = RedClothForTex.new(@page.content).to_tex
end
private
def convert_tex_to_pdf(tex_path)
# TODO remove earlier PDF files with the same prefix
# TODO handle gracefully situation where pdflatex is not available
logger.info `pdflatex --interaction=nonstopmode --output-directory #{File.dirname(tex_path)} #{File.basename(tex_path)}`
end
def export_page_to_tex(file_path)
tex
File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex')) }
end
def export_pages_as_zip(file_type, &block)
file_prefix = "#{@web.address}-#{file_type}-"
timestamp = @web.revised_on.strftime('%Y-%m-%d-%H-%M-%S')
file_path = @wiki.storage_path + file_prefix + timestamp + '.zip'
tmp_path = "#{file_path}.tmp"
Zip::ZipOutputStream.open(tmp_path) do |zip_out|
@web.select.by_name.each do |page|
zip_out.put_next_entry("#{page.name}.#{file_type}")
zip_out.puts(block.call(page))
end
# add an index file, if exporting to HTML
if file_type.to_s.downcase == 'html'
zip_out.put_next_entry 'index.html'
zip_out.puts <<-EOL
<html>
<head>
<META HTTP-EQUIV="Refresh" CONTENT="0;URL=HomePage.#{file_type}">
</head>
</html>
EOL
end
end
FileUtils.rm_rf(Dir[@wiki.storage_path + file_prefix + '*.zip'])
FileUtils.mv(tmp_path, file_path)
send_file file_path
end
def export_web_to_tex(file_path)
@tex_content = table_of_contents(@web.pages['HomePage'].content.dup, render_tex_web)
File.open(file_path, 'w') { |f| f.write(render_to_string('wiki/tex_web')) }
end
def get_page_and_revision
@revision = @page.revisions[@params['rev'].to_i]
end
def parse_category
@categories = @web.categories
@category = @params['category']
if @categories.include?(@category)
@pages_in_category = @web.select { |page| page.in_category?(@category) }
@set_name = "category '#{@category}'"
else
@pages_in_category = PageSet.new(@web).by_name
@set_name = 'the web'
end
@category_links = @categories.map { |c|
if @category == c
%{<span class="selected">#{c}</span>}
else
%{<a href="?category=#{c}">#{c}</a>}
end
}
end
def password_check(password)
if password == @web.password
cookies['web_address'] = password
true
else
false
end
end
def redirect_show(page_name = @page_name, web = @web_name)
redirect_to :web => web, :action => 'show', :id => CGI.escape(page_name)
end
def remote_ip
ip = @request.remote_ip
logger.info(ip)
ip
end
def render_rss(hide_description = false)
@pages_by_revision = @web.select.by_revision.first(15)
@hide_description = hide_description
@response.headers['Content-Type'] = 'text/xml'
render 'wiki/rss_feed'
end
def render_tex_web
@web.select.by_name.inject({}) do |tex_web, page|
tex_web[page.name] = RedClothForTex.new(page.content).to_tex
tex_web
end
end
def render_to_string(template_name)
add_variables_to_assigns
render template_name
@performed_render = false
@template.render_file(template_name)
end
def truncate(text, length = 30, truncate_string = '...')
if text.length > length then text[0..(length - 3)] + truncate_string else text end
end
end

6
app/models/author.rb Executable file → Normal file
View file

@ -1,4 +1,4 @@
class Author < String
attr_accessor :ip
def initialize(name, ip) @ip = ip; super(name) end
class Author < String
attr_accessor :ip
def initialize(name, ip) @ip = ip; super(name) end
end

70
app/models/chunks/category.rb Executable file → Normal file
View file

@ -1,35 +1,35 @@
require 'chunks/chunk'
# The category chunk looks for "category: news" on a line by
# itself and parses the terms after the ':' as categories.
# Other classes can search for Category chunks within
# rendered content to find out what categories this page
# should be in.
#
# Category lines can be hidden using ':category: news', for example
class Category < Chunk::Abstract
def self.pattern() return /^(:)?category\s*:(.*)$/i end
attr_reader :hidden, :list
def initialize(match_data)
super(match_data)
@hidden = match_data[1]
@list = match_data[2].split(',').map { |c| c.strip }
end
# If the chunk is hidden, erase the mask and return this chunk
# otherwise, surround it with a 'div' block.
def unmask(content)
return '' if hidden
category_urls = @list.map{|category| url(category) }.join(', ')
replacement = '<div class="property"> category: ' + category_urls + '</div>'
self if content.sub!(mask(content), replacement)
end
# TODO move presentation of page metadata to controller/view
def url(category)
%{<a class="category_link" href="../list/?category=#{category}">#{category}</a>}
end
end
require 'chunks/chunk'
# The category chunk looks for "category: news" on a line by
# itself and parses the terms after the ':' as categories.
# Other classes can search for Category chunks within
# rendered content to find out what categories this page
# should be in.
#
# Category lines can be hidden using ':category: news', for example
class Category < Chunk::Abstract
def self.pattern() return /^(:)?category\s*:(.*)$/i end
attr_reader :hidden, :list
def initialize(match_data)
super(match_data)
@hidden = match_data[1]
@list = match_data[2].split(',').map { |c| c.strip }
end
# If the chunk is hidden, erase the mask and return this chunk
# otherwise, surround it with a 'div' block.
def unmask(content)
return '' if hidden
category_urls = @list.map{|category| url(category) }.join(', ')
replacement = '<div class="property"> category: ' + category_urls + '</div>'
self if content.sub!(mask(content), replacement)
end
# TODO move presentation of page metadata to controller/view
def url(category)
%{<a class="category_link" href="../list/?category=#{category}">#{category}</a>}
end
end

80
app/models/chunks/chunk.rb Executable file → Normal file
View file

@ -1,40 +1,40 @@
require 'digest/md5'
require 'uri/common'
# A chunk is a pattern of text that can be protected
# and interrogated by a renderer. Each Chunk class has a
# +pattern+ that states what sort of text it matches.
# Chunks are initalized by passing in the result of a
# match by its pattern.
module Chunk
class Abstract
attr_reader :text
def initialize(match_data) @text = match_data[0] end
# Find all the chunks of the given type in content
# Each time the pattern is matched, create a new
# chunk for it, and replace the occurance of the chunk
# in this content with its mask.
def self.apply_to(content)
content.gsub!( self.pattern ) do |match|
new_chunk = self.new($~)
content.chunks << new_chunk
new_chunk.mask(content)
end
end
def mask(content)
"chunk#{self.object_id}#{self.class.to_s.delete(':').downcase}chunk"
end
def revert(content)
content.sub!( Regexp.new(mask(content)), text )
end
def unmask(content)
self if revert(content)
end
end
end
require 'digest/md5'
require 'uri/common'
# A chunk is a pattern of text that can be protected
# and interrogated by a renderer. Each Chunk class has a
# +pattern+ that states what sort of text it matches.
# Chunks are initalized by passing in the result of a
# match by its pattern.
module Chunk
class Abstract
attr_reader :text
def initialize(match_data) @text = match_data[0] end
# Find all the chunks of the given type in content
# Each time the pattern is matched, create a new
# chunk for it, and replace the occurance of the chunk
# in this content with its mask.
def self.apply_to(content)
content.gsub!( self.pattern ) do |match|
new_chunk = self.new($~)
content.chunks << new_chunk
new_chunk.mask(content)
end
end
def mask(content)
"chunk#{self.object_id}#{self.class.to_s.delete(':').downcase}chunk"
end
def revert(content)
content.sub!( Regexp.new(mask(content)), text )
end
def unmask(content)
self if revert(content)
end
end
end

76
app/models/chunks/engines.rb Executable file → Normal file
View file

@ -1,38 +1,38 @@
$: << File.dirname(__FILE__) + "../../libraries"
require 'redcloth'
require 'bluecloth'
require 'rdocsupport'
require 'chunks/chunk'
# The markup engines are Chunks that call the one of RedCloth, BlueCloth
# or RDoc to convert text. This markup occurs when the chunk is required
# to mask itself.
module Engines
class Textile < Chunk::Abstract
def self.pattern() /^(.*)$/m end
def mask(content)
RedCloth.new(text,content.options[:engine_opts]).to_html
end
def unmask(content) self end
end
class Markdown < Chunk::Abstract
def self.pattern() /^(.*)$/m end
def mask(content)
BlueCloth.new(text,content.options[:engine_opts]).to_html
end
def unmask(content) self end
end
class RDoc < Chunk::Abstract
def self.pattern() /^(.*)$/m end
def mask(content)
RDocSupport::RDocFormatter.new(text).to_html
end
def unmask(content) self end
end
MAP = { :textile => Textile, :markdown => Markdown, :rdoc => RDoc }
end
$: << File.dirname(__FILE__) + "../../libraries"
require 'redcloth'
require 'bluecloth'
require 'rdocsupport'
require 'chunks/chunk'
# The markup engines are Chunks that call the one of RedCloth, BlueCloth
# or RDoc to convert text. This markup occurs when the chunk is required
# to mask itself.
module Engines
class Textile < Chunk::Abstract
def self.pattern() /^(.*)$/m end
def mask(content)
RedCloth.new(text,content.options[:engine_opts]).to_html
end
def unmask(content) self end
end
class Markdown < Chunk::Abstract
def self.pattern() /^(.*)$/m end
def mask(content)
BlueCloth.new(text,content.options[:engine_opts]).to_html
end
def unmask(content) self end
end
class RDoc < Chunk::Abstract
def self.pattern() /^(.*)$/m end
def mask(content)
RDocSupport::RDocFormatter.new(text).to_html
end
def unmask(content) self end
end
MAP = { :textile => Textile, :markdown => Markdown, :rdoc => RDoc }
end

58
app/models/chunks/include.rb Executable file → Normal file
View file

@ -1,29 +1,29 @@
require 'chunks/wiki'
# Includes the contents of another page for rendering.
# The include command looks like this: "[[!include PageName]]".
# It is a WikiLink since it refers to another page (PageName)
# and the wiki content using this command must be notified
# of changes to that page.
# If the included page could not be found, a warning is displayed.
class Include < WikiChunk::WikiLink
def self.pattern() /^\[\[!include(.*)\]\]\s*$/i end
attr_reader :page_name
def initialize(match_data)
super(match_data)
@page_name = match_data[1].strip
end
# This replaces the [[!include PageName]] text with
# the contents of PageName if it exists. Otherwise
# a warning is displayed.
def mask(content)
page = content.web.pages[page_name]
(page ? page.content : "<em>Could not include #{page_name}</em>")
end
# Keep this chunk regardless of what happens.
def unmask(content) self end
end
require 'chunks/wiki'
# Includes the contents of another page for rendering.
# The include command looks like this: "[[!include PageName]]".
# It is a WikiLink since it refers to another page (PageName)
# and the wiki content using this command must be notified
# of changes to that page.
# If the included page could not be found, a warning is displayed.
class Include < WikiChunk::WikiLink
def self.pattern() /^\[\[!include(.*)\]\]\s*$/i end
attr_reader :page_name
def initialize(match_data)
super(match_data)
@page_name = match_data[1].strip
end
# This replaces the [[!include PageName]] text with
# the contents of PageName if it exists. Otherwise
# a warning is displayed.
def mask(content)
page = content.web.pages[page_name]
(page ? page.content : "<em>Could not include #{page_name}</em>")
end
# Keep this chunk regardless of what happens.
def unmask(content) self end
end

38
app/models/chunks/literal.rb Executable file → Normal file
View file

@ -1,19 +1,19 @@
require 'chunks/chunk'
# These are basic chunks that have a pattern and can be protected.
# They are used by rendering process to prevent wiki rendering
# occuring within literal areas such as <code> and <pre> blocks
# and within HTML tags.
module Literal
# A literal chunk that protects 'code' and 'pre' tags from wiki rendering.
class Pre < Chunk::Abstract
PRE_BLOCKS = "a|pre|code"
def self.pattern() Regexp.new('<('+PRE_BLOCKS+')\b[^>]*?>.*?</\1>', Regexp::MULTILINE) end
end
# A literal chunk that protects HTML tags from wiki rendering.
class Tags < Chunk::Abstract
TAGS = "a|img|em|strong|div|span|table|td|th|ul|ol|li|dl|dt|dd"
def self.pattern() Regexp.new('<(?:'+TAGS+')[^>]*?>', Regexp::MULTILINE) end
end
end
require 'chunks/chunk'
# These are basic chunks that have a pattern and can be protected.
# They are used by rendering process to prevent wiki rendering
# occuring within literal areas such as <code> and <pre> blocks
# and within HTML tags.
module Literal
# A literal chunk that protects 'code' and 'pre' tags from wiki rendering.
class Pre < Chunk::Abstract
PRE_BLOCKS = "a|pre|code"
def self.pattern() Regexp.new('<('+PRE_BLOCKS+')\b[^>]*?>.*?</\1>', Regexp::MULTILINE) end
end
# A literal chunk that protects HTML tags from wiki rendering.
class Tags < Chunk::Abstract
TAGS = "a|img|em|strong|div|span|table|td|th|ul|ol|li|dl|dt|dd"
def self.pattern() Regexp.new('<(?:'+TAGS+')[^>]*?>', Regexp::MULTILINE) end
end
end

62
app/models/chunks/nowiki.rb Executable file → Normal file
View file

@ -1,31 +1,31 @@
require 'chunks/chunk'
# This chunks allows certain parts of a wiki page to be hidden from the
# rest of the rendering pipeline. It should be run at the beginning
# of the pipeline in `wiki_content.rb`.
#
# An example use of this chunk is to markup double brackets or
# auto URI links:
# <nowiki>Here are [[double brackets]] and a URI: www.uri.org</nowiki>
#
# The contents of the chunks will not be processed by any other chunk
# so the `www.uri.org` and the double brackets will appear verbatim.
#
# Author: Mark Reid <mark at threewordslong dot com>
# Created: 8th June 2004
class NoWiki < Chunk::Abstract
def self.pattern() Regexp.new('<nowiki>(.*?)</nowiki>') end
attr_reader :plain_text
def initialize(match_data)
super(match_data)
@plain_text = match_data[1]
end
# The nowiki content is not unmasked. This means the chunk will be reverted
# using the plain text.
def unmask(content) nil end
def revert(content) content.sub!(mask(content), plain_text) end
end
require 'chunks/chunk'
# This chunks allows certain parts of a wiki page to be hidden from the
# rest of the rendering pipeline. It should be run at the beginning
# of the pipeline in `wiki_content.rb`.
#
# An example use of this chunk is to markup double brackets or
# auto URI links:
# <nowiki>Here are [[double brackets]] and a URI: www.uri.org</nowiki>
#
# The contents of the chunks will not be processed by any other chunk
# so the `www.uri.org` and the double brackets will appear verbatim.
#
# Author: Mark Reid <mark at threewordslong dot com>
# Created: 8th June 2004
class NoWiki < Chunk::Abstract
def self.pattern() Regexp.new('<nowiki>(.*?)</nowiki>') end
attr_reader :plain_text
def initialize(match_data)
super(match_data)
@plain_text = match_data[1]
end
# The nowiki content is not unmasked. This means the chunk will be reverted
# using the plain text.
def unmask(content) nil end
def revert(content) content.sub!(mask(content), plain_text) end
end

36
app/models/chunks/test.rb Executable file → Normal file
View file

@ -1,18 +1,18 @@
require 'test/unit'
class ChunkTest < Test::Unit::TestCase
# Asserts a number of tests for the given type and text.
def match(type, test_text, expected)
pattern = type.pattern
assert_match(pattern, test_text)
pattern =~ test_text # Previous assertion guarantees match
chunk = type.new($~)
# Test if requested parts are correct.
for method_sym, value in expected do
assert_respond_to(chunk, method_sym)
assert_equal(value, chunk.method(method_sym).call, "Checking value of '#{method_sym}'")
end
end
end
require 'test/unit'
class ChunkTest < Test::Unit::TestCase
# Asserts a number of tests for the given type and text.
def match(type, test_text, expected)
pattern = type.pattern
assert_match(pattern, test_text)
pattern =~ test_text # Previous assertion guarantees match
chunk = type.new($~)
# Test if requested parts are correct.
for method_sym, value in expected do
assert_respond_to(chunk, method_sym)
assert_equal(value, chunk.method(method_sym).call, "Checking value of '#{method_sym}'")
end
end
end

358
app/models/chunks/uri.rb Executable file → Normal file
View file

@ -1,179 +1,179 @@
require 'chunks/chunk'
# This wiki chunk matches arbitrary URIs, using patterns from the Ruby URI modules.
# It parses out a variety of fields that could be used by renderers to format
# the links in various ways (shortening domain names, hiding email addresses)
# It matches email addresses and host.com.au domains without schemes (http://)
# but adds these on as required.
#
# The heuristic used to match a URI is designed to err on the side of caution.
# That is, it is more likely to not autolink a URI than it is to accidently
# autolink something that is not a URI. The reason behind this is it is easier
# to force a URI link by prefixing 'http://' to it than it is to escape and
# incorrectly marked up non-URI.
#
# I'm using a part of the [ISO 3166-1 Standard][iso3166] for country name suffixes.
# The generic names are from www.bnoack.com/data/countrycode2.html)
# [iso3166]: http://geotags.com/iso3166/
class URIChunk < Chunk::Abstract
include URI::REGEXP::PATTERN
# this condition is to get rid of pesky warnings in tests
unless defined? URIChunk::INTERNET_URI_REGEXP
GENERIC = '(?:aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org)'
COUNTRY = '(?:au|at|be|ca|ch|de|dk|fr|hk|in|ir|it|jp|nl|no|pt|ru|se|sw|tv|tw|uk|us)'
# These are needed otherwise HOST will match almost anything
TLDS = "(?:#{GENERIC}|#{COUNTRY})"
# Redefine USERINFO so that it must have non-zero length
USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})+"
# unreserved_no_ending = alphanum | mark, but URI_ENDING [)!] excluded
UNRESERVED_NO_ENDING = "-_.~*'(#{ALNUM}"
# this ensures that query or fragment do not end with URI_ENDING
# and enable us to use a much simpler self.pattern Regexp
# uric_no_ending = reserved | unreserved_no_ending | escaped
URIC_NO_ENDING = "(?:[#{UNRESERVED_NO_ENDING}#{RESERVED}]|#{ESCAPED})"
# query = *uric
QUERY = "#{URIC_NO_ENDING}*"
# fragment = *uric
FRAGMENT = "#{URIC_NO_ENDING}*"
# DOMLABEL is defined in the ruby uri library, TLDS is defined above
INTERNET_HOSTNAME = "(?:#{DOMLABEL}\\.)+#{TLDS}"
# Correct a typo bug in ruby 1.8.x lib/uri/common.rb
PORT = '\\d*'
INTERNET_URI =
"(?:(#{SCHEME}):/{0,2})?" + # Optional scheme: (\1)
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
"(#{INTERNET_HOSTNAME})" + # Mandatory hostname (\3)
"(?::(#{PORT}))?" + # Optional :port (\4)
"(#{ABS_PATH})?" + # Optional absolute path (\5)
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
"(?:\\#(#{FRAGMENT}))?" # Optional #fragment (\7)
TEXTILE_SYNTAX_PREFIX = '(!)?'
INTERNET_URI_REGEXP = Regexp.new(TEXTILE_SYNTAX_PREFIX + INTERNET_URI, Regexp::EXTENDED, 'N')
end
def URIChunk.pattern
INTERNET_URI_REGEXP
end
attr_reader :user, :host, :port, :path, :query, :fragment, :link_text
def self.apply_to(content)
content.gsub!( self.pattern ) do |matched_text|
chunk = self.new($~)
if chunk.textile_url? or chunk.textile_image?
# do not substitute
matched_text
else
content.chunks << chunk
chunk.mask(content)
end
end
end
def initialize(match_data)
super(match_data)
@link_text = match_data[0]
@textile_prefix, @original_scheme, @user, @host, @port, @path, @query, @fragment =
match_data[1..-1]
treat_trailing_character
end
def textile_url?
@textile_prefix == '":'
end
def textile_image?
@textile_prefix == '!' and @trailing_punctuation == '!'
end
def treat_trailing_character
# If the last character matched by URI pattern is in ! or ), this may be part of the markup,
# not a URL. We should handle it as such. It is possible to do it by a regexp, but
# much easier to do programmatically
last_char = @link_text[-1..-1]
if last_char == ')' or last_char == '!'
@trailing_punctuation = last_char
@link_text.chop!
[@original_scheme, @user, @host, @port, @path, @query, @fragment].compact.last.chop!
end
end
# If the text should be escaped then don't keep this chunk.
# Otherwise only keep this chunk if it was substituted back into the
# content.
def unmask(content)
return nil if escaped_text
return self if content.sub!(mask(content), "<a href=\"#{uri}\">#{link_text}</a>")
end
# If there is no hostname in the URI, do not render it
# It's probably only contains the scheme, eg 'something:'
def escaped_text() ( host.nil? ? @uri : nil ) end
def scheme
@original_scheme or (@user ? 'mailto' : 'http')
end
def scheme_delimiter
scheme == 'mailto' ? ':' : '://'
end
def user_delimiter
'@' unless @user.nil?
end
def port_delimiter
':' unless @port.nil?
end
def query_delimiter
'?' unless @query.nil?
end
def uri
[scheme, scheme_delimiter, user, user_delimiter, host, port_delimiter, port, path,
query_delimiter, query].compact.join
end
end
# uri with mandatory scheme but less restrictive hostname, like
# http://localhost:2500/blah.html
class LocalURIChunk < URIChunk
unless defined? LocalURIChunk::LOCAL_URI_REGEXP
# hostname can be just a simple word like 'localhost'
ANY_HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
# The basic URI expression as a string
# Scheme and hostname are mandatory
LOCAL_URI =
"(?:(#{SCHEME})://)+" + # Mandatory scheme:// (\1)
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
"(#{ANY_HOSTNAME})" + # Mandatory hostname (\3)
"(?::(#{PORT}))?" + # Optional :port (\4)
"(#{ABS_PATH})?" + # Optional absolute path (\5)
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
"(?:\\#(#{FRAGMENT}))?" # Optional #fragment (\7)
LOCAL_URI_REGEXP = Regexp.new(TEXTILE_SYNTAX_PREFIX + LOCAL_URI, Regexp::EXTENDED, 'N')
end
def LocalURIChunk.pattern
LOCAL_URI_REGEXP
end
end
require 'chunks/chunk'
# This wiki chunk matches arbitrary URIs, using patterns from the Ruby URI modules.
# It parses out a variety of fields that could be used by renderers to format
# the links in various ways (shortening domain names, hiding email addresses)
# It matches email addresses and host.com.au domains without schemes (http://)
# but adds these on as required.
#
# The heuristic used to match a URI is designed to err on the side of caution.
# That is, it is more likely to not autolink a URI than it is to accidently
# autolink something that is not a URI. The reason behind this is it is easier
# to force a URI link by prefixing 'http://' to it than it is to escape and
# incorrectly marked up non-URI.
#
# I'm using a part of the [ISO 3166-1 Standard][iso3166] for country name suffixes.
# The generic names are from www.bnoack.com/data/countrycode2.html)
# [iso3166]: http://geotags.com/iso3166/
class URIChunk < Chunk::Abstract
include URI::REGEXP::PATTERN
# this condition is to get rid of pesky warnings in tests
unless defined? URIChunk::INTERNET_URI_REGEXP
GENERIC = '(?:aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org)'
COUNTRY = '(?:au|at|be|ca|ch|de|dk|fr|hk|in|ir|it|jp|nl|no|pt|ru|se|sw|tv|tw|uk|us)'
# These are needed otherwise HOST will match almost anything
TLDS = "(?:#{GENERIC}|#{COUNTRY})"
# Redefine USERINFO so that it must have non-zero length
USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})+"
# unreserved_no_ending = alphanum | mark, but URI_ENDING [)!] excluded
UNRESERVED_NO_ENDING = "-_.~*'(#{ALNUM}"
# this ensures that query or fragment do not end with URI_ENDING
# and enable us to use a much simpler self.pattern Regexp
# uric_no_ending = reserved | unreserved_no_ending | escaped
URIC_NO_ENDING = "(?:[#{UNRESERVED_NO_ENDING}#{RESERVED}]|#{ESCAPED})"
# query = *uric
QUERY = "#{URIC_NO_ENDING}*"
# fragment = *uric
FRAGMENT = "#{URIC_NO_ENDING}*"
# DOMLABEL is defined in the ruby uri library, TLDS is defined above
INTERNET_HOSTNAME = "(?:#{DOMLABEL}\\.)+#{TLDS}"
# Correct a typo bug in ruby 1.8.x lib/uri/common.rb
PORT = '\\d*'
INTERNET_URI =
"(?:(#{SCHEME}):/{0,2})?" + # Optional scheme: (\1)
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
"(#{INTERNET_HOSTNAME})" + # Mandatory hostname (\3)
"(?::(#{PORT}))?" + # Optional :port (\4)
"(#{ABS_PATH})?" + # Optional absolute path (\5)
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
"(?:\\#(#{FRAGMENT}))?" # Optional #fragment (\7)
TEXTILE_SYNTAX_PREFIX = '(!)?'
INTERNET_URI_REGEXP = Regexp.new(TEXTILE_SYNTAX_PREFIX + INTERNET_URI, Regexp::EXTENDED, 'N')
end
def URIChunk.pattern
INTERNET_URI_REGEXP
end
attr_reader :user, :host, :port, :path, :query, :fragment, :link_text
def self.apply_to(content)
content.gsub!( self.pattern ) do |matched_text|
chunk = self.new($~)
if chunk.textile_url? or chunk.textile_image?
# do not substitute
matched_text
else
content.chunks << chunk
chunk.mask(content)
end
end
end
def initialize(match_data)
super(match_data)
@link_text = match_data[0]
@textile_prefix, @original_scheme, @user, @host, @port, @path, @query, @fragment =
match_data[1..-1]
treat_trailing_character
end
def textile_url?
@textile_prefix == '":'
end
def textile_image?
@textile_prefix == '!' and @trailing_punctuation == '!'
end
def treat_trailing_character
# If the last character matched by URI pattern is in ! or ), this may be part of the markup,
# not a URL. We should handle it as such. It is possible to do it by a regexp, but
# much easier to do programmatically
last_char = @link_text[-1..-1]
if last_char == ')' or last_char == '!'
@trailing_punctuation = last_char
@link_text.chop!
[@original_scheme, @user, @host, @port, @path, @query, @fragment].compact.last.chop!
end
end
# If the text should be escaped then don't keep this chunk.
# Otherwise only keep this chunk if it was substituted back into the
# content.
def unmask(content)
return nil if escaped_text
return self if content.sub!(mask(content), "<a href=\"#{uri}\">#{link_text}</a>")
end
# If there is no hostname in the URI, do not render it
# It's probably only contains the scheme, eg 'something:'
def escaped_text() ( host.nil? ? @uri : nil ) end
def scheme
@original_scheme or (@user ? 'mailto' : 'http')
end
def scheme_delimiter
scheme == 'mailto' ? ':' : '://'
end
def user_delimiter
'@' unless @user.nil?
end
def port_delimiter
':' unless @port.nil?
end
def query_delimiter
'?' unless @query.nil?
end
def uri
[scheme, scheme_delimiter, user, user_delimiter, host, port_delimiter, port, path,
query_delimiter, query].compact.join
end
end
# uri with mandatory scheme but less restrictive hostname, like
# http://localhost:2500/blah.html
class LocalURIChunk < URIChunk
unless defined? LocalURIChunk::LOCAL_URI_REGEXP
# hostname can be just a simple word like 'localhost'
ANY_HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
# The basic URI expression as a string
# Scheme and hostname are mandatory
LOCAL_URI =
"(?:(#{SCHEME})://)+" + # Mandatory scheme:// (\1)
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
"(#{ANY_HOSTNAME})" + # Mandatory hostname (\3)
"(?::(#{PORT}))?" + # Optional :port (\4)
"(#{ABS_PATH})?" + # Optional absolute path (\5)
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
"(?:\\#(#{FRAGMENT}))?" # Optional #fragment (\7)
LOCAL_URI_REGEXP = Regexp.new(TEXTILE_SYNTAX_PREFIX + LOCAL_URI, Regexp::EXTENDED, 'N')
end
def LocalURIChunk.pattern
LOCAL_URI_REGEXP
end
end

284
app/models/chunks/wiki.rb Executable file → Normal file
View file

@ -1,142 +1,142 @@
require 'wiki_words'
require 'chunks/chunk'
require 'chunks/wiki'
require 'cgi'
# Contains all the methods for finding and replacing wiki related links.
module WikiChunk
include Chunk
# A wiki link is the top-level class for anything that refers to
# another wiki page.
class WikiLink < Chunk::Abstract
attr_reader :page_name, :link_text, :link_type
def initialize(*args)
super
@link_type = 'show'
end
def self.apply_to(content)
content.gsub!( self.pattern ) do |matched_text|
chunk = self.new($~)
if chunk.textile_url?
# do not substitute
matched_text
else
content.chunks << chunk
chunk.mask(content)
end
end
end
def textile_url?
not @textile_link_suffix.nil?
end
# By default, no escaped text
def escaped_text() nil end
# Replace link with a mask, but if the word is escaped, then don't replace it
def mask(content)
escaped_text || super(content)
end
def revert(content) content.sub!(mask(content), text) end
# Do not keep this chunk if it is escaped.
# Otherwise, pass the link procedure a page_name and link_text and
# get back a string of HTML to replace the mask with.
def unmask(content)
if escaped_text
return self
else
chunk_found = content.sub!(mask(content)) do |match|
content.page_link(page_name, link_text, link_type)
end
if chunk_found
return self
else
return nil
end
end
end
end
# This chunk matches a WikiWord. WikiWords can be escaped
# by prepending a '\'. When this is the case, the +escaped_text+
# method will return the WikiWord instead of the usual +nil+.
# The +page_name+ method returns the matched WikiWord.
class Word < WikiLink
unless defined? WIKI_LINK
WIKI_WORD = Regexp.new('(":)?(\\\\)?(' + WikiWords::WIKI_WORD_PATTERN + ')\b', 0, "utf-8")
end
def self.pattern
WIKI_WORD
end
def initialize(match_data)
super(match_data)
@textile_link_suffix, @escape, @page_name = match_data[1..3]
end
def escaped_text
page_name unless @escape.nil?
end
def link_text() WikiWords.separate(page_name) end
end
# This chunk handles [[bracketted wiki words]] and
# [[AliasedWords|aliased wiki words]]. The first part of an
# aliased wiki word must be a WikiWord. If the WikiWord
# is aliased, the +link_text+ field will contain the
# alias, otherwise +link_text+ will contain the entire
# contents within the double brackets.
#
# NOTE: This chunk must be tested before WikiWord since
# a WikiWords can be a substring of a WikiLink.
class Link < WikiLink
unless defined? WIKI_LINK
WIKI_LINK = /(":)?\[\[([^\]]+)\]\]/
LINK_TYPE_SEPARATION = Regexp.new('^(.+):((file)|(pic))$', 0, 'utf-8')
ALIAS_SEPARATION = Regexp.new('^(.+)\|(.+)$', 0, 'utf-8')
end
def self.pattern() WIKI_LINK end
def initialize(match_data)
super(match_data)
@textile_link_suffix, @page_name = match_data[1..2]
@link_text = @page_name
separate_link_type
separate_alias
end
private
# if link wihin the brackets has a form of [[filename:file]] or [[filename:pic]],
# this means a link to a picture or a file
def separate_link_type
link_type_match = LINK_TYPE_SEPARATION.match(@page_name)
if link_type_match
@link_text = @page_name = link_type_match[1]
@link_type = link_type_match[2..3].compact[0]
end
end
# link text may be different from page name. this will look like [[actual page|link text]]
def separate_alias
alias_match = ALIAS_SEPARATION.match(@page_name)
if alias_match
@page_name, @link_text = alias_match[1..2]
end
# note that [[filename|link text:file]] is also supported
end
end
end
require 'wiki_words'
require 'chunks/chunk'
require 'chunks/wiki'
require 'cgi'
# Contains all the methods for finding and replacing wiki related links.
module WikiChunk
include Chunk
# A wiki link is the top-level class for anything that refers to
# another wiki page.
class WikiLink < Chunk::Abstract
attr_reader :page_name, :link_text, :link_type
def initialize(*args)
super
@link_type = 'show'
end
def self.apply_to(content)
content.gsub!( self.pattern ) do |matched_text|
chunk = self.new($~)
if chunk.textile_url?
# do not substitute
matched_text
else
content.chunks << chunk
chunk.mask(content)
end
end
end
def textile_url?
not @textile_link_suffix.nil?
end
# By default, no escaped text
def escaped_text() nil end
# Replace link with a mask, but if the word is escaped, then don't replace it
def mask(content)
escaped_text || super(content)
end
def revert(content) content.sub!(mask(content), text) end
# Do not keep this chunk if it is escaped.
# Otherwise, pass the link procedure a page_name and link_text and
# get back a string of HTML to replace the mask with.
def unmask(content)
if escaped_text
return self
else
chunk_found = content.sub!(mask(content)) do |match|
content.page_link(page_name, link_text, link_type)
end
if chunk_found
return self
else
return nil
end
end
end
end
# This chunk matches a WikiWord. WikiWords can be escaped
# by prepending a '\'. When this is the case, the +escaped_text+
# method will return the WikiWord instead of the usual +nil+.
# The +page_name+ method returns the matched WikiWord.
class Word < WikiLink
unless defined? WIKI_LINK
WIKI_WORD = Regexp.new('(":)?(\\\\)?(' + WikiWords::WIKI_WORD_PATTERN + ')\b', 0, "utf-8")
end
def self.pattern
WIKI_WORD
end
def initialize(match_data)
super(match_data)
@textile_link_suffix, @escape, @page_name = match_data[1..3]
end
def escaped_text
page_name unless @escape.nil?
end
def link_text() WikiWords.separate(page_name) end
end
# This chunk handles [[bracketted wiki words]] and
# [[AliasedWords|aliased wiki words]]. The first part of an
# aliased wiki word must be a WikiWord. If the WikiWord
# is aliased, the +link_text+ field will contain the
# alias, otherwise +link_text+ will contain the entire
# contents within the double brackets.
#
# NOTE: This chunk must be tested before WikiWord since
# a WikiWords can be a substring of a WikiLink.
class Link < WikiLink
unless defined? WIKI_LINK
WIKI_LINK = /(":)?\[\[([^\]]+)\]\]/
LINK_TYPE_SEPARATION = Regexp.new('^(.+):((file)|(pic))$', 0, 'utf-8')
ALIAS_SEPARATION = Regexp.new('^(.+)\|(.+)$', 0, 'utf-8')
end
def self.pattern() WIKI_LINK end
def initialize(match_data)
super(match_data)
@textile_link_suffix, @page_name = match_data[1..2]
@link_text = @page_name
separate_link_type
separate_alias
end
private
# if link wihin the brackets has a form of [[filename:file]] or [[filename:pic]],
# this means a link to a picture or a file
def separate_link_type
link_type_match = LINK_TYPE_SEPARATION.match(@page_name)
if link_type_match
@link_text = @page_name = link_type_match[1]
@link_type = link_type_match[2..3].compact[0]
end
end
# link text may be different from page name. this will look like [[actual page|link text]]
def separate_alias
alias_match = ALIAS_SEPARATION.match(@page_name)
if alias_match
@page_name, @link_text = alias_match[1..2]
end
# note that [[filename|link text:file]] is also supported
end
end
end

View file

@ -1,45 +1,45 @@
require 'instiki_errors'
class FileYard
attr_reader :files_path
def initialize(files_path)
@files_path = files_path
@files = Dir["#{files_path}/*"].collect{|path| File.basename(path) if File.file?(path) }.compact
end
def upload_file(name, io)
sanitize_file_name(name)
if io.kind_of?(Tempfile)
io.close
FileUtils.mv(io.path, file_path(name))
else
File.open(file_path(name), 'wb') { |f| f.write(io.read) }
end
# just in case, restrict read access and prohibit write access to the uploaded file
FileUtils.chmod(0440, file_path(name))
end
def files
Dir["#{files_path}/*"].collect{|path| File.basename(path) if File.file?(path)}.compact
end
def has_file?(name)
files.include?(name)
end
def file_path(name)
"#{files_path}/#{name}"
end
SANE_FILE_NAME = /[-_\.A-Za-z0-9]{1,255}/
def sanitize_file_name(name)
unless name =~ SANE_FILE_NAME
raise Instiki::ValidationError.new("Invalid file name: '#{name}'.\n" +
"Only latin characters, digits, dots, underscores and dashes are accepted.")
end
end
end
require 'instiki_errors'
class FileYard
attr_reader :files_path
def initialize(files_path)
@files_path = files_path
@files = Dir["#{files_path}/*"].collect{|path| File.basename(path) if File.file?(path) }.compact
end
def upload_file(name, io)
sanitize_file_name(name)
if io.kind_of?(Tempfile)
io.close
FileUtils.mv(io.path, file_path(name))
else
File.open(file_path(name), 'wb') { |f| f.write(io.read) }
end
# just in case, restrict read access and prohibit write access to the uploaded file
FileUtils.chmod(0440, file_path(name))
end
def files
Dir["#{files_path}/*"].collect{|path| File.basename(path) if File.file?(path)}.compact
end
def has_file?(name)
files.include?(name)
end
def file_path(name)
"#{files_path}/#{name}"
end
SANE_FILE_NAME = /[-_\.A-Za-z0-9]{1,255}/
def sanitize_file_name(name)
unless name =~ SANE_FILE_NAME
raise Instiki::ValidationError.new("Invalid file name: '#{name}'.\n" +
"Only latin characters, digits, dots, underscores and dashes are accepted.")
end
end
end

184
app/models/page.rb Executable file → Normal file
View file

@ -1,92 +1,92 @@
require 'date'
require 'page_lock'
require 'revision'
require 'wiki_words'
require 'chunks/wiki'
class Page
include PageLock
attr_reader :name, :web
attr_accessor :revisions
def initialize(web, name, content, created_at, author)
@web, @name, @revisions = web, name, []
revise(content, created_at, author)
end
def revise(content, created_at, author)
if not @revisions.empty? and content == @revisions.last.content
raise Instiki::ValidationError.new(
"You have tried to save page '#{name}' without changing its content")
end
# A user may change a page, look at it and make some more changes - several times.
# Not to record every such iteration as a new revision, if the previous revision was done
# by the same author, not more than 30 minutes ago, then update the last revision instead of
# creating a new one
if !@revisions.empty? && continous_revision?(created_at, author)
@revisions.last.created_at = created_at
@revisions.last.content = content
@revisions.last.clear_display_cache
else
@revisions << Revision.new(self, @revisions.length, content, created_at, author)
end
web.refresh_pages_with_references(name) if @revisions.length == 1
end
def rollback(revision_number, created_at, author_ip = nil)
roll_back_revision = @revisions[revision_number].dup
revise(roll_back_revision.content, created_at, Author.new(roll_back_revision.author, author_ip))
end
def revisions?
revisions.length > 1
end
def revised_on
created_on
end
def in_category?(cat)
cat.nil? || cat.empty? || categories.include?(cat)
end
def categories
display_content.find_chunks(Category).map { |cat| cat.list }.flatten
end
def authors
revisions.collect { |rev| rev.author }
end
def references
web.select.pages_that_reference(name)
end
# Returns the original wiki-word name as separate words, so "MyPage" becomes "My Page".
def plain_name
web.brackets_only ? name : WikiWords.separate(name)
end
def link(options = {})
web.make_link(name, nil, options)
end
def author_link(options = {})
web.make_link(author, nil, options)
end
private
def continous_revision?(created_at, author)
@revisions.last.author == author && @revisions.last.created_at + 30.minutes > created_at
end
# Forward method calls to the current revision, so the page responds to all revision calls
def method_missing(method_symbol)
revisions.last.send(method_symbol)
end
end
require 'date'
require 'page_lock'
require 'revision'
require 'wiki_words'
require 'chunks/wiki'
class Page
include PageLock
attr_reader :name, :web
attr_accessor :revisions
def initialize(web, name, content, created_at, author)
@web, @name, @revisions = web, name, []
revise(content, created_at, author)
end
def revise(content, created_at, author)
if not @revisions.empty? and content == @revisions.last.content
raise Instiki::ValidationError.new(
"You have tried to save page '#{name}' without changing its content")
end
# A user may change a page, look at it and make some more changes - several times.
# Not to record every such iteration as a new revision, if the previous revision was done
# by the same author, not more than 30 minutes ago, then update the last revision instead of
# creating a new one
if !@revisions.empty? && continous_revision?(created_at, author)
@revisions.last.created_at = created_at
@revisions.last.content = content
@revisions.last.clear_display_cache
else
@revisions << Revision.new(self, @revisions.length, content, created_at, author)
end
web.refresh_pages_with_references(name) if @revisions.length == 1
end
def rollback(revision_number, created_at, author_ip = nil)
roll_back_revision = @revisions[revision_number].dup
revise(roll_back_revision.content, created_at, Author.new(roll_back_revision.author, author_ip))
end
def revisions?
revisions.length > 1
end
def revised_on
created_on
end
def in_category?(cat)
cat.nil? || cat.empty? || categories.include?(cat)
end
def categories
display_content.find_chunks(Category).map { |cat| cat.list }.flatten
end
def authors
revisions.collect { |rev| rev.author }
end
def references
web.select.pages_that_reference(name)
end
# Returns the original wiki-word name as separate words, so "MyPage" becomes "My Page".
def plain_name
web.brackets_only ? name : WikiWords.separate(name)
end
def link(options = {})
web.make_link(name, nil, options)
end
def author_link(options = {})
web.make_link(author, nil, options)
end
private
def continous_revision?(created_at, author)
@revisions.last.author == author && @revisions.last.created_at + 30.minutes > created_at
end
# Forward method calls to the current revision, so the page responds to all revision calls
def method_missing(method_symbol)
revisions.last.send(method_symbol)
end
end

46
app/models/page_lock.rb Executable file → Normal file
View file

@ -1,24 +1,24 @@
# Contains all the lock methods to be mixed in with the page
module PageLock
LOCKING_PERIOD = 30 * 60 # 30 minutes
def lock(time, locked_by)
@locked_at, @locked_by = time, locked_by
end
def lock_duration(time)
((time - @locked_at) / 60).to_i unless @locked_at.nil?
end
def unlock
@locked_at = nil
end
def locked?(comparison_time)
@locked_at + LOCKING_PERIOD > comparison_time unless @locked_at.nil?
end
def locked_by_link
web.make_link(@locked_by)
end
# Contains all the lock methods to be mixed in with the page
module PageLock
LOCKING_PERIOD = 30 * 60 # 30 minutes
def lock(time, locked_by)
@locked_at, @locked_by = time, locked_by
end
def lock_duration(time)
((time - @locked_at) / 60).to_i unless @locked_at.nil?
end
def unlock
@locked_at = nil
end
def locked?(comparison_time)
@locked_at + LOCKING_PERIOD > comparison_time unless @locked_at.nil?
end
def locked_by_link
web.make_link(@locked_by)
end
end

144
app/models/page_set.rb Executable file → Normal file
View file

@ -1,73 +1,73 @@
# Container for a set of pages with methods for manipulation.
class PageSet < Array
attr_reader :web
def initialize(web, pages = nil, condition = nil)
@web = web
# if pages is not specified, make a list of all pages in the web
if pages.nil?
super(web.pages.values)
# otherwise use specified pages and condition to produce a set of pages
elsif condition.nil?
super(pages)
else
super(pages.select { |page| condition[page] })
end
end
def most_recent_revision
self.map { |page| page.created_at }.max || Time.at(0)
end
def by_name
PageSet.new(@web, sort_by { |page| page.name })
end
alias :sort :by_name
def by_revision
PageSet.new(@web, sort_by { |page| page.created_at }).reverse
end
def pages_that_reference(page_name)
self.select { |page| page.wiki_words.include?(page_name) }
end
def pages_authored_by(author)
self.select { |page| page.authors.include?(author) }
end
def characters
self.inject(0) { |chars,page| chars += page.content.size }
end
# Returns all the orphaned pages in this page set. That is,
# pages in this set for which there is no reference in the web.
# The HomePage and author pages are always assumed to have
# references and so cannot be orphans
def orphaned_pages
references = web.select.wiki_words + ["HomePage"] + web.select.authors
self.reject { |page| references.include?(page.name) }
end
# Returns all the wiki words in this page set for which
# there are no pages in this page set's web
def wanted_pages
wiki_words - web.select.names
end
def names
self.map { |page| page.name }
end
def wiki_words
self.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq
end
def authors
self.inject([]) { |authors, page| authors << page.authors }.flatten.uniq.sort
end
# Container for a set of pages with methods for manipulation.
class PageSet < Array
attr_reader :web
def initialize(web, pages = nil, condition = nil)
@web = web
# if pages is not specified, make a list of all pages in the web
if pages.nil?
super(web.pages.values)
# otherwise use specified pages and condition to produce a set of pages
elsif condition.nil?
super(pages)
else
super(pages.select { |page| condition[page] })
end
end
def most_recent_revision
self.map { |page| page.created_at }.max || Time.at(0)
end
def by_name
PageSet.new(@web, sort_by { |page| page.name })
end
alias :sort :by_name
def by_revision
PageSet.new(@web, sort_by { |page| page.created_at }).reverse
end
def pages_that_reference(page_name)
self.select { |page| page.wiki_words.include?(page_name) }
end
def pages_authored_by(author)
self.select { |page| page.authors.include?(author) }
end
def characters
self.inject(0) { |chars,page| chars += page.content.size }
end
# Returns all the orphaned pages in this page set. That is,
# pages in this set for which there is no reference in the web.
# The HomePage and author pages are always assumed to have
# references and so cannot be orphans
def orphaned_pages
references = web.select.wiki_words + ["HomePage"] + web.select.authors
self.reject { |page| references.include?(page.name) }
end
# Returns all the wiki words in this page set for which
# there are no pages in this page set's web
def wanted_pages
wiki_words - web.select.names
end
def names
self.map { |page| page.name }
end
def wiki_words
self.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq
end
def authors
self.inject([]) { |authors, page| authors << page.authors }.flatten.uniq.sort
end
end

166
app/models/revision.rb Executable file → Normal file
View file

@ -1,83 +1,83 @@
require 'diff'
require 'wiki_content'
require 'chunks/wiki'
require 'date'
require 'author'
require 'page'
class Revision
attr_accessor :page, :number, :content, :created_at, :author
def initialize(page, number, content, created_at, author)
@page, @number, @created_at, @author = page, number, created_at, author
self.content = content
end
def created_on
Date.new(@created_at.year, @created_at.mon, @created_at.day)
end
def pretty_created_at
# Must use DateTime because Time doesn't support %e on at least some platforms
DateTime.new(
@created_at.year, @created_at.mon, @created_at.day, @created_at.hour, @created_at.min
).strftime "%B %e, %Y %H:%M"
end
def next_revision
page.revisions[number + 1]
end
def previous_revision
number > 0 ? page.revisions[number - 1] : nil
end
# Returns an array of all the WikiWords present in the content of this revision.
def wiki_words
unless @wiki_words_cache
wiki_chunks = display_content.find_chunks(WikiChunk::WikiLink)
@wiki_words_cache = wiki_chunks.map { |c| ( c.escaped_text ? nil : c.page_name ) }.compact.uniq
end
@wiki_words_cache
end
# Returns an array of all the WikiWords present in the content of this revision.
# that already exists as a page in the web.
def existing_pages
wiki_words.select { |wiki_word| page.web.pages[wiki_word] }
end
# Returns an array of all the WikiWords present in the content of this revision
# that *doesn't* already exists as a page in the web.
def unexisting_pages
wiki_words - existing_pages
end
# Explicit check for new type of display cache with find_chunks method.
# Ensures new version works with older snapshots.
def display_content
unless @display_cache && @display_cache.respond_to?(:find_chunks)
@display_cache = WikiContent.new(self)
end
@display_cache
end
def display_diff
previous_revision ? HTMLDiff.diff(previous_revision.display_content, display_content) : display_content
end
def clear_display_cache
@display_cache = @published_cache = @wiki_words_cache = nil
end
def display_published
@published_cache = WikiContent.new(self, {:mode => :publish}) if @published_cache.nil?
@published_cache
end
def display_content_for_export
WikiContent.new(self, {:mode => :export} )
end
end
require 'diff'
require 'wiki_content'
require 'chunks/wiki'
require 'date'
require 'author'
require 'page'
class Revision
attr_accessor :page, :number, :content, :created_at, :author
def initialize(page, number, content, created_at, author)
@page, @number, @created_at, @author = page, number, created_at, author
self.content = content
end
def created_on
Date.new(@created_at.year, @created_at.mon, @created_at.day)
end
def pretty_created_at
# Must use DateTime because Time doesn't support %e on at least some platforms
DateTime.new(
@created_at.year, @created_at.mon, @created_at.day, @created_at.hour, @created_at.min
).strftime "%B %e, %Y %H:%M"
end
def next_revision
page.revisions[number + 1]
end
def previous_revision
number > 0 ? page.revisions[number - 1] : nil
end
# Returns an array of all the WikiWords present in the content of this revision.
def wiki_words
unless @wiki_words_cache
wiki_chunks = display_content.find_chunks(WikiChunk::WikiLink)
@wiki_words_cache = wiki_chunks.map { |c| ( c.escaped_text ? nil : c.page_name ) }.compact.uniq
end
@wiki_words_cache
end
# Returns an array of all the WikiWords present in the content of this revision.
# that already exists as a page in the web.
def existing_pages
wiki_words.select { |wiki_word| page.web.pages[wiki_word] }
end
# Returns an array of all the WikiWords present in the content of this revision
# that *doesn't* already exists as a page in the web.
def unexisting_pages
wiki_words - existing_pages
end
# Explicit check for new type of display cache with find_chunks method.
# Ensures new version works with older snapshots.
def display_content
unless @display_cache && @display_cache.respond_to?(:find_chunks)
@display_cache = WikiContent.new(self)
end
@display_cache
end
def display_diff
previous_revision ? HTMLDiff.diff(previous_revision.display_content, display_content) : display_content
end
def clear_display_cache
@display_cache = @published_cache = @wiki_words_cache = nil
end
def display_published
@published_cache = WikiContent.new(self, {:mode => :publish}) if @published_cache.nil?
@published_cache
end
def display_content_for_export
WikiContent.new(self, {:mode => :export} )
end
end

308
app/models/web.rb Executable file → Normal file
View file

@ -1,155 +1,155 @@
require "cgi"
require "page"
require "page_set"
require "wiki_words"
require "zip/zip"
class Web
attr_accessor :name, :address, :password, :markup, :color, :safe_mode, :pages
attr_accessor :additional_style, :published, :brackets_only, :count_pages, :allow_uploads
def initialize(parent_wiki, name, address, password = nil)
@wiki, @name, @address, @password = parent_wiki, name, address, password
# default values
@markup = :textile
@color = '008B26'
@safe_mode = false
@pages = {}
@allow_uploads = true
@additional_style = nil
@published = false
@brackets_only = false
@count_pages = false
@allow_uploads = true
end
def add_page(page)
@pages[page.name] = page
end
def remove_pages(pages_to_be_removed)
pages.delete_if { |page_name, page| pages_to_be_removed.include?(page) }
end
def select(&condition)
PageSet.new(self, @pages.values, condition)
end
def revised_on
select.most_recent_revision
end
def authors
select.authors
end
def categories
select.map { |page| page.categories }.flatten.uniq.sort
end
# Create a link for the given page name and link text based
# on the render mode in options and whether the page exists
# in the this web.
def make_link(name, text = nil, options = {})
text = CGI.escapeHTML(text || WikiWords.separate(name))
mode = options[:mode]
link_type = options[:link_type] || 'show'
case link_type
when 'show'
make_page_link(mode, name, text)
when 'file'
make_file_link(mode, name, text)
when 'pic'
make_pic_link(mode, name, text)
else
raise "Unknown link type: #{link_type}"
end
end
def make_page_link(mode, name, text)
link = CGI.escape(name)
case mode
when :export
if has_page?(name) then "<a class=\"existingWikiWord\" href=\"#{link}.html\">#{text}</a>"
else "<span class=\"newWikiWord\">#{text}</span>" end
when :publish
if has_page?(name) then "<a class=\"existingWikiWord\" href=\"../published/#{link}\">#{text}</a>"
else "<span class=\"newWikiWord\">#{text}</span>" end
else
if has_page?(name)
"<a class=\"existingWikiWord\" href=\"../show/#{link}\">#{text}</a>"
else
"<span class=\"newWikiWord\">#{text}<a href=\"../show/#{link}\">?</a></span>"
end
end
end
def make_file_link(mode, name, text)
link = CGI.escape(name)
case mode
when :export
if has_file?(name) then "<a class=\"existingWikiWord\" href=\"#{link}.html\">#{text}</a>"
else "<span class=\"newWikiWord\">#{text}</span>" end
when :publish
if has_file?(name) then "<a class=\"existingWikiWord\" href=\"../published/#{link}\">#{text}</a>"
else "<span class=\"newWikiWord\">#{text}</span>" end
else
if has_file?(name)
"<a class=\"existingWikiWord\" href=\"../file/#{link}\">#{text}</a>"
else
"<span class=\"newWikiWord\">#{text}<a href=\"../file/#{link}\">?</a></span>"
end
end
end
def make_pic_link(mode, name, text)
link = CGI.escape(name)
case mode
when :export
if has_file?(name) then "<img alt=\"#{text}\" src=\"#{link}\" />"
else "<img alt=\"#{text}\" src=\"no image\" />" end
when :publish
if has_file?(name) then "<img alt=\"#{text}\" src=\"#{link}\" />"
else "<span class=\"newWikiWord\">#{text}</span>" end
else
if has_file?(name) then "<img alt=\"#{text}\" src=\"../pic/#{link}\" />"
else "<span class=\"newWikiWord\">#{text}<a href=\"../pic/#{link}\">?</a></span>" end
end
end
def has_page?(name)
pages[name]
end
def has_file?(name)
wiki.file_yard(self).has_file?(name)
end
# Clears the display cache for all the pages with references to
def refresh_pages_with_references(page_name)
select.pages_that_reference(page_name).each { |page|
page.revisions.each { |revision| revision.clear_display_cache }
}
end
def refresh_revisions
select.each { |page| page.revisions.each { |revision| revision.clear_display_cache } }
end
private
# Returns an array of all the wiki words in any current revision
def wiki_words
pages.values.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq
end
# Returns an array of all the page names on this web
def page_names
pages.keys
end
# This ensures compatibility with 0.9 storages
def wiki
@wiki ||= WikiService.instance
end
require "cgi"
require "page"
require "page_set"
require "wiki_words"
require "zip/zip"
class Web
attr_accessor :name, :address, :password, :markup, :color, :safe_mode, :pages
attr_accessor :additional_style, :published, :brackets_only, :count_pages, :allow_uploads
def initialize(parent_wiki, name, address, password = nil)
@wiki, @name, @address, @password = parent_wiki, name, address, password
# default values
@markup = :textile
@color = '008B26'
@safe_mode = false
@pages = {}
@allow_uploads = true
@additional_style = nil
@published = false
@brackets_only = false
@count_pages = false
@allow_uploads = true
end
def add_page(page)
@pages[page.name] = page
end
def remove_pages(pages_to_be_removed)
pages.delete_if { |page_name, page| pages_to_be_removed.include?(page) }
end
def select(&condition)
PageSet.new(self, @pages.values, condition)
end
def revised_on
select.most_recent_revision
end
def authors
select.authors
end
def categories
select.map { |page| page.categories }.flatten.uniq.sort
end
# Create a link for the given page name and link text based
# on the render mode in options and whether the page exists
# in the this web.
def make_link(name, text = nil, options = {})
text = CGI.escapeHTML(text || WikiWords.separate(name))
mode = options[:mode]
link_type = options[:link_type] || 'show'
case link_type
when 'show'
make_page_link(mode, name, text)
when 'file'
make_file_link(mode, name, text)
when 'pic'
make_pic_link(mode, name, text)
else
raise "Unknown link type: #{link_type}"
end
end
def make_page_link(mode, name, text)
link = CGI.escape(name)
case mode
when :export
if has_page?(name) then "<a class=\"existingWikiWord\" href=\"#{link}.html\">#{text}</a>"
else "<span class=\"newWikiWord\">#{text}</span>" end
when :publish
if has_page?(name) then "<a class=\"existingWikiWord\" href=\"../published/#{link}\">#{text}</a>"
else "<span class=\"newWikiWord\">#{text}</span>" end
else
if has_page?(name)
"<a class=\"existingWikiWord\" href=\"../show/#{link}\">#{text}</a>"
else
"<span class=\"newWikiWord\">#{text}<a href=\"../show/#{link}\">?</a></span>"
end
end
end
def make_file_link(mode, name, text)
link = CGI.escape(name)
case mode
when :export
if has_file?(name) then "<a class=\"existingWikiWord\" href=\"#{link}.html\">#{text}</a>"
else "<span class=\"newWikiWord\">#{text}</span>" end
when :publish
if has_file?(name) then "<a class=\"existingWikiWord\" href=\"../published/#{link}\">#{text}</a>"
else "<span class=\"newWikiWord\">#{text}</span>" end
else
if has_file?(name)
"<a class=\"existingWikiWord\" href=\"../file/#{link}\">#{text}</a>"
else
"<span class=\"newWikiWord\">#{text}<a href=\"../file/#{link}\">?</a></span>"
end
end
end
def make_pic_link(mode, name, text)
link = CGI.escape(name)
case mode
when :export
if has_file?(name) then "<img alt=\"#{text}\" src=\"#{link}\" />"
else "<img alt=\"#{text}\" src=\"no image\" />" end
when :publish
if has_file?(name) then "<img alt=\"#{text}\" src=\"#{link}\" />"
else "<span class=\"newWikiWord\">#{text}</span>" end
else
if has_file?(name) then "<img alt=\"#{text}\" src=\"../pic/#{link}\" />"
else "<span class=\"newWikiWord\">#{text}<a href=\"../pic/#{link}\">?</a></span>" end
end
end
def has_page?(name)
pages[name]
end
def has_file?(name)
wiki.file_yard(self).has_file?(name)
end
# Clears the display cache for all the pages with references to
def refresh_pages_with_references(page_name)
select.pages_that_reference(page_name).each { |page|
page.revisions.each { |revision| revision.clear_display_cache }
}
end
def refresh_revisions
select.each { |page| page.revisions.each { |revision| revision.clear_display_cache } }
end
private
# Returns an array of all the wiki words in any current revision
def wiki_words
pages.values.inject([]) { |wiki_words, page| wiki_words << page.wiki_words }.flatten.uniq
end
# Returns an array of all the page names on this web
def page_names
pages.keys
end
# This ensures compatibility with 0.9 storages
def wiki
@wiki ||= WikiService.instance
end
end

192
app/models/wiki_content.rb Executable file → Normal file
View file

@ -1,97 +1,97 @@
require 'cgi'
require 'chunks/engines'
require 'chunks/category'
require 'chunks/include'
require 'chunks/wiki'
require 'chunks/literal'
require 'chunks/uri'
require 'chunks/nowiki'
# Wiki content is just a string that can process itself with a chain of
# actions. The actions can modify wiki content so that certain parts of
# it are protected from being rendered by later actions.
#
# When wiki content is rendered, it can be interrogated to find out
# which chunks were rendered. This means things like categories, wiki
# links, can be determined.
#
# Exactly how wiki content is rendered is determined by a number of
# settings that are optionally passed in to a constructor. The current
# options are:
# * :engine
# => The structural markup engine to use (Textile, Markdown, RDoc)
# * :engine_opts
# => A list of options to pass to the markup engines (safe modes, etc)
# * :pre_engine_actions
# => A list of render actions or chunks to be processed before the
# markup engine is applied. By default this is:
# Category, Include, URIChunk, WikiChunk::Link, WikiChunk::Word
# * :post_engine_actions
# => A list of render actions or chunks to apply after the markup
# engine. By default these are:
# Literal::Pre, Literal::Tags
# * :mode
# => How should the content be rendered? For normal display (:display),
# publishing (:publish) or export (:export)?
#
# AUTHOR: Mark Reid <mark @ threewordslong . com>
# CREATED: 15th May 2004
# UPDATED: 22nd May 2004
class WikiContent < String
PRE_ENGINE_ACTIONS = [ NoWiki, Category, Include, WikiChunk::Link, URIChunk, LocalURIChunk,
WikiChunk::Word ]
POST_ENGINE_ACTIONS = [ Literal::Pre, Literal::Tags ]
DEFAULT_OPTS = {
:pre_engine_actions => PRE_ENGINE_ACTIONS,
:post_engine_actions => POST_ENGINE_ACTIONS,
:engine => Engines::Textile,
:engine_opts => [],
:mode => [:display]
}
attr_reader :web, :options, :rendered, :chunks
# Create a new wiki content string from the given one.
# The options are explained at the top of this file.
def initialize(revision, options = {})
@revision = revision
@web = @revision.page.web
# Deep copy of DEFAULT_OPTS to ensure that changes to PRE/POST_ENGINE_ACTIONS stay local
@options = Marshal.load(Marshal.dump(DEFAULT_OPTS)).update(options)
@options[:engine] = Engines::MAP[@web.markup] || Engines::Textile
@options[:engine_opts] = (@web.safe_mode ? [:filter_html, :filter_styles] : [])
@options[:pre_engine_actions].delete(WikiChunk::Word) if @web.brackets_only
super(@revision.content)
begin
render!(@options[:pre_engine_actions] + [@options[:engine]] + @options[:post_engine_actions])
# FIXME this is where all the parsing problems were shoved under the carpet
# rescue => e
# @rendered = e.message
end
end
# Call @web.page_link using current options.
def page_link(name, text, link_type)
@options[:link_type] = link_type || :show
@web.make_link(name, text, @options)
end
# Find all the chunks of the given types
def find_chunks(chunk_type)
rendered.select { |chunk| chunk.kind_of?(chunk_type) }
end
# Render this content using the specified actions.
def render!(chunk_types)
@chunks = []
chunk_types.each { |chunk_type| chunk_type.apply_to(self) }
@rendered = @chunks.map { |chunk| chunk.unmask(self) }.compact
(@chunks - @rendered).each { |chunk| chunk.revert(self) }
end
require 'cgi'
require 'chunks/engines'
require 'chunks/category'
require 'chunks/include'
require 'chunks/wiki'
require 'chunks/literal'
require 'chunks/uri'
require 'chunks/nowiki'
# Wiki content is just a string that can process itself with a chain of
# actions. The actions can modify wiki content so that certain parts of
# it are protected from being rendered by later actions.
#
# When wiki content is rendered, it can be interrogated to find out
# which chunks were rendered. This means things like categories, wiki
# links, can be determined.
#
# Exactly how wiki content is rendered is determined by a number of
# settings that are optionally passed in to a constructor. The current
# options are:
# * :engine
# => The structural markup engine to use (Textile, Markdown, RDoc)
# * :engine_opts
# => A list of options to pass to the markup engines (safe modes, etc)
# * :pre_engine_actions
# => A list of render actions or chunks to be processed before the
# markup engine is applied. By default this is:
# Category, Include, URIChunk, WikiChunk::Link, WikiChunk::Word
# * :post_engine_actions
# => A list of render actions or chunks to apply after the markup
# engine. By default these are:
# Literal::Pre, Literal::Tags
# * :mode
# => How should the content be rendered? For normal display (:display),
# publishing (:publish) or export (:export)?
#
# AUTHOR: Mark Reid <mark @ threewordslong . com>
# CREATED: 15th May 2004
# UPDATED: 22nd May 2004
class WikiContent < String
PRE_ENGINE_ACTIONS = [ NoWiki, Category, Include, WikiChunk::Link, URIChunk, LocalURIChunk,
WikiChunk::Word ]
POST_ENGINE_ACTIONS = [ Literal::Pre, Literal::Tags ]
DEFAULT_OPTS = {
:pre_engine_actions => PRE_ENGINE_ACTIONS,
:post_engine_actions => POST_ENGINE_ACTIONS,
:engine => Engines::Textile,
:engine_opts => [],
:mode => [:display]
}
attr_reader :web, :options, :rendered, :chunks
# Create a new wiki content string from the given one.
# The options are explained at the top of this file.
def initialize(revision, options = {})
@revision = revision
@web = @revision.page.web
# Deep copy of DEFAULT_OPTS to ensure that changes to PRE/POST_ENGINE_ACTIONS stay local
@options = Marshal.load(Marshal.dump(DEFAULT_OPTS)).update(options)
@options[:engine] = Engines::MAP[@web.markup] || Engines::Textile
@options[:engine_opts] = (@web.safe_mode ? [:filter_html, :filter_styles] : [])
@options[:pre_engine_actions].delete(WikiChunk::Word) if @web.brackets_only
super(@revision.content)
begin
render!(@options[:pre_engine_actions] + [@options[:engine]] + @options[:post_engine_actions])
# FIXME this is where all the parsing problems were shoved under the carpet
# rescue => e
# @rendered = e.message
end
end
# Call @web.page_link using current options.
def page_link(name, text, link_type)
@options[:link_type] = link_type || :show
@web.make_link(name, text, @options)
end
# Find all the chunks of the given types
def find_chunks(chunk_type)
rendered.select { |chunk| chunk.kind_of?(chunk_type) }
end
# Render this content using the specified actions.
def render!(chunk_types)
@chunks = []
chunk_types.each { |chunk_type| chunk_type.apply_to(self) }
@rendered = @chunks.map { |chunk| chunk.unmask(self) }.compact
(@chunks - @rendered).each { |chunk| chunk.revert(self) }
end
end

444
app/models/wiki_service.rb Executable file → Normal file
View file

@ -1,222 +1,222 @@
require 'open-uri'
require 'yaml'
require 'madeleine'
require 'madeleine/automatic'
require 'madeleine/zmarshal'
require 'web'
require 'page'
require 'author'
require 'file_yard'
module AbstractWikiService
attr_reader :webs, :system
def authenticate(password)
password == (@system[:password] || 'instiki')
end
def create_web(name, address, password = nil)
@webs[address] = Web.new(self, name, address, password) unless @webs[address]
end
def delete_web(address)
@webs[address] = nil
end
def file_yard(web)
raise "Web #{@web.name} does not belong to this wiki service" unless @webs.values.include?(web)
# TODO cache FileYards
FileYard.new("#{self.storage_path}/#{web.address}")
end
def init_wiki_service
@webs = {}
@system = {}
end
def read_page(web_address, page_name)
ApplicationController.logger.debug "Reading page '#{page_name}' from web '#{web_address}'"
web = @webs[web_address]
if web.nil?
ApplicationController.logger.debug "Web '#{web_address}' not found"
return nil
else
page = web.pages[page_name]
ApplicationController.logger.debug "Page '#{page_name}' #{page.nil? ? 'not' : ''} found"
return page
end
end
def remove_orphaned_pages(web_address)
@webs[web_address].remove_pages(@webs[web_address].select.orphaned_pages)
end
def revise_page(web_address, page_name, content, revised_on, author)
page = read_page(web_address, page_name)
page.revise(content, revised_on, author)
page
end
def rollback_page(web_address, page_name, revision_number, created_at, author_id = nil)
page = read_page(web_address, page_name)
page.rollback(revision_number, created_at, author_id)
page
end
def setup(password, web_name, web_address)
@system[:password] = password
create_web(web_name, web_address)
end
def setup?
not (@webs.empty?)
end
def update_web(old_address, new_address, name, markup, color, additional_style, safe_mode = false,
password = nil, published = false, brackets_only = false, count_pages = false,
allow_uploads = true)
if old_address != new_address
@webs[new_address] = @webs[old_address]
@webs.delete(old_address)
@webs[new_address].address = new_address
end
web = @webs[new_address]
web.refresh_revisions if settings_changed?(web, markup, safe_mode, brackets_only)
web.name, web.markup, web.color, web.additional_style, web.safe_mode =
name, markup, color, additional_style, safe_mode
web.password, web.published, web.brackets_only, web.count_pages, web.allow_uploads =
password, published, brackets_only, count_pages, allow_uploads
end
def write_page(web_address, page_name, content, written_on, author)
page = Page.new(@webs[web_address], page_name, content, written_on, author)
@webs[web_address].add_page(page)
page
end
def storage_path
self.class.storage_path
end
private
def settings_changed?(web, markup, safe_mode, brackets_only)
web.markup != markup ||
web.safe_mode != safe_mode ||
web.brackets_only != brackets_only
end
end
class WikiService
include AbstractWikiService
include Madeleine::Automatic::Interceptor
# These methods do not change the state of persistent objects, and
# should not be ogged by Madeleine
automatic_read_only :authenticate, :read_page, :setup?, :webs, :storage_path, :file_yard
@@storage_path = './storage/'
class << self
def storage_path=(storage_path)
@@storage_path = storage_path
end
def storage_path
@@storage_path
end
def clean_storage
MadeleineServer.clean_storage(self)
end
def instance
@madeleine ||= MadeleineServer.new(self)
@system = @madeleine.system
return @system
end
def snapshot
@madeleine.snapshot
end
end
def initialize
init_wiki_service
end
end
class MadeleineServer
attr_reader :storage_path
# Clears all the command_log and snapshot files located in the storage directory, so the
# database is essentially dropped and recreated as blank
def self.clean_storage(service)
begin
Dir.foreach(service.storage_path) do |file|
if file =~ /(command_log|snapshot)$/
File.delete(File.join(service.storage_path, file))
end
end
rescue
Dir.mkdir(service.storage_path)
end
end
def initialize(service)
@storage_path = service.storage_path
@server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path,
Madeleine::ZMarshal.new) {
service.new
}
start_snapshot_thread
end
def command_log_present?
not Dir[storage_path + '/*.command_log'].empty?
end
def snapshot
@server.take_snapshot
end
def start_snapshot_thread
Thread.new(@server) {
hours_since_last_snapshot = 0
while true
begin
hours_since_last_snapshot += 1
# Take a snapshot if there is a command log, or 24 hours
# have passed since the last snapshot
if command_log_present? or hours_since_last_snapshot >= 24
ActionController::Base.logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] " +
'Taking a Madeleine snapshot'
snapshot
hours_since_last_snapshot = 0
end
sleep(1.hour)
rescue => e
ActionController::Base.logger.error(e)
# wait for a minute (not to spoof the log with the same error)
# and go back into the loop, to keep trying
sleep(1.minute)
ActionController::Base.logger.info("Retrying to save a snapshot")
end
end
}
end
def system
@server.system
end
end
require 'open-uri'
require 'yaml'
require 'madeleine'
require 'madeleine/automatic'
require 'madeleine/zmarshal'
require 'web'
require 'page'
require 'author'
require 'file_yard'
module AbstractWikiService
attr_reader :webs, :system
def authenticate(password)
password == (@system[:password] || 'instiki')
end
def create_web(name, address, password = nil)
@webs[address] = Web.new(self, name, address, password) unless @webs[address]
end
def delete_web(address)
@webs[address] = nil
end
def file_yard(web)
raise "Web #{@web.name} does not belong to this wiki service" unless @webs.values.include?(web)
# TODO cache FileYards
FileYard.new("#{self.storage_path}/#{web.address}")
end
def init_wiki_service
@webs = {}
@system = {}
end
def read_page(web_address, page_name)
ApplicationController.logger.debug "Reading page '#{page_name}' from web '#{web_address}'"
web = @webs[web_address]
if web.nil?
ApplicationController.logger.debug "Web '#{web_address}' not found"
return nil
else
page = web.pages[page_name]
ApplicationController.logger.debug "Page '#{page_name}' #{page.nil? ? 'not' : ''} found"
return page
end
end
def remove_orphaned_pages(web_address)
@webs[web_address].remove_pages(@webs[web_address].select.orphaned_pages)
end
def revise_page(web_address, page_name, content, revised_on, author)
page = read_page(web_address, page_name)
page.revise(content, revised_on, author)
page
end
def rollback_page(web_address, page_name, revision_number, created_at, author_id = nil)
page = read_page(web_address, page_name)
page.rollback(revision_number, created_at, author_id)
page
end
def setup(password, web_name, web_address)
@system[:password] = password
create_web(web_name, web_address)
end
def setup?
not (@webs.empty?)
end
def update_web(old_address, new_address, name, markup, color, additional_style, safe_mode = false,
password = nil, published = false, brackets_only = false, count_pages = false,
allow_uploads = true)
if old_address != new_address
@webs[new_address] = @webs[old_address]
@webs.delete(old_address)
@webs[new_address].address = new_address
end
web = @webs[new_address]
web.refresh_revisions if settings_changed?(web, markup, safe_mode, brackets_only)
web.name, web.markup, web.color, web.additional_style, web.safe_mode =
name, markup, color, additional_style, safe_mode
web.password, web.published, web.brackets_only, web.count_pages, web.allow_uploads =
password, published, brackets_only, count_pages, allow_uploads
end
def write_page(web_address, page_name, content, written_on, author)
page = Page.new(@webs[web_address], page_name, content, written_on, author)
@webs[web_address].add_page(page)
page
end
def storage_path
self.class.storage_path
end
private
def settings_changed?(web, markup, safe_mode, brackets_only)
web.markup != markup ||
web.safe_mode != safe_mode ||
web.brackets_only != brackets_only
end
end
class WikiService
include AbstractWikiService
include Madeleine::Automatic::Interceptor
# These methods do not change the state of persistent objects, and
# should not be ogged by Madeleine
automatic_read_only :authenticate, :read_page, :setup?, :webs, :storage_path, :file_yard
@@storage_path = './storage/'
class << self
def storage_path=(storage_path)
@@storage_path = storage_path
end
def storage_path
@@storage_path
end
def clean_storage
MadeleineServer.clean_storage(self)
end
def instance
@madeleine ||= MadeleineServer.new(self)
@system = @madeleine.system
return @system
end
def snapshot
@madeleine.snapshot
end
end
def initialize
init_wiki_service
end
end
class MadeleineServer
attr_reader :storage_path
# Clears all the command_log and snapshot files located in the storage directory, so the
# database is essentially dropped and recreated as blank
def self.clean_storage(service)
begin
Dir.foreach(service.storage_path) do |file|
if file =~ /(command_log|snapshot)$/
File.delete(File.join(service.storage_path, file))
end
end
rescue
Dir.mkdir(service.storage_path)
end
end
def initialize(service)
@storage_path = service.storage_path
@server = Madeleine::Automatic::AutomaticSnapshotMadeleine.new(service.storage_path,
Madeleine::ZMarshal.new) {
service.new
}
start_snapshot_thread
end
def command_log_present?
not Dir[storage_path + '/*.command_log'].empty?
end
def snapshot
@server.take_snapshot
end
def start_snapshot_thread
Thread.new(@server) {
hours_since_last_snapshot = 0
while true
begin
hours_since_last_snapshot += 1
# Take a snapshot if there is a command log, or 24 hours
# have passed since the last snapshot
if command_log_present? or hours_since_last_snapshot >= 24
ActionController::Base.logger.info "[#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] " +
'Taking a Madeleine snapshot'
snapshot
hours_since_last_snapshot = 0
end
sleep(1.hour)
rescue => e
ActionController::Base.logger.error(e)
# wait for a minute (not to spoof the log with the same error)
# and go back into the loop, to keep trying
sleep(1.minute)
ActionController::Base.logger.info("Retrying to save a snapshot")
end
end
}
end
def system
@server.system
end
end

46
app/models/wiki_words.rb Executable file → Normal file
View file

@ -1,23 +1,23 @@
# Contains all the methods for finding and replacing wiki words
module WikiWords
# In order of appearance: Latin, greek, cyrillian, armenian
I18N_HIGHER_CASE_LETTERS =
"À<EFBFBD>?ÂÃÄÅĀĄĂÆÇĆČĈĊĎ<C48A>?ÈÉÊËĒĘĚĔĖĜĞĠĢĤĦÌ<C4A6><>?ĪĨĬĮİIJĴĶ<C4B4>?ĽĹĻĿÑŃŇŅŊÒÓÔÕÖØŌ<C398>?ŎŒŔŘŖŚŠŞŜȘŤŢŦȚÙÚÛÜŪŮŰŬŨŲŴ<C5B2>?ŶŸŹŽŻ" +
"ΑΒΓΔΕΖΗΘΙΚΛΜ<EFBFBD>?ΞΟΠΡΣΤΥΦΧΨΩ" +
"ΆΈΉΊΌΎ<EFBFBD>?ѠѢѤѦѨѪѬѮѰѲѴѶѸѺѼѾҀҊҌҎ<D28C>?ҒҔҖҘҚҜҞҠҢҤҦҨҪҬҮҰҲҴҶҸҺҼҾ<D2BC>?ӃӅӇӉӋ<D389>?<3F>?ӒӔӖӘӚӜӞӠӢӤӦӨӪӬӮӰӲӴӸЖ" +
"ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀ<EFBFBD>?ՂՃՄՅՆՇՈՉՊՋՌ<D58B>?<3F>?<3F>?ՑՒՓՔՕՖ"
I18N_LOWER_CASE_LETTERS =
"àáâãäå<EFBFBD>?ąăæçć<C3A7>?ĉċ<C489>?đèéêëēęěĕėƒ<C497>?ğġģĥħìíîïīĩĭįıijĵķĸłľĺļŀñńňņʼnŋòóôõöø<C3B6><>?œŕřŗśšş<C5A1>?șťţŧțùúûüūůűŭũųŵýÿŷžżźÞþßſ<C39F>" +
"άέήίΰαβγδεζηθικλμνξοπ<EFBFBD>στυφχψωϊϋό<CF8B><>?" +
"абвгдежзийклмнопр<EFBFBD>уфхцчшщъыь<D18B><>?<3F>?ёђѓєѕіїјљћќ<D19B>?ўџѡѣѥѧѩѫѭѯѱѳѵѷѹѻѽѿ<D1BD><>?<3F>?ґғҕҗҙқ<D299>?ҟҡңҥҧҩҫҭүұҳҵҷҹһҽҿӀӂӄӆӈӊӌӎӑӓӕӗәӛ<D399>?ӟӡӣӥӧөӫӭӯӱӳӵӹ" +
"աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտր<EFBFBD>?ւփքօֆև"
WIKI_WORD_PATTERN = '[A-Z' + I18N_HIGHER_CASE_LETTERS + '][a-z' + I18N_LOWER_CASE_LETTERS + ']+[A-Z' + I18N_HIGHER_CASE_LETTERS + ']\w+'
CAMEL_CASED_WORD_BORDER = /([a-z#{I18N_LOWER_CASE_LETTERS}])([A-Z#{I18N_HIGHER_CASE_LETTERS}])/u
def self.separate(wiki_word)
wiki_word.gsub(CAMEL_CASED_WORD_BORDER, '\1 \2')
end
end
# Contains all the methods for finding and replacing wiki words
module WikiWords
# In order of appearance: Latin, greek, cyrillian, armenian
I18N_HIGHER_CASE_LETTERS =
"À<EFBFBD>?ÂÃÄÅĀĄĂÆÇĆČĈĊĎ<C48A>?ÈÉÊËĒĘĚĔĖĜĞĠĢĤĦÌ<C4A6><>?ĪĨĬĮİIJĴĶ<C4B4>?ĽĹĻĿÑŃŇŅŊÒÓÔÕÖØŌ<C398>?ŎŒŔŘŖŚŠŞŜȘŤŢŦȚÙÚÛÜŪŮŰŬŨŲŴ<C5B2>?ŶŸŹŽŻ" +
"ΑΒΓΔΕΖΗΘΙΚΛΜ<EFBFBD>?ΞΟΠΡΣΤΥΦΧΨΩ" +
"ΆΈΉΊΌΎ<EFBFBD>?ѠѢѤѦѨѪѬѮѰѲѴѶѸѺѼѾҀҊҌҎ<D28C>?ҒҔҖҘҚҜҞҠҢҤҦҨҪҬҮҰҲҴҶҸҺҼҾ<D2BC>?ӃӅӇӉӋ<D389>?<3F>?ӒӔӖӘӚӜӞӠӢӤӦӨӪӬӮӰӲӴӸЖ" +
"ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀ<EFBFBD>?ՂՃՄՅՆՇՈՉՊՋՌ<D58B>?<3F>?<3F>?ՑՒՓՔՕՖ"
I18N_LOWER_CASE_LETTERS =
"àáâãäå<EFBFBD>?ąăæçć<C3A7>?ĉċ<C489>?đèéêëēęěĕėƒ<C497>?ğġģĥħìíîïīĩĭįıijĵķĸłľĺļŀñńňņʼnŋòóôõöø<C3B6><>?œŕřŗśšş<C5A1>?șťţŧțùúûüūůűŭũųŵýÿŷžżźÞþßſ<C39F>" +
"άέήίΰαβγδεζηθικλμνξοπ<EFBFBD>στυφχψωϊϋό<CF8B><>?" +
"абвгдежзийклмнопр<EFBFBD>уфхцчшщъыь<D18B><>?<3F>?ёђѓєѕіїјљћќ<D19B>?ўџѡѣѥѧѩѫѭѯѱѳѵѷѹѻѽѿ<D1BD><>?<3F>?ґғҕҗҙқ<D299>?ҟҡңҥҧҩҫҭүұҳҵҷҹһҽҿӀӂӄӆӈӊӌӎӑӓӕӗәӛ<D399>?ӟӡӣӥӧөӫӭӯӱӳӵӹ" +
"աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտր<EFBFBD>?ւփքօֆև"
WIKI_WORD_PATTERN = '[A-Z' + I18N_HIGHER_CASE_LETTERS + '][a-z' + I18N_LOWER_CASE_LETTERS + ']+[A-Z' + I18N_HIGHER_CASE_LETTERS + ']\w+'
CAMEL_CASED_WORD_BORDER = /([a-z#{I18N_LOWER_CASE_LETTERS}])([A-Z#{I18N_HIGHER_CASE_LETTERS}])/u
def self.separate(wiki_word)
wiki_word.gsub(CAMEL_CASED_WORD_BORDER, '\1 \2')
end
end

View file

@ -1,22 +1,22 @@
<%
@title = "Upload #{@file_name}"
@hide_navigatio = false
%>
<p>
<%= form_tag({}, {:multipart => true}) %>
<p>
File to upload:
<br/>
<input type="file" name="file" size="40" />
</p>
<p>
<input type="submit" value="Update" /> as
<input type="text" name="author" id="authorName" value="<%= @author %>"
onClick="this.value == 'AnonymousCoward' ? this.value = '' : true" />
<% if @page %>
| <a href="../file/">Cancel</a> <small>(unlocks page)</small>
<% end %>
</p>
<%= end_form_tag %>
<%
@title = "Upload #{@file_name}"
@hide_navigatio = false
%>
<p>
<%= form_tag({}, {:multipart => true}) %>
<p>
File to upload:
<br/>
<input type="file" name="file" size="40" />
</p>
<p>
<input type="submit" value="Update" /> as
<input type="text" name="author" id="authorName" value="<%= @author %>"
onClick="this.value == 'AnonymousCoward' ? this.value = '' : true" />
<% if @page %>
| <a href="../file/">Cancel</a> <small>(unlocks page)</small>
<% end %>
</p>
<%= end_form_tag %>
</p>

View file

@ -1,72 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
<% if @page and (@page.name == 'HomePage') and (%w( show published print ).include?(@action_name)) %>
<%= @web.name %>
<% elsif @web %>
<%= @title %> in <%= @web.name %>
<% else %>
<%= @title %>
<% end %>
</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1#pageName, .newWikiWord a, a.existingWikiWord, .newWikiWord a:hover, #TextileHelp h3 {
color: #<%= @web ? @web.color : "393" %>;
}
#Container, #Content {
width: <%= @content_width || "600" %>px;
}
<%= File.read(RAILS_ROOT + '/public/stylesheets/instiki.css') if @inline_style %>
</style>
<link rel="Stylesheet" href="/stylesheets/instiki.css" type="text/css" media="screen" />
<style type="text/css">
<%= @style_additions %>
<%= @web ? @web.additional_style : '' %>
</style>
</head>
<body>
<div id="Container">
<div id="Content">
<h1 id="pageName">
<% if @page and (@page.name == 'HomePage') and %w( show published print ).include?(@action_name) %>
<%= @web.name %>
<% elsif @web %>
<small><%= @web.name %></small><br />
<%= @title %>
<% else %>
<%= @title %>
<% end %>
</h1>
<% if @flash[:error] %> <div id="error">
<hr/><p><%= @flash[:error].to_s %></p><hr/></div>
<% end %>
<% if @flash[:info] %> <div id="info">
<hr/><p><%= @flash[:info].to_s %></p><hr/></div>
<% end %>
<%= render 'navigation' unless @web.nil? || @hide_navigation %>
<%= @content_for_layout %>
<div id="footer">
<hr/>
<p>This site is running on <a href="http://instiki.org/">Instiki</a></p>
<br/>
<p>Powered by <a href="http://rubyonrails.com/">Ruby on Rails</a></p>
</div>
</div> <!-- Content -->
</div> <!-- Container -->
</body>
</html>
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
<% if @page and (@page.name == 'HomePage') and (%w( show published print ).include?(@action_name)) %>
<%= @web.name %>
<% elsif @web %>
<%= @title %> in <%= @web.name %>
<% else %>
<%= @title %>
<% end %>
</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<style type="text/css">
h1#pageName, .newWikiWord a, a.existingWikiWord, .newWikiWord a:hover, #TextileHelp h3 {
color: #<%= @web ? @web.color : "393" %>;
}
#Container, #Content {
width: <%= @content_width || "600" %>px;
}
<%= File.read(RAILS_ROOT + '/public/stylesheets/instiki.css') if @inline_style %>
</style>
<link rel="Stylesheet" href="/stylesheets/instiki.css" type="text/css" media="screen" />
<style type="text/css">
<%= @style_additions %>
<%= @web ? @web.additional_style : '' %>
</style>
</head>
<body>
<div id="Container">
<div id="Content">
<h1 id="pageName">
<% if @page and (@page.name == 'HomePage') and %w( show published print ).include?(@action_name) %>
<%= @web.name %>
<% elsif @web %>
<small><%= @web.name %></small><br />
<%= @title %>
<% else %>
<%= @title %>
<% end %>
</h1>
<% if @flash[:error] %> <div id="error">
<hr/><p><%= @flash[:error].to_s %></p><hr/></div>
<% end %>
<% if @flash[:info] %> <div id="info">
<hr/><p><%= @flash[:info].to_s %></p><hr/></div>
<% end %>
<%= render 'navigation' unless @web.nil? || @hide_navigation %>
<%= @content_for_layout %>
<div id="footer">
<hr/>
<p>This site is running on <a href="http://instiki.org/">Instiki</a></p>
<br/>
<p>Powered by <a href="http://rubyonrails.com/">Ruby on Rails</a></p>
</div>
</div> <!-- Content -->
</div> <!-- Container -->
</body>
</html>

30
app/views/markdown_help.rhtml Executable file → Normal file
View file

@ -1,16 +1,16 @@
<div id="TextileHelp" style="float: right; width: 250px; margin-top: 5px">
<h3>Markdown formatting tips (<a target="_new" href="http://daringfireball.net/projects/markdown/syntax">advanced</a>)</h3>
<table cellspacing="0" cellpadding="0">
<tr><td>_your text_</td><td class="arrow">&rarr;</td><td><em>your text</em></td></tr>
<tr><td>**your text**</td><td class="arrow">&rarr;</td><td><strong>your text</strong></td></tr>
<tr><td>`my code`</td><td class="arrow">&rarr;</td><td><code>my code</code></td></tr>
<tr><td>* Bulleted list<br />* Second item</td><td class="arrow">&rarr;</td><td>&#8226; Bulleted list<br />&#8226; Second item</td></tr>
<tr><td>1. Numbered list<br />1. Second item</td><td class="arrow">&rarr;</td><td>1. Numbered list<br />2. Second item</td></tr>
<tr><td>[link name](URL)</td><td class="arrow">&rarr;</td><td><a href="URL">link name</a></td></tr>
<tr><td>***</td><td class="arrow">&rarr;</td><td>Horizontal ruler</td></tr>
<tr><td>&lt;http://url><br />&lt;email@add.com></td><td class="arrow">&rarr;</td><td>Auto-linked</td></tr>
<tr><td>![Alt text](URL)</td><td class="arrow">&rarr;</td><td>Image</td></tr>
</table>
<%= render 'wiki_words_help' %>
<div id="TextileHelp" style="float: right; width: 250px; margin-top: 5px">
<h3>Markdown formatting tips (<a target="_new" href="http://daringfireball.net/projects/markdown/syntax">advanced</a>)</h3>
<table cellspacing="0" cellpadding="0">
<tr><td>_your text_</td><td class="arrow">&rarr;</td><td><em>your text</em></td></tr>
<tr><td>**your text**</td><td class="arrow">&rarr;</td><td><strong>your text</strong></td></tr>
<tr><td>`my code`</td><td class="arrow">&rarr;</td><td><code>my code</code></td></tr>
<tr><td>* Bulleted list<br />* Second item</td><td class="arrow">&rarr;</td><td>&#8226; Bulleted list<br />&#8226; Second item</td></tr>
<tr><td>1. Numbered list<br />1. Second item</td><td class="arrow">&rarr;</td><td>1. Numbered list<br />2. Second item</td></tr>
<tr><td>[link name](URL)</td><td class="arrow">&rarr;</td><td><a href="URL">link name</a></td></tr>
<tr><td>***</td><td class="arrow">&rarr;</td><td>Horizontal ruler</td></tr>
<tr><td>&lt;http://url><br />&lt;email@add.com></td><td class="arrow">&rarr;</td><td>Auto-linked</td></tr>
<tr><td>![Alt text](URL)</td><td class="arrow">&rarr;</td><td>Image</td></tr>
</table>
<%= render 'wiki_words_help' %>
</div>

50
app/views/navigation.rhtml Executable file → Normal file
View file

@ -1,25 +1,25 @@
<%
def list_item(title, url, description, accesskey = nil)
if @title == title
"<b class=\"navOn\" title=\"#{description}\" accesskey=\"#{accesskey}\">#{title}</b>"
else
"<a href=\"#{url}\" title=\"#{description}\" accesskey=\"#{accesskey}\">#{title}</a>"
end
end
%>
<form id="navigationForm" class="navigation" action="../search/" method="get" style="font-size: 10px">
<% if @action_name != "published" then %>
<%= list_item "Home Page", "../show/HomePage", "Home, Sweet Home", "H" %> |
<%= list_item "All Pages", "../list/", "Alphabetically sorted list of pages", "A" %> |
<%= list_item "Recently Revised", "../recently_revised/", "Pages sorted by when they were last changed", "U" %> |
<%= list_item "Authors", "../authors/", "Who wrote what" %> |
<%= list_item "Feeds", "../feeds/", "Subscribe to changes by RSS" %> |
<%= list_item "Export", "../export/", "Download a zip with all the pages in this wiki", "X" %> |
<input type="text" id="searchField" name="query" style="font-size: 10px" value="Search" onClick="this.value == 'Search' ? this.value = '' : true" />
<% else %>
<%= list_item "Home Page", "../published/HomePage", "Home, Sweet Home", "H" %> |
<% end%>
</form>
<%
def list_item(title, url, description, accesskey = nil)
if @title == title
"<b class=\"navOn\" title=\"#{description}\" accesskey=\"#{accesskey}\">#{title}</b>"
else
"<a href=\"#{url}\" title=\"#{description}\" accesskey=\"#{accesskey}\">#{title}</a>"
end
end
%>
<form id="navigationForm" class="navigation" action="../search/" method="get" style="font-size: 10px">
<% if @action_name != "published" then %>
<%= list_item "Home Page", "../show/HomePage", "Home, Sweet Home", "H" %> |
<%= list_item "All Pages", "../list/", "Alphabetically sorted list of pages", "A" %> |
<%= list_item "Recently Revised", "../recently_revised/", "Pages sorted by when they were last changed", "U" %> |
<%= list_item "Authors", "../authors/", "Who wrote what" %> |
<%= list_item "Feeds", "../feeds/", "Subscribe to changes by RSS" %> |
<%= list_item "Export", "../export/", "Download a zip with all the pages in this wiki", "X" %> |
<input type="text" id="searchField" name="query" style="font-size: 10px" value="Search" onClick="this.value == 'Search' ? this.value = '' : true" />
<% else %>
<%= list_item "Home Page", "../published/HomePage", "Home, Sweet Home", "H" %> |
<% end%>
</form>

30
app/views/rdoc_help.rhtml Executable file → Normal file
View file

@ -1,16 +1,16 @@
<div id="TextileHelp" style="float: right; width: 250px; margin-top: 5px">
<h3>RDoc formatting tips (<a target="_new" href="http://rdoc.sourceforge.net/doc/files/markup/simple_markup_rb.html">advanced</a>)</h3>
<table cellspacing="0" cellpadding="0">
<tr><td>_your text_</td><td class="arrow">&rarr;</td><td><em>your text</em></td></tr>
<tr><td>*your text*</td><td class="arrow">&rarr;</td><td><strong>your text</strong></td></tr>
<tr><td>* Bulleted list<br />* Second item</td><td class="arrow">&rarr;</td><td>&#8226; Bulleted list<br />&#8226; Second item</td></tr>
<tr><td>1. Numbered list<br />2. Second item</td><td class="arrow">&rarr;</td><td>1. Numbered list<br />2. Second item</td></tr>
<tr><td>+my_code+</td><td class="arrow">&rarr;</td><td><code>my_code</code></td></tr>
<tr><td>---</td><td class="arrow">&rarr;</td><td>Horizontal ruler</td></tr>
<tr><td>[[URL linkname]]</td><td class="arrow">&rarr;</td><td><a href="URL">linkname</a></td></tr>
<tr><td>http://url<br />mailto:e@add.com</td><td class="arrow">&rarr;</td><td>Auto-linked</td></tr>
<tr><td>imageURL</td><td class="arrow">&rarr;</td><td>Image</td></tr>
</table>
<%= render 'wiki_words_help' %>
<div id="TextileHelp" style="float: right; width: 250px; margin-top: 5px">
<h3>RDoc formatting tips (<a target="_new" href="http://rdoc.sourceforge.net/doc/files/markup/simple_markup_rb.html">advanced</a>)</h3>
<table cellspacing="0" cellpadding="0">
<tr><td>_your text_</td><td class="arrow">&rarr;</td><td><em>your text</em></td></tr>
<tr><td>*your text*</td><td class="arrow">&rarr;</td><td><strong>your text</strong></td></tr>
<tr><td>* Bulleted list<br />* Second item</td><td class="arrow">&rarr;</td><td>&#8226; Bulleted list<br />&#8226; Second item</td></tr>
<tr><td>1. Numbered list<br />2. Second item</td><td class="arrow">&rarr;</td><td>1. Numbered list<br />2. Second item</td></tr>
<tr><td>+my_code+</td><td class="arrow">&rarr;</td><td><code>my_code</code></td></tr>
<tr><td>---</td><td class="arrow">&rarr;</td><td>Horizontal ruler</td></tr>
<tr><td>[[URL linkname]]</td><td class="arrow">&rarr;</td><td><a href="URL">linkname</a></td></tr>
<tr><td>http://url<br />mailto:e@add.com</td><td class="arrow">&rarr;</td><td>Auto-linked</td></tr>
<tr><td>imageURL</td><td class="arrow">&rarr;</td><td>Image</td></tr>
</table>
<%= render 'wiki_words_help' %>
</div>

54
app/views/textile_help.rhtml Executable file → Normal file
View file

@ -1,28 +1,28 @@
<div id="TextileHelp" style="float: right; width: 250px; margin-top: 5px">
<h3>Textile formatting tips (<a href="#" onClick="quickRedReference(); return false;">advanced</a>)</h3>
<table cellspacing="0" cellpadding="0">
<tr><td>_your text_</td><td class="arrow">&rarr;</td><td><em>your text</em></td></tr>
<tr><td>*your text*</td><td class="arrow">&rarr;</td><td><strong>your text</strong></td></tr>
<tr><td>%{color:red}hello%</td><td class="arrow">&rarr;</td><td><span style="color: red;">hello</span></td></tr>
<tr><td>* Bulleted list<br />* Second item</td><td class="arrow">&rarr;</td><td>&#8226; Bulleted list<br />&#8226; Second item</td></tr>
<tr><td># Numbered list<br /># Second item</td><td class="arrow">&rarr;</td><td>1. Numbered list<br />2. Second item</td></tr>
<tr><td>"linkname":URL</td><td class="arrow">&rarr;</td><td><a href="URL">linkname</a></td></tr>
<tr><td>|a|table|row|<br />|b|table|row|</td><td class="arrow">&rarr;</td><td>Table</td></tr>
<tr><td>http://url<br />email@address.com</td><td class="arrow">&rarr;</td><td>Auto-linked</td></tr>
<tr><td>!imageURL!</td><td class="arrow">&rarr;</td><td>Image</td></tr>
</table>
<%= render 'wiki_words_help' %>
</div>
<script language="JavaScript">
function quickRedReference() {
window.open(
"http://hobix.com/textile/quick.html",
"redRef",
"height=600,width=550,channelmode=0,dependent=0," +
"directories=0,fullscreen=0,location=0,menubar=0," +
"resizable=0,scrollbars=1,status=1,toolbar=0"
);
}
<div id="TextileHelp" style="float: right; width: 250px; margin-top: 5px">
<h3>Textile formatting tips (<a href="#" onClick="quickRedReference(); return false;">advanced</a>)</h3>
<table cellspacing="0" cellpadding="0">
<tr><td>_your text_</td><td class="arrow">&rarr;</td><td><em>your text</em></td></tr>
<tr><td>*your text*</td><td class="arrow">&rarr;</td><td><strong>your text</strong></td></tr>
<tr><td>%{color:red}hello%</td><td class="arrow">&rarr;</td><td><span style="color: red;">hello</span></td></tr>
<tr><td>* Bulleted list<br />* Second item</td><td class="arrow">&rarr;</td><td>&#8226; Bulleted list<br />&#8226; Second item</td></tr>
<tr><td># Numbered list<br /># Second item</td><td class="arrow">&rarr;</td><td>1. Numbered list<br />2. Second item</td></tr>
<tr><td>"linkname":URL</td><td class="arrow">&rarr;</td><td><a href="URL">linkname</a></td></tr>
<tr><td>|a|table|row|<br />|b|table|row|</td><td class="arrow">&rarr;</td><td>Table</td></tr>
<tr><td>http://url<br />email@address.com</td><td class="arrow">&rarr;</td><td>Auto-linked</td></tr>
<tr><td>!imageURL!</td><td class="arrow">&rarr;</td><td>Image</td></tr>
</table>
<%= render 'wiki_words_help' %>
</div>
<script language="JavaScript">
function quickRedReference() {
window.open(
"http://hobix.com/textile/quick.html",
"redRef",
"height=600,width=550,channelmode=0,dependent=0," +
"directories=0,fullscreen=0,location=0,menubar=0," +
"resizable=0,scrollbars=1,status=1,toolbar=0"
);
}
</script>

22
app/views/wiki/authors.rhtml Executable file → Normal file
View file

@ -1,11 +1,11 @@
<% @title = 'Authors' %>
<ul id="authorList">
<% for author in @authors %>
<li>
<%= @web.make_link(author) %>
co- or authored:
<%= @web.select.pages_authored_by(author).collect { |page| page.link }.join ', ' %>
</li>
<% end %>
</ul>
<% @title = 'Authors' %>
<ul id="authorList">
<% for author in @authors %>
<li>
<%= @web.make_link(author) %>
co- or authored:
<%= @web.select.pages_authored_by(author).collect { |page| page.link }.join ', ' %>
</li>
<% end %>
</ul>

58
app/views/wiki/edit.rhtml Executable file → Normal file
View file

@ -1,29 +1,29 @@
<%
@title = "Editing #{@page.name}"
@content_width = 720
@hide_navigation = true
%>
<%= "<p style='color:red'>Please correct the error that caused this error in rendering:<br/><small>#{@params["msg"]}</small></p>" if @params["msg"] %>
<%= render("#{@web.markup}_help") if @web %>
<form id="editForm" action="../save/<%= @page.name %>" method="post" onSubmit="cleanAuthorName();">
<p>
<textarea name="content" style="width: 450px; height: 500px"><%= @page.content %></textarea>
</p>
<p>
<input type="submit" value="Update" /> as
<input type="text" name="author" id="authorName" value="<%= @author %>"
onClick="this.value == 'AnonymousCoward' ? this.value = '' : true" />
| <a href="../cancel_edit/<%= @page.name %>">Cancel</a> <small>(unlocks page)</small>
</p>
</form>
<script language="JavaScript1.2">
function cleanAuthorName() {
if (document.getElementById('authorName').value == "") {
document.getElementById('authorName').value = 'AnonymousCoward';
}
}
</script>
<%
@title = "Editing #{@page.name}"
@content_width = 720
@hide_navigation = true
%>
<%= "<p style='color:red'>Please correct the error that caused this error in rendering:<br/><small>#{@params["msg"]}</small></p>" if @params["msg"] %>
<%= render("#{@web.markup}_help") if @web %>
<form id="editForm" action="../save/<%= @page.name %>" method="post" onSubmit="cleanAuthorName();">
<p>
<textarea name="content" style="width: 450px; height: 500px"><%= @page.content %></textarea>
</p>
<p>
<input type="submit" value="Update" /> as
<input type="text" name="author" id="authorName" value="<%= @author %>"
onClick="this.value == 'AnonymousCoward' ? this.value = '' : true" />
| <a href="../cancel_edit/<%= @page.name %>">Cancel</a> <small>(unlocks page)</small>
</p>
</form>
<script language="JavaScript1.2">
function cleanAuthorName() {
if (document.getElementById('authorName').value == "") {
document.getElementById('authorName').value = 'AnonymousCoward';
}
}
</script>

234
app/views/wiki/edit_web.rhtml Executable file → Normal file
View file

@ -1,117 +1,117 @@
<% @title = "Edit Web" %>
<form action="../update_web" id="setup" method="post" onSubmit="cleanAddress(); return validateSetup()">
<h2 style="margin-bottom: 3px">Name and address</h2>
<div class="help">
The name of the web is included in the title on all pages.
The address is the base path that all pages within the web live beneath.
Ex: the address "rails" gives URLs like <i>/rails/show/HomePage</i>.
</div>
<div class="inputBox, disableAutoComplete">
Name: <input type="text" id="name" name="name" value="<%= @web.name %>"
onChange="proposeAddress();" /> &nbsp;&nbsp;
Address: <input type="text" id="address" name="address" value="<%= @web.address %>"
onChange="cleanAddress();" />
<i>(Letters and digits only)</i>
</div>
<h2 style="margin-bottom: 3px">Specialize</h2>
<div class="help">
Turning safe mode on will strip HTML tags and stylesheet options from the content of all pages.
Turning on "brackets only" will require all wiki words to be as [[wiki word]] and WikiWord
won't work.
Turning "allow uploads" on will let wiki users to upload pictures and other files to the wiki
and include them on wiki pages.
Additions to the stylesheet take precedence over the existing styles.
<i>Hint:</i> View source on a page you want to style to find ID names on individual tags.
<a href="#" onClick="document.getElementById('additionalStyle').style.display='block';return false;">
See styles &gt;&gt;
</a>
</div>
<div class="inputBox, disableAutoComplete">
Markup:
<select name="markup">
<%= html_options({"Textile" => :textile, "Markdown" => :markdown, "RDoc" => :rdoc },
@web.markup) %>
</select>
&nbsp;&nbsp;
Color:
<select name="color">
<%= html_options({ "Green" => "008B26", "Purple" => "504685", "Red" => "DA0006",
"Orange" => "FA6F00", "Grey" => "8BA2B0" }, @web.color) %>
</select>
&nbsp;&nbsp;
<small>
<input type="checkbox" name="safe_mode" <%= 'checked="on"' if @web.safe_mode %> /> Safe mode
&nbsp;&nbsp;
<input type="checkbox" name="brackets_only" <%= 'checked="on"' if @web.brackets_only %> />
Brackets only
&nbsp;&nbsp;
<input type="checkbox" name="count_pages" <%= 'checked="on"' if @web.count_pages %> /> Count pages
&nbsp;&nbsp;
<input type="checkbox" name="allow_uploads" <%= 'checked="on"' if @web.allow_uploads %> /> Allow uploads
</small>
<textarea id="additionalStyle"
style="display: none; margin-top: 10px; margin-bottom: 5px; width: 560px; height: 200px"
name="additional_style"><%= @web.additional_style %>
</textarea>
</div>
<h2 style="margin-bottom: 3px">Password protection for this web (<%= @web.name %>)</h2>
<div class="help">
This is the password that visitors need to view and edit this web.
Setting the password to nothing will remove the password protection.
</div>
<div class="inputBox">
Password: <input class="disableAutoComplete" type="password" id="password"
name="password" value="<%= @web.password %>" />
&nbsp;&nbsp;
Verify: <input class="disableAutoComplete" type="password" id="password_check"
value="<%= @web.password %>" name="password_check" />
</div>
<h2 style="margin-bottom: 3px">Publish read-only version of this web (<%= @web.name %>)</h2>
<div class="help">
You can turn on a read-only version of this web that's accessible even when the regular web
is password protected.
The published version is accessible through URLs like /wiki/published/HomePage.
</div>
<div class="inputBox">
<input type="checkbox" name="published" <%= 'checked="on"' if @web.published %> /> Publish this web
</div>
<p align="right">
<small>
Enter system password
<input type="password" class="disableAutoComplete" id="system_password" name="system_password" />
and
<input type="submit" value="Update Web" />
<br/><br/>
...or forget changes and <a href="/new_web/">create a new web</a>
</small>
</p>
</form>
<br/>
<h1>Other administrative tasks</h1>
<form action="../remove_orphaned_pages" id="remove_orphaned_pages" method="post">
<p align="right">
<small>
Clean up by entering system password
<input type="password" id="system_password" name="system_password" />
and
<input type="submit" value="Delete Orphan Pages" />
</small>
</p>
</form>
<script type="text/javascript" src="/javascripts/edit_web.js" />
<script type="text/javascript">overrideAutocomplete()</script>
<% @title = "Edit Web" %>
<form action="../update_web" id="setup" method="post" onSubmit="cleanAddress(); return validateSetup()">
<h2 style="margin-bottom: 3px">Name and address</h2>
<div class="help">
The name of the web is included in the title on all pages.
The address is the base path that all pages within the web live beneath.
Ex: the address "rails" gives URLs like <i>/rails/show/HomePage</i>.
</div>
<div class="inputBox, disableAutoComplete">
Name: <input type="text" id="name" name="name" value="<%= @web.name %>"
onChange="proposeAddress();" /> &nbsp;&nbsp;
Address: <input type="text" id="address" name="address" value="<%= @web.address %>"
onChange="cleanAddress();" />
<i>(Letters and digits only)</i>
</div>
<h2 style="margin-bottom: 3px">Specialize</h2>
<div class="help">
Turning safe mode on will strip HTML tags and stylesheet options from the content of all pages.
Turning on "brackets only" will require all wiki words to be as [[wiki word]] and WikiWord
won't work.
Turning "allow uploads" on will let wiki users to upload pictures and other files to the wiki
and include them on wiki pages.
Additions to the stylesheet take precedence over the existing styles.
<i>Hint:</i> View source on a page you want to style to find ID names on individual tags.
<a href="#" onClick="document.getElementById('additionalStyle').style.display='block';return false;">
See styles &gt;&gt;
</a>
</div>
<div class="inputBox, disableAutoComplete">
Markup:
<select name="markup">
<%= html_options({"Textile" => :textile, "Markdown" => :markdown, "RDoc" => :rdoc },
@web.markup) %>
</select>
&nbsp;&nbsp;
Color:
<select name="color">
<%= html_options({ "Green" => "008B26", "Purple" => "504685", "Red" => "DA0006",
"Orange" => "FA6F00", "Grey" => "8BA2B0" }, @web.color) %>
</select>
&nbsp;&nbsp;
<small>
<input type="checkbox" name="safe_mode" <%= 'checked="on"' if @web.safe_mode %> /> Safe mode
&nbsp;&nbsp;
<input type="checkbox" name="brackets_only" <%= 'checked="on"' if @web.brackets_only %> />
Brackets only
&nbsp;&nbsp;
<input type="checkbox" name="count_pages" <%= 'checked="on"' if @web.count_pages %> /> Count pages
&nbsp;&nbsp;
<input type="checkbox" name="allow_uploads" <%= 'checked="on"' if @web.allow_uploads %> /> Allow uploads
</small>
<textarea id="additionalStyle"
style="display: none; margin-top: 10px; margin-bottom: 5px; width: 560px; height: 200px"
name="additional_style"><%= @web.additional_style %>
</textarea>
</div>
<h2 style="margin-bottom: 3px">Password protection for this web (<%= @web.name %>)</h2>
<div class="help">
This is the password that visitors need to view and edit this web.
Setting the password to nothing will remove the password protection.
</div>
<div class="inputBox">
Password: <input class="disableAutoComplete" type="password" id="password"
name="password" value="<%= @web.password %>" />
&nbsp;&nbsp;
Verify: <input class="disableAutoComplete" type="password" id="password_check"
value="<%= @web.password %>" name="password_check" />
</div>
<h2 style="margin-bottom: 3px">Publish read-only version of this web (<%= @web.name %>)</h2>
<div class="help">
You can turn on a read-only version of this web that's accessible even when the regular web
is password protected.
The published version is accessible through URLs like /wiki/published/HomePage.
</div>
<div class="inputBox">
<input type="checkbox" name="published" <%= 'checked="on"' if @web.published %> /> Publish this web
</div>
<p align="right">
<small>
Enter system password
<input type="password" class="disableAutoComplete" id="system_password" name="system_password" />
and
<input type="submit" value="Update Web" />
<br/><br/>
...or forget changes and <a href="/new_web/">create a new web</a>
</small>
</p>
</form>
<br/>
<h1>Other administrative tasks</h1>
<form action="../remove_orphaned_pages" id="remove_orphaned_pages" method="post">
<p align="right">
<small>
Clean up by entering system password
<input type="password" id="system_password" name="system_password" />
and
<input type="submit" value="Delete Orphan Pages" />
</small>
</p>
</form>
<script type="text/javascript" src="/javascripts/edit_web.js" />
<script type="text/javascript">overrideAutocomplete()</script>

24
app/views/wiki/export.rhtml Executable file → Normal file
View file

@ -1,12 +1,12 @@
<% @title = "Export" %>
<p>You can export all the pages in this web as a zip file in either HTML (with working links and all) or the pure markup (to import in another wiki).</p>
<ul id="feedsList">
<li><a href="../export_html">HTML</a>
<li><a href="../export_markup">Markup (<%= @web.markup %>)</a>
<% if OPTIONS[:pdflatex] && @web.markup == :textile %>
<li><a href="../export_tex">TeX</a>
<li><a href="../export_pdf">PDF</a>
<% end %>
</ul>
<% @title = "Export" %>
<p>You can export all the pages in this web as a zip file in either HTML (with working links and all) or the pure markup (to import in another wiki).</p>
<ul id="feedsList">
<li><a href="../export_html">HTML</a>
<li><a href="../export_markup">Markup (<%= @web.markup %>)</a>
<% if OPTIONS[:pdflatex] && @web.markup == :textile %>
<li><a href="../export_tex">TeX</a>
<li><a href="../export_pdf">PDF</a>
<% end %>
</ul>

16
app/views/wiki/feeds.rhtml Executable file → Normal file
View file

@ -1,8 +1,8 @@
<% @title = "Feeds" %>
<p>You can subscribe to this wiki by RSS and get either just the headlines of the pages that change or the entire page.</p>
<ul id="feedsList">
<li><a href="../rss_with_content<%= "?password=#{web.password}" if @web.password %>">Full content (RSS 2.0)</a>
<li><a href="../rss_with_headlines<%= "?password=#{web.password}" if @web.password %>">Headlines (RSS 2.0)</a>
</ul>
<% @title = "Feeds" %>
<p>You can subscribe to this wiki by RSS and get either just the headlines of the pages that change or the entire page.</p>
<ul id="feedsList">
<li><a href="../rss_with_content<%= "?password=#{web.password}" if @web.password %>">Full content (RSS 2.0)</a>
<li><a href="../rss_with_headlines<%= "?password=#{web.password}" if @web.password %>">Headlines (RSS 2.0)</a>
</ul>

114
app/views/wiki/list.rhtml Executable file → Normal file
View file

@ -1,57 +1,57 @@
<% @title = "All Pages" %>
<% unless @categories.empty? %>
<div id="categories">
<strong>Categories</strong>:
[<a href=".">Any</a>]
<%= @category_links.join(', ') %>
</div>
<% end %>
<div id="allPages" style="float: left; width: 280px; margin-right: 30px">
<% unless @pages_that_are_orphaned.empty? && @page_names_that_are_wanted.empty? %>
<h2>
All Pages
<br/><small style="font-size: 12px"><i>All pages in <%= @set_name %> listed alphabetically</i></small>
</h2>
<% end %>
<ul><% for page in @pages_by_name %>
<li><a href="../show/<%= page.name %>"><%= truncate(page.plain_name, 35) %></a></li>
<% end %></ul>
<% if @web.count_pages %>
<% total_chars = @pages_in_category.characters %>
<p><small>All content: <%= total_chars %> chars / <%= sprintf("%-.1f", (total_chars / 2275 )) %> pages</small></p>
<% end %>
</div>
<div style="float: left; width: 280px">
<% unless @page_names_that_are_wanted.empty? %>
<h2>
Wanted Pages
<br/><small style="font-size: 12px"><i>Unexisting pages that other pages in <%= @set_name %> reference</i></small>
</h2>
<ul style="margin-bottom: 10px">
<% for page_name in @page_names_that_are_wanted %>
<li>
<a href="../show/<%= page_name %>"><%= truncate(WikiWords.separate(page_name), 35) %></a>
wanted by
<%= @web.select.pages_that_reference(page_name).collect { |page| page.link }.join(", ") %>
</li>
<% end %>
</ul>
<% end %>
<% unless @pages_that_are_orphaned.empty? %>
<h2>
Orphaned Pages
<br/><small style="font-size: 12px"><i>Pages in <%= @set_name %> that no other page reference</i></small>
</h2>
<ul style="margin-bottom: 35px">
<% for page in @pages_that_are_orphaned %><li><a href="../show/<%= page.name %>"><%= truncate(page.plain_name, 35) %></a></li><% end %>
</ul>
<% end %>
</div>
<% @title = "All Pages" %>
<% unless @categories.empty? %>
<div id="categories">
<strong>Categories</strong>:
[<a href=".">Any</a>]
<%= @category_links.join(', ') %>
</div>
<% end %>
<div id="allPages" style="float: left; width: 280px; margin-right: 30px">
<% unless @pages_that_are_orphaned.empty? && @page_names_that_are_wanted.empty? %>
<h2>
All Pages
<br/><small style="font-size: 12px"><i>All pages in <%= @set_name %> listed alphabetically</i></small>
</h2>
<% end %>
<ul><% for page in @pages_by_name %>
<li><a href="../show/<%= page.name %>"><%= truncate(page.plain_name, 35) %></a></li>
<% end %></ul>
<% if @web.count_pages %>
<% total_chars = @pages_in_category.characters %>
<p><small>All content: <%= total_chars %> chars / <%= sprintf("%-.1f", (total_chars / 2275 )) %> pages</small></p>
<% end %>
</div>
<div style="float: left; width: 280px">
<% unless @page_names_that_are_wanted.empty? %>
<h2>
Wanted Pages
<br/><small style="font-size: 12px"><i>Unexisting pages that other pages in <%= @set_name %> reference</i></small>
</h2>
<ul style="margin-bottom: 10px">
<% for page_name in @page_names_that_are_wanted %>
<li>
<a href="../show/<%= page_name %>"><%= truncate(WikiWords.separate(page_name), 35) %></a>
wanted by
<%= @web.select.pages_that_reference(page_name).collect { |page| page.link }.join(", ") %>
</li>
<% end %>
</ul>
<% end %>
<% unless @pages_that_are_orphaned.empty? %>
<h2>
Orphaned Pages
<br/><small style="font-size: 12px"><i>Pages in <%= @set_name %> that no other page reference</i></small>
</h2>
<ul style="margin-bottom: 35px">
<% for page in @pages_that_are_orphaned %><li><a href="../show/<%= page.name %>"><%= truncate(page.plain_name, 35) %></a></li><% end %>
</ul>
<% end %>
</div>

40
app/views/wiki/locked.rhtml Executable file → Normal file
View file

@ -1,20 +1,20 @@
<% @title = "#{@page.plain_name} is locked" %>
<% if @page.lock_duration(Time.now) == 0 %>
<p><%= @page.locked_by_link %> just started editing this page.</p>
<% else %>
<p><%= @page.locked_by_link %> has been editing this page for <%= @page.lock_duration(Time.now) %> minutes.</p>
<% end %>
<p>
<%= link_to 'Edit the page anyway',
{:web => @web_name, :action => 'edit', :id => @page.name, :params => {'break_lock' => '1'} },
{:accesskey => 'E'}
%>
<%= link_to 'Cancel',
{:web => @web_name, :action => 'show', :id => @page.name},
{:accesskey => 'C'}
%>
</p>
<% @title = "#{@page.plain_name} is locked" %>
<% if @page.lock_duration(Time.now) == 0 %>
<p><%= @page.locked_by_link %> just started editing this page.</p>
<% else %>
<p><%= @page.locked_by_link %> has been editing this page for <%= @page.lock_duration(Time.now) %> minutes.</p>
<% end %>
<p>
<%= link_to 'Edit the page anyway',
{:web => @web_name, :action => 'edit', :id => @page.name, :params => {'break_lock' => '1'} },
{:accesskey => 'E'}
%>
<%= link_to 'Cancel',
{:web => @web_name, :action => 'show', :id => @page.name},
{:accesskey => 'C'}
%>
</p>

16
app/views/wiki/login.rhtml Executable file → Normal file
View file

@ -1,8 +1,8 @@
<% @title = "#{@web_name} Login" %><% @hide_navigation = true %>
<form action="authenticate" method="post">
<p>
<b>Password</b><br />
<input type="password" name="password" />
</p>
</form>
<% @title = "#{@web_name} Login" %><% @hide_navigation = true %>
<form action="authenticate" method="post">
<p>
<b>Password</b><br />
<input type="password" name="password" />
</p>
</form>

50
app/views/wiki/new.rhtml Executable file → Normal file
View file

@ -1,25 +1,25 @@
<%
@title = "Creating #{WikiWords.separate(CGI.unescape(@page_name))}"
@content_width = 720
@hide_navigation = true
%>
<%= render("#{@web.markup}_help") if @web %>
<form action="../save/<%= @page_name %>" method="post" onSubmit="cleanAuthorName();">
<p>
<textarea name="content" style="width: 450px; height: 500px"></textarea>
</p>
<p>
<input type="submit" value="Create" /> as
<input type="text" name="author" id="authorName" value="<%= @author %>" onClick="this.value == 'AnonymousCoward' ? this.value = '' : true" />
</p>
</form>
<script language="JavaScript1.2">
function cleanAuthorName() {
if (document.getElementById('authorName').value == "") {
document.getElementById('authorName').value = 'AnonymousCoward';
}
}
</script>
<%
@title = "Creating #{WikiWords.separate(CGI.unescape(@page_name))}"
@content_width = 720
@hide_navigation = true
%>
<%= render("#{@web.markup}_help") if @web %>
<form action="../save/<%= @page_name %>" method="post" onSubmit="cleanAuthorName();">
<p>
<textarea name="content" style="width: 450px; height: 500px"></textarea>
</p>
<p>
<input type="submit" value="Create" /> as
<input type="text" name="author" id="authorName" value="<%= @author %>" onClick="this.value == 'AnonymousCoward' ? this.value = '' : true" />
</p>
</form>
<script language="JavaScript1.2">
function cleanAuthorName() {
if (document.getElementById('authorName').value == "") {
document.getElementById('authorName').value = 'AnonymousCoward';
}
}
</script>

166
app/views/wiki/new_system.rhtml Executable file → Normal file
View file

@ -1,83 +1,83 @@
<% @title = "Instiki Setup"; @content_width = 500 %>
<p>
Congratulations on succesfully installing and starting Instiki.
Since this is the first time Instiki has been run on this port,
you'll need to do a brief one-time setup.
</p>
<form action="../create_system" id="setup" method="post" onSubmit="return validateSetup()">
<ol class="setup">
<li>
<h2 style="margin-bottom: 3px">Name and address for your first web</h2>
<div class="help">
The name of the web is included in the title on all pages.
The address is the base path that all pages within the web live beneath.
Ex: the address "rails" gives URLs like <i>/rails/show/HomePage</i>.
The address can only consist of letters and digits.
</div>
<div class="inputBox">
Name: <input type="text" id="web_name" name="web_name" value="Wiki"
onChange="proposeAddress();" onClick="this.value == 'Wiki' ? this.value = '' : true" />
&nbsp;&nbsp;
Address: <input type="text" id="web_address" name="web_address" onChange="cleanAddress();"
value="wiki" />
</div>
</li>
<li>
<h2 style="margin-bottom: 3px">Password for creating and changing webs</h2>
<div class="help">
Administrative access allows you to make new webs and change existing ones.<br/>
Everyone with this password will be able to do this, so pick it carefully.
</div>
<div class="inputBox">
Password: <input type="password" id="password" name="password" />
&nbsp;&nbsp;
Verify: <input type="password" id="password_check" name="password_check" />
</div>
</li>
</ol>
<p align="right">
<input type="submit" value="Setup" style="margin-left: 40px" />
</p>
</form>
<script>
function proposeAddress() {
document.getElementById('web_address').value =
document.getElementById('web_name').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function cleanAddress() {
document.getElementById('web_address').value =
document.getElementById('web_address').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function validateSetup() {
if (document.getElementById('web_name').value == "") {
alert("You must pick a name for the first web");
return false;
}
if (document.getElementById('web_address').value == "") {
alert("You must pick an address for the first web");
return false;
}
if (document.getElementById('password').value == "") {
alert("You must pick a system password");
return false;
}
if (document.getElementById('password_check').value == "" ||
document.getElementById('password').value != document.getElementById('password_check').value) {
alert("The password and its verification doesn't match");
return false;
}
return true;
}
</script>
<% @title = "Instiki Setup"; @content_width = 500 %>
<p>
Congratulations on succesfully installing and starting Instiki.
Since this is the first time Instiki has been run on this port,
you'll need to do a brief one-time setup.
</p>
<form action="../create_system" id="setup" method="post" onSubmit="return validateSetup()">
<ol class="setup">
<li>
<h2 style="margin-bottom: 3px">Name and address for your first web</h2>
<div class="help">
The name of the web is included in the title on all pages.
The address is the base path that all pages within the web live beneath.
Ex: the address "rails" gives URLs like <i>/rails/show/HomePage</i>.
The address can only consist of letters and digits.
</div>
<div class="inputBox">
Name: <input type="text" id="web_name" name="web_name" value="Wiki"
onChange="proposeAddress();" onClick="this.value == 'Wiki' ? this.value = '' : true" />
&nbsp;&nbsp;
Address: <input type="text" id="web_address" name="web_address" onChange="cleanAddress();"
value="wiki" />
</div>
</li>
<li>
<h2 style="margin-bottom: 3px">Password for creating and changing webs</h2>
<div class="help">
Administrative access allows you to make new webs and change existing ones.<br/>
Everyone with this password will be able to do this, so pick it carefully.
</div>
<div class="inputBox">
Password: <input type="password" id="password" name="password" />
&nbsp;&nbsp;
Verify: <input type="password" id="password_check" name="password_check" />
</div>
</li>
</ol>
<p align="right">
<input type="submit" value="Setup" style="margin-left: 40px" />
</p>
</form>
<script>
function proposeAddress() {
document.getElementById('web_address').value =
document.getElementById('web_name').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function cleanAddress() {
document.getElementById('web_address').value =
document.getElementById('web_address').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function validateSetup() {
if (document.getElementById('web_name').value == "") {
alert("You must pick a name for the first web");
return false;
}
if (document.getElementById('web_address').value == "") {
alert("You must pick an address for the first web");
return false;
}
if (document.getElementById('password').value == "") {
alert("You must pick a system password");
return false;
}
if (document.getElementById('password_check').value == "" ||
document.getElementById('password').value != document.getElementById('password_check').value) {
alert("The password and its verification doesn't match");
return false;
}
return true;
}
</script>

138
app/views/wiki/new_web.rhtml Executable file → Normal file
View file

@ -1,69 +1,69 @@
<% @title = "New Wiki Web"; @content_width = 500 %>
<p>
Each web serves as an isolated name space for wiki pages,
so different subjects or projects can write about different <i>MuppetShows</i>.
</p>
<form action="../create_web" id="setup" method="post" onSubmit="cleanAddress();
return validateSetup()">
<ol class="setup">
<li>
<h2 style="margin-bottom: 3px">Name and address for your new web</h2>
<div class="help">
The name of the web is included in the title on all pages.
The address is the base path that all pages within the web live beneath.
Ex: the address "rails" gives URLs like <i>/rails/show/HomePage</i>.
The address can only consist of letters and digits.
</div>
<div class="inputBox">
Name: <input type="text" id="web_name" name="name" onChange="proposeAddress();" />
&nbsp;&nbsp;
Address: <input type="text" id="web_address" name="address" onChange="cleanAddress();" />
</div>
</li>
</ol>
<p align="right">
<small>
Enter system password
<input type="password" id="system_password" name="system_password" />
and
<input type="submit" value="Create Web" />
</small>
</p>
</form>
<script>
function proposeAddress() {
document.getElementById('web_address').value =
document.getElementById('web_name').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function cleanAddress() {
document.getElementById('web_address').value =
document.getElementById('web_address').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function validateSetup() {
if (document.getElementById('web_name').value == "") {
alert("You must pick a name for the new web");
return false;
}
if (document.getElementById('web_address').value == "") {
alert("You must pick an address for the new web");
return false;
}
if (document.getElementById('system_password').value == "") {
alert("You must enter the system password");
return false;
}
return true;
}
</script>
<% @title = "New Wiki Web"; @content_width = 500 %>
<p>
Each web serves as an isolated name space for wiki pages,
so different subjects or projects can write about different <i>MuppetShows</i>.
</p>
<form action="../create_web" id="setup" method="post" onSubmit="cleanAddress();
return validateSetup()">
<ol class="setup">
<li>
<h2 style="margin-bottom: 3px">Name and address for your new web</h2>
<div class="help">
The name of the web is included in the title on all pages.
The address is the base path that all pages within the web live beneath.
Ex: the address "rails" gives URLs like <i>/rails/show/HomePage</i>.
The address can only consist of letters and digits.
</div>
<div class="inputBox">
Name: <input type="text" id="web_name" name="name" onChange="proposeAddress();" />
&nbsp;&nbsp;
Address: <input type="text" id="web_address" name="address" onChange="cleanAddress();" />
</div>
</li>
</ol>
<p align="right">
<small>
Enter system password
<input type="password" id="system_password" name="system_password" />
and
<input type="submit" value="Create Web" />
</small>
</p>
</form>
<script>
function proposeAddress() {
document.getElementById('web_address').value =
document.getElementById('web_name').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function cleanAddress() {
document.getElementById('web_address').value =
document.getElementById('web_address').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function validateSetup() {
if (document.getElementById('web_name').value == "") {
alert("You must pick a name for the new web");
return false;
}
if (document.getElementById('web_address').value == "") {
alert("You must pick an address for the new web");
return false;
}
if (document.getElementById('system_password').value == "") {
alert("You must enter the system password");
return false;
}
return true;
}
</script>

156
app/views/wiki/page.rhtml Executable file → Normal file
View file

@ -1,78 +1,78 @@
<% @title = @page.plain_name %>
<div id="revision">
<%= @page.display_content %>
</div>
<div id="changes" style="display: none">
<p style="background: #eee; padding: 3px; border: 1px solid silver">
<small>
Showing changes from revision #<%= @page.number - 1 %> to #<%= @page.number %>:
<ins class="diffins">Added</ins> | <del class="diffdel">Removed</del>
</small>
</p>
<%= @page.display_diff %>
</div>
<div class="byline">
<%= @page.revisions? ? "Revised" : "Created" %> on <%= @page.pretty_created_at %>
by <%= @page.author_link %>
<%= "(#{@page.author.ip})" if @page.author.respond_to?(:ip) %>
<% if @web.count_pages %>
<% total_chars = @page.content.length %>
(<%= total_chars %> characters / <%= sprintf("%-.1f", (total_chars / 2275 rescue 0)) %> pages)
<% end %>
</div>
<div class="navigation">
<% if @page.name == "HomePage" %>
<a href="../edit/<%= @page.name %>" class="navlink" accesskey="E">Edit Page</a>
| <a href="../edit_web/" class="navlink">Edit Web</a>
<% else %>
<a href="../edit/<%= @page.name %>" class="navlink" accesskey="E">Edit</a>
<% end %>
<% if @page.revisions.length > 1 %>
| <a href="../revision/<%= @page.name %>?rev=<%= @page.revisions.length - 2 %>" class="navlink" accesskey="R">Back in time</a>
<small>(<%= @page.revisions.length - 1 %> revisions)</small>
<% end %>
<% if @page.revisions.length > 1 %>
<span id="show_changes">
| <a href="#" onClick="toggleChanges(); return false;">See changes</a>
</span>
<span id="hide_changes" style="display: none">
| <a href="#" onClick="toggleChanges(); return false;">Hide changes</a>
</span>
<% end %>
<small>
| Views: <a href="../print/<%= @page.name %>">Print</a>
<% if defined? RedClothForTex and RedClothForTex.available? and @web.markup == :textile %>
| <a href="../tex/<%= @page.name %>">TeX</a> | <a href="../pdf/<%= @page.name %>">PDF</a>
<% end %>
</small>
<% if @page.references.length > 0 %>
<small>
| Linked from: <%= @page.references.collect { |ref| ref.link }.join(", ") %>
</small>
<% end %>
</div>
<script language="Javascript">
function toggleChanges() {
if (document.getElementById("changes").style.display == "none") {
document.getElementById("changes").style.display = "block";
document.getElementById("revision").style.display = "none";
document.getElementById("show_changes").style.display = "none";
document.getElementById("hide_changes").style.display = "inline";
} else {
document.getElementById("changes").style.display = "none";
document.getElementById("revision").style.display = "block";
document.getElementById("show_changes").style.display = "inline";
document.getElementById("hide_changes").style.display = "none";
}
}
</script>
<% @title = @page.plain_name %>
<div id="revision">
<%= @page.display_content %>
</div>
<div id="changes" style="display: none">
<p style="background: #eee; padding: 3px; border: 1px solid silver">
<small>
Showing changes from revision #<%= @page.number - 1 %> to #<%= @page.number %>:
<ins class="diffins">Added</ins> | <del class="diffdel">Removed</del>
</small>
</p>
<%= @page.display_diff %>
</div>
<div class="byline">
<%= @page.revisions? ? "Revised" : "Created" %> on <%= @page.pretty_created_at %>
by <%= @page.author_link %>
<%= "(#{@page.author.ip})" if @page.author.respond_to?(:ip) %>
<% if @web.count_pages %>
<% total_chars = @page.content.length %>
(<%= total_chars %> characters / <%= sprintf("%-.1f", (total_chars / 2275 rescue 0)) %> pages)
<% end %>
</div>
<div class="navigation">
<% if @page.name == "HomePage" %>
<a href="../edit/<%= @page.name %>" class="navlink" accesskey="E">Edit Page</a>
| <a href="../edit_web/" class="navlink">Edit Web</a>
<% else %>
<a href="../edit/<%= @page.name %>" class="navlink" accesskey="E">Edit</a>
<% end %>
<% if @page.revisions.length > 1 %>
| <a href="../revision/<%= @page.name %>?rev=<%= @page.revisions.length - 2 %>" class="navlink" accesskey="R">Back in time</a>
<small>(<%= @page.revisions.length - 1 %> revisions)</small>
<% end %>
<% if @page.revisions.length > 1 %>
<span id="show_changes">
| <a href="#" onClick="toggleChanges(); return false;">See changes</a>
</span>
<span id="hide_changes" style="display: none">
| <a href="#" onClick="toggleChanges(); return false;">Hide changes</a>
</span>
<% end %>
<small>
| Views: <a href="../print/<%= @page.name %>">Print</a>
<% if defined? RedClothForTex and RedClothForTex.available? and @web.markup == :textile %>
| <a href="../tex/<%= @page.name %>">TeX</a> | <a href="../pdf/<%= @page.name %>">PDF</a>
<% end %>
</small>
<% if @page.references.length > 0 %>
<small>
| Linked from: <%= @page.references.collect { |ref| ref.link }.join(", ") %>
</small>
<% end %>
</div>
<script language="Javascript">
function toggleChanges() {
if (document.getElementById("changes").style.display == "none") {
document.getElementById("changes").style.display = "block";
document.getElementById("revision").style.display = "none";
document.getElementById("show_changes").style.display = "none";
document.getElementById("hide_changes").style.display = "inline";
} else {
document.getElementById("changes").style.display = "none";
document.getElementById("revision").style.display = "block";
document.getElementById("show_changes").style.display = "inline";
document.getElementById("hide_changes").style.display = "none";
}
}
</script>

28
app/views/wiki/print.rhtml Executable file → Normal file
View file

@ -1,14 +1,14 @@
<%
@title = @page.plain_name
@hide_navigation = true
@style_additions = ".newWikiWord { background-color: white; font-style: italic; }"
@inline_style = true
%>
<%= @page.display_content_for_export %>
<div class="byline">
<%= @page.revisions? ? "Revised" : "Created" %> on <%= @page.pretty_created_at %>
by
<%= @page.author_link({ :mode => :export }) %>
</div>
<%
@title = @page.plain_name
@hide_navigation = true
@style_additions = ".newWikiWord { background-color: white; font-style: italic; }"
@inline_style = true
%>
<%= @page.display_content_for_export %>
<div class="byline">
<%= @page.revisions? ? "Revised" : "Created" %> on <%= @page.pretty_created_at %>
by
<%= @page.author_link({ :mode => :export }) %>
</div>

16
app/views/wiki/published.rhtml Executable file → Normal file
View file

@ -1,8 +1,8 @@
<%
@title = @page.plain_name
@hide_navigation = false
@style_additions = ".newWikiWord { background-color: white; font-style: italic; }"
@inline_style = true
%>
<%= @page.display_published %>
<%
@title = @page.plain_name
@hide_navigation = false
@style_additions = ".newWikiWord { background-color: white; font-style: italic; }"
@inline_style = true
%>
<%= @page.display_published %>

64
app/views/wiki/recently_revised.rhtml Executable file → Normal file
View file

@ -1,32 +1,32 @@
<% @title = "Recently Revised" %>
<% unless @categories.empty? %>
<div id="categories">
<strong>Categories</strong>:
[<a href=".">Any</a>]
<%= @category_links.join(', ') %>
</div>
<% end %>
<% unless @pages_by_revision.empty? %>
<% revision_date = @pages_by_revision.first.revised_on %>
<h3><%= revision_date.strftime('%B %e, %Y') %></h3>
<ul>
<% for page in @pages_by_revision %>
<% if page.revised_on < revision_date %>
<% revision_date = page.revised_on %>
</ul>
<h3><%= revision_date.strftime('%B %e, %Y') %></h3>
<ul>
<% end %>
<li>
<a href="../show/<%= page.name %>"><%= page.plain_name %></a>
<div class="byline" style="margin-bottom: 0px">
by <%= page.author_link %>
at <%= page.created_at.strftime "%H:%M" %>
<%= "from #{page.author.ip}" if page.author.respond_to?(:ip) %>
</div>
</li>
<% end %>
</ul>
<% end %>
<% @title = "Recently Revised" %>
<% unless @categories.empty? %>
<div id="categories">
<strong>Categories</strong>:
[<a href=".">Any</a>]
<%= @category_links.join(', ') %>
</div>
<% end %>
<% unless @pages_by_revision.empty? %>
<% revision_date = @pages_by_revision.first.revised_on %>
<h3><%= revision_date.strftime('%B %e, %Y') %></h3>
<ul>
<% for page in @pages_by_revision %>
<% if page.revised_on < revision_date %>
<% revision_date = page.revised_on %>
</ul>
<h3><%= revision_date.strftime('%B %e, %Y') %></h3>
<ul>
<% end %>
<li>
<a href="../show/<%= page.name %>"><%= page.plain_name %></a>
<div class="byline" style="margin-bottom: 0px">
by <%= page.author_link %>
at <%= page.created_at.strftime "%H:%M" %>
<%= "from #{page.author.ip}" if page.author.respond_to?(:ip) %>
</div>
</li>
<% end %>
</ul>
<% end %>

158
app/views/wiki/revision.rhtml Executable file → Normal file
View file

@ -1,79 +1,79 @@
<% @title = "#{@page.plain_name} (Rev ##{@revision.number})" %>
<div id="revision">
<%= @revision.display_content %>
</div>
<div id="changes" style="display: none">
<p style="background: #eee; padding: 3px; border: 1px solid silver">
<small>
Showing changes from revision #<%= @revision.number - 1 %> to #<%= @revision.number %>:
<ins class="diffins">Added</ins> | <del class="diffdel">Removed</del>
</small>
</p>
<%= @revision.display_diff %>
</div>
<div class="byline">
<%= "Revision from #{@revision.pretty_created_at} by" %>
<%= @page.web.make_link(@revision.author) %>
</div>
<div class="navigation">
<% if @revision.next_revision %>
<% if @revision.next_revision.number < (@page.revisions.length - 1) %>
<a href="../revision/<%= @page.name %>?rev=<%= @revision.next_revision.number %>" class="navlink">
<% else %>
<a href="../show/<%= @page.name %>" class="navlink">
<% end %>
Forward in time</a>
(<%= @revision.page.revisions.length - @revision.next_revision.number %> more)
<% end %>
<% if @revision.next_revision && @revision.previous_revision %>
|
<% end %>
<% if @revision.previous_revision %>
<a href="../revision/<%= @page.name %>?rev=<%= @revision.previous_revision.number %>" class="navlink">Back in time</a>
(<%= @revision.previous_revision.number + 1 %> more)
<% end %>
| <a href="../show/<%= @page.name %>" class="navlink">See current</a>
<% if @revision.previous_revision %>
<span id="show_changes">
| <a href="#" onClick="toggleChanges(); return false;">See changes</a>
</span>
<span id="hide_changes" style="display: none">
| <a href="#" onClick="toggleChanges(); return false;">Hide changes</a>
</span>
<% end %>
| <a href="../rollback/<%= @page.name %>?rev=<%= @revision.number %>" class="navlink">Rollback</a>
<% if @page.references.length > 0 %>
<small>
| Linked from: <%= @page.references.collect { |ref| "<a href='#{ref.name}'>#{ref.name}</a>" }.join(", ") %>
</small>
<% end %>
</div>
<script language="Javascript">
function toggleChanges() {
if (document.getElementById("changes").style.display == "none") {
document.getElementById("changes").style.display = "block";
document.getElementById("revision").style.display = "none";
document.getElementById("show_changes").style.display = "none";
document.getElementById("hide_changes").style.display = "inline";
} else {
document.getElementById("changes").style.display = "none";
document.getElementById("revision").style.display = "block";
document.getElementById("show_changes").style.display = "inline";
document.getElementById("hide_changes").style.display = "none";
}
}
</script>
<% @title = "#{@page.plain_name} (Rev ##{@revision.number})" %>
<div id="revision">
<%= @revision.display_content %>
</div>
<div id="changes" style="display: none">
<p style="background: #eee; padding: 3px; border: 1px solid silver">
<small>
Showing changes from revision #<%= @revision.number - 1 %> to #<%= @revision.number %>:
<ins class="diffins">Added</ins> | <del class="diffdel">Removed</del>
</small>
</p>
<%= @revision.display_diff %>
</div>
<div class="byline">
<%= "Revision from #{@revision.pretty_created_at} by" %>
<%= @page.web.make_link(@revision.author) %>
</div>
<div class="navigation">
<% if @revision.next_revision %>
<% if @revision.next_revision.number < (@page.revisions.length - 1) %>
<a href="../revision/<%= @page.name %>?rev=<%= @revision.next_revision.number %>" class="navlink">
<% else %>
<a href="../show/<%= @page.name %>" class="navlink">
<% end %>
Forward in time</a>
(<%= @revision.page.revisions.length - @revision.next_revision.number %> more)
<% end %>
<% if @revision.next_revision && @revision.previous_revision %>
|
<% end %>
<% if @revision.previous_revision %>
<a href="../revision/<%= @page.name %>?rev=<%= @revision.previous_revision.number %>" class="navlink">Back in time</a>
(<%= @revision.previous_revision.number + 1 %> more)
<% end %>
| <a href="../show/<%= @page.name %>" class="navlink">See current</a>
<% if @revision.previous_revision %>
<span id="show_changes">
| <a href="#" onClick="toggleChanges(); return false;">See changes</a>
</span>
<span id="hide_changes" style="display: none">
| <a href="#" onClick="toggleChanges(); return false;">Hide changes</a>
</span>
<% end %>
| <a href="../rollback/<%= @page.name %>?rev=<%= @revision.number %>" class="navlink">Rollback</a>
<% if @page.references.length > 0 %>
<small>
| Linked from: <%= @page.references.collect { |ref| "<a href='#{ref.name}'>#{ref.name}</a>" }.join(", ") %>
</small>
<% end %>
</div>
<script language="Javascript">
function toggleChanges() {
if (document.getElementById("changes").style.display == "none") {
document.getElementById("changes").style.display = "block";
document.getElementById("revision").style.display = "none";
document.getElementById("show_changes").style.display = "none";
document.getElementById("hide_changes").style.display = "inline";
} else {
document.getElementById("changes").style.display = "none";
document.getElementById("revision").style.display = "block";
document.getElementById("show_changes").style.display = "inline";
document.getElementById("hide_changes").style.display = "none";
}
}
</script>

0
app/views/wiki/rollback.rhtml Executable file → Normal file
View file

44
app/views/wiki/rss_feed.rhtml Executable file → Normal file
View file

@ -1,22 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title><%= @web.name %></title>
<link><%= url_for :only_path => false, :web => @web_name, :action => 'show', :id => 'HomePage' %></link>
<description>An Instiki wiki</description>
<language>en-us</language>
<ttl>40</ttl>
<% for page in @pages_by_revision %>
<item>
<title><%= page.plain_name %></title>
<% unless @hide_description %>
<description><%= CGI.escapeHTML(page.display_content) %></description>
<% end %>
<pubDate><%= page.created_at.strftime "%a, %e %b %Y %H:%M:%S %Z" %></pubDate>
<guid><%= url_for :only_path => false, :web => @web_name, :action => 'show', :id => page.name %></guid>
<link><%= url_for :only_path => false, :web => @web_name, :action => 'show', :id => page.name %></link>
<dc:creator><%= WikiWords.separate(page.author) %></dc:creator>
</item>
<% end %>
</channel>
</rss>
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title><%= @web.name %></title>
<link><%= url_for :only_path => false, :web => @web_name, :action => 'show', :id => 'HomePage' %></link>
<description>An Instiki wiki</description>
<language>en-us</language>
<ttl>40</ttl>
<% for page in @pages_by_revision %>
<item>
<title><%= page.plain_name %></title>
<% unless @hide_description %>
<description><%= CGI.escapeHTML(page.display_content) %></description>
<% end %>
<pubDate><%= page.created_at.strftime "%a, %e %b %Y %H:%M:%S %Z" %></pubDate>
<guid><%= url_for :only_path => false, :web => @web_name, :action => 'show', :id => page.name %></guid>
<link><%= url_for :only_path => false, :web => @web_name, :action => 'show', :id => page.name %></link>
<dc:creator><%= WikiWords.separate(page.author) %></dc:creator>
</item>
<% end %>
</channel>
</rss>

26
app/views/wiki/search.rhtml Executable file → Normal file
View file

@ -1,13 +1,13 @@
<% @title = @results.length > 0 ? "#{@results.length} pages contains \"#{@params["query"]}\"" : "No pages contains \"#{@query}\"" %>
<% if @results.length > 0 %>
<ul>
<% for page in @results %>
<li><a href="../show/<%= page.name %>"><%= page.plain_name %></a></li>
<% end %>
</ul>
<% else %>
<p>Perhaps you should try expanding your query. Remember that Instiki searches for entire phrases, so if you search for "all that jazz" it will not match pages that contain these words in separation&mdash;only as a sentence fragment.</p>
<p>If you're a high-tech computer wizard, you might even want try constructing a regular expression. That's actually what Instiki uses, so go right ahead and flex your "[a-z]*Leet?RegExpSkill(s|z)"</p>
<% end %>
<% @title = @results.length > 0 ? "#{@results.length} pages contains \"#{@params["query"]}\"" : "No pages contains \"#{@query}\"" %>
<% if @results.length > 0 %>
<ul>
<% for page in @results %>
<li><a href="../show/<%= page.name %>"><%= page.plain_name %></a></li>
<% end %>
</ul>
<% else %>
<p>Perhaps you should try expanding your query. Remember that Instiki searches for entire phrases, so if you search for "all that jazz" it will not match pages that contain these words in separation&mdash;only as a sentence fragment.</p>
<p>If you're a high-tech computer wizard, you might even want try constructing a regular expression. That's actually what Instiki uses, so go right ahead and flex your "[a-z]*Leet?RegExpSkill(s|z)"</p>
<% end %>

44
app/views/wiki/tex.rhtml Executable file → Normal file
View file

@ -1,23 +1,23 @@
\documentclass[12pt,titlepage]{article}
\usepackage[danish]{babel} %danske tekster
\usepackage[OT1]{fontenc} %rigtige danske bogstaver...
\usepackage{a4}
\usepackage{graphicx}
\usepackage{ucs}
\usepackage[utf8x]{inputenc}
\input epsf
%-------------------------------------------------------------------
\begin{document}
\sloppy
%-------------------------------------------------------------------
\section*{<%= @page.name %>}
<%= @tex_content %>
\documentclass[12pt,titlepage]{article}
\usepackage[danish]{babel} %danske tekster
\usepackage[OT1]{fontenc} %rigtige danske bogstaver...
\usepackage{a4}
\usepackage{graphicx}
\usepackage{ucs}
\usepackage[utf8x]{inputenc}
\input epsf
%-------------------------------------------------------------------
\begin{document}
\sloppy
%-------------------------------------------------------------------
\section*{<%= @page.name %>}
<%= @tex_content %>
\end{document}

68
app/views/wiki/tex_web.rhtml Executable file → Normal file
View file

@ -1,35 +1,35 @@
\documentclass[12pt,titlepage]{article}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[LE,RO]{}
\fancyhead[LO,RE]{\nouppercase{\bfseries \leftmark}}
\fancyfoot[C]{\thepage}
\usepackage[danish]{babel} %danske tekster
\usepackage{a4}
\usepackage{graphicx}
\usepackage{ucs}
\usepackage[utf8]{inputenc}
\input epsf
%-------------------------------------------------------------------
\title{<%= @web_name %>}
\begin{document}
\maketitle
\tableofcontents
\pagebreak
\sloppy
%-------------------------------------------------------------------
<%= @tex_content %>
\documentclass[12pt,titlepage]{article}
\usepackage{fancyhdr}
\pagestyle{fancy}
\fancyhead[LE,RO]{}
\fancyhead[LO,RE]{\nouppercase{\bfseries \leftmark}}
\fancyfoot[C]{\thepage}
\usepackage[danish]{babel} %danske tekster
\usepackage{a4}
\usepackage{graphicx}
\usepackage{ucs}
\usepackage[utf8]{inputenc}
\input epsf
%-------------------------------------------------------------------
\title{<%= @web_name %>}
\begin{document}
\maketitle
\tableofcontents
\pagebreak
\sloppy
%-------------------------------------------------------------------
<%= @tex_content %>
\end{document}

36
app/views/wiki/web_list.rhtml Executable file → Normal file
View file

@ -1,18 +1,18 @@
<% @title = "Wiki webs" %>
<ul>
<% for web in @webs %>
<li>
<% if web.published %>
<%= web.make_link 'HomePage', web.name, :mode => :publish %> (read-only) /
<%= web.make_link 'HomePage', 'editable version', :mode => :edit %> (requires login)
<% else %>
<%= web.make_link 'HomePage', nil, :mode => :edit %>
<% end %>
<div class="byline" style="margin-bottom: 0px">
<%= web.pages.length %> pages by <%= web.authors.length %> authors
</div>
</li>
<% end %>
</ul>
<% @title = "Wiki webs" %>
<ul>
<% for web in @webs %>
<li>
<% if web.published %>
<%= web.make_link 'HomePage', web.name, :mode => :publish %> (read-only) /
<%= web.make_link 'HomePage', 'editable version', :mode => :edit %> (requires login)
<% else %>
<%= web.make_link 'HomePage', nil, :mode => :edit %>
<% end %>
<div class="byline" style="margin-bottom: 0px">
<%= web.pages.length %> pages by <%= web.authors.length %> authors
</div>
</li>
<% end %>
</ul>

18
app/views/wiki_words_help.rhtml Executable file → Normal file
View file

@ -1,9 +1,9 @@
<h3>Wiki words</h3>
<p style="border-top: 1px dotted #ccc; margin-top: 0px">
Two or more uppercase words stuck together (camel case) or any phrase surrounded by double
brackets is a wiki word. A camel-case wiki word can be escaped by putting \ in front of it.
</p>
<p>
Wiki words: <i>HomePage, ThreeWordsTogether, [[C++]], [[Let's play again!]]</i><br/>
Not wiki words: <i>IBM, School</i>
</p>
<h3>Wiki words</h3>
<p style="border-top: 1px dotted #ccc; margin-top: 0px">
Two or more uppercase words stuck together (camel case) or any phrase surrounded by double
brackets is a wiki word. A camel-case wiki word can be escaped by putting \ in front of it.
</p>
<p>
Wiki words: <i>HomePage, ThreeWordsTogether, [[C++]], [[Let's play again!]]</i><br/>
Not wiki words: <i>IBM, School</i>
</p>

8
config/environments/development.rb Executable file → Normal file
View file

@ -1,4 +1,4 @@
Dependencies.mechanism = :require
ActionController::Base.consider_all_requests_local = true
BREAKPOINT_SERVER_PORT = 42531
ActionController::Base.logger.level = Logger::DEBUG
Dependencies.mechanism = :require
ActionController::Base.consider_all_requests_local = true
BREAKPOINT_SERVER_PORT = 42531
ActionController::Base.logger.level = Logger::DEBUG

44
libraries/active_record_stub.rb Executable file → Normal file
View file

@ -1,23 +1,23 @@
# This project uses Railties, which has an external dependency on ActiveRecord
# Since ActiveRecord may not be present in Instiki runtime environment, this
# file provides a stub replacement for it
unless defined? ActiveRecord::Base
module ActiveRecord
class Base
# dependency in railties/lib/dispatcher.rb
def self.reset_column_information_and_inheritable_attributes_for_all_subclasses
# noop
end
# dependency in actionpack/lib/action_controller/benchmarking.rb
def self.connected?
false
end
end
end
# This project uses Railties, which has an external dependency on ActiveRecord
# Since ActiveRecord may not be present in Instiki runtime environment, this
# file provides a stub replacement for it
unless defined? ActiveRecord::Base
module ActiveRecord
class Base
# dependency in railties/lib/dispatcher.rb
def self.reset_column_information_and_inheritable_attributes_for_all_subclasses
# noop
end
# dependency in actionpack/lib/action_controller/benchmarking.rb
def self.connected?
false
end
end
end
end

948
libraries/diff.rb Executable file → Normal file
View file

@ -1,475 +1,475 @@
# heavily based off difflib.py - see that file for documentation
# ported from Python by Bill Atkins
# This does not support all features offered by difflib; it
# implements only the subset of features necessary
# to support a Ruby version of HTML Differ. You're welcome to finish this off.
# By default, String#each iterates by line. This isn't really appropriate
# for diff, so often a string will be split by // to get an array of one-
# character strings.
# Some methods in Diff are untested and are not guaranteed to work. The
# methods in HTMLDiff and any methods it calls should work quite well.
# changes by DenisMertz
# * main change:
# ** get the tag soup away
# the tag soup problem was first reported with <p> tags, but it appeared also with
# <li>, <ul> etc... tags
# this version should mostly fix these problems
# ** added a Builder class to manage the creation of the final htmldiff
# * minor changes:
# ** use symbols instead of string to represent opcodes
# ** small fix to html2list
#
module Enumerable
def reduce(init)
result = init
each { |item| result = yield(result, item) }
result
end
end
module Diff
class SequenceMatcher
def initialize(a=[''], b=[''], isjunk=nil, byline=false)
a = (!byline and a.kind_of? String) ? a.split(//) : a
b = (!byline and b.kind_of? String) ? b.split(//) : b
@isjunk = isjunk || proc {}
set_seqs a, b
end
def set_seqs(a, b)
set_seq_a a
set_seq_b b
end
def set_seq_a(a)
@a = a
@matching_blocks = @opcodes = nil
end
def set_seq_b(b)
@b = b
@matching_blocks = @opcodes = nil
chain_b
end
def chain_b
@fullbcount = nil
@b2j = {}
pophash = {}
junkdict = {}
@b.each_with_index do |elt, i|
if @b2j.has_key? elt
indices = @b2j[elt]
if @b.length >= 200 and indices.length * 100 > @b.length
pophash[elt] = 1
indices.clear
else
indices.push i
end
else
@b2j[elt] = [i]
end
end
pophash.each_key { |elt| @b2j.delete elt }
junkdict = {}
unless @isjunk.nil?
[pophash, @b2j].each do |d|
d.each_key do |elt|
if @isjunk.call(elt)
junkdict[elt] = 1
d.delete elt
end
end
end
end
@isbjunk = junkdict.method(:has_key?)
@isbpopular = junkdict.method(:has_key?)
end
def find_longest_match(alo, ahi, blo, bhi)
besti, bestj, bestsize = alo, blo, 0
j2len = {}
(alo..ahi).step do |i|
newj2len = {}
(@b2j[@a[i]] || []).each do |j|
if j < blo
next
end
if j >= bhi
break
end
k = newj2len[j] = (j2len[j - 1] || 0) + 1
if k > bestsize
besti, bestj, bestsize = i - k + 1, j - k + 1, k
end
end
j2len = newj2len
end
while besti > alo and bestj > blo and
not @isbjunk.call(@b[bestj-1]) and
@a[besti-1] == @b[bestj-1]
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
end
while besti+bestsize < ahi and bestj+bestsize < bhi and
not @isbjunk.call(@b[bestj+bestsize]) and
@a[besti+bestsize] == @b[bestj+bestsize]
bestsize += 1
end
while besti > alo and bestj > blo and
@isbjunk.call(@b[bestj-1]) and
@a[besti-1] == @b[bestj-1]
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
end
while besti+bestsize < ahi and bestj+bestsize < bhi and
@isbjunk.call(@b[bestj+bestsize]) and
@a[besti+bestsize] == @b[bestj+bestsize]
bestsize += 1
end
[besti, bestj, bestsize]
end
def get_matching_blocks
return @matching_blocks unless @matching_blocks.nil? or
@matching_blocks.empty?
@matching_blocks = []
la, lb = @a.length, @b.length
match_block_helper(0, la, 0, lb, @matching_blocks)
@matching_blocks.push [la, lb, 0]
end
def match_block_helper(alo, ahi, blo, bhi, answer)
i, j, k = x = find_longest_match(alo, ahi, blo, bhi)
if not k.zero?
if alo < i and blo < j
match_block_helper(alo, i, blo, j, answer)
end
answer.push x
if i + k < ahi and j + k < bhi
match_block_helper(i + k, ahi, j + k, bhi, answer)
end
end
end
def get_opcodes
unless @opcodes.nil? or @opcodes.empty?
return @opcodes
end
i = j = 0
@opcodes = answer = []
get_matching_blocks.each do |ai, bj, size|
tag = if i < ai and j < bj
:replace
elsif i < ai
:delete
elsif j < bj
:insert
end
answer.push [tag, i, ai, j, bj] if tag
i, j = ai + size, bj + size
answer.push [:equal, ai, i, bj, j] unless size.zero?
end
return answer
end
# XXX: untested
def get_grouped_opcodes(n=3)
codes = get_opcodes
if codes[0][0] == :equal
tag, i1, i2, j1, j2 = codes[0]
codes[0] = tag, [i1, i2 - n].max, i2, [j1, j2-n].max, j2
end
if codes[-1][0] == :equal
tag, i1, i2, j1, j2 = codes[-1]
codes[-1] = tag, i1, min(i2, i1+n), j1, min(j2, j1+n)
end
nn = n + n
group = []
codes.each do |tag, i1, i2, j1, j2|
if tag == :equal and i2-i1 > nn
group.push [tag, i1, [i2, i1 + n].min, j1, [j2, j1 + n].min]
yield group
group = []
i1, j1 = [i1, i2-n].max, [j1, j2-n].max
group.push [tag, i1, i2, j1 ,j2]
end
end
if group and group.length != 1 and group[0][0] == :equal
yield group
end
end
def ratio
matches = get_matching_blocks.reduce(0) do |sum, triple|
sum + triple[-1]
end
Diff.calculate_ratio(matches, @a.length + @b.length)
end
def quick_ratio
if @fullbcount.nil? or @fullbcount.empty?
@fullbcount = {}
@b.each do |elt|
@fullbcount[elt] = (@fullbcount[elt] || 0) + 1
end
end
avail = {}
matches = 0
@a.each do |elt|
if avail.has_key? elt
numb = avail[elt]
else
numb = @fullbcount[elt] || 0
end
avail[elt] = numb - 1
if numb > 0
matches += 1
end
end
Diff.calculate_ratio matches, @a.length + @b.length
end
def real_quick_ratio
la, lb = @a.length, @b.length
Diff.calculate_ratio([la, lb].min, la + lb)
end
protected :chain_b, :match_block_helper
end # end class SequenceMatcher
def self.calculate_ratio(matches, length)
return 1.0 if length.zero?
2.0 * matches / length
end
# XXX: untested
def self.get_close_matches(word, possibilities, n=3, cutoff=0.6)
unless n > 0
raise "n must be > 0: #{n}"
end
unless 0.0 <= cutoff and cutoff <= 1.0
raise "cutoff must be in (0.0..1.0): #{cutoff}"
end
result = []
s = SequenceMatcher.new
s.set_seq_b word
possibilities.each do |x|
s.set_seq_a x
if s.real_quick_ratio >= cutoff and
s.quick_ratio >= cutoff and
s.ratio >= cutoff
result.push [s.ratio, x]
end
end
unless result.nil? or result.empty?
result.sort
result.reverse!
result = result[-n..-1]
end
result.collect { |score, x| x }
end
def self.count_leading(line, ch)
i, n = 0, line.length
while i < n and line[i].chr == ch
i += 1
end
i
end
end
module HTMLDiff
include Diff
class Builder
VALID_METHODS = [:replace, :insert, :delete, :equal]
def initialize(a, b)
@a = a
@b = b
@content = []
end
def do_op(opcode)
@opcode = opcode
op = @opcode[0]
VALID_METHODS.include?(op) or raise(NameError, "Invalid opcode #{op}")
self.method(op).call
end
def result
@content.join('')
end
#this methods have to be called via do_op(opcode) so that @opcode is set properly
private
def replace
delete("diffmod")
insert("diffmod")
end
def insert(tagclass="diffins")
op_helper("ins", tagclass, @b[@opcode[3]...@opcode[4]])
end
def delete(tagclass="diffdel")
op_helper("del", tagclass, @a[@opcode[1]...@opcode[2]])
end
def equal
@content += @b[@opcode[3]...@opcode[4]]
end
# using this as op_helper would be equivalent to the first version of diff.rb by Bill Atkins
def op_helper_simple(tagname, tagclass, to_add)
@content << "<#{tagname} class=\"#{tagclass}\">"
@content += to_add
@content << "</#{tagname}>"
end
# this tries to put <p> tags or newline chars before the opening diff tags (<ins> or <del>)
# or after the ending diff tags
# as a result the diff tags should be the "more inside" possible.
# this seems to work nice with html containing only paragraphs
# but not sure it works if there are other tags (div, span ... ? ) around
def op_helper(tagname, tagclass, to_add)
@content << to_add.shift while ( HTMLDiff.is_newline(to_add.first) or
HTMLDiff.is_p_close_tag(to_add.first) or
HTMLDiff.is_p_open_tag(to_add.first) )
@content << "<#{tagname} class=\"#{tagclass}\">"
@content += to_add
last_tags = []
last_tags.unshift(@content.pop) while ( HTMLDiff.is_newline(@content.last) or
HTMLDiff.is_p_close_tag(@content.last) or
HTMLDiff.is_p_open_tag(@content.last) )
last_tags.unshift "</#{tagname}>"
@content += last_tags
remove_empty_diff(tagname, tagclass)
end
def remove_empty_diff(tagname, tagclass)
if @content[-2] == "<#{tagname} class=\"#{tagclass}\">" and @content[-1] == "</#{tagname}>" then
@content.pop
@content.pop
end
end
end
def self.is_newline(x)
(x == "\n") or (x == "\r") or (x == "\t")
end
def self.is_p_open_tag(x)
x =~ /\A<(p|li|ul|ol|dir|dt|dl)/
end
def self.is_p_close_tag(x)
x =~ %r!\A</(p|li|ul|ol|dir|dt|dl)!
end
def self.diff(a, b)
a, b = a.split(//), b.split(//) if a.kind_of? String and b.kind_of? String
a, b = html2list(a), html2list(b)
out = Builder.new(a, b)
s = SequenceMatcher.new(a, b)
s.get_opcodes.each do |opcode|
out.do_op(opcode)
end
out.result
end
def self.html2list(x, b=false)
mode = 'char'
cur = ''
out = []
x = x.split(//) if x.kind_of? String
x.each do |c|
if mode == 'tag'
if c == '>'
if b
cur += ']'
else
cur += c
end
out.push(cur)
cur = ''
mode = 'char'
else
cur += c
end
elsif mode == 'char'
if c == '<'
out.push cur
if b
cur = '['
else
cur = c
end
mode = 'tag'
elsif /\s/.match c
out.push cur + c
cur = ''
else
cur += c
end
end
end
out.push cur
# TODO: make something better here
out.each{|x| x.chomp! unless is_newline(x)}
out.find_all { |x| x != '' }
end
end
if __FILE__ == $0
require 'pp'
# a = "<p>this is the original string</p>" # \n<p>but around the world</p>"
# b = "<p>this is the original </p><p>other parag</p><p>string</p>"
a = "<ul>\n\t<li>one</li>\n\t<li>two</li>\n</ul>"
b = "<ul>\n\t<li>one</li>\n\t<li>two\n\t<ul><li>abc</li></ul></li>\n</ul>"
puts a
pp HTMLDiff.html2list(a)
puts
puts b
pp HTMLDiff.html2list(b)
puts
puts HTMLDiff.diff(a, b)
# heavily based off difflib.py - see that file for documentation
# ported from Python by Bill Atkins
# This does not support all features offered by difflib; it
# implements only the subset of features necessary
# to support a Ruby version of HTML Differ. You're welcome to finish this off.
# By default, String#each iterates by line. This isn't really appropriate
# for diff, so often a string will be split by // to get an array of one-
# character strings.
# Some methods in Diff are untested and are not guaranteed to work. The
# methods in HTMLDiff and any methods it calls should work quite well.
# changes by DenisMertz
# * main change:
# ** get the tag soup away
# the tag soup problem was first reported with <p> tags, but it appeared also with
# <li>, <ul> etc... tags
# this version should mostly fix these problems
# ** added a Builder class to manage the creation of the final htmldiff
# * minor changes:
# ** use symbols instead of string to represent opcodes
# ** small fix to html2list
#
module Enumerable
def reduce(init)
result = init
each { |item| result = yield(result, item) }
result
end
end
module Diff
class SequenceMatcher
def initialize(a=[''], b=[''], isjunk=nil, byline=false)
a = (!byline and a.kind_of? String) ? a.split(//) : a
b = (!byline and b.kind_of? String) ? b.split(//) : b
@isjunk = isjunk || proc {}
set_seqs a, b
end
def set_seqs(a, b)
set_seq_a a
set_seq_b b
end
def set_seq_a(a)
@a = a
@matching_blocks = @opcodes = nil
end
def set_seq_b(b)
@b = b
@matching_blocks = @opcodes = nil
chain_b
end
def chain_b
@fullbcount = nil
@b2j = {}
pophash = {}
junkdict = {}
@b.each_with_index do |elt, i|
if @b2j.has_key? elt
indices = @b2j[elt]
if @b.length >= 200 and indices.length * 100 > @b.length
pophash[elt] = 1
indices.clear
else
indices.push i
end
else
@b2j[elt] = [i]
end
end
pophash.each_key { |elt| @b2j.delete elt }
junkdict = {}
unless @isjunk.nil?
[pophash, @b2j].each do |d|
d.each_key do |elt|
if @isjunk.call(elt)
junkdict[elt] = 1
d.delete elt
end
end
end
end
@isbjunk = junkdict.method(:has_key?)
@isbpopular = junkdict.method(:has_key?)
end
def find_longest_match(alo, ahi, blo, bhi)
besti, bestj, bestsize = alo, blo, 0
j2len = {}
(alo..ahi).step do |i|
newj2len = {}
(@b2j[@a[i]] || []).each do |j|
if j < blo
next
end
if j >= bhi
break
end
k = newj2len[j] = (j2len[j - 1] || 0) + 1
if k > bestsize
besti, bestj, bestsize = i - k + 1, j - k + 1, k
end
end
j2len = newj2len
end
while besti > alo and bestj > blo and
not @isbjunk.call(@b[bestj-1]) and
@a[besti-1] == @b[bestj-1]
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
end
while besti+bestsize < ahi and bestj+bestsize < bhi and
not @isbjunk.call(@b[bestj+bestsize]) and
@a[besti+bestsize] == @b[bestj+bestsize]
bestsize += 1
end
while besti > alo and bestj > blo and
@isbjunk.call(@b[bestj-1]) and
@a[besti-1] == @b[bestj-1]
besti, bestj, bestsize = besti-1, bestj-1, bestsize+1
end
while besti+bestsize < ahi and bestj+bestsize < bhi and
@isbjunk.call(@b[bestj+bestsize]) and
@a[besti+bestsize] == @b[bestj+bestsize]
bestsize += 1
end
[besti, bestj, bestsize]
end
def get_matching_blocks
return @matching_blocks unless @matching_blocks.nil? or
@matching_blocks.empty?
@matching_blocks = []
la, lb = @a.length, @b.length
match_block_helper(0, la, 0, lb, @matching_blocks)
@matching_blocks.push [la, lb, 0]
end
def match_block_helper(alo, ahi, blo, bhi, answer)
i, j, k = x = find_longest_match(alo, ahi, blo, bhi)
if not k.zero?
if alo < i and blo < j
match_block_helper(alo, i, blo, j, answer)
end
answer.push x
if i + k < ahi and j + k < bhi
match_block_helper(i + k, ahi, j + k, bhi, answer)
end
end
end
def get_opcodes
unless @opcodes.nil? or @opcodes.empty?
return @opcodes
end
i = j = 0
@opcodes = answer = []
get_matching_blocks.each do |ai, bj, size|
tag = if i < ai and j < bj
:replace
elsif i < ai
:delete
elsif j < bj
:insert
end
answer.push [tag, i, ai, j, bj] if tag
i, j = ai + size, bj + size
answer.push [:equal, ai, i, bj, j] unless size.zero?
end
return answer
end
# XXX: untested
def get_grouped_opcodes(n=3)
codes = get_opcodes
if codes[0][0] == :equal
tag, i1, i2, j1, j2 = codes[0]
codes[0] = tag, [i1, i2 - n].max, i2, [j1, j2-n].max, j2
end
if codes[-1][0] == :equal
tag, i1, i2, j1, j2 = codes[-1]
codes[-1] = tag, i1, min(i2, i1+n), j1, min(j2, j1+n)
end
nn = n + n
group = []
codes.each do |tag, i1, i2, j1, j2|
if tag == :equal and i2-i1 > nn
group.push [tag, i1, [i2, i1 + n].min, j1, [j2, j1 + n].min]
yield group
group = []
i1, j1 = [i1, i2-n].max, [j1, j2-n].max
group.push [tag, i1, i2, j1 ,j2]
end
end
if group and group.length != 1 and group[0][0] == :equal
yield group
end
end
def ratio
matches = get_matching_blocks.reduce(0) do |sum, triple|
sum + triple[-1]
end
Diff.calculate_ratio(matches, @a.length + @b.length)
end
def quick_ratio
if @fullbcount.nil? or @fullbcount.empty?
@fullbcount = {}
@b.each do |elt|
@fullbcount[elt] = (@fullbcount[elt] || 0) + 1
end
end
avail = {}
matches = 0
@a.each do |elt|
if avail.has_key? elt
numb = avail[elt]
else
numb = @fullbcount[elt] || 0
end
avail[elt] = numb - 1
if numb > 0
matches += 1
end
end
Diff.calculate_ratio matches, @a.length + @b.length
end
def real_quick_ratio
la, lb = @a.length, @b.length
Diff.calculate_ratio([la, lb].min, la + lb)
end
protected :chain_b, :match_block_helper
end # end class SequenceMatcher
def self.calculate_ratio(matches, length)
return 1.0 if length.zero?
2.0 * matches / length
end
# XXX: untested
def self.get_close_matches(word, possibilities, n=3, cutoff=0.6)
unless n > 0
raise "n must be > 0: #{n}"
end
unless 0.0 <= cutoff and cutoff <= 1.0
raise "cutoff must be in (0.0..1.0): #{cutoff}"
end
result = []
s = SequenceMatcher.new
s.set_seq_b word
possibilities.each do |x|
s.set_seq_a x
if s.real_quick_ratio >= cutoff and
s.quick_ratio >= cutoff and
s.ratio >= cutoff
result.push [s.ratio, x]
end
end
unless result.nil? or result.empty?
result.sort
result.reverse!
result = result[-n..-1]
end
result.collect { |score, x| x }
end
def self.count_leading(line, ch)
i, n = 0, line.length
while i < n and line[i].chr == ch
i += 1
end
i
end
end
module HTMLDiff
include Diff
class Builder
VALID_METHODS = [:replace, :insert, :delete, :equal]
def initialize(a, b)
@a = a
@b = b
@content = []
end
def do_op(opcode)
@opcode = opcode
op = @opcode[0]
VALID_METHODS.include?(op) or raise(NameError, "Invalid opcode #{op}")
self.method(op).call
end
def result
@content.join('')
end
#this methods have to be called via do_op(opcode) so that @opcode is set properly
private
def replace
delete("diffmod")
insert("diffmod")
end
def insert(tagclass="diffins")
op_helper("ins", tagclass, @b[@opcode[3]...@opcode[4]])
end
def delete(tagclass="diffdel")
op_helper("del", tagclass, @a[@opcode[1]...@opcode[2]])
end
def equal
@content += @b[@opcode[3]...@opcode[4]]
end
# using this as op_helper would be equivalent to the first version of diff.rb by Bill Atkins
def op_helper_simple(tagname, tagclass, to_add)
@content << "<#{tagname} class=\"#{tagclass}\">"
@content += to_add
@content << "</#{tagname}>"
end
# this tries to put <p> tags or newline chars before the opening diff tags (<ins> or <del>)
# or after the ending diff tags
# as a result the diff tags should be the "more inside" possible.
# this seems to work nice with html containing only paragraphs
# but not sure it works if there are other tags (div, span ... ? ) around
def op_helper(tagname, tagclass, to_add)
@content << to_add.shift while ( HTMLDiff.is_newline(to_add.first) or
HTMLDiff.is_p_close_tag(to_add.first) or
HTMLDiff.is_p_open_tag(to_add.first) )
@content << "<#{tagname} class=\"#{tagclass}\">"
@content += to_add
last_tags = []
last_tags.unshift(@content.pop) while ( HTMLDiff.is_newline(@content.last) or
HTMLDiff.is_p_close_tag(@content.last) or
HTMLDiff.is_p_open_tag(@content.last) )
last_tags.unshift "</#{tagname}>"
@content += last_tags
remove_empty_diff(tagname, tagclass)
end
def remove_empty_diff(tagname, tagclass)
if @content[-2] == "<#{tagname} class=\"#{tagclass}\">" and @content[-1] == "</#{tagname}>" then
@content.pop
@content.pop
end
end
end
def self.is_newline(x)
(x == "\n") or (x == "\r") or (x == "\t")
end
def self.is_p_open_tag(x)
x =~ /\A<(p|li|ul|ol|dir|dt|dl)/
end
def self.is_p_close_tag(x)
x =~ %r!\A</(p|li|ul|ol|dir|dt|dl)!
end
def self.diff(a, b)
a, b = a.split(//), b.split(//) if a.kind_of? String and b.kind_of? String
a, b = html2list(a), html2list(b)
out = Builder.new(a, b)
s = SequenceMatcher.new(a, b)
s.get_opcodes.each do |opcode|
out.do_op(opcode)
end
out.result
end
def self.html2list(x, b=false)
mode = 'char'
cur = ''
out = []
x = x.split(//) if x.kind_of? String
x.each do |c|
if mode == 'tag'
if c == '>'
if b
cur += ']'
else
cur += c
end
out.push(cur)
cur = ''
mode = 'char'
else
cur += c
end
elsif mode == 'char'
if c == '<'
out.push cur
if b
cur = '['
else
cur = c
end
mode = 'tag'
elsif /\s/.match c
out.push cur + c
cur = ''
else
cur += c
end
end
end
out.push cur
# TODO: make something better here
out.each{|x| x.chomp! unless is_newline(x)}
out.find_all { |x| x != '' }
end
end
if __FILE__ == $0
require 'pp'
# a = "<p>this is the original string</p>" # \n<p>but around the world</p>"
# b = "<p>this is the original </p><p>other parag</p><p>string</p>"
a = "<ul>\n\t<li>one</li>\n\t<li>two</li>\n</ul>"
b = "<ul>\n\t<li>one</li>\n\t<li>two\n\t<ul><li>abc</li></ul></li>\n</ul>"
puts a
pp HTMLDiff.html2list(a)
puts
puts b
pp HTMLDiff.html2list(b)
puts
puts HTMLDiff.diff(a, b)
end

View file

@ -1,15 +1,15 @@
# Model methods that want to rollback transactions gracefully
# (i.e, returning the user back to the form from which the request was posted)
# should raise Instiki::ValidationError.
#
# E.g. if a model object does
# raise "Foo: '#{foo}' is not equal to Bar: '#{bar}'" if (foo != bar)
#
# then the operation is not committed; Rails returns the user to the page
# where s/he was entering foo and bar, and the error message will be displayed
# on the page
module Instiki
class ValidationError < StandardError
end
# Model methods that want to rollback transactions gracefully
# (i.e, returning the user back to the form from which the request was posted)
# should raise Instiki::ValidationError.
#
# E.g. if a model object does
# raise "Foo: '#{foo}' is not equal to Bar: '#{bar}'" if (foo != bar)
#
# then the operation is not committed; Rails returns the user to the page
# where s/he was entering foo and bar, and the error message will be displayed
# on the page
module Instiki
class ValidationError < StandardError
end
end

302
libraries/rdocsupport.rb Executable file → Normal file
View file

@ -1,152 +1,152 @@
begin
require "rdoc/markup/simple_markup"
require 'rdoc/markup/simple_markup/to_html'
rescue LoadError
# use old version if available
require 'markup/simple_markup'
require 'markup/simple_markup/to_html'
end
module RDocSupport
# A simple +rdoc+ markup class which recognizes some additional
# formatting commands suitable for Wiki use.
class RDocMarkup < SM::SimpleMarkup
def initialize
super()
pre = '(?:\\s|^|\\\\)'
# links of the form
# [[<url> description with spaces]]
add_special(/((\\)?\[\[\S+?\s+.+?\]\])/,:TIDYLINK)
# and external references
add_special(/((\\)?(link:|anchor:|http:|mailto:|ftp:|img:|www\.)\S+\w\/?)/,
:HYPERLINK)
# <br/>
add_special(%r{(#{pre}<br/>)}, :BR)
# and <center> ... </center>
add_html("center", :CENTER)
end
def convert(text, handler)
super.sub(/^<p>\n/, '').sub(/<\/p>$/, '')
end
end
# Handle special hyperlinking requirments for RDoc formatted
# entries. Requires RDoc
class HyperLinkHtml < SM::ToHtml
# Initialize the HyperLinkHtml object.
# [path] location of the node
# [site] object representing the whole site (typically of class
# +Site+)
def initialize
super()
add_tag(:CENTER, "<center>", "</center>")
end
# handle <br/>
def handle_special_BR(special)
return "&lt;br/&gt" if special.text[0,1] == '\\'
special.text
end
# We're invoked with a potential external hyperlink.
# [mailto:] just gets inserted.
# [http:] links are checked to see if they
# reference an image. If so, that image gets inserted
# using an <img> tag. Otherwise a conventional <a href>
# is used.
# [img:] insert a <tt><img></tt> tag
# [link:] used to insert arbitrary <tt><a></tt> references
# [anchor:] used to create an anchor
def handle_special_HYPERLINK(special)
text = special.text.strip
return text[1..-1] if text[0,1] == '\\'
url = special.text.strip
if url =~ /([A-Za-z]+):(.*)/
type = $1
path = $2
else
type = "http"
path = url
url = "http://#{url}"
end
case type
when "http"
if url =~ /\.(gif|png|jpg|jpeg|bmp)$/
"<img src=\"#{url}\"/>"
else
"<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
end
when "img"
"<img src=\"#{path}\"/>"
when "link"
"<a href=\"#{path}\">#{path}</a>"
when "anchor"
"<a name=\"#{path}\"></a>"
else
"<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
end
end
# Here's a hyperlink where the label is different to the URL
# [[url label that may contain spaces]]
#
def handle_special_TIDYLINK(special)
text = special.text.strip
return text[1..-1] if text[0,1] == '\\'
unless text =~ /\[\[(\S+?)\s+(.+?)\]\]/
return text
end
url = $1
label = $2
label = RDocFormatter.new(label).to_html
label = label.split.select{|x| x =~ /\S/}.
map{|x| x.chomp}.join(' ')
case url
when /link:(\S+)/
return %{<a href="#{$1}">#{label}</a>}
when /img:(\S+)/
return %{<img src="http://#{$1}" alt="#{label}" />}
when /rubytalk:(\S+)/
return %{<a href="http://ruby-talk.org/blade/#{$1}">#{label}</a>}
when /rubygarden:(\S+)/
return %{<a href="http://www.rubygarden.org/ruby?#{$1}">#{label}</a>}
when /c2:(\S+)/
return %{<a href="http://c2.com/cgi/wiki?#{$1}">#{label}</a>}
when /isbn:(\S+)/
return %{<a href="http://search.barnesandnoble.com/bookSearch/} +
%{isbnInquiry.asp?isbn=#{$1}">#{label}</a>}
end
unless url =~ /\w+?:/
url = "http://#{url}"
end
"<a href=\"#{url}\">#{label}</a>"
end
end
class RDocFormatter
def initialize(text)
@text = text
end
def to_html
markup = RDocMarkup.new
h = HyperLinkHtml.new
markup.convert(@text, h)
end
end
begin
require "rdoc/markup/simple_markup"
require 'rdoc/markup/simple_markup/to_html'
rescue LoadError
# use old version if available
require 'markup/simple_markup'
require 'markup/simple_markup/to_html'
end
module RDocSupport
# A simple +rdoc+ markup class which recognizes some additional
# formatting commands suitable for Wiki use.
class RDocMarkup < SM::SimpleMarkup
def initialize
super()
pre = '(?:\\s|^|\\\\)'
# links of the form
# [[<url> description with spaces]]
add_special(/((\\)?\[\[\S+?\s+.+?\]\])/,:TIDYLINK)
# and external references
add_special(/((\\)?(link:|anchor:|http:|mailto:|ftp:|img:|www\.)\S+\w\/?)/,
:HYPERLINK)
# <br/>
add_special(%r{(#{pre}<br/>)}, :BR)
# and <center> ... </center>
add_html("center", :CENTER)
end
def convert(text, handler)
super.sub(/^<p>\n/, '').sub(/<\/p>$/, '')
end
end
# Handle special hyperlinking requirments for RDoc formatted
# entries. Requires RDoc
class HyperLinkHtml < SM::ToHtml
# Initialize the HyperLinkHtml object.
# [path] location of the node
# [site] object representing the whole site (typically of class
# +Site+)
def initialize
super()
add_tag(:CENTER, "<center>", "</center>")
end
# handle <br/>
def handle_special_BR(special)
return "&lt;br/&gt" if special.text[0,1] == '\\'
special.text
end
# We're invoked with a potential external hyperlink.
# [mailto:] just gets inserted.
# [http:] links are checked to see if they
# reference an image. If so, that image gets inserted
# using an <img> tag. Otherwise a conventional <a href>
# is used.
# [img:] insert a <tt><img></tt> tag
# [link:] used to insert arbitrary <tt><a></tt> references
# [anchor:] used to create an anchor
def handle_special_HYPERLINK(special)
text = special.text.strip
return text[1..-1] if text[0,1] == '\\'
url = special.text.strip
if url =~ /([A-Za-z]+):(.*)/
type = $1
path = $2
else
type = "http"
path = url
url = "http://#{url}"
end
case type
when "http"
if url =~ /\.(gif|png|jpg|jpeg|bmp)$/
"<img src=\"#{url}\"/>"
else
"<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
end
when "img"
"<img src=\"#{path}\"/>"
when "link"
"<a href=\"#{path}\">#{path}</a>"
when "anchor"
"<a name=\"#{path}\"></a>"
else
"<a href=\"#{url}\">#{url.sub(%r{^\w+:/*}, '')}</a>"
end
end
# Here's a hyperlink where the label is different to the URL
# [[url label that may contain spaces]]
#
def handle_special_TIDYLINK(special)
text = special.text.strip
return text[1..-1] if text[0,1] == '\\'
unless text =~ /\[\[(\S+?)\s+(.+?)\]\]/
return text
end
url = $1
label = $2
label = RDocFormatter.new(label).to_html
label = label.split.select{|x| x =~ /\S/}.
map{|x| x.chomp}.join(' ')
case url
when /link:(\S+)/
return %{<a href="#{$1}">#{label}</a>}
when /img:(\S+)/
return %{<img src="http://#{$1}" alt="#{label}" />}
when /rubytalk:(\S+)/
return %{<a href="http://ruby-talk.org/blade/#{$1}">#{label}</a>}
when /rubygarden:(\S+)/
return %{<a href="http://www.rubygarden.org/ruby?#{$1}">#{label}</a>}
when /c2:(\S+)/
return %{<a href="http://c2.com/cgi/wiki?#{$1}">#{label}</a>}
when /isbn:(\S+)/
return %{<a href="http://search.barnesandnoble.com/bookSearch/} +
%{isbnInquiry.asp?isbn=#{$1}">#{label}</a>}
end
unless url =~ /\w+?:/
url = "http://#{url}"
end
"<a href=\"#{url}\">#{label}</a>"
end
end
class RDocFormatter
def initialize(text)
@text = text
end
def to_html
markup = RDocMarkup.new
h = HyperLinkHtml.new
markup.convert(@text, h)
end
end
end

1466
libraries/redcloth_for_tex.rb Executable file → Normal file

File diff suppressed because it is too large Load diff

214
libraries/url_rewriting_hack.rb Executable file → Normal file
View file

@ -1,107 +1,107 @@
# Below are some hacks to Rails internal classes that implement Instiki URLs scheme.
# It is no doubt a bad practice to override internal implementation of anything.
# When Rails implements some way to do it in the framework, this code should be replaced
# with something more legitimate.
# In Instiki URLs are mapped to the ActionPack actions, possibly performed on a particular
# web (sub-wiki) and page within that web.
#
# 1. Controller is determined by action name (default is 'wiki')
# 2. '/name1/' maps to action 'name1', unspecified web
# Example: http://localhost/new_system/
# 3. Special case of above, URI '/wiki/' maps to action 'index', because Rails sets this address
# when default controller name is specified as 'wiki', and an application root
# (http://localhost:2500/)is requested.
# 4. '/name1/name2/' maps to web 'name1', action 'name2'
# Example: http://localhost/mywiki/search/
# 5. '/name1/name2/name3/' maps to web 'name1', action 'name2',
# Example: http://localhost/mywiki/show/HomePage
require 'dispatcher'
# Overrides Rails DispatchServlet.parse_uri
class DispatchServlet
def self.parse_uri(path)
result = parse_path(path)
if result
result[:controller] = ActionMapper.map_to_controller(result[:action])
result
else
false
end
end
def self.parse_path(path)
ApplicationController.logger.debug "Parsing URI '#{path}'"
component = '([-_a-zA-Z0-9]+)'
page_name = '(.*)'
case path.sub(%r{^/(?:fcgi|mruby|cgi)/}, "/")
when '/wiki/'
{ :web => nil, :controller => 'wiki', :action => 'index' }
when %r{^/#{component}/?$}
{ :web => nil, :controller => 'wiki', :action => $1 }
when %r{^/#{component}/#{component}/?$}
{ :web => $1, :controller => 'wiki', :action => $2 }
when %r{^/#{component}/#{component}/(.*)/?$}
{ :web => $1, :controller => 'wiki', :action => $2, :id => drop_trailing_slash($3) }
else
false
end
end
def self.drop_trailing_slash(line)
if line[-1] == ?/
line.chop
else
line
end
end
class ActionMapper
@@action_to_controller_map = {
'file' => 'file',
'pic' => 'file'
}
def self.map_to_controller(action)
@@action_to_controller_map[action] || 'wiki'
end
end
end
require 'action_controller/url_rewriter.rb'
# Overrides parts of AP UrlRewriter to achieve the Instiki's legacy URL scheme
module ActionController
class UrlRewriter
VALID_OPTIONS << :web unless VALID_OPTIONS.include? :web
private
def resolve_aliases(options)
options[:controller_prefix] = options[:web] unless options[:web].nil?
options
end
def controller_name(options, controller_prefix)
ensure_slash_suffix(options, :controller_prefix)
controller_name = case options[:controller_prefix]
when String: options[:controller_prefix]
when false : ""
when nil : controller_prefix || ""
end
# In Instiki we don't need the controller name (there is only one comtroller, anyway)
# therefore the below line is commented out
# controller_name << (options[:controller] + "/") if options[:controller]
return controller_name
end
end
end
# Below are some hacks to Rails internal classes that implement Instiki URLs scheme.
# It is no doubt a bad practice to override internal implementation of anything.
# When Rails implements some way to do it in the framework, this code should be replaced
# with something more legitimate.
# In Instiki URLs are mapped to the ActionPack actions, possibly performed on a particular
# web (sub-wiki) and page within that web.
#
# 1. Controller is determined by action name (default is 'wiki')
# 2. '/name1/' maps to action 'name1', unspecified web
# Example: http://localhost/new_system/
# 3. Special case of above, URI '/wiki/' maps to action 'index', because Rails sets this address
# when default controller name is specified as 'wiki', and an application root
# (http://localhost:2500/)is requested.
# 4. '/name1/name2/' maps to web 'name1', action 'name2'
# Example: http://localhost/mywiki/search/
# 5. '/name1/name2/name3/' maps to web 'name1', action 'name2',
# Example: http://localhost/mywiki/show/HomePage
require 'dispatcher'
# Overrides Rails DispatchServlet.parse_uri
class DispatchServlet
def self.parse_uri(path)
result = parse_path(path)
if result
result[:controller] = ActionMapper.map_to_controller(result[:action])
result
else
false
end
end
def self.parse_path(path)
ApplicationController.logger.debug "Parsing URI '#{path}'"
component = '([-_a-zA-Z0-9]+)'
page_name = '(.*)'
case path.sub(%r{^/(?:fcgi|mruby|cgi)/}, "/")
when '/wiki/'
{ :web => nil, :controller => 'wiki', :action => 'index' }
when %r{^/#{component}/?$}
{ :web => nil, :controller => 'wiki', :action => $1 }
when %r{^/#{component}/#{component}/?$}
{ :web => $1, :controller => 'wiki', :action => $2 }
when %r{^/#{component}/#{component}/(.*)/?$}
{ :web => $1, :controller => 'wiki', :action => $2, :id => drop_trailing_slash($3) }
else
false
end
end
def self.drop_trailing_slash(line)
if line[-1] == ?/
line.chop
else
line
end
end
class ActionMapper
@@action_to_controller_map = {
'file' => 'file',
'pic' => 'file'
}
def self.map_to_controller(action)
@@action_to_controller_map[action] || 'wiki'
end
end
end
require 'action_controller/url_rewriter.rb'
# Overrides parts of AP UrlRewriter to achieve the Instiki's legacy URL scheme
module ActionController
class UrlRewriter
VALID_OPTIONS << :web unless VALID_OPTIONS.include? :web
private
def resolve_aliases(options)
options[:controller_prefix] = options[:web] unless options[:web].nil?
options
end
def controller_name(options, controller_prefix)
ensure_slash_suffix(options, :controller_prefix)
controller_name = case options[:controller_prefix]
when String: options[:controller_prefix]
when false : ""
when nil : controller_prefix || ""
end
# In Instiki we don't need the controller name (there is only one comtroller, anyway)
# therefore the below line is commented out
# controller_name << (options[:controller] + "/") if options[:controller]
return controller_name
end
end
end

36
natives/osx/desktop_launcher/AppDelegate.h Executable file → Normal file
View file

@ -1,18 +1,18 @@
/* AppDelegate */
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject
{
IBOutlet NSMenu* statusMenu;
NSTask* serverCommand;
int processID;
BOOL shouldOpenUntitled;
NSNetService* service;
}
- (IBAction)about:(id)sender;
- (IBAction)goToHomepage:(id)sender;
- (IBAction)goToInstikiOrg:(id)sender;
- (IBAction)quit:(id)sender;
@end
/* AppDelegate */
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject
{
IBOutlet NSMenu* statusMenu;
NSTask* serverCommand;
int processID;
BOOL shouldOpenUntitled;
NSNetService* service;
}
- (IBAction)about:(id)sender;
- (IBAction)goToHomepage:(id)sender;
- (IBAction)goToInstikiOrg:(id)sender;
- (IBAction)quit:(id)sender;
@end

218
natives/osx/desktop_launcher/AppDelegate.mm Executable file → Normal file
View file

@ -1,109 +1,109 @@
#include <unistd.h>
#include <sys/wait.h>
#import "AppDelegate.h"
int launch_ruby (char const* cmd)
{
int pId, parentID = getpid();
if((pId = fork()) == 0) // child
{
NSLog(@"set child (%d) to pgrp %d", getpid(), parentID);
setpgrp(0, parentID);
system(cmd);
return 0;
}
else // parent
{
NSLog(@"started child process: %d", pId);
return pId;
}
}
@implementation AppDelegate
- (NSString*)storageDirectory
{
NSString* dir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Instiki"];
[[NSFileManager defaultManager] createDirectoryAtPath:dir attributes:nil];
return dir;
}
- (void)awakeFromNib
{
setpgrp(0, getpid());
if([[[[NSBundle mainBundle] infoDictionary] objectForKey:@"LSUIElement"] isEqualToString:@"1"])
{
NSStatusBar* bar = [NSStatusBar systemStatusBar];
NSStatusItem* item = [[bar statusItemWithLength:NSVariableStatusItemLength] retain];
[item setTitle:@"Wiki"];
[item setHighlightMode:YES];
[item setMenu:statusMenu];
}
NSBundle* bundle = [NSBundle bundleForClass:[self class]];
NSString* ruby = [bundle pathForResource:@"ruby" ofType:nil];
NSString* script = [[bundle resourcePath] stringByAppendingPathComponent:@"rb_src/instiki.rb"];
if(ruby && script)
{
NSString* cmd = [NSString stringWithFormat:
@"%@ -I '%@' -I '%@' '%@' -s --storage='%@'",
ruby,
[[bundle resourcePath] stringByAppendingPathComponent:@"lib/ruby/1.8"],
[[bundle resourcePath] stringByAppendingPathComponent:@"lib/ruby/1.8/powerpc-darwin"],
script,
[self storageDirectory]
];
NSLog(@"starting %@", cmd);
processID = launch_ruby([cmd UTF8String]);
}
/* public the service using rendezvous */
service = [[NSNetService alloc]
initWithDomain:@"" // default domain
type:@"_http._tcp."
name:[NSString stringWithFormat:@"%@'s Instiki", NSFullUserName()]
port:2500];
[service publish];
}
- (void)applicationWillTerminate:(NSNotification*)aNotification
{
[service stop];
[service release];
kill(0, SIGTERM);
}
- (IBAction)about:(id)sender
{
[NSApp activateIgnoringOtherApps:YES];
[NSApp orderFrontStandardAboutPanel:self];
}
- (IBAction)goToHomepage:(id)sender
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://localhost:2500/"]];
}
- (IBAction)goToInstikiOrg:(id)sender
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.instiki.org/"]];
}
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication*)sender
{
return shouldOpenUntitled ?: (shouldOpenUntitled = YES, NO);
}
- (BOOL)applicationOpenUntitledFile:(NSApplication*)theApplication
{
return [self goToHomepage:self], YES;
}
- (IBAction)quit:(id)sender
{
[NSApp terminate:self];
}
@end
#include <unistd.h>
#include <sys/wait.h>
#import "AppDelegate.h"
int launch_ruby (char const* cmd)
{
int pId, parentID = getpid();
if((pId = fork()) == 0) // child
{
NSLog(@"set child (%d) to pgrp %d", getpid(), parentID);
setpgrp(0, parentID);
system(cmd);
return 0;
}
else // parent
{
NSLog(@"started child process: %d", pId);
return pId;
}
}
@implementation AppDelegate
- (NSString*)storageDirectory
{
NSString* dir = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Instiki"];
[[NSFileManager defaultManager] createDirectoryAtPath:dir attributes:nil];
return dir;
}
- (void)awakeFromNib
{
setpgrp(0, getpid());
if([[[[NSBundle mainBundle] infoDictionary] objectForKey:@"LSUIElement"] isEqualToString:@"1"])
{
NSStatusBar* bar = [NSStatusBar systemStatusBar];
NSStatusItem* item = [[bar statusItemWithLength:NSVariableStatusItemLength] retain];
[item setTitle:@"Wiki"];
[item setHighlightMode:YES];
[item setMenu:statusMenu];
}
NSBundle* bundle = [NSBundle bundleForClass:[self class]];
NSString* ruby = [bundle pathForResource:@"ruby" ofType:nil];
NSString* script = [[bundle resourcePath] stringByAppendingPathComponent:@"rb_src/instiki.rb"];
if(ruby && script)
{
NSString* cmd = [NSString stringWithFormat:
@"%@ -I '%@' -I '%@' '%@' -s --storage='%@'",
ruby,
[[bundle resourcePath] stringByAppendingPathComponent:@"lib/ruby/1.8"],
[[bundle resourcePath] stringByAppendingPathComponent:@"lib/ruby/1.8/powerpc-darwin"],
script,
[self storageDirectory]
];
NSLog(@"starting %@", cmd);
processID = launch_ruby([cmd UTF8String]);
}
/* public the service using rendezvous */
service = [[NSNetService alloc]
initWithDomain:@"" // default domain
type:@"_http._tcp."
name:[NSString stringWithFormat:@"%@'s Instiki", NSFullUserName()]
port:2500];
[service publish];
}
- (void)applicationWillTerminate:(NSNotification*)aNotification
{
[service stop];
[service release];
kill(0, SIGTERM);
}
- (IBAction)about:(id)sender
{
[NSApp activateIgnoringOtherApps:YES];
[NSApp orderFrontStandardAboutPanel:self];
}
- (IBAction)goToHomepage:(id)sender
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://localhost:2500/"]];
}
- (IBAction)goToInstikiOrg:(id)sender
{
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.instiki.org/"]];
}
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication*)sender
{
return shouldOpenUntitled ?: (shouldOpenUntitled = YES, NO);
}
- (BOOL)applicationOpenUntitledFile:(NSApplication*)theApplication
{
return [self goToHomepage:self], YES;
}
- (IBAction)quit:(id)sender
{
[NSApp terminate:self];
}
@end

30
natives/osx/desktop_launcher/Credits.html Executable file → Normal file
View file

@ -1,16 +1,16 @@
<dl>
<dt>Engineering:</dt>
<dd>Some people</dd>
<dt>Human Interface Design:</dt>
<dd>Some other people</dd>
<dt>Testing:</dt>
<dd>Hopefully not nobody</dd>
<dt>Documentation:</dt>
<dd>Whoever</dd>
<dt>With special thanks to:</dt>
<dd>Mom</dd>
<dl>
<dt>Engineering:</dt>
<dd>Some people</dd>
<dt>Human Interface Design:</dt>
<dd>Some other people</dd>
<dt>Testing:</dt>
<dd>Hopefully not nobody</dd>
<dt>Documentation:</dt>
<dd>Whoever</dd>
<dt>With special thanks to:</dt>
<dd>Mom</dd>
</dl>

View file

24
natives/osx/desktop_launcher/English.lproj/MainMenu.nib/classes.nib generated Executable file → Normal file
View file

@ -1,13 +1,13 @@
{
IBClasses = (
{
ACTIONS = {about = id; goToHomepage = id; goToInstikiOrg = id; quit = id; };
CLASS = AppDelegate;
LANGUAGE = ObjC;
OUTLETS = {statusMenu = NSMenu; };
SUPERCLASS = NSObject;
},
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }
);
IBVersion = 1;
{
IBClasses = (
{
ACTIONS = {about = id; goToHomepage = id; goToInstikiOrg = id; quit = id; };
CLASS = AppDelegate;
LANGUAGE = ObjC;
OUTLETS = {statusMenu = NSMenu; };
SUPERCLASS = NSObject;
},
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }
);
IBVersion = 1;
}

48
natives/osx/desktop_launcher/English.lproj/MainMenu.nib/info.nib generated Executable file → Normal file
View file

@ -1,24 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>109 6 356 240 0 0 1440 878 </string>
<key>IBEditorPositions</key>
<dict>
<key>206</key>
<string>112 300 116 87 0 0 1440 878 </string>
<key>29</key>
<string>241 316 70 44 0 0 1440 878 </string>
</dict>
<key>IBFramework Version</key>
<string>349.0</string>
<key>IBOpenObjects</key>
<array>
<integer>206</integer>
<integer>29</integer>
</array>
<key>IBSystem Version</key>
<string>7H63</string>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>109 6 356 240 0 0 1440 878 </string>
<key>IBEditorPositions</key>
<dict>
<key>206</key>
<string>112 300 116 87 0 0 1440 878 </string>
<key>29</key>
<string>241 316 70 44 0 0 1440 878 </string>
</dict>
<key>IBFramework Version</key>
<string>349.0</string>
<key>IBOpenObjects</key>
<array>
<integer>206</integer>
<integer>29</integer>
</array>
<key>IBSystem Version</key>
<string>7H63</string>
</dict>
</plist>

0
natives/osx/desktop_launcher/English.lproj/MainMenu.nib/objects.nib generated Executable file → Normal file
View file

24
natives/osx/desktop_launcher/Info.plist Executable file → Normal file
View file

@ -1,13 +1,13 @@
{
CFBundleDevelopmentRegion = English;
CFBundleExecutable = Instiki;
CFBundleIconFile = "";
CFBundleIdentifier = "com.nextangle.instiki";
CFBundleInfoDictionaryVersion = "6.0";
CFBundlePackageType = APPL;
CFBundleSignature = WIKI;
CFBundleVersion = "0.9.0";
LSUIElement = 1;
NSMainNibFile = MainMenu;
NSPrincipalClass = NSApplication;
{
CFBundleDevelopmentRegion = English;
CFBundleExecutable = Instiki;
CFBundleIconFile = "";
CFBundleIdentifier = "com.nextangle.instiki";
CFBundleInfoDictionaryVersion = "6.0";
CFBundlePackageType = APPL;
CFBundleSignature = WIKI;
CFBundleVersion = "0.9.0";
LSUIElement = 1;
NSMainNibFile = MainMenu;
NSPrincipalClass = NSApplication;
}

1184
natives/osx/desktop_launcher/Instiki.xcode/project.pbxproj Executable file → Normal file

File diff suppressed because it is too large Load diff

14
natives/osx/desktop_launcher/Instiki_Prefix.pch Executable file → Normal file
View file

@ -1,7 +1,7 @@
//
// Prefix header for all source files of the 'Instiki' target in the 'Instiki' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif
//
// Prefix header for all source files of the 'Instiki' target in the 'Instiki' project
//
#ifdef __OBJC__
#import <Cocoa/Cocoa.h>
#endif

18
natives/osx/desktop_launcher/MakeDMG.sh Executable file → Normal file
View file

@ -1,9 +1,9 @@
#!/bin/sh
hdiutil create -size 12m -fs HFS+ -volname Instiki -ov /tmp/Instiki_12MB.dmg
hdiutil mount /tmp/Instiki_12MB.dmg
# strip ~/ruby/instiki/natives/osx/build/Instiki.app/Contents/MacOS/Instiki
ditto ~/ruby/instiki/natives/osx/desktop_launcher/build/Instiki.app /Volumes/Instiki/Instiki.app
hdiutil unmount /Volumes/Instiki
hdiutil convert -format UDZO -o /tmp/Instiki.dmg /tmp/Instiki_12MB.dmg
hdiutil internet-enable -yes /tmp/Instiki.dmg
#!/bin/sh
hdiutil create -size 12m -fs HFS+ -volname Instiki -ov /tmp/Instiki_12MB.dmg
hdiutil mount /tmp/Instiki_12MB.dmg
# strip ~/ruby/instiki/natives/osx/build/Instiki.app/Contents/MacOS/Instiki
ditto ~/ruby/instiki/natives/osx/desktop_launcher/build/Instiki.app /Volumes/Instiki/Instiki.app
hdiutil unmount /Volumes/Instiki
hdiutil convert -format UDZO -o /tmp/Instiki.dmg /tmp/Instiki_12MB.dmg
hdiutil internet-enable -yes /tmp/Instiki.dmg

28
natives/osx/desktop_launcher/main.mm Executable file → Normal file
View file

@ -1,14 +1,14 @@
//
// main.mm
// Instiki
//
// Created by Allan Odgaard on Thu May 20 2004.
// Copyright (c) 2004 MacroMates. All rights reserved.
//
#import <Cocoa/Cocoa.h>
int main (int argc, char const* argv[])
{
return NSApplicationMain(argc, argv);
}
//
// main.mm
// Instiki
//
// Created by Allan Odgaard on Thu May 20 2004.
// Copyright (c) 2004 MacroMates. All rights reserved.
//
#import <Cocoa/Cocoa.h>
int main (int argc, char const* argv[])
{
return NSApplicationMain(argc, argv);
}

32
natives/osx/desktop_launcher/version.plist Executable file → Normal file
View file

@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildVersion</key>
<string>17</string>
<key>CFBundleShortVersionString</key>
<string>0.1</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>ProjectName</key>
<string>NibPBTemplates</string>
<key>SourceVersion</key>
<string>1150000</string>
</dict>
</plist>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildVersion</key>
<string>17</string>
<key>CFBundleShortVersionString</key>
<string>0.1</string>
<key>CFBundleVersion</key>
<string>0.1</string>
<key>ProjectName</key>
<string>NibPBTemplates</string>
<key>SourceVersion</key>
<string>1150000</string>
</dict>
</plist>

0
public/images/.images_go_here Executable file → Normal file
View file

View file

@ -1,48 +1,48 @@
function proposeAddress() {
document.getElementById('address').value =
document.getElementById('name').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function cleanAddress() {
document.getElementById('address').value =
document.getElementById('address').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function validateSetup() {
if (document.getElementById('system_password').value == "") {
alert("You must enter the system password");
return false;
}
if (document.getElementById('name').value == "") {
alert("You must pick a name for the web");
return false;
}
if (document.getElementById('address').value == "") {
alert("You must pick an address for the web");
return false;
}
if (document.getElementById('password').value != "" &&
document.getElementById('password').value != document.getElementById('password_check').value) {
alert("The password and its verification doesn't match");
return false;
}
return true;
}
// overriding auto-complete by form managers
// code by Chris Holland, lifted from
// http://chrisholland.blogspot.com/2004/11/banks-protect-privacy-disable.html
function overrideAutocomplete() {
if (document.getElementsByTagName) {
var inputElements = document.getElementsByTagName("input");
for (i=0; inputElements[i]; i++) {
if (inputElements[i].className && (inputElements[i].className.indexOf("disableAutoComplete") != -1)) {
inputElements[i].setAttribute("autocomplete","off");
}//if current input element has the disableAutoComplete class set.
}//loop thru input elements
}
}
function proposeAddress() {
document.getElementById('address').value =
document.getElementById('name').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function cleanAddress() {
document.getElementById('address').value =
document.getElementById('address').value.replace(/[^a-zA-Z0-9]/g, "").toLowerCase();
}
function validateSetup() {
if (document.getElementById('system_password').value == "") {
alert("You must enter the system password");
return false;
}
if (document.getElementById('name').value == "") {
alert("You must pick a name for the web");
return false;
}
if (document.getElementById('address').value == "") {
alert("You must pick an address for the web");
return false;
}
if (document.getElementById('password').value != "" &&
document.getElementById('password').value != document.getElementById('password_check').value) {
alert("The password and its verification doesn't match");
return false;
}
return true;
}
// overriding auto-complete by form managers
// code by Chris Holland, lifted from
// http://chrisholland.blogspot.com/2004/11/banks-protect-privacy-disable.html
function overrideAutocomplete() {
if (document.getElementsByTagName) {
var inputElements = document.getElementsByTagName("input");
for (i=0; inputElements[i]; i++) {
if (inputElements[i].className && (inputElements[i].className.indexOf("disableAutoComplete") != -1)) {
inputElements[i].setAttribute("autocomplete","off");
}//if current input element has the disableAutoComplete class set.
}//loop thru input elements
}
}

442
public/stylesheets/instiki.css Executable file → Normal file
View file

@ -1,222 +1,222 @@
#Container {
float: none;
margin: 0 auto;
text-align: center;
}
#Content {
margin: 0;
padding: 5px;
text-align: left;
border-top: none;
float: left;
}
body { background-color: #fff; color: #333; }
body, p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
a { color: #000; }
.newWikiWord { background-color: #eee; }
.newWikiWord a:hover { background-color: white; }
a:visited { color: #666; }
a:hover { color: #fff; background-color:#000; }
h1, h2, h3 { color: #333; font-family: georgia, verdana; }
h1 { font-size: 28px }
h2 { font-size: 19px }
h3 { font-size: 16px }
h1#pageName {
margin: 5px 0px 0px 0px;
padding: 0px 0px 0px 0px;
line-height: 28px;
}
h1#pageName small {
color: grey;
line-height: 10px;
font-size: 10px;
padding: 0px;
}
a.nav, a.nav:link, a.nav:visited { color: #000; }
a.nav:hover { color: #fff; background-color:#000; }
li { margin-bottom: 7px }
.navigation {
margin-top: 5px;
font-size : 12px;
color: #999;
}
.navigation a:hover { color: #fff; background-color:#000; }
.navigation a {
font-size: 11px;
color: black;
font-weight: bold;
}
.navigation small a {
font-weight: normal;
font-size: 11px;
}
.navOn{
font-size: 11px;
color: grey;
font-weight: bold;
text-decoration: none;
}
.help {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 11px;
}
.inputBox {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 11px;
background-color: #eee;
padding: 5px;
margin-bottom: 20px;
}
blockquote {
display: block;
margin: 0px 0px 20px 0px;
padding: 0px 30px;
font-size:11px;
line-height:17px;
font-style: italic;
}
pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
}
ol.setup {
font-size: 19px;
font-family: georgia, verdana;
padding-left: 25px;
}
ol.setup li {
margin-bottom: 20px
}
.byline {
font-size: 10px;
font-style: italic;
margin-bottom: 10px;
color: #999;
}
.references {
font-size: 10px;
}
.diffdel, del.diffmod {
background: pink;
}
.diffins, ins.diffmod {
background: lightgreen;
}
#footer {
height: 14px;
padding: .25em 0;
}
#footer p {
font-size: 10px;
color: gray;
font-style: italic;
margin: 0;
float: right;
text-align: right;
}
#error {
color: darkred;
font-style: italic;
width: 450px;
}
#info {
color: darkgreen;
font-style: italic;
width: 450px;
}
#TextileHelp table {
margin-bottom: 0;
}
#TextileHelp table+h3 {
margin-top: 11px;
}
#TextileHelp table td {
font-size: 11px;
padding: 3px;
vertical-align: top;
border-top: 1px dotted #ccc;
}
#TextileHelp table td.arrow {
padding-right: 5px;
padding-left: 10px;
color: #999;
}
#TextileHelp table td.label {
font-weight: bold;
white-space: nowrap;
font-size: 10px;
padding-right: 15px;
color: #000;
}
#TextileHelp h3 {
font-size: 11px;
font-weight: bold;
font-weight: normal;
margin: 0 0 5px 0;
padding: 5px 0 0 0;
}
#TextileHelp p {
font-size: 10px;
}
.rightHandSide {
float: right;
width: 147px;
margin-left: 10px;
padding-left: 20px;
border-left: 1px dotted #ccc;
}
.rightHandSide p {
font-size: 10px;
}
.newsList {
margin-top: 20px;
}
.newsList p {
margin-bottom:30px
#Container {
float: none;
margin: 0 auto;
text-align: center;
}
#Content {
margin: 0;
padding: 5px;
text-align: left;
border-top: none;
float: left;
}
body { background-color: #fff; color: #333; }
body, p, ol, ul, td {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 13px;
line-height: 18px;
}
a { color: #000; }
.newWikiWord { background-color: #eee; }
.newWikiWord a:hover { background-color: white; }
a:visited { color: #666; }
a:hover { color: #fff; background-color:#000; }
h1, h2, h3 { color: #333; font-family: georgia, verdana; }
h1 { font-size: 28px }
h2 { font-size: 19px }
h3 { font-size: 16px }
h1#pageName {
margin: 5px 0px 0px 0px;
padding: 0px 0px 0px 0px;
line-height: 28px;
}
h1#pageName small {
color: grey;
line-height: 10px;
font-size: 10px;
padding: 0px;
}
a.nav, a.nav:link, a.nav:visited { color: #000; }
a.nav:hover { color: #fff; background-color:#000; }
li { margin-bottom: 7px }
.navigation {
margin-top: 5px;
font-size : 12px;
color: #999;
}
.navigation a:hover { color: #fff; background-color:#000; }
.navigation a {
font-size: 11px;
color: black;
font-weight: bold;
}
.navigation small a {
font-weight: normal;
font-size: 11px;
}
.navOn{
font-size: 11px;
color: grey;
font-weight: bold;
text-decoration: none;
}
.help {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 11px;
}
.inputBox {
font-family: verdana, arial, helvetica, sans-serif;
font-size: 11px;
background-color: #eee;
padding: 5px;
margin-bottom: 20px;
}
blockquote {
display: block;
margin: 0px 0px 20px 0px;
padding: 0px 30px;
font-size:11px;
line-height:17px;
font-style: italic;
}
pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
}
ol.setup {
font-size: 19px;
font-family: georgia, verdana;
padding-left: 25px;
}
ol.setup li {
margin-bottom: 20px
}
.byline {
font-size: 10px;
font-style: italic;
margin-bottom: 10px;
color: #999;
}
.references {
font-size: 10px;
}
.diffdel, del.diffmod {
background: pink;
}
.diffins, ins.diffmod {
background: lightgreen;
}
#footer {
height: 14px;
padding: .25em 0;
}
#footer p {
font-size: 10px;
color: gray;
font-style: italic;
margin: 0;
float: right;
text-align: right;
}
#error {
color: darkred;
font-style: italic;
width: 450px;
}
#info {
color: darkgreen;
font-style: italic;
width: 450px;
}
#TextileHelp table {
margin-bottom: 0;
}
#TextileHelp table+h3 {
margin-top: 11px;
}
#TextileHelp table td {
font-size: 11px;
padding: 3px;
vertical-align: top;
border-top: 1px dotted #ccc;
}
#TextileHelp table td.arrow {
padding-right: 5px;
padding-left: 10px;
color: #999;
}
#TextileHelp table td.label {
font-weight: bold;
white-space: nowrap;
font-size: 10px;
padding-right: 15px;
color: #000;
}
#TextileHelp h3 {
font-size: 11px;
font-weight: bold;
font-weight: normal;
margin: 0 0 5px 0;
padding: 5px 0 0 0;
}
#TextileHelp p {
font-size: 10px;
}
.rightHandSide {
float: right;
width: 147px;
margin-left: 10px;
padding-left: 20px;
border-left: 1px dotted #ccc;
}
.rightHandSide p {
font-size: 10px;
}
.newsList {
margin-top: 20px;
}
.newsList p {
margin-bottom:30px
}

View file

@ -1,83 +1,83 @@
#!/usr/bin/ruby
require 'webrick'
require 'optparse'
require 'fileutils'
pwd = File.expand_path(File.dirname(__FILE__) + "/..")
OPTIONS = {
# Overridable options
:port => 2500,
:ip => '127.0.0.1',
:environment => 'production',
:server_root => File.expand_path(File.dirname(__FILE__) + '/../public/'),
:server_type => WEBrick::SimpleServer,
:storage => "#{File.expand_path(FileUtils.pwd)}/storage",
}
ARGV.options do |opts|
script_name = File.basename($0)
opts.banner = "Usage: ruby #{script_name} [options]"
opts.separator ''
opts.on('-p', '--port=port', Integer,
'Runs Instiki on the specified port.',
'Default: 2500') { |OPTIONS[:port]| }
opts.on('-b', '--binding=ip', String,
'Binds Rails to the specified ip.',
'Default: 127.0.0.1') { |OPTIONS[:ip]| }
opts.on('-i', '--index=controller', String,
'Specifies an index controller that requests for root will go to (instead of congratulations screen).'
) { |OPTIONS[:index_controller]| }
opts.on('-e', '--environment=name', String,
'Specifies the environment to run this server under (test/development/production).',
'Default: production') { |OPTIONS[:environment]| }
opts.on('-d', '--daemon',
'Make Rails run as a Daemon (only works if fork is available -- meaning on *nix).'
) { OPTIONS[:server_type] = WEBrick::Daemon }
opts.on('-s', '--simple', '--simple-server',
'[deprecated] Forces Instiki not to run as a Daemon if fork is available.',
'Since version 0.10.0 this option is ignored.'
) { puts "Warning: -s (--simple) option is deprecated. See instiki --help for details." }
opts.on('-t', '--storage=storage', String,
'Makes Instiki use the specified directory for storage.',
'Default: ./storage/[port]') { |OPTIONS[:storage]| }
opts.on('-v', '--verbose',
'Enable debug-level logging'
) { OPTIONS[:verbose] = true }
opts.separator ''
opts.on('-h', '--help',
'Show this help message.') { puts opts; exit }
opts.parse!
end
ENV['RAILS_ENV'] = OPTIONS[:environment]
require File.expand_path(File.dirname(__FILE__) + '/../config/environment')
if OPTIONS[:verbose]
ActionController::Base.logger.level = Logger::DEBUG
end
OPTIONS[:index_controller] = 'wiki'
require 'webrick_server'
if OPTIONS[:environment] == 'production'
storage_path = OPTIONS[:storage] + "/" + OPTIONS[:port].to_s
else
storage_path = OPTIONS[:storage] + "/" + OPTIONS[:environment] + "/" + OPTIONS[:port].to_s
end
FileUtils.mkdir_p(storage_path)
puts "=> Starting Instiki on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
puts "=> Data files are stored in #{storage_path}"
require 'application'
WikiService.storage_path = storage_path
ApplicationController.wiki = WikiService.instance
DispatchServlet.dispatch(OPTIONS)
#!/usr/bin/ruby
require 'webrick'
require 'optparse'
require 'fileutils'
pwd = File.expand_path(File.dirname(__FILE__) + "/..")
OPTIONS = {
# Overridable options
:port => 2500,
:ip => '127.0.0.1',
:environment => 'production',
:server_root => File.expand_path(File.dirname(__FILE__) + '/../public/'),
:server_type => WEBrick::SimpleServer,
:storage => "#{File.expand_path(FileUtils.pwd)}/storage",
}
ARGV.options do |opts|
script_name = File.basename($0)
opts.banner = "Usage: ruby #{script_name} [options]"
opts.separator ''
opts.on('-p', '--port=port', Integer,
'Runs Instiki on the specified port.',
'Default: 2500') { |OPTIONS[:port]| }
opts.on('-b', '--binding=ip', String,
'Binds Rails to the specified ip.',
'Default: 127.0.0.1') { |OPTIONS[:ip]| }
opts.on('-i', '--index=controller', String,
'Specifies an index controller that requests for root will go to (instead of congratulations screen).'
) { |OPTIONS[:index_controller]| }
opts.on('-e', '--environment=name', String,
'Specifies the environment to run this server under (test/development/production).',
'Default: production') { |OPTIONS[:environment]| }
opts.on('-d', '--daemon',
'Make Rails run as a Daemon (only works if fork is available -- meaning on *nix).'
) { OPTIONS[:server_type] = WEBrick::Daemon }
opts.on('-s', '--simple', '--simple-server',
'[deprecated] Forces Instiki not to run as a Daemon if fork is available.',
'Since version 0.10.0 this option is ignored.'
) { puts "Warning: -s (--simple) option is deprecated. See instiki --help for details." }
opts.on('-t', '--storage=storage', String,
'Makes Instiki use the specified directory for storage.',
'Default: ./storage/[port]') { |OPTIONS[:storage]| }
opts.on('-v', '--verbose',
'Enable debug-level logging'
) { OPTIONS[:verbose] = true }
opts.separator ''
opts.on('-h', '--help',
'Show this help message.') { puts opts; exit }
opts.parse!
end
ENV['RAILS_ENV'] = OPTIONS[:environment]
require File.expand_path(File.dirname(__FILE__) + '/../config/environment')
if OPTIONS[:verbose]
ActionController::Base.logger.level = Logger::DEBUG
end
OPTIONS[:index_controller] = 'wiki'
require 'webrick_server'
if OPTIONS[:environment] == 'production'
storage_path = OPTIONS[:storage] + "/" + OPTIONS[:port].to_s
else
storage_path = OPTIONS[:storage] + "/" + OPTIONS[:environment] + "/" + OPTIONS[:port].to_s
end
FileUtils.mkdir_p(storage_path)
puts "=> Starting Instiki on http://#{OPTIONS[:ip]}:#{OPTIONS[:port]}"
puts "=> Data files are stored in #{storage_path}"
require 'application'
WikiService.storage_path = storage_path
ApplicationController.wiki = WikiService.instance
DispatchServlet.dispatch(OPTIONS)

18
test/all_tests.rb Normal file → Executable file
View file

@ -1,9 +1,9 @@
require 'test_helper'
require 'find'
test_root = File.dirname(__FILE__)
Find.find(test_root) { |path|
if File.file?(path) and path =~ /.*_test\.rb$/
require path[(test_root.size + 1)..-4]
end
}
require 'test_helper'
require 'find'
test_root = File.dirname(__FILE__)
Find.find(test_root) { |path|
if File.file?(path) and path =~ /.*_test\.rb$/
require path[(test_root.size + 1)..-4]
end
}

0
test/fixtures/rails.gif vendored Normal file → Executable file
View file

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

52
test/functional/application_test.rb Normal file → Executable file
View file

@ -1,26 +1,26 @@
# Unit tests for ApplicationController (the abstract controller class)
require File.dirname(__FILE__) + '/../test_helper'
require 'wiki_controller'
require 'rexml/document'
# Need some concrete class to test the abstract class features
class WikiController; def rescue_action(e) logger.error(e); raise e end; end
class ApplicationTest < Test::Unit::TestCase
def setup
setup_test_wiki
setup_controller_test(WikiController)
end
def tear_down
tear_down_wiki
end
def test_utf8_header
r = process('show', 'web' => 'wiki1', 'id' => 'HomePage')
assert_equal 'text/html; charset=UTF-8', r.headers['Content-Type']
end
end
# Unit tests for ApplicationController (the abstract controller class)
require File.dirname(__FILE__) + '/../test_helper'
require 'wiki_controller'
require 'rexml/document'
# Need some concrete class to test the abstract class features
class WikiController; def rescue_action(e) logger.error(e); raise e end; end
class ApplicationTest < Test::Unit::TestCase
def setup
setup_test_wiki
setup_controller_test(WikiController)
end
def tear_down
tear_down_wiki
end
def test_utf8_header
r = process('show', 'web' => 'wiki1', 'id' => 'HomePage')
assert_equal 'text/html; charset=UTF-8', r.headers['Content-Type']
end
end

254
test/functional/file_controller_test.rb Normal file → Executable file
View file

@ -1,127 +1,127 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'file_controller'
require 'fileutils'
# Raise errors beyond the default web-based presentation
class FileController; def rescue_action(e) logger.error(e); raise e end; end
class FileControllerTest < Test::Unit::TestCase
FILE_AREA = RAILS_ROOT + '/storage/test/wiki1'
FileUtils.mkdir_p(FILE_AREA) unless File.directory?(FILE_AREA)
FileUtils.rm(Dir["#{FILE_AREA}/*"])
def setup
setup_test_wiki
setup_controller_test
end
def tear_down
tear_down_wiki
end
def test_file
process 'file', 'web' => 'wiki1', 'id' => 'foo.tgz'
assert_success
assert_rendered_file 'file/file'
end
def test_file_download_text_file
File.open("#{FILE_AREA}/foo.txt", 'wb') { |f| f.write "aaa\nbbb\n" }
r = process 'file', 'web' => 'wiki1', 'id' => 'foo.txt'
assert_success
assert_equal "aaa\nbbb\n", r.binary_content
assert_equal 'text/plain', r.headers['Content-Type']
end
def test_file_download_pdf_file
File.open("#{FILE_AREA}/foo.pdf", 'wb') { |f| f.write "aaa\nbbb\n" }
r = process 'file', 'web' => 'wiki1', 'id' => 'foo.pdf'
assert_success
assert_equal "aaa\nbbb\n", r.binary_content
assert_equal 'application/pdf', r.headers['Content-Type']
end
def test_pic_download_gif
FileUtils.cp("#{RAILS_ROOT}/test/fixtures/rails.gif", FILE_AREA)
r = process 'pic', 'web' => 'wiki1', 'id' => 'rails.gif'
assert_success
assert_equal File.size("#{FILE_AREA}/rails.gif"), r.binary_content.size
end
def test_pic_unknown_pic
r = process 'pic', 'web' => 'wiki1', 'id' => 'non-existant.gif'
assert_success
assert_rendered_file 'file/file'
end
def test_pic_upload_end_to_end
# edit and re-render home page so that it has an "unknown file" link to 'rails-e2e.gif'
@wiki.revise_page('wiki1', 'HomePage', '[[rails-e2e.gif:pic]]', Time.now, 'AnonymousBrave')
assert_equal "<p><span class=\"newWikiWord\">rails-e2e.gif<a href=\"../pic/rails-e2e.gif\">" +
"?</a></span></p>",
@home.display_content
# rails-e2e.gif is unknown to the system, so pic action goes to the file [upload] form
r = process 'pic', 'web' => 'wiki1', 'id' => 'rails-e2e.gif'
assert_success
assert_rendered_file 'file/file'
# User uploads the picture
picture = File.read("#{RAILS_ROOT}/test/fixtures/rails.gif")
r = process 'pic', 'web' => 'wiki1', 'id' => 'rails-e2e.gif', 'file' => StringIO.new(picture)
assert_redirect_url '/'
assert @wiki.file_yard(@web).has_file?('rails-e2e.gif')
assert_equal(picture, File.read("#{RAILS_ROOT}/storage/test/wiki1/rails-e2e.gif"))
# this should refresh the page display content (cached)
assert_equal "<p><img alt=\"rails-e2e.gif\" src=\"../pic/rails-e2e.gif\" /></p>",
@home.display_content
end
def test_pic_upload_end_to_end
# edit and re-render home page so that it has an "unknown file" link to 'rails-e2e.gif'
@wiki.revise_page('wiki1', 'HomePage', '[[instiki-e2e.txt:file]]', Time.now, 'AnonymousBrave')
assert_equal "<p><span class=\"newWikiWord\">instiki-e2e.txt" +
"<a href=\"../file/instiki-e2e.txt\">?</a></span></p>",
@home.display_content
# rails-e2e.gif is unknown to the system, so pic action goes to the file [upload] form
r = process 'file', 'web' => 'wiki1', 'id' => 'instiki-e2e.txt'
assert_success
assert_rendered_file 'file/file'
# User uploads the picture
file = "abcdefgh\n123"
r = process 'file', 'web' => 'wiki1', 'id' => 'instiki-e2e.txt', 'file' => StringIO.new(file)
assert_redirect_url '/'
assert @wiki.file_yard(@web).has_file?('instiki-e2e.txt')
assert_equal(file, File.read("#{RAILS_ROOT}/storage/test/wiki1/instiki-e2e.txt"))
# this should refresh the page display content (cached)
assert_equal "<p><a class=\"existingWikiWord\" href=\"../file/instiki-e2e.txt\">" +
"instiki-e2e.txt</a></p>",
@home.display_content
end
def test_uploads_blocking
@web.allow_uploads = true
r = process 'file', 'web' => 'wiki1', 'id' => 'filename'
assert_success
@web.allow_uploads = false
r = process 'file', 'web' => 'wiki1', 'id' => 'filename'
assert_equal '403 Forbidden', r.headers['Status']
end
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'file_controller'
require 'fileutils'
# Raise errors beyond the default web-based presentation
class FileController; def rescue_action(e) logger.error(e); raise e end; end
class FileControllerTest < Test::Unit::TestCase
FILE_AREA = RAILS_ROOT + '/storage/test/wiki1'
FileUtils.mkdir_p(FILE_AREA) unless File.directory?(FILE_AREA)
FileUtils.rm(Dir["#{FILE_AREA}/*"])
def setup
setup_test_wiki
setup_controller_test
end
def tear_down
tear_down_wiki
end
def test_file
process 'file', 'web' => 'wiki1', 'id' => 'foo.tgz'
assert_success
assert_rendered_file 'file/file'
end
def test_file_download_text_file
File.open("#{FILE_AREA}/foo.txt", 'wb') { |f| f.write "aaa\nbbb\n" }
r = process 'file', 'web' => 'wiki1', 'id' => 'foo.txt'
assert_success
assert_equal "aaa\nbbb\n", r.binary_content
assert_equal 'text/plain', r.headers['Content-Type']
end
def test_file_download_pdf_file
File.open("#{FILE_AREA}/foo.pdf", 'wb') { |f| f.write "aaa\nbbb\n" }
r = process 'file', 'web' => 'wiki1', 'id' => 'foo.pdf'
assert_success
assert_equal "aaa\nbbb\n", r.binary_content
assert_equal 'application/pdf', r.headers['Content-Type']
end
def test_pic_download_gif
FileUtils.cp("#{RAILS_ROOT}/test/fixtures/rails.gif", FILE_AREA)
r = process 'pic', 'web' => 'wiki1', 'id' => 'rails.gif'
assert_success
assert_equal File.size("#{FILE_AREA}/rails.gif"), r.binary_content.size
end
def test_pic_unknown_pic
r = process 'pic', 'web' => 'wiki1', 'id' => 'non-existant.gif'
assert_success
assert_rendered_file 'file/file'
end
def test_pic_upload_end_to_end
# edit and re-render home page so that it has an "unknown file" link to 'rails-e2e.gif'
@wiki.revise_page('wiki1', 'HomePage', '[[rails-e2e.gif:pic]]', Time.now, 'AnonymousBrave')
assert_equal "<p><span class=\"newWikiWord\">rails-e2e.gif<a href=\"../pic/rails-e2e.gif\">" +
"?</a></span></p>",
@home.display_content
# rails-e2e.gif is unknown to the system, so pic action goes to the file [upload] form
r = process 'pic', 'web' => 'wiki1', 'id' => 'rails-e2e.gif'
assert_success
assert_rendered_file 'file/file'
# User uploads the picture
picture = File.read("#{RAILS_ROOT}/test/fixtures/rails.gif")
r = process 'pic', 'web' => 'wiki1', 'id' => 'rails-e2e.gif', 'file' => StringIO.new(picture)
assert_redirect_url '/'
assert @wiki.file_yard(@web).has_file?('rails-e2e.gif')
assert_equal(picture, File.read("#{RAILS_ROOT}/storage/test/wiki1/rails-e2e.gif"))
# this should refresh the page display content (cached)
assert_equal "<p><img alt=\"rails-e2e.gif\" src=\"../pic/rails-e2e.gif\" /></p>",
@home.display_content
end
def test_pic_upload_end_to_end
# edit and re-render home page so that it has an "unknown file" link to 'rails-e2e.gif'
@wiki.revise_page('wiki1', 'HomePage', '[[instiki-e2e.txt:file]]', Time.now, 'AnonymousBrave')
assert_equal "<p><span class=\"newWikiWord\">instiki-e2e.txt" +
"<a href=\"../file/instiki-e2e.txt\">?</a></span></p>",
@home.display_content
# rails-e2e.gif is unknown to the system, so pic action goes to the file [upload] form
r = process 'file', 'web' => 'wiki1', 'id' => 'instiki-e2e.txt'
assert_success
assert_rendered_file 'file/file'
# User uploads the picture
file = "abcdefgh\n123"
r = process 'file', 'web' => 'wiki1', 'id' => 'instiki-e2e.txt', 'file' => StringIO.new(file)
assert_redirect_url '/'
assert @wiki.file_yard(@web).has_file?('instiki-e2e.txt')
assert_equal(file, File.read("#{RAILS_ROOT}/storage/test/wiki1/instiki-e2e.txt"))
# this should refresh the page display content (cached)
assert_equal "<p><a class=\"existingWikiWord\" href=\"../file/instiki-e2e.txt\">" +
"instiki-e2e.txt</a></p>",
@home.display_content
end
def test_uploads_blocking
@web.allow_uploads = true
r = process 'file', 'web' => 'wiki1', 'id' => 'filename'
assert_success
@web.allow_uploads = false
r = process 'file', 'web' => 'wiki1', 'id' => 'filename'
assert_equal '403 Forbidden', r.headers['Status']
end
end

File diff suppressed because it is too large Load diff

226
test/test_helper.rb Executable file → Normal file
View file

@ -1,113 +1,113 @@
ENV['RAILS_ENV'] ||= 'test'
require File.dirname(__FILE__) + '/../config/environment'
require 'application'
require 'test/unit'
require 'action_controller/test_process'
# Uncomment this variable to have assert_success check that response bodies are valid XML
$validate_xml_in_assert_success = true
# Convenient setup method for Test::Unit::TestCase
class Test::Unit::TestCase
private
def setup_controller_test(controller_class = nil, host = nil)
if controller_class
@controller = controller_class
elsif self.class.to_s =~ /^(\w+Controller)Test$/
@controller = Object::const_get($1)
else
raise "Cannot derive the name of controller under test from class name #{self.class}"
end
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
@request.host = host || 'localhost'
return @request, @response
end
# Wiki fixture for tests
def setup_test_wiki
@wiki = ApplicationController.wiki = WikiServiceWithNoPersistence.new
@web = @wiki.create_web('Test Wiki 1', 'wiki1')
@home = @wiki.write_page('wiki1', 'HomePage', 'First revision of the HomePage end', Time.now,
Author.new('AnAuthor', '127.0.0.1'))
end
def setup_wiki_with_three_pages
@oak = @wiki.write_page('wiki1', 'Oak',
"All about oak.\n" +
"category: trees",
5.minutes.ago, Author.new('TreeHugger', '127.0.0.2'))
@elephant = @wiki.write_page('wiki1', 'Elephant',
"All about elephants.\n" +
"category: animals",
10.minutes.ago, Author.new('Guest', '127.0.0.2'))
end
def tear_down_wiki
ApplicationController.wiki = nil
end
end
class WikiServiceWithNoPersistence
include AbstractWikiService
def initialize
init_wiki_service
end
def storage_path
RAILS_ROOT + '/storage/test/'
end
end
# This module is to be included in unit tests that involve matching chunks.
# It provides a easy way to test whether a chunk matches a particular string
# and any the values of any fields that should be set after a match.
class ContentStub < String
attr_reader :chunks, :content
def initialize(str)
super
@chunks = []
end
end
module ChunkMatch
# Asserts a number of tests for the given type and text.
def match(chunk_type, test_text, expected_chunk_state)
if chunk_type.respond_to? :pattern
assert_match(chunk_type.pattern, test_text)
end
content = ContentStub.new(test_text)
chunk_type.apply_to(content)
# Test if requested parts are correct.
expected_chunk_state.each_pair do |a_method, expected_value|
assert content.chunks.last.kind_of?(chunk_type)
assert_respond_to(content.chunks.last, a_method)
assert_equal(expected_value, content.chunks.last.send(a_method.to_sym),
"Wrong #{a_method} value")
end
end
end
if defined? $validate_xml_in_assert_success and $validate_xml_in_assert_success == true
module Test
module Unit
module Assertions
unless method_defined? :__assert_success_before_ovverride_by_instiki
alias :__assert_success_before_ovverride_by_instiki :assert_success
end
def assert_success
__assert_success_before_ovverride_by_instiki
if @response.body.kind_of?(Proc) then # it's a file download, not an HTML content
else assert_nothing_raised(@response.body) { REXML::Document.new(@response.body) } end
end
end
end
end
end
ENV['RAILS_ENV'] ||= 'test'
require File.dirname(__FILE__) + '/../config/environment'
require 'application'
require 'test/unit'
require 'action_controller/test_process'
# Uncomment this variable to have assert_success check that response bodies are valid XML
$validate_xml_in_assert_success = true
# Convenient setup method for Test::Unit::TestCase
class Test::Unit::TestCase
private
def setup_controller_test(controller_class = nil, host = nil)
if controller_class
@controller = controller_class
elsif self.class.to_s =~ /^(\w+Controller)Test$/
@controller = Object::const_get($1)
else
raise "Cannot derive the name of controller under test from class name #{self.class}"
end
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
@request.host = host || 'localhost'
return @request, @response
end
# Wiki fixture for tests
def setup_test_wiki
@wiki = ApplicationController.wiki = WikiServiceWithNoPersistence.new
@web = @wiki.create_web('Test Wiki 1', 'wiki1')
@home = @wiki.write_page('wiki1', 'HomePage', 'First revision of the HomePage end', Time.now,
Author.new('AnAuthor', '127.0.0.1'))
end
def setup_wiki_with_three_pages
@oak = @wiki.write_page('wiki1', 'Oak',
"All about oak.\n" +
"category: trees",
5.minutes.ago, Author.new('TreeHugger', '127.0.0.2'))
@elephant = @wiki.write_page('wiki1', 'Elephant',
"All about elephants.\n" +
"category: animals",
10.minutes.ago, Author.new('Guest', '127.0.0.2'))
end
def tear_down_wiki
ApplicationController.wiki = nil
end
end
class WikiServiceWithNoPersistence
include AbstractWikiService
def initialize
init_wiki_service
end
def storage_path
RAILS_ROOT + '/storage/test/'
end
end
# This module is to be included in unit tests that involve matching chunks.
# It provides a easy way to test whether a chunk matches a particular string
# and any the values of any fields that should be set after a match.
class ContentStub < String
attr_reader :chunks, :content
def initialize(str)
super
@chunks = []
end
end
module ChunkMatch
# Asserts a number of tests for the given type and text.
def match(chunk_type, test_text, expected_chunk_state)
if chunk_type.respond_to? :pattern
assert_match(chunk_type.pattern, test_text)
end
content = ContentStub.new(test_text)
chunk_type.apply_to(content)
# Test if requested parts are correct.
expected_chunk_state.each_pair do |a_method, expected_value|
assert content.chunks.last.kind_of?(chunk_type)
assert_respond_to(content.chunks.last, a_method)
assert_equal(expected_value, content.chunks.last.send(a_method.to_sym),
"Wrong #{a_method} value")
end
end
end
if defined? $validate_xml_in_assert_success and $validate_xml_in_assert_success == true
module Test
module Unit
module Assertions
unless method_defined? :__assert_success_before_ovverride_by_instiki
alias :__assert_success_before_ovverride_by_instiki :assert_success
end
def assert_success
__assert_success_before_ovverride_by_instiki
if @response.body.kind_of?(Proc) then # it's a file download, not an HTML content
else assert_nothing_raised(@response.body) { REXML::Document.new(@response.body) } end
end
end
end
end
end

View file

@ -1,23 +1,23 @@
#!/bin/env ruby
require File.dirname(__FILE__) + '/../../test_helper'
require 'chunks/category'
require 'chunks/match'
class CategoryTest < Test::Unit::TestCase
include ChunkMatch
def test_single_category
match(Category, 'category: test', :list => ['test'], :hidden => nil)
match(Category, 'category : chunk test ', :list => ['chunk test'], :hidden => nil)
match(Category, ':category: test', :list => ['test'], :hidden => ':')
end
def test_multiple_categories
match(Category, 'category: test, multiple', :list => ['test', 'multiple'], :hidden => nil)
match(Category, 'category : chunk test , multi category,regression test case ',
:list => ['chunk test','multi category','regression test case'], :hidden => nil
)
end
end
#!/bin/env ruby
require File.dirname(__FILE__) + '/../../test_helper'
require 'chunks/category'
require 'chunks/match'
class CategoryTest < Test::Unit::TestCase
include ChunkMatch
def test_single_category
match(Category, 'category: test', :list => ['test'], :hidden => nil)
match(Category, 'category : chunk test ', :list => ['chunk test'], :hidden => nil)
match(Category, ':category: test', :list => ['test'], :hidden => ':')
end
def test_multiple_categories
match(Category, 'category: test, multiple', :list => ['test', 'multiple'], :hidden => nil)
match(Category, 'category : chunk test , multi category,regression test case ',
:list => ['chunk test','multi category','regression test case'], :hidden => nil
)
end
end

View file

@ -1,16 +1,16 @@
#!/bin/env ruby
require File.dirname(__FILE__) + '/../../test_helper'
require 'chunks/nowiki'
require 'chunks/match'
class NoWikiTest < Test::Unit::TestCase
include ChunkMatch
def test_simple_nowiki
match(NoWiki, 'This sentence contains <nowiki>[[raw text]]</nowiki>. Do not touch!',
:plain_text => '[[raw text]]'
)
end
end
#!/bin/env ruby
require File.dirname(__FILE__) + '/../../test_helper'
require 'chunks/nowiki'
require 'chunks/match'
class NoWikiTest < Test::Unit::TestCase
include ChunkMatch
def test_simple_nowiki
match(NoWiki, 'This sentence contains <nowiki>[[raw text]]</nowiki>. Do not touch!',
:plain_text => '[[raw text]]'
)
end
end

View file

@ -1,81 +1,81 @@
#!/bin/env ruby
require File.dirname(__FILE__) + '/../../test_helper'
require 'chunks/wiki'
class WikiTest < Test::Unit::TestCase
class ContentStub < String
def chunks
@chunks ||= []
end
end
include ChunkMatch
def test_simple
match(WikiChunk::Word, 'This is a WikiWord okay?', :page_name => 'WikiWord')
end
def test_escaped
match(WikiChunk::Word, 'Do not link to an \EscapedWord',
:page_name => 'EscapedWord', :escaped_text => 'EscapedWord'
)
end
def test_simple_brackets
match(WikiChunk::Link, 'This is a [[bracketted link]]',
:page_name => 'bracketted link', :escaped_text => nil
)
end
def test_complex_brackets
match(WikiChunk::Link, 'This is a tricky link [[Sperberg-McQueen]]',
:page_name => 'Sperberg-McQueen', :escaped_text => nil
)
end
def test_textile_link
textile_link = ContentStub.new('"Here is a special link":SpecialLink')
WikiChunk::Word.apply_to(textile_link)
assert_equal '"Here is a special link":SpecialLink', textile_link
assert textile_link.chunks.empty?
end
def test_file_types
# only link
assert_link_parsed_as 'only text', 'only text', 'show', '[[only text]]'
# link and text
assert_link_parsed_as 'page name', 'link text', 'show', '[[page name|link text]]'
# link and type (file)
assert_link_parsed_as 'foo.tar.gz', 'foo.tar.gz', 'file', '[[foo.tar.gz:file]]'
# link and type (pic)
assert_link_parsed_as 'foo.tar.gz', 'foo.tar.gz', 'pic', '[[foo.tar.gz:pic]]'
# link, text and type
assert_link_parsed_as 'foo.tar.gz', 'FooTar', 'file', '[[foo.tar.gz|FooTar:file]]'
# NEGATIVE TEST CASES
# empty page name
assert_link_parsed_as '|link text?', '|link text?', 'file', '[[|link text?:file]]'
# empty link text
assert_link_parsed_as 'page name?|', 'page name?|', 'file', '[[page name?|:file]]'
# empty link type
assert_link_parsed_as 'page name', 'link?:', 'show', '[[page name|link?:]]'
# unknown link type
assert_link_parsed_as 'page name:create_system', 'page name:create_system', 'show',
'[[page name:create_system]]'
end
def assert_link_parsed_as(expected_page_name, expected_link_text, expected_link_type, link)
link_to_file = ContentStub.new(link)
WikiChunk::Link.apply_to(link_to_file)
chunk = link_to_file.chunks.last
assert chunk
assert_equal expected_page_name, chunk.page_name
assert_equal expected_link_text, chunk.link_text
assert_equal expected_link_type, chunk.link_type
end
end
#!/bin/env ruby
require File.dirname(__FILE__) + '/../../test_helper'
require 'chunks/wiki'
class WikiTest < Test::Unit::TestCase
class ContentStub < String
def chunks
@chunks ||= []
end
end
include ChunkMatch
def test_simple
match(WikiChunk::Word, 'This is a WikiWord okay?', :page_name => 'WikiWord')
end
def test_escaped
match(WikiChunk::Word, 'Do not link to an \EscapedWord',
:page_name => 'EscapedWord', :escaped_text => 'EscapedWord'
)
end
def test_simple_brackets
match(WikiChunk::Link, 'This is a [[bracketted link]]',
:page_name => 'bracketted link', :escaped_text => nil
)
end
def test_complex_brackets
match(WikiChunk::Link, 'This is a tricky link [[Sperberg-McQueen]]',
:page_name => 'Sperberg-McQueen', :escaped_text => nil
)
end
def test_textile_link
textile_link = ContentStub.new('"Here is a special link":SpecialLink')
WikiChunk::Word.apply_to(textile_link)
assert_equal '"Here is a special link":SpecialLink', textile_link
assert textile_link.chunks.empty?
end
def test_file_types
# only link
assert_link_parsed_as 'only text', 'only text', 'show', '[[only text]]'
# link and text
assert_link_parsed_as 'page name', 'link text', 'show', '[[page name|link text]]'
# link and type (file)
assert_link_parsed_as 'foo.tar.gz', 'foo.tar.gz', 'file', '[[foo.tar.gz:file]]'
# link and type (pic)
assert_link_parsed_as 'foo.tar.gz', 'foo.tar.gz', 'pic', '[[foo.tar.gz:pic]]'
# link, text and type
assert_link_parsed_as 'foo.tar.gz', 'FooTar', 'file', '[[foo.tar.gz|FooTar:file]]'
# NEGATIVE TEST CASES
# empty page name
assert_link_parsed_as '|link text?', '|link text?', 'file', '[[|link text?:file]]'
# empty link text
assert_link_parsed_as 'page name?|', 'page name?|', 'file', '[[page name?|:file]]'
# empty link type
assert_link_parsed_as 'page name', 'link?:', 'show', '[[page name|link?:]]'
# unknown link type
assert_link_parsed_as 'page name:create_system', 'page name:create_system', 'show',
'[[page name:create_system]]'
end
def assert_link_parsed_as(expected_page_name, expected_link_text, expected_link_type, link)
link_to_file = ContentStub.new(link)
WikiChunk::Link.apply_to(link_to_file)
chunk = link_to_file.chunks.last
assert chunk
assert_equal expected_page_name, chunk.page_name
assert_equal expected_link_text, chunk.link_text
assert_equal expected_link_type, chunk.link_type
end
end

View file

@ -1,82 +1,82 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'diff'
include Diff
class DiffTest < Test::Unit::TestCase
def test_init
assert(1 == 1, "tests working")
assert_nothing_raised("object created") do
s = SequenceMatcher.new "private Thread currentThread;",
"private volatile Thread currentThread;",
proc { |x| x == ' ' }
end
end
def test_matching_blocks
s = SequenceMatcher.new "abxcd", "abcd"
assert(s.get_matching_blocks == [[0, 0, 2], [3, 2, 2], [5, 4, 0]],
"get_matching_blocks works")
end
def test_ratio
s = SequenceMatcher.new "abcd", "bcde"
assert(s.ratio == 0.75, "ratio works")
assert(s.quick_ratio == 0.75, "quick_ratio works")
assert(s.real_quick_ratio == 1.0, "real_quick_ratio works")
end
def test_longest_match
s = SequenceMatcher.new(" abcd", "abcd abcd")
assert(s.find_longest_match(0, 5, 0, 9) == [0, 4, 5],
"find_longest_match works")
s = SequenceMatcher.new()
end
def test_opcodes
s = SequenceMatcher.new("qabxcd", "abycdf")
assert(s.get_opcodes == [
[:delete, 0, 1, 0, 0],
[:equal, 1, 3, 0, 2],
[:replace, 3, 4, 2, 3],
[:equal, 4, 6, 3, 5],
[:insert, 6, 6, 5, 6]], "get_opcodes works")
end
def test_count_leading
assert(Diff.count_leading(' abc', ' ') == 3,
"count_leading works")
end
def test_html2list
a = "here is the original text"
#p HTMLDiff.html2list(a)
end
def test_html_diff
a = "this was the original string"
b = "this is the super string"
assert_equal 'this <del class="diffmod">was </del>' +
'<ins class="diffmod">is </ins>the ' +
'<del class="diffmod">original </del>' +
'<ins class="diffmod">super </ins>string',
HTMLDiff.diff(a, b)
end
def test_html_diff_with_multiple_paragraphs
a = "<p>this was the original string</p>"
b = "<p>this is</p>\r\n<p>the super string</p>\r\n<p>around the world</p>"
assert_equal(
"<p>this <del class=\"diffmod\">was </del>" +
"<ins class=\"diffmod\">is</ins></p>\r\n<p>the " +
"<del class=\"diffmod\">original </del>" +
"<ins class=\"diffmod\">super </ins>string</p>\r\n" +
"<p><ins class=\"diffins\">around the world</ins></p>",
HTMLDiff.diff(a, b)
)
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'diff'
include Diff
class DiffTest < Test::Unit::TestCase
def test_init
assert(1 == 1, "tests working")
assert_nothing_raised("object created") do
s = SequenceMatcher.new "private Thread currentThread;",
"private volatile Thread currentThread;",
proc { |x| x == ' ' }
end
end
def test_matching_blocks
s = SequenceMatcher.new "abxcd", "abcd"
assert(s.get_matching_blocks == [[0, 0, 2], [3, 2, 2], [5, 4, 0]],
"get_matching_blocks works")
end
def test_ratio
s = SequenceMatcher.new "abcd", "bcde"
assert(s.ratio == 0.75, "ratio works")
assert(s.quick_ratio == 0.75, "quick_ratio works")
assert(s.real_quick_ratio == 1.0, "real_quick_ratio works")
end
def test_longest_match
s = SequenceMatcher.new(" abcd", "abcd abcd")
assert(s.find_longest_match(0, 5, 0, 9) == [0, 4, 5],
"find_longest_match works")
s = SequenceMatcher.new()
end
def test_opcodes
s = SequenceMatcher.new("qabxcd", "abycdf")
assert(s.get_opcodes == [
[:delete, 0, 1, 0, 0],
[:equal, 1, 3, 0, 2],
[:replace, 3, 4, 2, 3],
[:equal, 4, 6, 3, 5],
[:insert, 6, 6, 5, 6]], "get_opcodes works")
end
def test_count_leading
assert(Diff.count_leading(' abc', ' ') == 3,
"count_leading works")
end
def test_html2list
a = "here is the original text"
#p HTMLDiff.html2list(a)
end
def test_html_diff
a = "this was the original string"
b = "this is the super string"
assert_equal 'this <del class="diffmod">was </del>' +
'<ins class="diffmod">is </ins>the ' +
'<del class="diffmod">original </del>' +
'<ins class="diffmod">super </ins>string',
HTMLDiff.diff(a, b)
end
def test_html_diff_with_multiple_paragraphs
a = "<p>this was the original string</p>"
b = "<p>this is</p>\r\n<p>the super string</p>\r\n<p>around the world</p>"
assert_equal(
"<p>this <del class=\"diffmod\">was </del>" +
"<ins class=\"diffmod\">is</ins></p>\r\n<p>the " +
"<del class=\"diffmod\">original </del>" +
"<ins class=\"diffmod\">super </ins>string</p>\r\n" +
"<p><ins class=\"diffins\">around the world</ins></p>",
HTMLDiff.diff(a, b)
)
end
end

68
test/unit/file_yard_test.rb Normal file → Executable file
View file

@ -1,35 +1,35 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'fileutils'
require 'file_yard'
require 'stringio'
class FileYardTest < Test::Unit::TestCase
def setup
FileUtils.mkdir_p(file_path)
FileUtils.rm(Dir["#{file_path}/*"])
@yard = FileYard.new(file_path)
end
def test_files
assert_equal [], @yard.files
# FileYard gets the list of files from directory in the constructor
@yard.upload_file('aaa', StringIO.new('file contents'))
assert_equal ["#{file_path}/aaa"], Dir["#{file_path}/*"]
assert_equal ['aaa'], @yard.files
assert @yard.has_file?('aaa')
assert_equal 'file contents', File.read(@yard.file_path('aaa'))
end
def test_file_path
assert_equal "#{file_path}/abcd", @yard.file_path('abcd')
end
def file_path
"#{RAILS_ROOT}/storage/test/instiki"
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'fileutils'
require 'file_yard'
require 'stringio'
class FileYardTest < Test::Unit::TestCase
def setup
FileUtils.mkdir_p(file_path)
FileUtils.rm(Dir["#{file_path}/*"])
@yard = FileYard.new(file_path)
end
def test_files
assert_equal [], @yard.files
# FileYard gets the list of files from directory in the constructor
@yard.upload_file('aaa', StringIO.new('file contents'))
assert_equal ["#{file_path}/aaa"], Dir["#{file_path}/*"]
assert_equal ['aaa'], @yard.files
assert @yard.has_file?('aaa')
assert_equal 'file contents', File.read(@yard.file_path('aaa'))
end
def test_file_path
assert_equal "#{file_path}/abcd", @yard.file_path('abcd')
end
def file_path
"#{RAILS_ROOT}/storage/test/instiki"
end
end

View file

@ -1,91 +1,91 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'web'
require 'page'
class PageTest < Test::Unit::TestCase
class MockWeb < Web
def initialize() super(nil, 'test','test') end
def [](wiki_word) %w( MyWay ThatWay SmartEngine ).include?(wiki_word) end
def refresh_pages_with_references(name) end
end
def setup
@page = Page.new(
MockWeb.new,
"FirstPage",
"HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \\OverThere -- see SmartEngine in that SmartEngineGUI",
Time.local(2004, 4, 4, 16, 50),
"DavidHeinemeierHansson")
end
def test_lock
assert !@page.locked?(Time.local(2004, 4, 4, 16, 50))
@page.lock(Time.local(2004, 4, 4, 16, 30), "DavidHeinemeierHansson")
assert @page.locked?(Time.local(2004, 4, 4, 16, 50))
assert !@page.locked?(Time.local(2004, 4, 4, 17, 1))
@page.unlock
assert !@page.locked?(Time.local(2004, 4, 4, 16, 50))
end
def test_lock_duration
@page.lock(Time.local(2004, 4, 4, 16, 30), "DavidHeinemeierHansson")
assert_equal 15, @page.lock_duration(Time.local(2004, 4, 4, 16, 45))
end
def test_plain_name
assert_equal "First Page", @page.plain_name
end
def test_revise
@page.revise('HisWay would be MyWay in kinda lame', Time.local(2004, 4, 4, 16, 55), 'MarianneSyhler')
assert_equal 2, @page.revisions.length, 'Should have two revisions'
assert_equal 'MarianneSyhler', @page.author, 'Mary should be the author now'
assert_equal 'DavidHeinemeierHansson', @page.revisions.first.author, 'David was the first author'
end
def test_revise_continous_revision
@page.revise('HisWay would be MyWay in kinda lame', Time.local(2004, 4, 4, 16, 55), 'MarianneSyhler')
assert_equal 2, @page.revisions.length
@page.revise('HisWay would be MyWay in kinda update', Time.local(2004, 4, 4, 16, 57), 'MarianneSyhler')
assert_equal 2, @page.revisions.length
assert_equal 'HisWay would be MyWay in kinda update', @page.revisions.last.content
assert_equal Time.local(2004, 4, 4, 16, 57), @page.revisions.last.created_at
@page.revise('HisWay would be MyWay in the house', Time.local(2004, 4, 4, 16, 58), 'DavidHeinemeierHansson')
assert_equal 3, @page.revisions.length
assert_equal 'HisWay would be MyWay in the house', @page.revisions.last.content
@page.revise('HisWay would be MyWay in my way', Time.local(2004, 4, 4, 17, 30), 'DavidHeinemeierHansson')
assert_equal 4, @page.revisions.length
end
def test_revise_content_unchanged
last_revision_before = @page.revisions.last
revisions_number_before = @page.revisions.size
assert_raises(Instiki::ValidationError) {
@page.revise(@page.revisions.last.content.dup, Time.now, 'AlexeyVerkhovsky')
}
assert_same last_revision_before, @page.revisions.last
assert_equal revisions_number_before, @page.revisions.size
end
def test_rollback
@page.revise("spot two", Time.now, "David")
@page.revise("spot three", Time.now + 2000, "David")
assert_equal 3, @page.revisions.length, "Should have three revisions"
@page.rollback(1, Time.now)
assert_equal "spot two", @page.content
end
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'web'
require 'page'
class PageTest < Test::Unit::TestCase
class MockWeb < Web
def initialize() super(nil, 'test','test') end
def [](wiki_word) %w( MyWay ThatWay SmartEngine ).include?(wiki_word) end
def refresh_pages_with_references(name) end
end
def setup
@page = Page.new(
MockWeb.new,
"FirstPage",
"HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \\OverThere -- see SmartEngine in that SmartEngineGUI",
Time.local(2004, 4, 4, 16, 50),
"DavidHeinemeierHansson")
end
def test_lock
assert !@page.locked?(Time.local(2004, 4, 4, 16, 50))
@page.lock(Time.local(2004, 4, 4, 16, 30), "DavidHeinemeierHansson")
assert @page.locked?(Time.local(2004, 4, 4, 16, 50))
assert !@page.locked?(Time.local(2004, 4, 4, 17, 1))
@page.unlock
assert !@page.locked?(Time.local(2004, 4, 4, 16, 50))
end
def test_lock_duration
@page.lock(Time.local(2004, 4, 4, 16, 30), "DavidHeinemeierHansson")
assert_equal 15, @page.lock_duration(Time.local(2004, 4, 4, 16, 45))
end
def test_plain_name
assert_equal "First Page", @page.plain_name
end
def test_revise
@page.revise('HisWay would be MyWay in kinda lame', Time.local(2004, 4, 4, 16, 55), 'MarianneSyhler')
assert_equal 2, @page.revisions.length, 'Should have two revisions'
assert_equal 'MarianneSyhler', @page.author, 'Mary should be the author now'
assert_equal 'DavidHeinemeierHansson', @page.revisions.first.author, 'David was the first author'
end
def test_revise_continous_revision
@page.revise('HisWay would be MyWay in kinda lame', Time.local(2004, 4, 4, 16, 55), 'MarianneSyhler')
assert_equal 2, @page.revisions.length
@page.revise('HisWay would be MyWay in kinda update', Time.local(2004, 4, 4, 16, 57), 'MarianneSyhler')
assert_equal 2, @page.revisions.length
assert_equal 'HisWay would be MyWay in kinda update', @page.revisions.last.content
assert_equal Time.local(2004, 4, 4, 16, 57), @page.revisions.last.created_at
@page.revise('HisWay would be MyWay in the house', Time.local(2004, 4, 4, 16, 58), 'DavidHeinemeierHansson')
assert_equal 3, @page.revisions.length
assert_equal 'HisWay would be MyWay in the house', @page.revisions.last.content
@page.revise('HisWay would be MyWay in my way', Time.local(2004, 4, 4, 17, 30), 'DavidHeinemeierHansson')
assert_equal 4, @page.revisions.length
end
def test_revise_content_unchanged
last_revision_before = @page.revisions.last
revisions_number_before = @page.revisions.size
assert_raises(Instiki::ValidationError) {
@page.revise(@page.revisions.last.content.dup, Time.now, 'AlexeyVerkhovsky')
}
assert_same last_revision_before, @page.revisions.last
assert_equal revisions_number_before, @page.revisions.size
end
def test_rollback
@page.revise("spot two", Time.now, "David")
@page.revise("spot three", Time.now + 2000, "David")
assert_equal 3, @page.revisions.length, "Should have three revisions"
@page.rollback(1, Time.now)
assert_equal "spot two", @page.content
end
end

View file

@ -1,69 +1,69 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'redcloth_for_tex'
class RedClothForTexTest < Test::Unit::TestCase
def test_basics
assert_equal '{\bf First Page}', RedClothForTex.new("*First Page*").to_tex
assert_equal '{\em First Page}', RedClothForTex.new("_First Page_").to_tex
assert_equal "\\begin{itemize}\n\t\\item A\n\t\t\\item B\n\t\t\\item C\n\t\\end{itemize}", RedClothForTex.new("* A\n* B\n* C").to_tex
end
def test_blocks
assert_equal '\section*{hello}', RedClothForTex.new("h1. hello").to_tex
assert_equal '\subsection*{hello}', RedClothForTex.new("h2. hello").to_tex
end
def test_table_of_contents
source = <<EOL
* [[A]]
** [[B]]
** [[C]]
* D
** [[E]]
*** F
EOL
expected_result = <<EOL
\\pagebreak
\\section{A}
Abe
\\subsection{B}
Babe
\\subsection{C}
\\pagebreak
\\section{D}
\\subsection{E}
\\subsubsection{F}
EOL
expected_result.chop!
assert_equal(expected_result, table_of_contents(source, 'A' => 'Abe', 'B' => 'Babe'))
end
def test_entities
assert_equal "Beck \\& Fowler are 100\\% cool", RedClothForTex.new("Beck & Fowler are 100% cool").to_tex
end
def test_bracket_links
assert_equal "such a Horrible Day, but I won't be Made Useless", RedClothForTex.new("such a [[Horrible Day]], but I won't be [[Made Useless]]").to_tex
end
def test_footnotes_on_abbreviations
assert_equal(
"such a Horrible Day\\footnote{1}, but I won't be Made Useless",
RedClothForTex.new("such a [[Horrible Day]][1], but I won't be [[Made Useless]]").to_tex
)
end
def test_subsection_depth
assert_equal "\\subsubsection*{Hello}", RedClothForTex.new("h4. Hello").to_tex
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'redcloth_for_tex'
class RedClothForTexTest < Test::Unit::TestCase
def test_basics
assert_equal '{\bf First Page}', RedClothForTex.new("*First Page*").to_tex
assert_equal '{\em First Page}', RedClothForTex.new("_First Page_").to_tex
assert_equal "\\begin{itemize}\n\t\\item A\n\t\t\\item B\n\t\t\\item C\n\t\\end{itemize}", RedClothForTex.new("* A\n* B\n* C").to_tex
end
def test_blocks
assert_equal '\section*{hello}', RedClothForTex.new("h1. hello").to_tex
assert_equal '\subsection*{hello}', RedClothForTex.new("h2. hello").to_tex
end
def test_table_of_contents
source = <<EOL
* [[A]]
** [[B]]
** [[C]]
* D
** [[E]]
*** F
EOL
expected_result = <<EOL
\\pagebreak
\\section{A}
Abe
\\subsection{B}
Babe
\\subsection{C}
\\pagebreak
\\section{D}
\\subsection{E}
\\subsubsection{F}
EOL
expected_result.chop!
assert_equal(expected_result, table_of_contents(source, 'A' => 'Abe', 'B' => 'Babe'))
end
def test_entities
assert_equal "Beck \\& Fowler are 100\\% cool", RedClothForTex.new("Beck & Fowler are 100% cool").to_tex
end
def test_bracket_links
assert_equal "such a Horrible Day, but I won't be Made Useless", RedClothForTex.new("such a [[Horrible Day]], but I won't be [[Made Useless]]").to_tex
end
def test_footnotes_on_abbreviations
assert_equal(
"such a Horrible Day\\footnote{1}, but I won't be Made Useless",
RedClothForTex.new("such a [[Horrible Day]][1], but I won't be [[Made Useless]]").to_tex
)
end
def test_subsection_depth
assert_equal "\\subsubsection*{Hello}", RedClothForTex.new("h4. Hello").to_tex
end
end

View file

@ -1,255 +1,255 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'web'
require 'revision'
require 'fileutils'
class RevisionTest < Test::Unit::TestCase
def setup
setup_test_wiki
@web.markup = :textile
@page = @wiki.read_page('wiki1', 'HomePage')
['MyWay', 'SmartEngine', 'ThatWay'].each do |page|
@wiki.write_page('wiki1', page, page, Time.now, 'Me')
end
@revision = Revision.new(@page, 1,
'HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \OverThere -- ' +
'see SmartEngine in that SmartEngineGUI',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson')
end
def test_wiki_words
assert_equal %w( HisWay MyWay SmartEngine SmartEngineGUI ThatWay ), @revision.wiki_words.sort
end
def test_existing_pages
assert_equal %w( MyWay SmartEngine ThatWay ), @revision.existing_pages.sort
end
def test_unexisting_pages
assert_equal %w( HisWay SmartEngineGUI ), @revision.unexisting_pages.sort
end
def test_content_with_wiki_links
assert_equal '<p><span class="newWikiWord">His Way<a href="../show/HisWay">?</a></span> ' +
'would be <a class="existingWikiWord" href="../show/MyWay">My Way</a> in kinda ' +
'<a class="existingWikiWord" href="../show/ThatWay">That Way</a> in ' +
'<span class="newWikiWord">His Way<a href="../show/HisWay">?</a></span> ' +
'though <a class="existingWikiWord" href="../show/MyWay">My Way</a> OverThere&#8212;see ' +
'<a class="existingWikiWord" href="../show/SmartEngine">Smart Engine</a> in that ' +
'<span class="newWikiWord">Smart Engine GUI' +
'<a href="../show/SmartEngineGUI">?</a></span></p>',
@revision.display_content
end
def test_bluecloth
@web.markup = :markdown
assert_markup_parsed_as(
%{<h1>My Headline</h1>\n\n<p>that <span class="newWikiWord">} +
%{Smart Engine GUI<a href="../show/SmartEngineGUI">?</a></span></p>},
"My Headline\n===========\n\n that SmartEngineGUI")
code_block = [
'This is a code block:',
'',
' def a_method(arg)',
' return ThatWay',
'',
'Nice!'
].join("\n")
assert_markup_parsed_as(
%{<p>This is a code block:</p>\n\n<pre><code>def a_method(arg)\n} +
%{return ThatWay\n</code></pre>\n\n<p>Nice!</p>},
code_block)
end
def test_rdoc
@web.markup = :rdoc
@revision = Revision.new(@page, 1, '+hello+ that SmartEngineGUI',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson')
assert_equal "<tt>hello</tt> that <span class=\"newWikiWord\">Smart Engine GUI" +
"<a href=\"../show/SmartEngineGUI\">?</a></span>\n\n", @revision.display_content
end
def test_content_with_auto_links
assert_markup_parsed_as(
'<p><a href="http://www.loudthinking.com/">http://www.loudthinking.com/</a> ' +
'points to <a class="existingWikiWord" href="../show/ThatWay">That Way</a> from ' +
'<a href="mailto:david@loudthinking.com">david@loudthinking.com</a></p>',
'http://www.loudthinking.com/ points to ThatWay from david@loudthinking.com')
end
def test_content_with_aliased_links
assert_markup_parsed_as(
'<p>Would a <a class="existingWikiWord" href="../show/SmartEngine">clever motor' +
'</a> go by any other name?</p>',
'Would a [[SmartEngine|clever motor]] go by any other name?')
end
def test_content_with_wikiword_in_em
assert_markup_parsed_as(
'<p><em>should we go <a class="existingWikiWord" href="../show/ThatWay">' +
'That Way</a> or <span class="newWikiWord">This Way<a href="../show/ThisWay">?</a>' +
'</span> </em></p>',
'_should we go ThatWay or ThisWay _')
end
def test_content_with_wikiword_in_tag
assert_markup_parsed_as(
'<p>That is some <em style="WikiWord">Stylish Emphasis</em></p>',
'That is some <em style="WikiWord">Stylish Emphasis</em>')
end
def test_content_with_escaped_wikiword
# there should be no wiki link
assert_markup_parsed_as('<p>WikiWord</p>', '\WikiWord')
end
def test_content_with_pre_blocks
assert_markup_parsed_as(
'A <code>class SmartEngine end</code> would not mark up <pre>CodeBlocks</pre>',
'A <code>class SmartEngine end</code> would not mark up <pre>CodeBlocks</pre>')
end
def test_content_with_autolink_in_parentheses
assert_markup_parsed_as(
'<p>The <span class="caps">W3C</span> body (<a href="http://www.w3c.org">' +
'http://www.w3c.org</a>) sets web standards</p>',
'The W3C body (http://www.w3c.org) sets web standards')
end
def test_content_with_link_in_parentheses
assert_markup_parsed_as(
'<p>(<a href="http://wiki.org/wiki.cgi?WhatIsWiki">What is a wiki?</a>)</p>',
'("What is a wiki?":http://wiki.org/wiki.cgi?WhatIsWiki)')
end
def test_content_with_image_link
assert_markup_parsed_as(
'<p>This <img src="http://hobix.com/sample.jpg" alt="" /> is a Textile image link.</p>',
'This !http://hobix.com/sample.jpg! is a Textile image link.')
end
def test_content_with_nowiki_text
assert_markup_parsed_as(
'<p>Do not mark up [[this text]] or http://www.thislink.com.</p>',
'Do not mark up <nowiki>[[this text]]</nowiki> ' +
'or <nowiki>http://www.thislink.com</nowiki>.')
end
def test_content_with_bracketted_wiki_word
@web.brackets_only = true
assert_markup_parsed_as(
'<p>This is a WikiWord and a tricky name <span class="newWikiWord">' +
'Sperberg-McQueen<a href="../show/Sperberg-McQueen">?</a></span>.</p>',
'This is a WikiWord and a tricky name [[Sperberg-McQueen]].')
end
def test_content_for_export
assert_equal '<p><span class="newWikiWord">His Way</span> would be ' +
'<a class="existingWikiWord" href="MyWay.html">My Way</a> in kinda ' +
'<a class="existingWikiWord" href="ThatWay.html">That Way</a> in ' +
'<span class="newWikiWord">His Way</span> though ' +
'<a class="existingWikiWord" href="MyWay.html">My Way</a> OverThere&#8212;see ' +
'<a class="existingWikiWord" href="SmartEngine.html">Smart Engine</a> in that ' +
'<span class="newWikiWord">Smart Engine GUI</span></p>',
@revision.display_content_for_export
end
def test_double_replacing
@revision.content = "VersionHistory\r\n\r\ncry VersionHistory"
assert_equal '<p><span class="newWikiWord">Version History' +
"<a href=\"../show/VersionHistory\">?</a></span></p>\n\n\t<p>cry " +
'<span class="newWikiWord">Version History<a href="../show/VersionHistory">?</a>' +
'</span></p>',
@revision.display_content
@revision.clear_display_cache
@revision.content = "f\r\nVersionHistory\r\n\r\ncry VersionHistory"
assert_equal "<p>f<br />\n<span class=\"newWikiWord\">Version History" +
"<a href=\"../show/VersionHistory\">?</a></span></p>\n\n\t<p>cry " +
"<span class=\"newWikiWord\">Version History<a href=\"../show/VersionHistory\">?</a>" +
"</span></p>",
@revision.display_content
end
def test_difficult_wiki_words
@revision.content = "[[It's just awesome GUI!]]"
assert_equal "<p><span class=\"newWikiWord\">It's just awesome GUI!" +
"<a href=\"../show/It%27s+just+awesome+GUI%21\">?</a></span></p>",
@revision.display_content
end
def test_revisions_diff
@page.revisions = [
Revision.new(@page, 0, 'What a blue and lovely morning',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson'),
Revision.new(@page, 1, 'What a red and lovely morning today',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson')
]
assert_equal "<p>What a <del class=\"diffmod\">blue </del><ins class=\"diffmod\">red " +
"</ins>and lovely <del class=\"diffmod\">morning</del><ins class=\"diffmod\">morning " +
"today</ins></p>", @page.revisions.last.display_diff
end
def test_link_to_file
assert_markup_parsed_as(
'<p><span class="newWikiWord">doc.pdf<a href="../file/doc.pdf">?</a></span></p>',
'[[doc.pdf:file]]')
end
def test_link_to_pic
@wiki.file_yard(@web).upload_file('square.jpg', StringIO.new(''))
assert_markup_parsed_as(
'<p><img alt="Square" src="../pic/square.jpg" /></p>',
'[[square.jpg|Square:pic]]')
assert_markup_parsed_as(
'<p><img alt="square.jpg" src="../pic/square.jpg" /></p>',
'[[square.jpg:pic]]')
end
def test_link_to_non_existant_pic
assert_markup_parsed_as(
'<p><span class="newWikiWord">NonExistant<a href="../pic/NonExistant.jpg">?</a>' +
'</span></p>',
'[[NonExistant.jpg|NonExistant:pic]]')
assert_markup_parsed_as(
'<p><span class="newWikiWord">NonExistant.jpg<a href="../pic/NonExistant.jpg">?</a>' +
'</span></p>',
'[[NonExistant.jpg:pic]]')
end
# TODO Remove the leading underscores from this test when upgrading to RedCloth 3.0.1;
# also add a test for the "Unhappy Face" problem (another interesting RedCloth bug)
def __test_list_with_tildas
list_with_tildas = <<-EOL
* "a":~b
* c~ d
EOL
assert_markup_parsed_as(
"<li><a href=\"~b\">a</a></li>\n" +
"<li>c~ d</li>\n",
list_with_tildas)
end
def assert_markup_parsed_as(expected_output, input)
revision = Revision.new(@page, 1, input, Time.local(2004, 4, 4, 16, 50), 'AnAuthor')
assert_equal expected_output, revision.display_content, 'Textile output not as expected'
end
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'web'
require 'revision'
require 'fileutils'
class RevisionTest < Test::Unit::TestCase
def setup
setup_test_wiki
@web.markup = :textile
@page = @wiki.read_page('wiki1', 'HomePage')
['MyWay', 'SmartEngine', 'ThatWay'].each do |page|
@wiki.write_page('wiki1', page, page, Time.now, 'Me')
end
@revision = Revision.new(@page, 1,
'HisWay would be MyWay in kinda ThatWay in HisWay though MyWay \OverThere -- ' +
'see SmartEngine in that SmartEngineGUI',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson')
end
def test_wiki_words
assert_equal %w( HisWay MyWay SmartEngine SmartEngineGUI ThatWay ), @revision.wiki_words.sort
end
def test_existing_pages
assert_equal %w( MyWay SmartEngine ThatWay ), @revision.existing_pages.sort
end
def test_unexisting_pages
assert_equal %w( HisWay SmartEngineGUI ), @revision.unexisting_pages.sort
end
def test_content_with_wiki_links
assert_equal '<p><span class="newWikiWord">His Way<a href="../show/HisWay">?</a></span> ' +
'would be <a class="existingWikiWord" href="../show/MyWay">My Way</a> in kinda ' +
'<a class="existingWikiWord" href="../show/ThatWay">That Way</a> in ' +
'<span class="newWikiWord">His Way<a href="../show/HisWay">?</a></span> ' +
'though <a class="existingWikiWord" href="../show/MyWay">My Way</a> OverThere&#8212;see ' +
'<a class="existingWikiWord" href="../show/SmartEngine">Smart Engine</a> in that ' +
'<span class="newWikiWord">Smart Engine GUI' +
'<a href="../show/SmartEngineGUI">?</a></span></p>',
@revision.display_content
end
def test_bluecloth
@web.markup = :markdown
assert_markup_parsed_as(
%{<h1>My Headline</h1>\n\n<p>that <span class="newWikiWord">} +
%{Smart Engine GUI<a href="../show/SmartEngineGUI">?</a></span></p>},
"My Headline\n===========\n\n that SmartEngineGUI")
code_block = [
'This is a code block:',
'',
' def a_method(arg)',
' return ThatWay',
'',
'Nice!'
].join("\n")
assert_markup_parsed_as(
%{<p>This is a code block:</p>\n\n<pre><code>def a_method(arg)\n} +
%{return ThatWay\n</code></pre>\n\n<p>Nice!</p>},
code_block)
end
def test_rdoc
@web.markup = :rdoc
@revision = Revision.new(@page, 1, '+hello+ that SmartEngineGUI',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson')
assert_equal "<tt>hello</tt> that <span class=\"newWikiWord\">Smart Engine GUI" +
"<a href=\"../show/SmartEngineGUI\">?</a></span>\n\n", @revision.display_content
end
def test_content_with_auto_links
assert_markup_parsed_as(
'<p><a href="http://www.loudthinking.com/">http://www.loudthinking.com/</a> ' +
'points to <a class="existingWikiWord" href="../show/ThatWay">That Way</a> from ' +
'<a href="mailto:david@loudthinking.com">david@loudthinking.com</a></p>',
'http://www.loudthinking.com/ points to ThatWay from david@loudthinking.com')
end
def test_content_with_aliased_links
assert_markup_parsed_as(
'<p>Would a <a class="existingWikiWord" href="../show/SmartEngine">clever motor' +
'</a> go by any other name?</p>',
'Would a [[SmartEngine|clever motor]] go by any other name?')
end
def test_content_with_wikiword_in_em
assert_markup_parsed_as(
'<p><em>should we go <a class="existingWikiWord" href="../show/ThatWay">' +
'That Way</a> or <span class="newWikiWord">This Way<a href="../show/ThisWay">?</a>' +
'</span> </em></p>',
'_should we go ThatWay or ThisWay _')
end
def test_content_with_wikiword_in_tag
assert_markup_parsed_as(
'<p>That is some <em style="WikiWord">Stylish Emphasis</em></p>',
'That is some <em style="WikiWord">Stylish Emphasis</em>')
end
def test_content_with_escaped_wikiword
# there should be no wiki link
assert_markup_parsed_as('<p>WikiWord</p>', '\WikiWord')
end
def test_content_with_pre_blocks
assert_markup_parsed_as(
'A <code>class SmartEngine end</code> would not mark up <pre>CodeBlocks</pre>',
'A <code>class SmartEngine end</code> would not mark up <pre>CodeBlocks</pre>')
end
def test_content_with_autolink_in_parentheses
assert_markup_parsed_as(
'<p>The <span class="caps">W3C</span> body (<a href="http://www.w3c.org">' +
'http://www.w3c.org</a>) sets web standards</p>',
'The W3C body (http://www.w3c.org) sets web standards')
end
def test_content_with_link_in_parentheses
assert_markup_parsed_as(
'<p>(<a href="http://wiki.org/wiki.cgi?WhatIsWiki">What is a wiki?</a>)</p>',
'("What is a wiki?":http://wiki.org/wiki.cgi?WhatIsWiki)')
end
def test_content_with_image_link
assert_markup_parsed_as(
'<p>This <img src="http://hobix.com/sample.jpg" alt="" /> is a Textile image link.</p>',
'This !http://hobix.com/sample.jpg! is a Textile image link.')
end
def test_content_with_nowiki_text
assert_markup_parsed_as(
'<p>Do not mark up [[this text]] or http://www.thislink.com.</p>',
'Do not mark up <nowiki>[[this text]]</nowiki> ' +
'or <nowiki>http://www.thislink.com</nowiki>.')
end
def test_content_with_bracketted_wiki_word
@web.brackets_only = true
assert_markup_parsed_as(
'<p>This is a WikiWord and a tricky name <span class="newWikiWord">' +
'Sperberg-McQueen<a href="../show/Sperberg-McQueen">?</a></span>.</p>',
'This is a WikiWord and a tricky name [[Sperberg-McQueen]].')
end
def test_content_for_export
assert_equal '<p><span class="newWikiWord">His Way</span> would be ' +
'<a class="existingWikiWord" href="MyWay.html">My Way</a> in kinda ' +
'<a class="existingWikiWord" href="ThatWay.html">That Way</a> in ' +
'<span class="newWikiWord">His Way</span> though ' +
'<a class="existingWikiWord" href="MyWay.html">My Way</a> OverThere&#8212;see ' +
'<a class="existingWikiWord" href="SmartEngine.html">Smart Engine</a> in that ' +
'<span class="newWikiWord">Smart Engine GUI</span></p>',
@revision.display_content_for_export
end
def test_double_replacing
@revision.content = "VersionHistory\r\n\r\ncry VersionHistory"
assert_equal '<p><span class="newWikiWord">Version History' +
"<a href=\"../show/VersionHistory\">?</a></span></p>\n\n\t<p>cry " +
'<span class="newWikiWord">Version History<a href="../show/VersionHistory">?</a>' +
'</span></p>',
@revision.display_content
@revision.clear_display_cache
@revision.content = "f\r\nVersionHistory\r\n\r\ncry VersionHistory"
assert_equal "<p>f<br />\n<span class=\"newWikiWord\">Version History" +
"<a href=\"../show/VersionHistory\">?</a></span></p>\n\n\t<p>cry " +
"<span class=\"newWikiWord\">Version History<a href=\"../show/VersionHistory\">?</a>" +
"</span></p>",
@revision.display_content
end
def test_difficult_wiki_words
@revision.content = "[[It's just awesome GUI!]]"
assert_equal "<p><span class=\"newWikiWord\">It's just awesome GUI!" +
"<a href=\"../show/It%27s+just+awesome+GUI%21\">?</a></span></p>",
@revision.display_content
end
def test_revisions_diff
@page.revisions = [
Revision.new(@page, 0, 'What a blue and lovely morning',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson'),
Revision.new(@page, 1, 'What a red and lovely morning today',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson')
]
assert_equal "<p>What a <del class=\"diffmod\">blue </del><ins class=\"diffmod\">red " +
"</ins>and lovely <del class=\"diffmod\">morning</del><ins class=\"diffmod\">morning " +
"today</ins></p>", @page.revisions.last.display_diff
end
def test_link_to_file
assert_markup_parsed_as(
'<p><span class="newWikiWord">doc.pdf<a href="../file/doc.pdf">?</a></span></p>',
'[[doc.pdf:file]]')
end
def test_link_to_pic
@wiki.file_yard(@web).upload_file('square.jpg', StringIO.new(''))
assert_markup_parsed_as(
'<p><img alt="Square" src="../pic/square.jpg" /></p>',
'[[square.jpg|Square:pic]]')
assert_markup_parsed_as(
'<p><img alt="square.jpg" src="../pic/square.jpg" /></p>',
'[[square.jpg:pic]]')
end
def test_link_to_non_existant_pic
assert_markup_parsed_as(
'<p><span class="newWikiWord">NonExistant<a href="../pic/NonExistant.jpg">?</a>' +
'</span></p>',
'[[NonExistant.jpg|NonExistant:pic]]')
assert_markup_parsed_as(
'<p><span class="newWikiWord">NonExistant.jpg<a href="../pic/NonExistant.jpg">?</a>' +
'</span></p>',
'[[NonExistant.jpg:pic]]')
end
# TODO Remove the leading underscores from this test when upgrading to RedCloth 3.0.1;
# also add a test for the "Unhappy Face" problem (another interesting RedCloth bug)
def __test_list_with_tildas
list_with_tildas = <<-EOL
* "a":~b
* c~ d
EOL
assert_markup_parsed_as(
"<li><a href=\"~b\">a</a></li>\n" +
"<li>c~ d</li>\n",
list_with_tildas)
end
def assert_markup_parsed_as(expected_output, input)
revision = Revision.new(@page, 1, input, Time.local(2004, 4, 4, 16, 50), 'AnAuthor')
assert_equal expected_output, revision.display_content, 'Textile output not as expected'
end
end

View file

@ -1,179 +1,179 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'chunks/uri'
class URITest < Test::Unit::TestCase
include ChunkMatch
def test_non_matches
assert_conversion_does_not_apply(URIChunk, 'There is no URI here')
assert_conversion_does_not_apply(URIChunk,
'One gemstone is the garnet:reddish in colour, like ruby')
end
def test_simple_uri
# Simplest case
match(URIChunk, 'http://www.example.com',
:scheme =>'http', :host =>'www.example.com', :path => nil,
:link_text => 'http://www.example.com'
)
# With trailing slash
match(URIChunk, 'http://www.example.com/',
:scheme =>'http', :host =>'www.example.com', :path => '/',
:link_text => 'http://www.example.com/'
)
# Without http://
match(URIChunk, 'www.example.com',
:scheme =>'http', :host =>'www.example.com', :link_text => 'www.example.com'
)
# two parts
match(URIChunk, 'example.com',
:scheme =>'http',:host =>'example.com', :link_text => 'example.com'
)
# "unusual" base domain (was a bug in an early version)
match(URIChunk, 'http://example.com.au/',
:scheme =>'http', :host =>'example.com.au', :link_text => 'http://example.com.au/'
)
# "unusual" base domain without http://
match(URIChunk, 'example.com.au',
:scheme =>'http', :host =>'example.com.au', :link_text => 'example.com.au'
)
# Another "unusual" base domain
match(URIChunk, 'http://www.example.co.uk/',
:scheme =>'http', :host =>'www.example.co.uk',
:link_text => 'http://www.example.co.uk/'
)
match(URIChunk, 'example.co.uk',
:scheme =>'http', :host =>'example.co.uk', :link_text => 'example.co.uk'
)
# With some path at the end
match(URIChunk, 'http://moinmoin.wikiwikiweb.de/HelpOnNavigation',
:scheme => 'http', :host => 'moinmoin.wikiwikiweb.de', :path => '/HelpOnNavigation',
:link_text => 'http://moinmoin.wikiwikiweb.de/HelpOnNavigation'
)
# With some path at the end, and withot http:// prefix
match(URIChunk, 'moinmoin.wikiwikiweb.de/HelpOnNavigation',
:scheme => 'http', :host => 'moinmoin.wikiwikiweb.de', :path => '/HelpOnNavigation',
:link_text => 'moinmoin.wikiwikiweb.de/HelpOnNavigation'
)
# With a port number
match(URIChunk, 'http://www.example.com:80',
:scheme =>'http', :host =>'www.example.com', :port => '80', :path => nil,
:link_text => 'http://www.example.com:80')
# With a port number and a path
match(URIChunk, 'http://www.example.com.tw:80/HelpOnNavigation',
:scheme =>'http', :host =>'www.example.com.tw', :port => '80', :path => '/HelpOnNavigation',
:link_text => 'http://www.example.com.tw:80/HelpOnNavigation')
# With a query
match(URIChunk, 'http://www.example.com.tw:80/HelpOnNavigation?arg=val',
:scheme =>'http', :host =>'www.example.com.tw', :port => '80', :path => '/HelpOnNavigation',
:query => 'arg=val',
:link_text => 'http://www.example.com.tw:80/HelpOnNavigation?arg=val')
# Query with two arguments
match(URIChunk, 'http://www.example.com.tw:80/HelpOnNavigation?arg=val&arg2=val2',
:scheme =>'http', :host =>'www.example.com.tw', :port => '80', :path => '/HelpOnNavigation',
:query => 'arg=val&arg2=val2',
:link_text => 'http://www.example.com.tw:80/HelpOnNavigation?arg=val&arg2=val2')
# HTTPS
match(URIChunk, 'https://www.example.com',
:scheme =>'https', :host =>'www.example.com', :port => nil, :path => nil, :query => nil,
:link_text => 'https://www.example.com')
# FTP
match(URIChunk, 'ftp://www.example.com',
:scheme =>'ftp', :host =>'www.example.com', :port => nil, :path => nil, :query => nil,
:link_text => 'ftp://www.example.com')
# mailto
match(URIChunk, 'mailto:jdoe123@example.com',
:scheme =>'mailto', :host =>'example.com', :port => nil, :path => nil, :query => nil,
:user => 'jdoe123', :link_text => 'mailto:jdoe123@example.com')
# something nonexistant
match(URIChunk, 'foobar://www.example.com',
:scheme =>'foobar', :host =>'www.example.com', :port => nil, :path => nil, :query => nil,
:link_text => 'foobar://www.example.com')
# Soap opera (the most complex case imaginable... well, not really, there should be more evil)
match(URIChunk, 'http://www.example.com.tw:80/~jdoe123/Help%20Me%20?arg=val&arg2=val2',
:scheme =>'http', :host =>'www.example.com.tw', :port => '80',
:path => '/~jdoe123/Help%20Me%20', :query => 'arg=val&arg2=val2',
:link_text => 'http://www.example.com.tw:80/~jdoe123/Help%20Me%20?arg=val&arg2=val2')
end
def test_email_uri
match(URIChunk, 'mail@example.com',
:user => 'mail', :host => 'example.com', :link_text => 'mail@example.com'
)
end
def test_non_email
# The @ is part of the normal text, but 'example.com' is marked up.
match(URIChunk, 'Not an email: @example.com', :user => nil, :uri => 'http://example.com')
end
def test_non_uri
assert_conversion_does_not_apply URIChunk, 'httpd.conf'
assert_conversion_does_not_apply URIChunk, 'libproxy.so'
assert_conversion_does_not_apply URIChunk, 'ld.so.conf'
end
def test_uri_in_text
match(URIChunk, 'Go to: http://www.example.com/', :host => 'www.example.com', :path =>'/')
match(URIChunk, 'http://www.example.com/ is a link.', :host => 'www.example.com')
match(URIChunk,
'Email david@loudthinking.com',
:scheme =>'mailto', :user =>'david', :host =>'loudthinking.com')
# check that trailing punctuation is not included in the hostname
match(URIChunk, '"link":http://fake.link.com.', :scheme => 'http', :host => 'fake.link.com')
end
def test_uri_in_parentheses
match(URIChunk, 'URI (http://brackets.com.de) in brackets', :host => 'brackets.com.de')
match(URIChunk, 'because (as shown at research.net) the results', :host => 'research.net')
match(URIChunk,
'A wiki (http://wiki.org/wiki.cgi?WhatIsWiki) page',
:scheme => 'http', :host => 'wiki.org', :path => '/wiki.cgi', :query => 'WhatIsWiki'
)
end
def test_uri_list_item
match(
URIChunk,
'* http://www.btinternet.com/~mail2minh/SonyEricssonP80xPlatform.sis',
:path => '/~mail2minh/SonyEricssonP80xPlatform.sis'
)
end
def test_interesting_uri_with__comma
# Counter-intuitively, this URL matches, but the query part includes the trailing comma.
# It has no way to know that the query does not include the comma.
match(
URIChunk,
"This text contains a URL http://someplace.org:8080/~person/stuff.cgi?arg=val, doesn't it?",
:scheme => 'http', :host => 'someplace.org', :port => '8080', :path => '/~person/stuff.cgi',
:query => 'arg=val,')
end
def test_local_urls
# normal
match(LocalURIChunk, 'http://perforce:8001/toto.html',
:scheme => 'http', :host => 'perforce',
:port => '8001', :link_text => 'http://perforce:8001/toto.html')
# in parentheses
match(LocalURIChunk, 'URI (http://localhost:2500) in brackets',
:host => 'localhost', :port => '2500')
match(LocalURIChunk, 'because (as shown at http://perforce:8001) the results',
:host => 'perforce', :port => '8001')
match(LocalURIChunk,
'A wiki (http://localhost:2500/wiki.cgi?WhatIsWiki) page',
:scheme => 'http', :host => 'localhost', :path => '/wiki.cgi',
:port => '2500', :query => 'WhatIsWiki')
end
def assert_conversion_does_not_apply(chunk_type, str)
processed_str = str.dup
URIChunk.apply_to(processed_str)
assert_equal(str, processed_str)
end
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'chunks/uri'
class URITest < Test::Unit::TestCase
include ChunkMatch
def test_non_matches
assert_conversion_does_not_apply(URIChunk, 'There is no URI here')
assert_conversion_does_not_apply(URIChunk,
'One gemstone is the garnet:reddish in colour, like ruby')
end
def test_simple_uri
# Simplest case
match(URIChunk, 'http://www.example.com',
:scheme =>'http', :host =>'www.example.com', :path => nil,
:link_text => 'http://www.example.com'
)
# With trailing slash
match(URIChunk, 'http://www.example.com/',
:scheme =>'http', :host =>'www.example.com', :path => '/',
:link_text => 'http://www.example.com/'
)
# Without http://
match(URIChunk, 'www.example.com',
:scheme =>'http', :host =>'www.example.com', :link_text => 'www.example.com'
)
# two parts
match(URIChunk, 'example.com',
:scheme =>'http',:host =>'example.com', :link_text => 'example.com'
)
# "unusual" base domain (was a bug in an early version)
match(URIChunk, 'http://example.com.au/',
:scheme =>'http', :host =>'example.com.au', :link_text => 'http://example.com.au/'
)
# "unusual" base domain without http://
match(URIChunk, 'example.com.au',
:scheme =>'http', :host =>'example.com.au', :link_text => 'example.com.au'
)
# Another "unusual" base domain
match(URIChunk, 'http://www.example.co.uk/',
:scheme =>'http', :host =>'www.example.co.uk',
:link_text => 'http://www.example.co.uk/'
)
match(URIChunk, 'example.co.uk',
:scheme =>'http', :host =>'example.co.uk', :link_text => 'example.co.uk'
)
# With some path at the end
match(URIChunk, 'http://moinmoin.wikiwikiweb.de/HelpOnNavigation',
:scheme => 'http', :host => 'moinmoin.wikiwikiweb.de', :path => '/HelpOnNavigation',
:link_text => 'http://moinmoin.wikiwikiweb.de/HelpOnNavigation'
)
# With some path at the end, and withot http:// prefix
match(URIChunk, 'moinmoin.wikiwikiweb.de/HelpOnNavigation',
:scheme => 'http', :host => 'moinmoin.wikiwikiweb.de', :path => '/HelpOnNavigation',
:link_text => 'moinmoin.wikiwikiweb.de/HelpOnNavigation'
)
# With a port number
match(URIChunk, 'http://www.example.com:80',
:scheme =>'http', :host =>'www.example.com', :port => '80', :path => nil,
:link_text => 'http://www.example.com:80')
# With a port number and a path
match(URIChunk, 'http://www.example.com.tw:80/HelpOnNavigation',
:scheme =>'http', :host =>'www.example.com.tw', :port => '80', :path => '/HelpOnNavigation',
:link_text => 'http://www.example.com.tw:80/HelpOnNavigation')
# With a query
match(URIChunk, 'http://www.example.com.tw:80/HelpOnNavigation?arg=val',
:scheme =>'http', :host =>'www.example.com.tw', :port => '80', :path => '/HelpOnNavigation',
:query => 'arg=val',
:link_text => 'http://www.example.com.tw:80/HelpOnNavigation?arg=val')
# Query with two arguments
match(URIChunk, 'http://www.example.com.tw:80/HelpOnNavigation?arg=val&arg2=val2',
:scheme =>'http', :host =>'www.example.com.tw', :port => '80', :path => '/HelpOnNavigation',
:query => 'arg=val&arg2=val2',
:link_text => 'http://www.example.com.tw:80/HelpOnNavigation?arg=val&arg2=val2')
# HTTPS
match(URIChunk, 'https://www.example.com',
:scheme =>'https', :host =>'www.example.com', :port => nil, :path => nil, :query => nil,
:link_text => 'https://www.example.com')
# FTP
match(URIChunk, 'ftp://www.example.com',
:scheme =>'ftp', :host =>'www.example.com', :port => nil, :path => nil, :query => nil,
:link_text => 'ftp://www.example.com')
# mailto
match(URIChunk, 'mailto:jdoe123@example.com',
:scheme =>'mailto', :host =>'example.com', :port => nil, :path => nil, :query => nil,
:user => 'jdoe123', :link_text => 'mailto:jdoe123@example.com')
# something nonexistant
match(URIChunk, 'foobar://www.example.com',
:scheme =>'foobar', :host =>'www.example.com', :port => nil, :path => nil, :query => nil,
:link_text => 'foobar://www.example.com')
# Soap opera (the most complex case imaginable... well, not really, there should be more evil)
match(URIChunk, 'http://www.example.com.tw:80/~jdoe123/Help%20Me%20?arg=val&arg2=val2',
:scheme =>'http', :host =>'www.example.com.tw', :port => '80',
:path => '/~jdoe123/Help%20Me%20', :query => 'arg=val&arg2=val2',
:link_text => 'http://www.example.com.tw:80/~jdoe123/Help%20Me%20?arg=val&arg2=val2')
end
def test_email_uri
match(URIChunk, 'mail@example.com',
:user => 'mail', :host => 'example.com', :link_text => 'mail@example.com'
)
end
def test_non_email
# The @ is part of the normal text, but 'example.com' is marked up.
match(URIChunk, 'Not an email: @example.com', :user => nil, :uri => 'http://example.com')
end
def test_non_uri
assert_conversion_does_not_apply URIChunk, 'httpd.conf'
assert_conversion_does_not_apply URIChunk, 'libproxy.so'
assert_conversion_does_not_apply URIChunk, 'ld.so.conf'
end
def test_uri_in_text
match(URIChunk, 'Go to: http://www.example.com/', :host => 'www.example.com', :path =>'/')
match(URIChunk, 'http://www.example.com/ is a link.', :host => 'www.example.com')
match(URIChunk,
'Email david@loudthinking.com',
:scheme =>'mailto', :user =>'david', :host =>'loudthinking.com')
# check that trailing punctuation is not included in the hostname
match(URIChunk, '"link":http://fake.link.com.', :scheme => 'http', :host => 'fake.link.com')
end
def test_uri_in_parentheses
match(URIChunk, 'URI (http://brackets.com.de) in brackets', :host => 'brackets.com.de')
match(URIChunk, 'because (as shown at research.net) the results', :host => 'research.net')
match(URIChunk,
'A wiki (http://wiki.org/wiki.cgi?WhatIsWiki) page',
:scheme => 'http', :host => 'wiki.org', :path => '/wiki.cgi', :query => 'WhatIsWiki'
)
end
def test_uri_list_item
match(
URIChunk,
'* http://www.btinternet.com/~mail2minh/SonyEricssonP80xPlatform.sis',
:path => '/~mail2minh/SonyEricssonP80xPlatform.sis'
)
end
def test_interesting_uri_with__comma
# Counter-intuitively, this URL matches, but the query part includes the trailing comma.
# It has no way to know that the query does not include the comma.
match(
URIChunk,
"This text contains a URL http://someplace.org:8080/~person/stuff.cgi?arg=val, doesn't it?",
:scheme => 'http', :host => 'someplace.org', :port => '8080', :path => '/~person/stuff.cgi',
:query => 'arg=val,')
end
def test_local_urls
# normal
match(LocalURIChunk, 'http://perforce:8001/toto.html',
:scheme => 'http', :host => 'perforce',
:port => '8001', :link_text => 'http://perforce:8001/toto.html')
# in parentheses
match(LocalURIChunk, 'URI (http://localhost:2500) in brackets',
:host => 'localhost', :port => '2500')
match(LocalURIChunk, 'because (as shown at http://perforce:8001) the results',
:host => 'perforce', :port => '8001')
match(LocalURIChunk,
'A wiki (http://localhost:2500/wiki.cgi?WhatIsWiki) page',
:scheme => 'http', :host => 'localhost', :path => '/wiki.cgi',
:port => '2500', :query => 'WhatIsWiki')
end
def assert_conversion_does_not_apply(chunk_type, str)
processed_str = str.dup
URIChunk.apply_to(processed_str)
assert_equal(str, processed_str)
end
end

View file

@ -1,92 +1,92 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'url_rewriting_hack'
class UrlRewritingHackTest < Test::Unit::TestCase
def test_parse_uri
assert_equal({:controller => 'wiki', :action => 'x', :web => nil},
DispatchServlet.parse_uri('/x/'))
assert_equal({:web => 'x', :controller => 'wiki', :action => 'y'},
DispatchServlet.parse_uri('/x/y'))
assert_equal({:web => 'x', :controller => 'wiki', :action => 'y'},
DispatchServlet.parse_uri('/x/y/'))
assert_equal({:web => 'x', :controller => 'wiki', :action => 'y', :id => 'z'},
DispatchServlet.parse_uri('/x/y/z'))
assert_equal({:web => 'x', :controller => 'wiki', :action => 'y', :id => 'z'},
DispatchServlet.parse_uri('/x/y/z/'))
end
def test_parse_uri_approot
assert_equal({:controller => 'wiki', :action => 'index', :web => nil},
DispatchServlet.parse_uri('/wiki/'))
end
def test_parse_uri_interestng_cases
assert_equal({:web => '_veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery-long_web_',
:controller => 'wiki',
:action => 'an_action', :id => 'HomePage'
},
DispatchServlet.parse_uri(
'/_veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery-long_web_/an_action/HomePage')
)
assert_equal false, DispatchServlet.parse_uri('')
assert_equal false, DispatchServlet.parse_uri('//')
assert_equal false, DispatchServlet.parse_uri('web')
end
def test_parse_uri_liberal_with_pagenames
assert_equal({:controller => 'wiki', :web => 'web', :action => 'show', :id => '$HOME_PAGE'},
DispatchServlet.parse_uri('/web/show/$HOME_PAGE'))
assert_equal({:controller => 'wiki', :web => 'web', :action => 'show',
:id => 'HomePage/something_else'},
DispatchServlet.parse_uri('/web/show/HomePage/something_else'))
assert_equal({:controller => 'wiki', :web => 'web', :action => 'show',
:id => 'HomePage?arg1=value1&arg2=value2'},
DispatchServlet.parse_uri('/web/show/HomePage?arg1=value1&arg2=value2'))
assert_equal({:controller => 'wiki', :web => 'web', :action => 'show',
:id => 'Page+With+Spaces'},
DispatchServlet.parse_uri('/web/show/Page+With+Spaces'))
end
def test_url_rewriting
request = ActionController::TestRequest.new
ur = ActionController::UrlRewriter.new(request, 'wiki', 'show')
assert_equal 'http://test.host/myweb/myaction',
ur.rewrite(:web => 'myweb', :controller => 'wiki', :action => 'myaction')
assert_equal 'http://test.host/myOtherWeb/',
ur.rewrite(:web => 'myOtherWeb', :controller => 'wiki')
assert_equal 'http://test.host/myaction',
ur.rewrite(:controller => 'wiki', :action => 'myaction')
assert_equal 'http://test.host/',
ur.rewrite(:controller => 'wiki')
end
def test_controller_mapping
request = ActionController::TestRequest.new
ur = ActionController::UrlRewriter.new(request, 'wiki', 'show')
assert_equal 'http://test.host/file',
ur.rewrite(:controller => 'file', :action => 'file')
assert_equal 'http://test.host/pic/abc.jpg',
ur.rewrite(:controller => 'file', :action => 'pic', :id => 'abc.jpg')
assert_equal 'http://test.host/web/pic/abc.jpg',
ur.rewrite(:web => 'web', :controller => 'file', :action => 'pic', :id => 'abc.jpg')
# default option is wiki
assert_equal 'http://test.host/unknown_action',
ur.rewrite(:controller => 'wiki', :action => 'unknown_action')
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'url_rewriting_hack'
class UrlRewritingHackTest < Test::Unit::TestCase
def test_parse_uri
assert_equal({:controller => 'wiki', :action => 'x', :web => nil},
DispatchServlet.parse_uri('/x/'))
assert_equal({:web => 'x', :controller => 'wiki', :action => 'y'},
DispatchServlet.parse_uri('/x/y'))
assert_equal({:web => 'x', :controller => 'wiki', :action => 'y'},
DispatchServlet.parse_uri('/x/y/'))
assert_equal({:web => 'x', :controller => 'wiki', :action => 'y', :id => 'z'},
DispatchServlet.parse_uri('/x/y/z'))
assert_equal({:web => 'x', :controller => 'wiki', :action => 'y', :id => 'z'},
DispatchServlet.parse_uri('/x/y/z/'))
end
def test_parse_uri_approot
assert_equal({:controller => 'wiki', :action => 'index', :web => nil},
DispatchServlet.parse_uri('/wiki/'))
end
def test_parse_uri_interestng_cases
assert_equal({:web => '_veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery-long_web_',
:controller => 'wiki',
:action => 'an_action', :id => 'HomePage'
},
DispatchServlet.parse_uri(
'/_veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeery-long_web_/an_action/HomePage')
)
assert_equal false, DispatchServlet.parse_uri('')
assert_equal false, DispatchServlet.parse_uri('//')
assert_equal false, DispatchServlet.parse_uri('web')
end
def test_parse_uri_liberal_with_pagenames
assert_equal({:controller => 'wiki', :web => 'web', :action => 'show', :id => '$HOME_PAGE'},
DispatchServlet.parse_uri('/web/show/$HOME_PAGE'))
assert_equal({:controller => 'wiki', :web => 'web', :action => 'show',
:id => 'HomePage/something_else'},
DispatchServlet.parse_uri('/web/show/HomePage/something_else'))
assert_equal({:controller => 'wiki', :web => 'web', :action => 'show',
:id => 'HomePage?arg1=value1&arg2=value2'},
DispatchServlet.parse_uri('/web/show/HomePage?arg1=value1&arg2=value2'))
assert_equal({:controller => 'wiki', :web => 'web', :action => 'show',
:id => 'Page+With+Spaces'},
DispatchServlet.parse_uri('/web/show/Page+With+Spaces'))
end
def test_url_rewriting
request = ActionController::TestRequest.new
ur = ActionController::UrlRewriter.new(request, 'wiki', 'show')
assert_equal 'http://test.host/myweb/myaction',
ur.rewrite(:web => 'myweb', :controller => 'wiki', :action => 'myaction')
assert_equal 'http://test.host/myOtherWeb/',
ur.rewrite(:web => 'myOtherWeb', :controller => 'wiki')
assert_equal 'http://test.host/myaction',
ur.rewrite(:controller => 'wiki', :action => 'myaction')
assert_equal 'http://test.host/',
ur.rewrite(:controller => 'wiki')
end
def test_controller_mapping
request = ActionController::TestRequest.new
ur = ActionController::UrlRewriter.new(request, 'wiki', 'show')
assert_equal 'http://test.host/file',
ur.rewrite(:controller => 'file', :action => 'file')
assert_equal 'http://test.host/pic/abc.jpg',
ur.rewrite(:controller => 'file', :action => 'pic', :id => 'abc.jpg')
assert_equal 'http://test.host/web/pic/abc.jpg',
ur.rewrite(:web => 'web', :controller => 'file', :action => 'pic', :id => 'abc.jpg')
# default option is wiki
assert_equal 'http://test.host/unknown_action',
ur.rewrite(:controller => 'wiki', :action => 'unknown_action')
end
end

View file

@ -1,130 +1,130 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'wiki_service'
class WebTest < Test::Unit::TestCase
def setup
@web = Web.new nil, 'Instiki', 'instiki'
end
def test_wiki_word_linking
@web.add_page(Page.new(@web, 'SecondPage', 'Yo, yo. Have you EverBeenHated', Time.now,
'DavidHeinemeierHansson'))
assert_equal('<p>Yo, yo. Have you <span class="newWikiWord">Ever Been Hated' +
'<a href="../show/EverBeenHated">?</a></span></p>',
@web.pages["SecondPage"].display_content)
@web.add_page(Page.new(@web, 'EverBeenHated', 'Yo, yo. Have you EverBeenHated', Time.now,
'DavidHeinemeierHansson'))
assert_equal('<p>Yo, yo. Have you <a class="existingWikiWord" ' +
'href="../show/EverBeenHated">Ever Been Hated</a></p>',
@web.pages['SecondPage'].display_content)
end
def test_pages_by_revision
add_sample_pages
assert_equal 'EverBeenHated', @web.select.by_revision.first.name
end
def test_pages_by_match
add_sample_pages
assert_equal 2, @web.select { |page| page.content =~ /me/i }.length
assert_equal 1, @web.select { |page| page.content =~ /Who/i }.length
assert_equal 0, @web.select { |page| page.content =~ /none/i }.length
end
def test_references
add_sample_pages
assert_equal 1, @web.select.pages_that_reference('EverBeenHated').length
assert_equal 0, @web.select.pages_that_reference('EverBeenInLove').length
end
def test_delete
add_sample_pages
assert_equal 2, @web.pages.length
@web.remove_pages([ @web.pages['EverBeenInLove'] ])
assert_equal 1, @web.pages.length
end
def test_make_link
add_sample_pages
existing_page_wiki_url =
'<a class="existingWikiWord" href="../show/EverBeenInLove">Ever Been In Love</a>'
existing_page_published_url =
'<a class="existingWikiWord" href="../published/EverBeenInLove">Ever Been In Love</a>'
existing_page_static_url =
'<a class="existingWikiWord" href="EverBeenInLove.html">Ever Been In Love</a>'
new_page_wiki_url =
'<span class="newWikiWord">Unknown Word<a href="../show/UnknownWord">?</a></span>'
new_page_published_url =
new_page_static_url =
'<span class="newWikiWord">Unknown Word</span>'
# no options
assert_equal existing_page_wiki_url, @web.make_link('EverBeenInLove')
# :mode => :export
assert_equal existing_page_static_url, @web.make_link('EverBeenInLove', nil, :mode => :export)
# :mode => :publish
assert_equal existing_page_published_url,
@web.make_link('EverBeenInLove', nil, :mode => :publish)
# new page, no options
assert_equal new_page_wiki_url, @web.make_link('UnknownWord')
# new page, :mode => :export
assert_equal new_page_static_url, @web.make_link('UnknownWord', nil, :mode => :export)
# new page, :mode => :publish
assert_equal new_page_published_url, @web.make_link('UnknownWord', nil, :mode => :publish)
# Escaping special characters in the name
assert_equal(
'<span class="newWikiWord">Smith &amp; Wesson<a href="../show/Smith+%26+Wesson">?</a></span>',
@web.make_link('Smith & Wesson'))
# optionally using text as the link text
assert_equal(
existing_page_published_url.sub(/>Ever Been In Love</, ">Haven't you ever been in love?<"),
@web.make_link('EverBeenInLove', "Haven't you ever been in love?", :mode => :publish))
end
def test_initialize
wiki_stub = Object.new
web = Web.new(wiki_stub, 'Wiki2', 'wiki2', '123')
assert_equal wiki_stub, web.wiki
assert_equal 'Wiki2', web.name
assert_equal 'wiki2', web.address
assert_equal '123', web.password
# new web should be set for maximum features enabled
assert_equal :textile, web.markup
assert_equal '008B26', web.color
assert !web.safe_mode
assert_equal {}, web.pages
assert web.allow_uploads
assert_equal @wiki, web.parent_wiki
assert_nil web.additional_style
assert !web.published
assert !web.brackets_only
assert !web.count_pages
assert web.allow_uploads
end
private
def add_sample_pages
@web.add_page(Page.new(@web, 'EverBeenInLove', 'Who am I me',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson'))
@web.add_page(Page.new(@web, 'EverBeenHated', 'I am me EverBeenHated',
Time.local(2004, 4, 4, 16, 51), 'DavidHeinemeierHansson'))
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'wiki_service'
class WebTest < Test::Unit::TestCase
def setup
@web = Web.new nil, 'Instiki', 'instiki'
end
def test_wiki_word_linking
@web.add_page(Page.new(@web, 'SecondPage', 'Yo, yo. Have you EverBeenHated', Time.now,
'DavidHeinemeierHansson'))
assert_equal('<p>Yo, yo. Have you <span class="newWikiWord">Ever Been Hated' +
'<a href="../show/EverBeenHated">?</a></span></p>',
@web.pages["SecondPage"].display_content)
@web.add_page(Page.new(@web, 'EverBeenHated', 'Yo, yo. Have you EverBeenHated', Time.now,
'DavidHeinemeierHansson'))
assert_equal('<p>Yo, yo. Have you <a class="existingWikiWord" ' +
'href="../show/EverBeenHated">Ever Been Hated</a></p>',
@web.pages['SecondPage'].display_content)
end
def test_pages_by_revision
add_sample_pages
assert_equal 'EverBeenHated', @web.select.by_revision.first.name
end
def test_pages_by_match
add_sample_pages
assert_equal 2, @web.select { |page| page.content =~ /me/i }.length
assert_equal 1, @web.select { |page| page.content =~ /Who/i }.length
assert_equal 0, @web.select { |page| page.content =~ /none/i }.length
end
def test_references
add_sample_pages
assert_equal 1, @web.select.pages_that_reference('EverBeenHated').length
assert_equal 0, @web.select.pages_that_reference('EverBeenInLove').length
end
def test_delete
add_sample_pages
assert_equal 2, @web.pages.length
@web.remove_pages([ @web.pages['EverBeenInLove'] ])
assert_equal 1, @web.pages.length
end
def test_make_link
add_sample_pages
existing_page_wiki_url =
'<a class="existingWikiWord" href="../show/EverBeenInLove">Ever Been In Love</a>'
existing_page_published_url =
'<a class="existingWikiWord" href="../published/EverBeenInLove">Ever Been In Love</a>'
existing_page_static_url =
'<a class="existingWikiWord" href="EverBeenInLove.html">Ever Been In Love</a>'
new_page_wiki_url =
'<span class="newWikiWord">Unknown Word<a href="../show/UnknownWord">?</a></span>'
new_page_published_url =
new_page_static_url =
'<span class="newWikiWord">Unknown Word</span>'
# no options
assert_equal existing_page_wiki_url, @web.make_link('EverBeenInLove')
# :mode => :export
assert_equal existing_page_static_url, @web.make_link('EverBeenInLove', nil, :mode => :export)
# :mode => :publish
assert_equal existing_page_published_url,
@web.make_link('EverBeenInLove', nil, :mode => :publish)
# new page, no options
assert_equal new_page_wiki_url, @web.make_link('UnknownWord')
# new page, :mode => :export
assert_equal new_page_static_url, @web.make_link('UnknownWord', nil, :mode => :export)
# new page, :mode => :publish
assert_equal new_page_published_url, @web.make_link('UnknownWord', nil, :mode => :publish)
# Escaping special characters in the name
assert_equal(
'<span class="newWikiWord">Smith &amp; Wesson<a href="../show/Smith+%26+Wesson">?</a></span>',
@web.make_link('Smith & Wesson'))
# optionally using text as the link text
assert_equal(
existing_page_published_url.sub(/>Ever Been In Love</, ">Haven't you ever been in love?<"),
@web.make_link('EverBeenInLove', "Haven't you ever been in love?", :mode => :publish))
end
def test_initialize
wiki_stub = Object.new
web = Web.new(wiki_stub, 'Wiki2', 'wiki2', '123')
assert_equal wiki_stub, web.wiki
assert_equal 'Wiki2', web.name
assert_equal 'wiki2', web.address
assert_equal '123', web.password
# new web should be set for maximum features enabled
assert_equal :textile, web.markup
assert_equal '008B26', web.color
assert !web.safe_mode
assert_equal {}, web.pages
assert web.allow_uploads
assert_equal @wiki, web.parent_wiki
assert_nil web.additional_style
assert !web.published
assert !web.brackets_only
assert !web.count_pages
assert web.allow_uploads
end
private
def add_sample_pages
@web.add_page(Page.new(@web, 'EverBeenInLove', 'Who am I me',
Time.local(2004, 4, 4, 16, 50), 'DavidHeinemeierHansson'))
@web.add_page(Page.new(@web, 'EverBeenHated', 'I am me EverBeenHated',
Time.local(2004, 4, 4, 16, 51), 'DavidHeinemeierHansson'))
end
end

View file

@ -1,116 +1,116 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'wiki_service'
require 'fileutils'
class WikiServiceTest < Test::Unit::TestCase
# Clean the test storage directory before the run
unless defined? @@storage_cleaned
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.command_log'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.snapshot'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.tex'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.zip'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.pdf'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/instiki/*'])
@@cleaned_storage = true
WikiService.instance.setup('pswd', 'Wiki', 'wiki')
end
def setup
@s = WikiService.instance
@s.create_web 'Instiki', 'instiki'
@web = @s.webs['instiki']
end
def teardown
@s.delete_web 'instiki'
end
def test_read_write_page
@s.write_page 'instiki', 'FirstPage', "Electric shocks, I love 'em",
Time.now, 'DavidHeinemeierHansson'
assert_equal "Electric shocks, I love 'em", @s.read_page('instiki', 'FirstPage').content
end
def test_read_only_operations
@s.write_page 'instiki', 'TestReadOnlyOperations', 'Read only operations dont change the' +
'state of any object, and therefore should not be logged by Madeleine!',
Time.now, 'AlexeyVerkhovsky'
assert_doesnt_change_state_or_log :authenticate, 'pswd'
assert_doesnt_change_state_or_log :read_page, 'instiki', 'TestReadOnlyOperations'
assert_doesnt_change_state_or_log :setup?
assert_doesnt_change_state_or_log :webs
@s.write_page 'instiki', 'FirstPage', "Electric shocks, I love 'em",
Time.now, 'DavidHeinemeierHansson'
assert_equal "Electric shocks, I love 'em", @s.read_page('instiki', 'FirstPage').content
end
def test_aborted_transaction
@s.write_page 'instiki', 'FirstPage', "Electric shocks, I love 'em",
10.minutes.ago, 'DavidHeinemeierHansson'
assert_doesnt_change_state('revise_page with unchanged content') {
begin
@s.revise_page 'instiki', 'FirstPage', "Electric shocks, I love 'em",
Time.now, 'DavidHeinemeierHansson'
fail 'Expected Instiki::ValidationError not raised'
rescue Instiki::ValidationError
end
}
end
def test_file_yard
file_yard = @s.file_yard(@web)
assert_equal FileYard, file_yard.class
assert_equal(@s.storage_path + '/instiki', file_yard.files_path)
end
# Checks that a method call or a block doesn;t change the persisted state of the wiki
# Usage:
# assert_doesnt_change_state :read_page, 'instiki', 'TestReadOnlyOperations'
# or
# assert_doesnt_change_state {|wiki| wiki.webs}
def assert_doesnt_change_state(method, *args, &block)
_assert_doesnt_change_state(including_command_log = false, method, *args, &block)
end
# Same as assert_doesnt_change_state, but also asserts that no vommand log is generated
def assert_doesnt_change_state_or_log(method, *args, &block)
_assert_doesnt_change_state(including_command_log = true, method, *args, &block)
end
private
def _assert_doesnt_change_state(including_log, method, *args)
WikiService.snapshot
last_snapshot_before = last_snapshot
if block_given?
yield @s
else
@s.send(method, *args)
end
if including_log
command_logs = Dir[RAILS_ROOT + 'storage/test/*.command_log']
assert command_logs.empty?, "Calls to #{method} should not be logged"
end
last_snapshot_after = last_snapshot
assert last_snapshot_before == last_snapshot_after,
'Calls to #{method} should not change the state of any persisted object'
end
def last_snapshot
snapshots = Dir[RAILS_ROOT + '/storage/test/*.snapshot']
assert !snapshots.empty?, "No snapshots found at #{RAILS_ROOT}/storage/test/"
File.read(snapshots.last)
end
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'wiki_service'
require 'fileutils'
class WikiServiceTest < Test::Unit::TestCase
# Clean the test storage directory before the run
unless defined? @@storage_cleaned
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.command_log'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.snapshot'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.tex'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.zip'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/*.pdf'])
FileUtils.rm(Dir[RAILS_ROOT + '/storage/test/instiki/*'])
@@cleaned_storage = true
WikiService.instance.setup('pswd', 'Wiki', 'wiki')
end
def setup
@s = WikiService.instance
@s.create_web 'Instiki', 'instiki'
@web = @s.webs['instiki']
end
def teardown
@s.delete_web 'instiki'
end
def test_read_write_page
@s.write_page 'instiki', 'FirstPage', "Electric shocks, I love 'em",
Time.now, 'DavidHeinemeierHansson'
assert_equal "Electric shocks, I love 'em", @s.read_page('instiki', 'FirstPage').content
end
def test_read_only_operations
@s.write_page 'instiki', 'TestReadOnlyOperations', 'Read only operations dont change the' +
'state of any object, and therefore should not be logged by Madeleine!',
Time.now, 'AlexeyVerkhovsky'
assert_doesnt_change_state_or_log :authenticate, 'pswd'
assert_doesnt_change_state_or_log :read_page, 'instiki', 'TestReadOnlyOperations'
assert_doesnt_change_state_or_log :setup?
assert_doesnt_change_state_or_log :webs
@s.write_page 'instiki', 'FirstPage', "Electric shocks, I love 'em",
Time.now, 'DavidHeinemeierHansson'
assert_equal "Electric shocks, I love 'em", @s.read_page('instiki', 'FirstPage').content
end
def test_aborted_transaction
@s.write_page 'instiki', 'FirstPage', "Electric shocks, I love 'em",
10.minutes.ago, 'DavidHeinemeierHansson'
assert_doesnt_change_state('revise_page with unchanged content') {
begin
@s.revise_page 'instiki', 'FirstPage', "Electric shocks, I love 'em",
Time.now, 'DavidHeinemeierHansson'
fail 'Expected Instiki::ValidationError not raised'
rescue Instiki::ValidationError
end
}
end
def test_file_yard
file_yard = @s.file_yard(@web)
assert_equal FileYard, file_yard.class
assert_equal(@s.storage_path + '/instiki', file_yard.files_path)
end
# Checks that a method call or a block doesn;t change the persisted state of the wiki
# Usage:
# assert_doesnt_change_state :read_page, 'instiki', 'TestReadOnlyOperations'
# or
# assert_doesnt_change_state {|wiki| wiki.webs}
def assert_doesnt_change_state(method, *args, &block)
_assert_doesnt_change_state(including_command_log = false, method, *args, &block)
end
# Same as assert_doesnt_change_state, but also asserts that no vommand log is generated
def assert_doesnt_change_state_or_log(method, *args, &block)
_assert_doesnt_change_state(including_command_log = true, method, *args, &block)
end
private
def _assert_doesnt_change_state(including_log, method, *args)
WikiService.snapshot
last_snapshot_before = last_snapshot
if block_given?
yield @s
else
@s.send(method, *args)
end
if including_log
command_logs = Dir[RAILS_ROOT + 'storage/test/*.command_log']
assert command_logs.empty?, "Calls to #{method} should not be logged"
end
last_snapshot_after = last_snapshot
assert last_snapshot_before == last_snapshot_after,
'Calls to #{method} should not change the state of any persisted object'
end
def last_snapshot
snapshots = Dir[RAILS_ROOT + '/storage/test/*.snapshot']
assert !snapshots.empty?, "No snapshots found at #{RAILS_ROOT}/storage/test/"
File.read(snapshots.last)
end
end

View file

@ -1,14 +1,14 @@
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'wiki_words'
class WikiWordsTest < Test::Unit::TestCase
def test_utf8_characters_in_wiki_word
assert_equal "Æåle Øen", WikiWords.separate("ÆåleØen")
assert_equal "ÆÅØle Øen", WikiWords.separate("ÆÅØleØen")
assert_equal "Æe ÅØle Øen", WikiWords.separate("ÆeÅØleØen")
assert_equal "Legetøj", WikiWords.separate("Legetøj")
end
end
#!/bin/env ruby -w
require File.dirname(__FILE__) + '/../test_helper'
require 'wiki_words'
class WikiWordsTest < Test::Unit::TestCase
def test_utf8_characters_in_wiki_word
assert_equal "Æåle Øen", WikiWords.separate("ÆåleØen")
assert_equal "ÆÅØle Øen", WikiWords.separate("ÆÅØleØen")
assert_equal "Æe ÅØle Øen", WikiWords.separate("ÆeÅØleØen")
assert_equal "Legetøj", WikiWords.separate("Legetøj")
end
end

View file

@ -1,99 +1,99 @@
BlueCloth
=========
Version 1.0.0 - 2004/08/24
Original version by John Gruber <http://daringfireball.net/>.
Ruby port by Michael Granger <http://www.deveiate.org/>.
BlueCloth is a Ruby implementation of [Markdown][1], a text-to-HTML conversion
tool for web writers. To quote from the project page: Markdown allows you to
write using an easy-to-read, easy-to-write plain text format, then convert it to
structurally valid XHTML (or HTML).
It borrows a naming convention and several helpings of interface from
[Redcloth][2], [Why the Lucky Stiff][3]'s processor for a similar text-to-HTML
conversion syntax called [Textile][4].
Installation
------------
You can install this module either by running the included `install.rb` script,
or by simply copying `lib/bluecloth.rb` to a directory in your load path.
Dependencies
------------
BlueCloth uses the `StringScanner` class from the `strscan` library, which comes
with Ruby 1.8.x and later or may be downloaded from the RAA for earlier
versions, and the `logger` library, which is also included in 1.8.x and later.
Example Usage
-------------
The BlueCloth class is a subclass of Ruby's String, and can be used thusly:
bc = BlueCloth::new( str )
puts bc.to_html
This `README` file is an example of Markdown syntax. The sample program
`bluecloth` in the `bin/` directory can be used to convert this (or any other)
file with Markdown syntax into HTML:
$ bin/bluecloth README > README.html
Acknowledgements
----------------
This library is a port of the canonical Perl one, and so owes most of its
functionality to its author, John Gruber. The bugs in this code are most
certainly an artifact of my porting it and not an artifact of the excellent code
from which it is derived.
It also, as mentioned before, borrows its API liberally from RedCloth, both for
compatibility's sake, and because I think Why's code is beautiful. His excellent
code and peerless prose have been an inspiration to me, and this module is
intended as the sincerest flattery.
Also contributing to any success this module may enjoy are those among my peers
who have taken the time to help out, either by submitting patches, testing, or
offering suggestions and review:
* Martin Chase <stillflame@FaerieMUD.org>
* Florian Gross <flgr@ccan.de>
Author/Legal
------------
Original version:
Copyright (c) 2003-2004 John Gruber
<http://daringfireball.net/>
All rights reserved.
Ruby version:
Copyright (c) 2004 The FaerieMUD Consortium
BlueCloth is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
BlueCloth is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
[1]: http://daringfireball.net/projects/markdown/
[2]: http://www.whytheluckystiff.net/ruby/redcloth/
[3]: http://www.whytheluckystiff.net/
[4]: http://www.textism.com/tools/textile/
$Id: README,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
$URL: svn+ssh://svn.FaerieMUD.org/usr/local/svn/BlueCloth/trunk/README $
BlueCloth
=========
Version 1.0.0 - 2004/08/24
Original version by John Gruber <http://daringfireball.net/>.
Ruby port by Michael Granger <http://www.deveiate.org/>.
BlueCloth is a Ruby implementation of [Markdown][1], a text-to-HTML conversion
tool for web writers. To quote from the project page: Markdown allows you to
write using an easy-to-read, easy-to-write plain text format, then convert it to
structurally valid XHTML (or HTML).
It borrows a naming convention and several helpings of interface from
[Redcloth][2], [Why the Lucky Stiff][3]'s processor for a similar text-to-HTML
conversion syntax called [Textile][4].
Installation
------------
You can install this module either by running the included `install.rb` script,
or by simply copying `lib/bluecloth.rb` to a directory in your load path.
Dependencies
------------
BlueCloth uses the `StringScanner` class from the `strscan` library, which comes
with Ruby 1.8.x and later or may be downloaded from the RAA for earlier
versions, and the `logger` library, which is also included in 1.8.x and later.
Example Usage
-------------
The BlueCloth class is a subclass of Ruby's String, and can be used thusly:
bc = BlueCloth::new( str )
puts bc.to_html
This `README` file is an example of Markdown syntax. The sample program
`bluecloth` in the `bin/` directory can be used to convert this (or any other)
file with Markdown syntax into HTML:
$ bin/bluecloth README > README.html
Acknowledgements
----------------
This library is a port of the canonical Perl one, and so owes most of its
functionality to its author, John Gruber. The bugs in this code are most
certainly an artifact of my porting it and not an artifact of the excellent code
from which it is derived.
It also, as mentioned before, borrows its API liberally from RedCloth, both for
compatibility's sake, and because I think Why's code is beautiful. His excellent
code and peerless prose have been an inspiration to me, and this module is
intended as the sincerest flattery.
Also contributing to any success this module may enjoy are those among my peers
who have taken the time to help out, either by submitting patches, testing, or
offering suggestions and review:
* Martin Chase <stillflame@FaerieMUD.org>
* Florian Gross <flgr@ccan.de>
Author/Legal
------------
Original version:
Copyright (c) 2003-2004 John Gruber
<http://daringfireball.net/>
All rights reserved.
Ruby version:
Copyright (c) 2004 The FaerieMUD Consortium
BlueCloth is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
BlueCloth is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
[1]: http://daringfireball.net/projects/markdown/
[2]: http://www.whytheluckystiff.net/ruby/redcloth/
[3]: http://www.whytheluckystiff.net/
[4]: http://www.textism.com/tools/textile/
$Id: README,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
$URL: svn+ssh://svn.FaerieMUD.org/usr/local/svn/BlueCloth/trunk/README $

View file

@ -1,150 +1,150 @@
#!/usr/bin/ruby
#
# BlueCloth Module Install Script
# $Id: install.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
#
# Thanks to Masatoshi SEKI for ideas found in his install.rb.
#
# Copyright (c) 2001-2004 The FaerieMUD Consortium.
#
# This is free software. You may use, modify, and/or redistribute this
# software under the terms of the Perl Artistic License. (See
# http://language.perl.com/misc/Artistic.html)
#
require './utils.rb'
include UtilityFunctions
require 'rbconfig'
include Config
require 'find'
require 'ftools'
$version = %q$Revision: 1.1 $
$rcsId = %q$Id: install.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
# Define required libraries
RequiredLibraries = [
# libraryname, nice name, RAA URL, Download URL
[ 'strscan', "StrScan",
'http://raa.ruby-lang.org/list.rhtml?name=strscan',
'http://i.loveruby.net/archive/strscan/strscan-0.6.7.tar.gz' ],
[ 'logger', "Devel-Logger",
'http://raa.ruby-lang.org/list.rhtml?name=devel-logger',
'http://rrr.jin.gr.jp/download/devel-logger-1_2_2.tar.gz' ],
]
class Installer
@@PrunePatterns = [
/CVS/,
/~$/,
%r:(^|/)\.:,
/\.tpl$/,
]
def initialize( testing=false )
@ftools = (testing) ? self : File
end
### Make the specified dirs (which can be a String or an Array of Strings)
### with the specified mode.
def makedirs( dirs, mode=0755, verbose=false )
dirs = [ dirs ] unless dirs.is_a? Array
oldumask = File::umask
File::umask( 0777 - mode )
for dir in dirs
if @ftools == File
File::mkpath( dir, $verbose )
else
$stderr.puts "Make path %s with mode %o" % [ dir, mode ]
end
end
File::umask( oldumask )
end
def install( srcfile, dstfile, mode=nil, verbose=false )
dstfile = File.catname(srcfile, dstfile)
unless FileTest.exist? dstfile and File.cmp srcfile, dstfile
$stderr.puts " install #{srcfile} -> #{dstfile}"
else
$stderr.puts " skipping #{dstfile}: unchanged"
end
end
public
def installFiles( src, dstDir, mode=0444, verbose=false )
directories = []
files = []
if File.directory?( src )
Find.find( src ) {|f|
Find.prune if @@PrunePatterns.find {|pat| f =~ pat}
next if f == src
if FileTest.directory?( f )
directories << f.gsub( /^#{src}#{File::Separator}/, '' )
next
elsif FileTest.file?( f )
files << f.gsub( /^#{src}#{File::Separator}/, '' )
else
Find.prune
end
}
else
files << File.basename( src )
src = File.dirname( src )
end
dirs = [ dstDir ]
dirs |= directories.collect {|d| File.join(dstDir,d)}
makedirs( dirs, 0755, verbose )
files.each {|f|
srcfile = File.join(src,f)
dstfile = File.dirname(File.join( dstDir,f ))
if verbose
if mode
$stderr.puts "Install #{srcfile} -> #{dstfile} (mode %o)" % mode
else
$stderr.puts "Install #{srcfile} -> #{dstfile}"
end
end
@ftools.install( srcfile, dstfile, mode, verbose )
}
end
end
if $0 == __FILE__
header "BlueCloth Installer #$version"
for lib in RequiredLibraries
testForRequiredLibrary( *lib )
end
viewOnly = ARGV.include? '-n'
verbose = ARGV.include? '-v'
debugMsg "Sitelibdir = '#{CONFIG['sitelibdir']}'"
sitelibdir = CONFIG['sitelibdir']
debugMsg "Sitearchdir = '#{CONFIG['sitearchdir']}'"
sitearchdir = CONFIG['sitearchdir']
message "Installing\n"
i = Installer.new( viewOnly )
i.installFiles( "lib", sitelibdir, 0444, verbose )
end
#!/usr/bin/ruby
#
# BlueCloth Module Install Script
# $Id: install.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
#
# Thanks to Masatoshi SEKI for ideas found in his install.rb.
#
# Copyright (c) 2001-2004 The FaerieMUD Consortium.
#
# This is free software. You may use, modify, and/or redistribute this
# software under the terms of the Perl Artistic License. (See
# http://language.perl.com/misc/Artistic.html)
#
require './utils.rb'
include UtilityFunctions
require 'rbconfig'
include Config
require 'find'
require 'ftools'
$version = %q$Revision: 1.1 $
$rcsId = %q$Id: install.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
# Define required libraries
RequiredLibraries = [
# libraryname, nice name, RAA URL, Download URL
[ 'strscan', "StrScan",
'http://raa.ruby-lang.org/list.rhtml?name=strscan',
'http://i.loveruby.net/archive/strscan/strscan-0.6.7.tar.gz' ],
[ 'logger', "Devel-Logger",
'http://raa.ruby-lang.org/list.rhtml?name=devel-logger',
'http://rrr.jin.gr.jp/download/devel-logger-1_2_2.tar.gz' ],
]
class Installer
@@PrunePatterns = [
/CVS/,
/~$/,
%r:(^|/)\.:,
/\.tpl$/,
]
def initialize( testing=false )
@ftools = (testing) ? self : File
end
### Make the specified dirs (which can be a String or an Array of Strings)
### with the specified mode.
def makedirs( dirs, mode=0755, verbose=false )
dirs = [ dirs ] unless dirs.is_a? Array
oldumask = File::umask
File::umask( 0777 - mode )
for dir in dirs
if @ftools == File
File::mkpath( dir, $verbose )
else
$stderr.puts "Make path %s with mode %o" % [ dir, mode ]
end
end
File::umask( oldumask )
end
def install( srcfile, dstfile, mode=nil, verbose=false )
dstfile = File.catname(srcfile, dstfile)
unless FileTest.exist? dstfile and File.cmp srcfile, dstfile
$stderr.puts " install #{srcfile} -> #{dstfile}"
else
$stderr.puts " skipping #{dstfile}: unchanged"
end
end
public
def installFiles( src, dstDir, mode=0444, verbose=false )
directories = []
files = []
if File.directory?( src )
Find.find( src ) {|f|
Find.prune if @@PrunePatterns.find {|pat| f =~ pat}
next if f == src
if FileTest.directory?( f )
directories << f.gsub( /^#{src}#{File::Separator}/, '' )
next
elsif FileTest.file?( f )
files << f.gsub( /^#{src}#{File::Separator}/, '' )
else
Find.prune
end
}
else
files << File.basename( src )
src = File.dirname( src )
end
dirs = [ dstDir ]
dirs |= directories.collect {|d| File.join(dstDir,d)}
makedirs( dirs, 0755, verbose )
files.each {|f|
srcfile = File.join(src,f)
dstfile = File.dirname(File.join( dstDir,f ))
if verbose
if mode
$stderr.puts "Install #{srcfile} -> #{dstfile} (mode %o)" % mode
else
$stderr.puts "Install #{srcfile} -> #{dstfile}"
end
end
@ftools.install( srcfile, dstfile, mode, verbose )
}
end
end
if $0 == __FILE__
header "BlueCloth Installer #$version"
for lib in RequiredLibraries
testForRequiredLibrary( *lib )
end
viewOnly = ARGV.include? '-n'
verbose = ARGV.include? '-v'
debugMsg "Sitelibdir = '#{CONFIG['sitelibdir']}'"
sitelibdir = CONFIG['sitelibdir']
debugMsg "Sitearchdir = '#{CONFIG['sitearchdir']}'"
sitearchdir = CONFIG['sitearchdir']
message "Installing\n"
i = Installer.new( viewOnly )
i.installFiles( "lib", sitelibdir, 0444, verbose )
end

File diff suppressed because it is too large Load diff

View file

@ -1,117 +1,117 @@
#!/usr/bin/ruby
#
# Test suite for BlueCloth classes
# $Id: test.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
#
BEGIN {
$basedir = File::dirname( __FILE__ )
["lib", "tests", "redist"].each do |subdir|
$LOAD_PATH.unshift File::join( $basedir, subdir )
end
require "#{$basedir}/utils"
include UtilityFunctions
}
verboseOff {
require 'bctestcase'
require 'find'
require 'test/unit'
require 'test/unit/testsuite'
require 'test/unit/ui/console/testrunner'
require 'optparse'
}
# Turn off output buffering
$stderr.sync = $stdout.sync = true
$DebugPattern = nil
# Initialize variables
safelevel = 0
patterns = []
requires = []
# Parse command-line switches
ARGV.options {|oparser|
oparser.banner = "Usage: #$0 [options] [TARGETS]\n"
oparser.on( "--debug[=PATTERN]", "-d[=PATTERN]", String,
"Turn debugging on (for tests which match PATTERN)" ) {|arg|
if arg
$DebugPattern = Regexp::new( arg )
puts "Turned debugging on for %p." % $DebugPattern
else
$DEBUG = true
debugMsg "Turned debugging on globally."
end
}
oparser.on( "--verbose", "-v", TrueClass, "Make progress verbose" ) {
$VERBOSE = true
debugMsg "Turned verbose on."
}
# Handle the 'help' option
oparser.on( "--help", "-h", "Display this text." ) {
$stderr.puts oparser
exit!(0)
}
oparser.parse!
}
# Parse test patterns
ARGV.each {|pat| patterns << Regexp::new( pat, Regexp::IGNORECASE )}
$stderr.puts "#{patterns.length} patterns given on the command line"
### Load all the tests from the tests dir
Find.find("#{$basedir}/tests") {|file|
Find.prune if /\/\./ =~ file or /~$/ =~ file
Find.prune if /TEMPLATE/ =~ file
next if File.stat( file ).directory?
unless patterns.empty?
Find.prune unless patterns.find {|pat| pat =~ file}
end
debugMsg "Considering '%s': " % file
next unless file =~ /\.tests.rb$/
debugMsg "Requiring '%s'..." % file
require "#{file}"
requires << file
}
$stderr.puts "Required #{requires.length} files."
unless patterns.empty?
$stderr.puts "[" + requires.sort.join( ", " ) + "]"
end
# Build the test suite
class BlueClothTests
class << self
def suite
suite = Test::Unit::TestSuite.new( "BlueCloth" )
if suite.respond_to?( :add )
ObjectSpace.each_object( Class ) {|klass|
suite.add( klass.suite ) if klass < BlueCloth::TestCase
}
else
ObjectSpace.each_object( Class ) {|klass|
suite << klass.suite if klass < BlueCloth::TestCase
}
end
return suite
end
end
end
# Run tests
$SAFE = safelevel
Test::Unit::UI::Console::TestRunner.new( BlueClothTests ).start
#!/usr/bin/ruby
#
# Test suite for BlueCloth classes
# $Id: test.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
#
BEGIN {
$basedir = File::dirname( __FILE__ )
["lib", "tests", "redist"].each do |subdir|
$LOAD_PATH.unshift File::join( $basedir, subdir )
end
require "#{$basedir}/utils"
include UtilityFunctions
}
verboseOff {
require 'bctestcase'
require 'find'
require 'test/unit'
require 'test/unit/testsuite'
require 'test/unit/ui/console/testrunner'
require 'optparse'
}
# Turn off output buffering
$stderr.sync = $stdout.sync = true
$DebugPattern = nil
# Initialize variables
safelevel = 0
patterns = []
requires = []
# Parse command-line switches
ARGV.options {|oparser|
oparser.banner = "Usage: #$0 [options] [TARGETS]\n"
oparser.on( "--debug[=PATTERN]", "-d[=PATTERN]", String,
"Turn debugging on (for tests which match PATTERN)" ) {|arg|
if arg
$DebugPattern = Regexp::new( arg )
puts "Turned debugging on for %p." % $DebugPattern
else
$DEBUG = true
debugMsg "Turned debugging on globally."
end
}
oparser.on( "--verbose", "-v", TrueClass, "Make progress verbose" ) {
$VERBOSE = true
debugMsg "Turned verbose on."
}
# Handle the 'help' option
oparser.on( "--help", "-h", "Display this text." ) {
$stderr.puts oparser
exit!(0)
}
oparser.parse!
}
# Parse test patterns
ARGV.each {|pat| patterns << Regexp::new( pat, Regexp::IGNORECASE )}
$stderr.puts "#{patterns.length} patterns given on the command line"
### Load all the tests from the tests dir
Find.find("#{$basedir}/tests") {|file|
Find.prune if /\/\./ =~ file or /~$/ =~ file
Find.prune if /TEMPLATE/ =~ file
next if File.stat( file ).directory?
unless patterns.empty?
Find.prune unless patterns.find {|pat| pat =~ file}
end
debugMsg "Considering '%s': " % file
next unless file =~ /\.tests.rb$/
debugMsg "Requiring '%s'..." % file
require "#{file}"
requires << file
}
$stderr.puts "Required #{requires.length} files."
unless patterns.empty?
$stderr.puts "[" + requires.sort.join( ", " ) + "]"
end
# Build the test suite
class BlueClothTests
class << self
def suite
suite = Test::Unit::TestSuite.new( "BlueCloth" )
if suite.respond_to?( :add )
ObjectSpace.each_object( Class ) {|klass|
suite.add( klass.suite ) if klass < BlueCloth::TestCase
}
else
ObjectSpace.each_object( Class ) {|klass|
suite << klass.suite if klass < BlueCloth::TestCase
}
end
return suite
end
end
end
# Run tests
$SAFE = safelevel
Test::Unit::UI::Console::TestRunner.new( BlueClothTests ).start

View file

@ -1,71 +1,71 @@
#!/usr/bin/ruby
#
# Unit test for the BlueCloth class object
# $Id: 00_Class.tests.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
#
# Copyright (c) 2004 The FaerieMUD Consortium.
#
if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
basedir = File::dirname( __FILE__ )
require File::join( basedir, 'bctestcase' )
end
### This test case tests ...
class BlueClothClassTestCase < BlueCloth::TestCase
TestString = "foo"
def test_00_class_constant
printTestHeader "BlueCloth: Class Constant"
assert Object::constants.include?( "BlueCloth" ),
"No BlueCloth constant in Object"
assert_instance_of Class, BlueCloth
end
def test_01_instantiation
printTestHeader "BlueCloth: Instantiation"
rval = nil
# With no argument... ("")
assert_nothing_raised {
rval = BlueCloth::new
}
assert_instance_of BlueCloth, rval
assert_kind_of String, rval
assert_equal "", rval
# String argument
assert_nothing_raised {
rval = BlueCloth::new TestString
}
assert_instance_of BlueCloth, rval
assert_kind_of String, rval
assert_equal TestString, rval
addSetupBlock {
debugMsg "Creating a new BlueCloth"
@obj = BlueCloth::new( TestString )
}
addTeardownBlock {
@obj = nil
}
end
def test_02_duplication
printTestHeader "BlueCloth: Duplication"
rval = nil
assert_nothing_raised {
rval = @obj.dup
}
assert_instance_of BlueCloth, rval
assert_kind_of String, rval
assert_equal TestString, rval
end
end
#!/usr/bin/ruby
#
# Unit test for the BlueCloth class object
# $Id: 00_Class.tests.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
#
# Copyright (c) 2004 The FaerieMUD Consortium.
#
if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
basedir = File::dirname( __FILE__ )
require File::join( basedir, 'bctestcase' )
end
### This test case tests ...
class BlueClothClassTestCase < BlueCloth::TestCase
TestString = "foo"
def test_00_class_constant
printTestHeader "BlueCloth: Class Constant"
assert Object::constants.include?( "BlueCloth" ),
"No BlueCloth constant in Object"
assert_instance_of Class, BlueCloth
end
def test_01_instantiation
printTestHeader "BlueCloth: Instantiation"
rval = nil
# With no argument... ("")
assert_nothing_raised {
rval = BlueCloth::new
}
assert_instance_of BlueCloth, rval
assert_kind_of String, rval
assert_equal "", rval
# String argument
assert_nothing_raised {
rval = BlueCloth::new TestString
}
assert_instance_of BlueCloth, rval
assert_kind_of String, rval
assert_equal TestString, rval
addSetupBlock {
debugMsg "Creating a new BlueCloth"
@obj = BlueCloth::new( TestString )
}
addTeardownBlock {
@obj = nil
}
end
def test_02_duplication
printTestHeader "BlueCloth: Duplication"
rval = nil
assert_nothing_raised {
rval = @obj.dup
}
assert_instance_of BlueCloth, rval
assert_kind_of String, rval
assert_equal TestString, rval
end
end

File diff suppressed because it is too large Load diff

View file

@ -1,57 +1,57 @@
#!/usr/bin/ruby
#
# Unit test for bugs found in BlueCloth
# $Id: 10_Bug.tests.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
#
# Copyright (c) 2004 The FaerieMUD Consortium.
#
if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
basedir = File::dirname( __FILE__ )
require File::join( basedir, 'bctestcase' )
end
require 'timeout'
### This test case tests ...
class BugsTestCase < BlueCloth::TestCase
BaseDir = File::dirname( File::dirname(File::expand_path( __FILE__ )) )
### Test to be sure the README file can be transformed.
def test_00_slow_block_regex
contents = File::read( File::join(BaseDir,"README") )
bcobj = BlueCloth::new( contents )
assert_nothing_raised {
timeout( 2 ) do
bcobj.to_html
end
}
end
### :TODO: Add more documents and test their transforms.
def test_10_regexp_engine_overflow_bug
contents = File::read( File::join(BaseDir,"tests/data/re-overflow.txt") )
bcobj = BlueCloth::new( contents )
assert_nothing_raised {
bcobj.to_html
}
end
def test_15_regexp_engine_overflow_bug2
contents = File::read( File::join(BaseDir,"tests/data/re-overflow2.txt") )
bcobj = BlueCloth::new( contents )
assert_nothing_raised {
bcobj.to_html
}
end
end
__END__
#!/usr/bin/ruby
#
# Unit test for bugs found in BlueCloth
# $Id: 10_Bug.tests.rb,v 1.1 2005/01/07 23:01:51 alexeyv Exp $
#
# Copyright (c) 2004 The FaerieMUD Consortium.
#
if !defined?( BlueCloth ) || !defined?( BlueCloth::TestCase )
basedir = File::dirname( __FILE__ )
require File::join( basedir, 'bctestcase' )
end
require 'timeout'
### This test case tests ...
class BugsTestCase < BlueCloth::TestCase
BaseDir = File::dirname( File::dirname(File::expand_path( __FILE__ )) )
### Test to be sure the README file can be transformed.
def test_00_slow_block_regex
contents = File::read( File::join(BaseDir,"README") )
bcobj = BlueCloth::new( contents )
assert_nothing_raised {
timeout( 2 ) do
bcobj.to_html
end
}
end
### :TODO: Add more documents and test their transforms.
def test_10_regexp_engine_overflow_bug
contents = File::read( File::join(BaseDir,"tests/data/re-overflow.txt") )
bcobj = BlueCloth::new( contents )
assert_nothing_raised {
bcobj.to_html
}
end
def test_15_regexp_engine_overflow_bug2
contents = File::read( File::join(BaseDir,"tests/data/re-overflow2.txt") )
bcobj = BlueCloth::new( contents )
assert_nothing_raised {
bcobj.to_html
}
end
end
__END__

Some files were not shown because too many files have changed in this diff Show more