diff --git a/app/models/chunks/wiki.rb b/app/models/chunks/wiki.rb index aa834d6b..978c3b1e 100755 --- a/app/models/chunks/wiki.rb +++ b/app/models/chunks/wiki.rb @@ -3,14 +3,31 @@ require 'chunks/chunk' require 'chunks/wiki' require 'cgi' -# Contains all the methods for finding and replacing wiki related -# links. +# 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 + + 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 @@ -31,6 +48,7 @@ module WikiChunk content.page_link(page_name, $1) end end + end # This chunk matches a WikiWord. WikiWords can be escaped @@ -39,9 +57,9 @@ module WikiChunk # 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") + WIKI_WORD = Regexp.new('(":)?(\\\\)?(' + WikiWords::WIKI_WORD_PATTERN + ')\b', 0, "utf-8") end - + def self.pattern WIKI_WORD end @@ -50,8 +68,7 @@ module WikiChunk def initialize(match_data) super(match_data) - @escape = match_data[1] - @page_name = match_data[2] + @textile_link_suffix, @escape, @page_name = match_data[1..3] end def escaped_text() (@escape.nil? ? nil : page_name) end @@ -69,25 +86,41 @@ module WikiChunk # a WikiWords can be a substring of a WikiLink. class Link < WikiLink - WIKI_LINK = /\[\[([^\]]+)\]\]/ unless defined? WIKI_LINK - ALIASED_LINK_PATTERN = - Regexp.new('^(.*)?\|(.*)$', 0, 'utf-8') unless defined? ALIASED_LINK_PATTERN - + 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 - attr_reader :page_name, :link_text + + attr_reader :page_name, :link_text, :link_type def initialize(match_data) super(match_data) - # If the like is aliased, set the page name to the first bit - # and the link text to the second, otherwise set both to the - # contents of the double brackets. - if match_data[1] =~ ALIASED_LINK_PATTERN - @page_name, @link_text = $1, $2 - else - @page_name, @link_text = match_data[1], match_data[1] + @textile_link_suffix, @page_name = match_data[1..2] + + # defaults + @link_type = 'show' + @link_text = @page_name + + # if link wihin the brackets has a form of [[filename:file]] or [[filename:pic]], + # this means a link to a picture or a file + 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 + + # link text may be different from page name. this will look like [[actual page|link text]] + 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 diff --git a/test/unit/chunks/wiki_test.rb b/test/unit/chunks/wiki_test.rb index 8b435c83..600d9350 100755 --- a/test/unit/chunks/wiki_test.rb +++ b/test/unit/chunks/wiki_test.rb @@ -2,9 +2,15 @@ require File.dirname(__FILE__) + '/../../test_helper' require 'chunks/wiki' -require 'chunks/match' class WikiTest < Test::Unit::TestCase + + class ContentStub < String + def chunks + @chunks ||= [] + end + end + include ChunkMatch def test_simple @@ -30,7 +36,46 @@ class WikiTest < Test::Unit::TestCase end def test_textile_link - assert_no_match(WikiChunk::Word.pattern, '"Here is a special link":SpecialLink') + 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 +