rails_autolink 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +3 -3
- data/README.rdoc +12 -4
- data/Rakefile +1 -1
- data/lib/rails_autolink.rb +137 -129
- data/test/test_rails_autolink.rb +27 -11
- metadata +7 -6
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -8,9 +8,11 @@ This is an extraction of the `auto_link` method from rails. The `auto_link`
|
|
8
8
|
method was removed from Rails in version Rails 3.1. This gem is meant to
|
9
9
|
bridge the gap for people migrating.
|
10
10
|
|
11
|
-
== FEATURES
|
11
|
+
== FEATURES:
|
12
12
|
|
13
|
-
|
13
|
+
By default auto_link returns sanitized html_safe strings.
|
14
|
+
This behaviour can be overriden setting the <tt>:sanitize</tt> option to false
|
15
|
+
(thus making it insecure if you don't have the content under control).
|
14
16
|
|
15
17
|
== SYNOPSIS:
|
16
18
|
|
@@ -27,6 +29,12 @@ bridge the gap for people migrating.
|
|
27
29
|
auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
|
28
30
|
# => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
29
31
|
|
32
|
+
auto_link("Go to http://www.rubyonrails.org <script>Malicious code!</script>")
|
33
|
+
# => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> "
|
34
|
+
|
35
|
+
auto_link("Go to http://www.rubyonrails.org <script>alert('Script!')</script>", :sanitize => false)
|
36
|
+
# => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> <script>alert('Script!')</script>"
|
37
|
+
|
30
38
|
post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
|
31
39
|
auto_link(post_body, :html => { :target => '_blank' }) do |text|
|
32
40
|
truncate(text, :length => 15)
|
@@ -35,11 +43,11 @@ bridge the gap for people migrating.
|
|
35
43
|
|
36
44
|
== REQUIREMENTS:
|
37
45
|
|
38
|
-
* rails
|
46
|
+
* rails >= 3.1
|
39
47
|
|
40
48
|
== INSTALL:
|
41
49
|
|
42
|
-
* gem install
|
50
|
+
* gem install rails_autolink
|
43
51
|
|
44
52
|
== LICENSE:
|
45
53
|
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ Hoe.spec 'rails_autolink' do
|
|
13
13
|
self.readme_file = 'README.rdoc'
|
14
14
|
self.history_file = 'CHANGELOG.rdoc'
|
15
15
|
self.extra_rdoc_files = FileList['*.rdoc']
|
16
|
-
self.extra_deps << ['rails', '~> 3.1.0']
|
16
|
+
self.extra_deps << ['rails', '~> 3.1.0.a']
|
17
17
|
end
|
18
18
|
|
19
19
|
# vim: syntax=ruby
|
data/lib/rails_autolink.rb
CHANGED
@@ -1,141 +1,149 @@
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
2
|
-
require 'active_support/core_ext/array/extract_options'
|
3
|
-
require 'active_support/core_ext/hash/reverse_merge'
|
4
|
-
require 'active_support/core_ext/hash/keys'
|
5
|
-
|
6
1
|
module RailsAutolink
|
7
|
-
VERSION = '1.0.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
# regexps for determining context, used high-volume
|
75
|
-
AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
|
76
|
-
|
77
|
-
AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
|
78
|
-
|
79
|
-
BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
|
80
|
-
|
81
|
-
# Turns all urls into clickable links. If a block is given, each url
|
82
|
-
# is yielded and the result is used as the link text.
|
83
|
-
def auto_link_urls(text, html_options = {}, options = {})
|
84
|
-
link_attributes = html_options.stringify_keys
|
85
|
-
text.gsub(AUTO_LINK_RE) do
|
86
|
-
scheme, href = $1, $&
|
87
|
-
punctuation = []
|
88
|
-
|
89
|
-
if auto_linked?($`, $')
|
90
|
-
# do not change string; URL is already linked
|
91
|
-
href
|
92
|
-
else
|
93
|
-
# don't include trailing punctuation character as part of the URL
|
94
|
-
while href.sub!(/[^\w\/-]$/, '')
|
95
|
-
punctuation.push $&
|
96
|
-
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
|
97
|
-
href << punctuation.pop
|
98
|
-
break
|
2
|
+
VERSION = '1.0.1'
|
3
|
+
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
initializer 'nested_form' do |app|
|
6
|
+
ActiveSupport.on_load(:action_view) do
|
7
|
+
require 'active_support/core_ext/object/blank'
|
8
|
+
require 'active_support/core_ext/array/extract_options'
|
9
|
+
require 'active_support/core_ext/hash/reverse_merge'
|
10
|
+
require 'active_support/core_ext/hash/keys'
|
11
|
+
|
12
|
+
module ::ActionView
|
13
|
+
module Helpers # :nodoc:
|
14
|
+
module TextHelper
|
15
|
+
# Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
|
16
|
+
# will limit what should be linked. You can add HTML attributes to the links using
|
17
|
+
# <tt>:html</tt>. Possible values for <tt>:link</tt> are <tt>:all</tt> (default),
|
18
|
+
# <tt>:email_addresses</tt>, and <tt>:urls</tt>. If a block is given, each URL and
|
19
|
+
# e-mail address is yielded and the result is used as the link text. By default the
|
20
|
+
# text given is sanitized, you can override this behaviour setting the
|
21
|
+
# <tt>:sanitize</tt> option to false.
|
22
|
+
#
|
23
|
+
# ==== Examples
|
24
|
+
# auto_link("Go to http://www.rubyonrails.org and say hello to david@loudthinking.com")
|
25
|
+
# # => "Go to <a href=\"http://www.rubyonrails.org\">http://www.rubyonrails.org</a> and
|
26
|
+
# # say hello to <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
27
|
+
#
|
28
|
+
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :urls)
|
29
|
+
# # => "Visit <a href=\"http://www.loudthinking.com/\">http://www.loudthinking.com/</a>
|
30
|
+
# # or e-mail david@loudthinking.com"
|
31
|
+
#
|
32
|
+
# auto_link("Visit http://www.loudthinking.com/ or e-mail david@loudthinking.com", :link => :email_addresses)
|
33
|
+
# # => "Visit http://www.loudthinking.com/ or e-mail <a href=\"mailto:david@loudthinking.com\">david@loudthinking.com</a>"
|
34
|
+
#
|
35
|
+
# post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
|
36
|
+
# auto_link(post_body, :html => { :target => '_blank' }) do |text|
|
37
|
+
# truncate(text, :length => 15)
|
38
|
+
# end
|
39
|
+
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.m...</a>.
|
40
|
+
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
41
|
+
#
|
42
|
+
#
|
43
|
+
# You can still use <tt>auto_link</tt> with the old API that accepts the
|
44
|
+
# +link+ as its optional second parameter and the +html_options+ hash
|
45
|
+
# as its optional third parameter:
|
46
|
+
# post_body = "Welcome to my new blog at http://www.myblog.com/. Please e-mail me at me@email.com."
|
47
|
+
# auto_link(post_body, :urls)
|
48
|
+
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\">http://www.myblog.com</a>.
|
49
|
+
# Please e-mail me at me@email.com."
|
50
|
+
#
|
51
|
+
# auto_link(post_body, :all, :target => "_blank")
|
52
|
+
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
|
53
|
+
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
|
54
|
+
def auto_link(text, *args, &block)#link = :all, html = {}, &block)
|
55
|
+
return ''.html_safe if text.blank?
|
56
|
+
|
57
|
+
options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
|
58
|
+
unless args.empty?
|
59
|
+
options[:link] = args[0] || :all
|
60
|
+
options[:html] = args[1] || {}
|
61
|
+
end
|
62
|
+
options.reverse_merge!(:link => :all, :html => {})
|
63
|
+
text = sanitize(text) unless options[:sanitize] == false
|
64
|
+
case options[:link].to_sym
|
65
|
+
when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block)
|
66
|
+
when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
|
67
|
+
when :urls then auto_link_urls(text, options[:html], options, &block)
|
99
68
|
end
|
100
69
|
end
|
101
70
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
71
|
+
private
|
72
|
+
|
73
|
+
AUTO_LINK_RE = %r{
|
74
|
+
(?: ([0-9A-Za-z+.:-]+:)// | www\. )
|
75
|
+
[^\s<]+
|
76
|
+
}x
|
77
|
+
|
78
|
+
# regexps for determining context, used high-volume
|
79
|
+
AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
|
80
|
+
|
81
|
+
AUTO_EMAIL_RE = /[\w.!#\$%+-]+@[\w-]+(?:\.[\w-]+)+/
|
82
|
+
|
83
|
+
BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
|
84
|
+
|
85
|
+
# Turns all urls into clickable links. If a block is given, each url
|
86
|
+
# is yielded and the result is used as the link text.
|
87
|
+
def auto_link_urls(text, html_options = {}, options = {})
|
88
|
+
link_attributes = html_options.stringify_keys
|
89
|
+
text.gsub(AUTO_LINK_RE) do
|
90
|
+
scheme, href = $1, $&
|
91
|
+
punctuation = []
|
92
|
+
|
93
|
+
if auto_linked?($`, $')
|
94
|
+
# do not change string; URL is already linked
|
95
|
+
href
|
96
|
+
else
|
97
|
+
# don't include trailing punctuation character as part of the URL
|
98
|
+
while href.sub!(/[^\w\/-]$/, '')
|
99
|
+
punctuation.push $&
|
100
|
+
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
|
101
|
+
href << punctuation.pop
|
102
|
+
break
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
link_text = block_given?? yield(href) : href
|
107
|
+
href = 'http://' + href unless scheme
|
108
|
+
|
109
|
+
unless options[:sanitize] == false
|
110
|
+
link_text = sanitize(link_text)
|
111
|
+
href = sanitize(href)
|
112
|
+
end
|
113
|
+
content_tag(:a, link_text, link_attributes.merge('href' => href), !!options[:sanitize]) + punctuation.reverse.join('')
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
119
117
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
118
|
+
# Turns all email addresses into clickable links. If a block is given,
|
119
|
+
# each email is yielded and the result is used as the link text.
|
120
|
+
def auto_link_email_addresses(text, html_options = {}, options = {})
|
121
|
+
text.gsub(AUTO_EMAIL_RE) do
|
122
|
+
text = $&
|
123
|
+
|
124
|
+
if auto_linked?($`, $')
|
125
|
+
text.html_safe
|
126
|
+
else
|
127
|
+
display_text = (block_given?) ? yield(text) : text
|
128
|
+
|
129
|
+
unless options[:sanitize] == false
|
130
|
+
text = sanitize(text)
|
131
|
+
display_text = sanitize(display_text) unless text == display_text
|
132
|
+
end
|
133
|
+
mail_to text, display_text, html_options
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
124
137
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
138
|
+
# Detects already linked context or position in the middle of a tag
|
139
|
+
def auto_linked?(left, right)
|
140
|
+
(left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
|
141
|
+
(left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
|
142
|
+
end
|
130
143
|
end
|
131
144
|
end
|
132
145
|
end
|
133
|
-
|
134
|
-
# Detects already linked context or position in the middle of a tag
|
135
|
-
def auto_linked?(left, right)
|
136
|
-
(left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
|
137
|
-
(left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
|
138
|
-
end
|
146
|
+
end
|
139
147
|
end
|
140
148
|
end
|
141
149
|
end
|
data/test/test_rails_autolink.rb
CHANGED
@@ -84,12 +84,17 @@ class TestRailsAutolink < MiniTest::Unit::TestCase
|
|
84
84
|
|
85
85
|
def test_auto_link_should_sanitize_input_when_sanitize_option_is_not_false
|
86
86
|
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
|
87
|
-
|
87
|
+
malicious_script = '<script>alert("malicious!")</script>'
|
88
|
+
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a>}, auto_link("#{link_raw}#{malicious_script}")
|
89
|
+
assert auto_link("#{link_raw}#{malicious_script}").html_safe?
|
88
90
|
end
|
89
91
|
|
90
92
|
def test_auto_link_should_not_sanitize_input_when_sanitize_option_is_false
|
91
93
|
link_raw = %{http://www.rubyonrails.com?id=1&num=2}
|
92
|
-
|
94
|
+
malicious_script = '<script>alert("malicious!")</script>'
|
95
|
+
|
96
|
+
assert_equal %{<a href="http://www.rubyonrails.com?id=1&num=2">http://www.rubyonrails.com?id=1&num=2</a><script>alert("malicious!")</script>}, auto_link("#{link_raw}#{malicious_script}", :sanitize => false)
|
97
|
+
assert !auto_link("#{link_raw}#{malicious_script}", :sanitize => false).html_safe?
|
93
98
|
end
|
94
99
|
|
95
100
|
def test_auto_link_other_protocols
|
@@ -114,7 +119,7 @@ class TestRailsAutolink < MiniTest::Unit::TestCase
|
|
114
119
|
linked5 = %('<a href="#close">close</a> <a href="http://www.example.com"><b>www.example.com</b></a>')
|
115
120
|
assert_equal linked1, auto_link(linked1)
|
116
121
|
assert_equal linked2, auto_link(linked2)
|
117
|
-
assert_equal linked3, auto_link(linked3)
|
122
|
+
assert_equal linked3, auto_link(linked3, :sanitize => false)
|
118
123
|
assert_equal linked4, auto_link(linked4)
|
119
124
|
assert_equal linked5, auto_link(linked5)
|
120
125
|
|
@@ -130,14 +135,25 @@ class TestRailsAutolink < MiniTest::Unit::TestCase
|
|
130
135
|
assert_equal %(<p><a href="#{url1}">#{url1}</a><br /><a href="#{url2}">#{url2}</a><br /></p>), auto_link("<p>#{url1}<br />#{url2}<br /></p>")
|
131
136
|
end
|
132
137
|
|
133
|
-
def
|
134
|
-
email_raw
|
135
|
-
link_raw
|
136
|
-
|
137
|
-
|
138
|
-
assert
|
139
|
-
assert
|
140
|
-
assert
|
138
|
+
def test_auto_link_should_be_html_safe
|
139
|
+
email_raw = 'santiago@wyeworks.com'
|
140
|
+
link_raw = 'http://www.rubyonrails.org'
|
141
|
+
malicious_script = '<script>alert("malicious!")</script>'
|
142
|
+
|
143
|
+
assert auto_link(nil).html_safe?, 'should be html safe'
|
144
|
+
assert auto_link('').html_safe?, 'should be html safe'
|
145
|
+
assert auto_link("#{link_raw} #{link_raw} #{link_raw}").html_safe?, 'should be html safe'
|
146
|
+
assert auto_link("hello #{email_raw}").html_safe?, 'should be html safe'
|
147
|
+
assert auto_link("hello #{email_raw} #{malicious_script}").html_safe?, 'should be html safe'
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_auto_link_should_not_be_html_safe_when_sanitize_option_false
|
151
|
+
email_raw = 'santiago@wyeworks.com'
|
152
|
+
link_raw = 'http://www.rubyonrails.org'
|
153
|
+
|
154
|
+
assert !auto_link("hello", :sanitize => false).html_safe?, 'should not be html safe'
|
155
|
+
assert !auto_link("#{link_raw} #{link_raw} #{link_raw}", :sanitize => false).html_safe?, 'should not be html safe'
|
156
|
+
assert !auto_link("hello #{email_raw}", :sanitize => false).html_safe?, 'should not be html safe'
|
141
157
|
end
|
142
158
|
|
143
159
|
def test_auto_link_email_address
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_autolink
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 1.0.
|
9
|
+
- 1
|
10
|
+
version: 1.0.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Aaron Patterson
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-06 00:00:00 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: rails
|
@@ -25,12 +25,13 @@ dependencies:
|
|
25
25
|
requirements:
|
26
26
|
- - ~>
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
hash:
|
28
|
+
hash: 18
|
29
29
|
segments:
|
30
30
|
- 3
|
31
31
|
- 1
|
32
32
|
- 0
|
33
|
-
|
33
|
+
- a
|
34
|
+
version: 3.1.0.a
|
34
35
|
type: :runtime
|
35
36
|
version_requirements: *id001
|
36
37
|
- !ruby/object:Gem::Dependency
|