Autolink URLs like http://localhost:8000 (anything that has a schema like http:// and looks like a URL), in addition to internet URLs.
This commit is contained in:
parent
b74244ee3f
commit
dce2af06aa
|
@ -19,8 +19,7 @@ class URIChunk < Chunk::Abstract
|
||||||
include URI::REGEXP::PATTERN
|
include URI::REGEXP::PATTERN
|
||||||
|
|
||||||
# this condition is to get rid of pesky warnings in tests
|
# this condition is to get rid of pesky warnings in tests
|
||||||
unless defined? URI_CHUNK_CONSTANTS_DEFINED
|
unless defined? URIChunk::INTERNET_URI_REGEXP
|
||||||
URI_CHUNK_CONSTANTS_DEFINED = true
|
|
||||||
|
|
||||||
GENERIC = '(?:aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org)'
|
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)'
|
COUNTRY = '(?:au|at|be|ca|ch|de|dk|fr|hk|in|ir|it|jp|nl|no|pt|ru|se|sw|tv|tw|uk|us)'
|
||||||
|
@ -45,27 +44,28 @@ class URIChunk < Chunk::Abstract
|
||||||
FRAGMENT = "#{URIC_NO_ENDING}*"
|
FRAGMENT = "#{URIC_NO_ENDING}*"
|
||||||
|
|
||||||
# DOMLABEL is defined in the ruby uri library, TLDS is defined above
|
# DOMLABEL is defined in the ruby uri library, TLDS is defined above
|
||||||
FULL_HOSTNAME = "(?:#{DOMLABEL}\\.)+#{TLDS}"
|
INTERNET_HOSTNAME = "(?:#{DOMLABEL}\\.)+#{TLDS}"
|
||||||
|
|
||||||
# Correct a typo bug in ruby 1.8.x lib/uri/common.rb
|
# Correct a typo bug in ruby 1.8.x lib/uri/common.rb
|
||||||
PORT = '\\d*'
|
PORT = '\\d*'
|
||||||
|
|
||||||
URI_PATTERN =
|
INTERNET_URI =
|
||||||
"(?:(#{SCHEME}):/{0,2})?" + # Optional scheme: (\1)
|
"(?:(#{SCHEME}):/{0,2})?" + # Optional scheme: (\1)
|
||||||
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
|
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
|
||||||
"(#{FULL_HOSTNAME})" + # Mandatory hostname (\3)
|
"(#{INTERNET_HOSTNAME})" + # Mandatory hostname (\3)
|
||||||
"(?::(#{PORT}))?" + # Optional :port (\4)
|
"(?::(#{PORT}))?" + # Optional :port (\4)
|
||||||
"(#{ABS_PATH})?" + # Optional absolute path (\5)
|
"(#{ABS_PATH})?" + # Optional absolute path (\5)
|
||||||
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
|
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
|
||||||
"(?:\\#(#{FRAGMENT}))?" # Optional #fragment (\7)
|
"(?:\\#(#{FRAGMENT}))?" # Optional #fragment (\7)
|
||||||
|
|
||||||
|
TEXTILE_SYNTAX_PREFIX = '(!)?'
|
||||||
|
|
||||||
|
INTERNET_URI_REGEXP = Regexp.new(TEXTILE_SYNTAX_PREFIX + INTERNET_URI, Regexp::EXTENDED, 'N')
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
TEXTILE_SYNTAX_PREFIX = '(!)?'
|
|
||||||
|
|
||||||
URI_PATTERN_REGEXP = Regexp.new(TEXTILE_SYNTAX_PREFIX + URI_PATTERN, Regexp::EXTENDED, 'N')
|
|
||||||
|
|
||||||
def self.pattern
|
def self.pattern
|
||||||
URI_PATTERN_REGEXP
|
INTERNET_URI_REGEXP
|
||||||
end
|
end
|
||||||
|
|
||||||
attr_reader :uri, :scheme, :user, :host, :port, :path, :query, :fragment, :link_text
|
attr_reader :uri, :scheme, :user, :host, :port, :path, :query, :fragment, :link_text
|
||||||
|
@ -149,3 +149,31 @@ class URIChunk < Chunk::Abstract
|
||||||
end
|
end
|
||||||
|
|
||||||
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 self.pattern
|
||||||
|
LOCAL_URI_REGEXP
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -39,7 +39,9 @@ require 'chunks/nowiki'
|
||||||
# UPDATED: 22nd May 2004
|
# UPDATED: 22nd May 2004
|
||||||
class WikiContent < String
|
class WikiContent < String
|
||||||
|
|
||||||
PRE_ENGINE_ACTIONS = [ NoWiki, Category, Include, URIChunk, WikiChunk::Link, WikiChunk::Word ]
|
PRE_ENGINE_ACTIONS = [ NoWiki, Category, Include,
|
||||||
|
URIChunk, LocalURIChunk,
|
||||||
|
WikiChunk::Link, WikiChunk::Word ]
|
||||||
POST_ENGINE_ACTIONS = [ Literal::Pre, Literal::Tags ]
|
POST_ENGINE_ACTIONS = [ Literal::Pre, Literal::Tags ]
|
||||||
DEFAULT_OPTS = {
|
DEFAULT_OPTS = {
|
||||||
:pre_engine_actions => PRE_ENGINE_ACTIONS,
|
:pre_engine_actions => PRE_ENGINE_ACTIONS,
|
||||||
|
|
|
@ -36,37 +36,32 @@ end
|
||||||
# This module is to be included in unit tests that involve matching chunks.
|
# 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
|
# 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.
|
# 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
|
module ChunkMatch
|
||||||
|
|
||||||
# Asserts a number of tests for the given type and text.
|
# Asserts a number of tests for the given type and text.
|
||||||
def match(type, test_text, expected)
|
def match(chunk_type, test_text, expected_chunk_state)
|
||||||
pattern = type.pattern
|
if chunk_type.respond_to? :pattern
|
||||||
assert_match(pattern, test_text)
|
assert_match(chunk_type.pattern, test_text)
|
||||||
pattern =~ test_text # Previous assertion guarantees match
|
end
|
||||||
chunk = type.new($~)
|
|
||||||
|
content = ContentStub.new(test_text)
|
||||||
|
chunk_type.apply_to(content)
|
||||||
|
|
||||||
# Test if requested parts are correct.
|
# Test if requested parts are correct.
|
||||||
for method_sym, value in expected do
|
expected_chunk_state.each_pair do |a_method, expected_value|
|
||||||
assert_respond_to(chunk, method_sym)
|
assert content.chunks.last.kind_of?(chunk_type)
|
||||||
assert_equal(value, chunk.method(method_sym).call, "Checking value of '#{method_sym}'")
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
module ActionController
|
|
||||||
class TestResponse
|
|
||||||
def binary_content
|
|
||||||
sio = StringIO.new
|
|
||||||
begin
|
|
||||||
$stdout = sio
|
|
||||||
body.call
|
|
||||||
ensure
|
|
||||||
$stdout = STDOUT
|
|
||||||
end
|
|
||||||
|
|
||||||
sio.rewind
|
|
||||||
sio.read
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
|
@ -7,8 +7,9 @@ class URITest < Test::Unit::TestCase
|
||||||
include ChunkMatch
|
include ChunkMatch
|
||||||
|
|
||||||
def test_non_matches
|
def test_non_matches
|
||||||
assert_no_match(URIChunk.pattern, 'There is no URI here')
|
assert_conversion_does_not_apply(URIChunk, 'There is no URI here')
|
||||||
assert_no_match(URIChunk.pattern, 'One gemstone is the garnet:reddish in colour, like ruby')
|
assert_conversion_does_not_apply(URIChunk,
|
||||||
|
'One gemstone is the garnet:reddish in colour, like ruby')
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_simple_uri
|
def test_simple_uri
|
||||||
|
@ -110,9 +111,9 @@ class URITest < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_non_uri
|
def test_non_uri
|
||||||
assert_no_match(URIChunk.pattern, 'httpd.conf')
|
assert_conversion_does_not_apply URIChunk, 'httpd.conf'
|
||||||
assert_no_match(URIChunk.pattern, 'libproxy.so')
|
assert_conversion_does_not_apply URIChunk, 'libproxy.so'
|
||||||
assert_no_match(URIChunk.pattern, 'ld.so.conf')
|
assert_conversion_does_not_apply URIChunk, 'ld.so.conf'
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_uri_in_text
|
def test_uri_in_text
|
||||||
|
@ -152,4 +153,27 @@ class URITest < Test::Unit::TestCase
|
||||||
:query => 'arg=val,')
|
:query => 'arg=val,')
|
||||||
end
|
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
|
end
|
||||||
|
|
Loading…
Reference in a new issue