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

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