twitter-text 1.4.8 → 1.4.9
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.lock +1 -27
- data/README.rdoc +1 -0
- data/lib/autolink.rb +55 -47
- data/lib/extractor.rb +36 -2
- data/lib/regex.rb +49 -24
- data/lib/rewriter.rb +63 -0
- data/lib/twitter-text.rb +7 -4
- data/lib/validation.rb +5 -5
- data/spec/autolinking_spec.rb +41 -3
- data/spec/extractor_spec.rb +2 -2
- data/spec/rewriter_spec.rb +558 -0
- data/spec/spec_helper.rb +10 -4
- data/test/conformance_test.rb +18 -5
- data/twitter-text.gemspec +6 -4
- metadata +12 -7
data/lib/twitter-text.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
major, minor, patch = RUBY_VERSION.split('.')
|
2
2
|
|
3
|
-
if major.to_i == 1 && minor.to_i < 9
|
3
|
+
$RUBY_1_9 = if major.to_i == 1 && minor.to_i < 9
|
4
4
|
# Ruby 1.8 KCODE check. Not needed on 1.9 and later.
|
5
5
|
raise("twitter-text requires the $KCODE variable be set to 'UTF8' or 'u'") unless $KCODE[0].chr =~ /u/i
|
6
|
+
false
|
7
|
+
else
|
8
|
+
true
|
6
9
|
end
|
7
10
|
|
8
|
-
|
9
|
-
require '
|
10
|
-
require 'action_view'
|
11
|
+
require 'active_support'
|
12
|
+
require 'active_support/core_ext/string/multibyte.rb'
|
11
13
|
|
12
14
|
require File.join(File.dirname(__FILE__), 'regex')
|
15
|
+
require File.join(File.dirname(__FILE__), 'rewriter')
|
13
16
|
require File.join(File.dirname(__FILE__), 'autolink')
|
14
17
|
require File.join(File.dirname(__FILE__), 'extractor')
|
15
18
|
require File.join(File.dirname(__FILE__), 'unicode')
|
data/lib/validation.rb
CHANGED
@@ -35,7 +35,7 @@ module Twitter
|
|
35
35
|
# <tt>:empty</tt>:: if the <tt>text</tt> is nil or empty
|
36
36
|
# <tt>:invalid_characters</tt>:: if the <tt>text</tt> contains non-Unicode or any of the disallowed Unicode characters
|
37
37
|
def tweet_invalid?(text)
|
38
|
-
return :empty if text.
|
38
|
+
return :empty if !text || text.empty?
|
39
39
|
begin
|
40
40
|
return :too_long if tweet_length(text) > MAX_LENGTH
|
41
41
|
return :invalid_characters if INVALID_CHARACTERS.any?{|invalid_char| text.include?(invalid_char) }
|
@@ -52,7 +52,7 @@ module Twitter
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def valid_username?(username)
|
55
|
-
return false if username.
|
55
|
+
return false if !username || username.empty?
|
56
56
|
|
57
57
|
extracted = Twitter::Extractor.extract_mentioned_screen_names(username)
|
58
58
|
# Should extract the username minus the @ sign, hence the [1..-1]
|
@@ -63,11 +63,11 @@ module Twitter
|
|
63
63
|
def valid_list?(username_list)
|
64
64
|
match = username_list.match(VALID_LIST_RE)
|
65
65
|
# Must have matched and had nothing before or after
|
66
|
-
!!(match && match[1] == "" && !match[4].
|
66
|
+
!!(match && match[1] == "" && match[4] && !match[4].empty?)
|
67
67
|
end
|
68
68
|
|
69
69
|
def valid_hashtag?(hashtag)
|
70
|
-
return false if hashtag.
|
70
|
+
return false if !hashtag || hashtag.empty?
|
71
71
|
|
72
72
|
extracted = Twitter::Extractor.extract_hashtags(hashtag)
|
73
73
|
# Should extract the hashtag minus the # sign, hence the [1..-1]
|
@@ -75,7 +75,7 @@ module Twitter
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def valid_url?(url, unicode_domains=true)
|
78
|
-
return false if url.
|
78
|
+
return false if !url || url.empty?
|
79
79
|
|
80
80
|
url_parts = url.match(Twitter::Regex[:validate_url_unencoded])
|
81
81
|
return false unless (url_parts && url_parts.to_s == url)
|
data/spec/autolinking_spec.rb
CHANGED
@@ -36,7 +36,7 @@ describe Twitter::Autolink do
|
|
36
36
|
def original_text; "meet@the beach"; end
|
37
37
|
|
38
38
|
it "should not be linked" do
|
39
|
-
Nokogiri::HTML(@autolinked_text).search('a').should
|
39
|
+
Nokogiri::HTML(@autolinked_text).search('a').should be_empty
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
@@ -133,7 +133,7 @@ describe Twitter::Autolink do
|
|
133
133
|
def original_text; "hello @/my-list"; end
|
134
134
|
|
135
135
|
it "should NOT be linked" do
|
136
|
-
Nokogiri::HTML(@autolinked_text).search('a').should
|
136
|
+
Nokogiri::HTML(@autolinked_text).search('a').should be_empty
|
137
137
|
end
|
138
138
|
end
|
139
139
|
|
@@ -149,7 +149,7 @@ describe Twitter::Autolink do
|
|
149
149
|
def original_text; "meet@the/beach"; end
|
150
150
|
|
151
151
|
it "should not be linked" do
|
152
|
-
Nokogiri::HTML(@autolinked_text).search('a').should
|
152
|
+
Nokogiri::HTML(@autolinked_text).search('a').should be_empty
|
153
153
|
end
|
154
154
|
end
|
155
155
|
|
@@ -505,6 +505,24 @@ describe Twitter::Autolink do
|
|
505
505
|
end
|
506
506
|
end
|
507
507
|
|
508
|
+
context "regex engine quirks" do
|
509
|
+
context "does not spiral out of control on repeated periods" do
|
510
|
+
def original_text; "Test a ton of periods http://example.com/path.........................................."; end
|
511
|
+
|
512
|
+
it "should autolink" do
|
513
|
+
@autolinked_text.should have_autolinked_url('http://example.com/path')
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
context "does not spiral out of control on repeated dashes" do
|
518
|
+
def original_text; "Single char file ext http://www.bestbuy.com/site/Currie+Technologies+-+Ezip+400+Scooter/9885188.p?id=1218189013070&skuId=9885188"; end
|
519
|
+
|
520
|
+
it "should autolink" do
|
521
|
+
@autolinked_text.should have_autolinked_url('http://www.bestbuy.com/site/Currie+Technologies+-+Ezip+400+Scooter/9885188.p?id=1218189013070&skuId=9885188')
|
522
|
+
end
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
508
526
|
end
|
509
527
|
|
510
528
|
describe "Autolink all" do
|
@@ -558,6 +576,26 @@ describe Twitter::Autolink do
|
|
558
576
|
linked.should have_autolinked_url('http://example.com/')
|
559
577
|
linked.should match(/target="mywindow"/)
|
560
578
|
end
|
579
|
+
|
580
|
+
it "should customize href by username_url_block option" do
|
581
|
+
linked = TestAutolink.new.auto_link("@test", :username_url_block => lambda{|a| "dummy"})
|
582
|
+
linked.should have_autolinked_url('dummy', 'test')
|
583
|
+
end
|
584
|
+
|
585
|
+
it "should customize href by list_url_block option" do
|
586
|
+
linked = TestAutolink.new.auto_link("@test/list", :list_url_block => lambda{|a| "dummy"})
|
587
|
+
linked.should have_autolinked_url('dummy', 'test/list')
|
588
|
+
end
|
589
|
+
|
590
|
+
it "should customize href by hashtag_url_block option" do
|
591
|
+
linked = TestAutolink.new.auto_link("#hashtag", :hashtag_url_block => lambda{|a| "dummy"})
|
592
|
+
linked.should have_autolinked_url('dummy', '#hashtag')
|
593
|
+
end
|
594
|
+
|
595
|
+
it "should customize href by link_url_block option" do
|
596
|
+
linked = TestAutolink.new.auto_link("http://example.com/", :link_url_block => lambda{|a| "dummy"})
|
597
|
+
linked.should have_autolinked_url('dummy', 'http://example.com/')
|
598
|
+
end
|
561
599
|
end
|
562
600
|
|
563
601
|
describe "html_escape" do
|
data/spec/extractor_spec.rb
CHANGED
@@ -228,11 +228,11 @@ describe Twitter::Extractor do
|
|
228
228
|
end
|
229
229
|
|
230
230
|
it "should not allow the multiplication character" do
|
231
|
-
@extractor.extract_hashtags("#pre#{
|
231
|
+
@extractor.extract_hashtags("#pre#{Twitter::Unicode::U00D7}post").should == []
|
232
232
|
end
|
233
233
|
|
234
234
|
it "should not allow the division character" do
|
235
|
-
@extractor.extract_hashtags("#pre#{
|
235
|
+
@extractor.extract_hashtags("#pre#{Twitter::Unicode::U00F7}post").should == []
|
236
236
|
end
|
237
237
|
end
|
238
238
|
|
@@ -0,0 +1,558 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Twitter::Rewriter do
|
6
|
+
def original_text; end
|
7
|
+
def url; end
|
8
|
+
|
9
|
+
def block(*args)
|
10
|
+
if Array === @block_args
|
11
|
+
unless Array === @block_args.first
|
12
|
+
@block_args = [@block_args]
|
13
|
+
end
|
14
|
+
@block_args << args
|
15
|
+
else
|
16
|
+
@block_args = args
|
17
|
+
end
|
18
|
+
"[rewritten]"
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "rewrite usernames" do #{{{
|
22
|
+
before do
|
23
|
+
@rewritten_text = Twitter::Rewriter.rewrite_usernames_or_lists(original_text, &method(:block))
|
24
|
+
end
|
25
|
+
|
26
|
+
context "username preceded by a space" do
|
27
|
+
def original_text; "hello @jacob"; end
|
28
|
+
|
29
|
+
it "should be rewritten" do
|
30
|
+
@block_args.should == ["@", "jacob", nil]
|
31
|
+
@rewritten_text.should == "hello [rewritten]"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "username at beginning of line" do
|
36
|
+
def original_text; "@jacob you're cool"; end
|
37
|
+
|
38
|
+
it "should be rewritten" do
|
39
|
+
@block_args.should == ["@", "jacob", nil]
|
40
|
+
@rewritten_text.should == "[rewritten] you're cool"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "username preceded by word character" do
|
45
|
+
def original_text; "meet@the beach"; end
|
46
|
+
|
47
|
+
it "should not be rewritten" do
|
48
|
+
@block_args.should be_nil
|
49
|
+
@rewritten_text.should == "meet@the beach"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "username preceded by non-word character" do
|
54
|
+
def original_text; "great.@jacob"; end
|
55
|
+
|
56
|
+
it "should be rewritten" do
|
57
|
+
@block_args.should == ["@", "jacob", nil]
|
58
|
+
@rewritten_text.should == "great.[rewritten]"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "username containing non-word characters" do
|
63
|
+
def original_text; "@jacob&^$%^"; end
|
64
|
+
|
65
|
+
it "should be rewritten" do
|
66
|
+
@block_args.should == ["@", "jacob", nil]
|
67
|
+
@rewritten_text.should == "[rewritten]&^$%^"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "username over twenty characters" do
|
72
|
+
def original_text
|
73
|
+
@twenty_character_username = "zach" * 5
|
74
|
+
"@" + @twenty_character_username + "1"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should be rewritten" do
|
78
|
+
@block_args.should == ["@", @twenty_character_username, nil]
|
79
|
+
@rewritten_text.should == "[rewritten]1"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context "username followed by japanese" do
|
84
|
+
def original_text; "@jacobの"; end
|
85
|
+
|
86
|
+
it "should be rewritten" do
|
87
|
+
@block_args.should == ["@", "jacob", nil]
|
88
|
+
@rewritten_text.should == "[rewritten]の"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context "username preceded by japanese" do
|
93
|
+
def original_text; "あ@jacob"; end
|
94
|
+
|
95
|
+
it "should be rewritten" do
|
96
|
+
@block_args.should == ["@", "jacob", nil]
|
97
|
+
@rewritten_text.should == "あ[rewritten]"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "username surrounded by japanese" do
|
102
|
+
def original_text; "あ@jacobの"; end
|
103
|
+
|
104
|
+
it "should be rewritten" do
|
105
|
+
@block_args.should == ["@", "jacob", nil]
|
106
|
+
@rewritten_text.should == "あ[rewritten]の"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "username using full-width at-sign" do
|
111
|
+
def original_text
|
112
|
+
"#{[0xFF20].pack('U')}jacob"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should be rewritten" do
|
116
|
+
@block_args.should == ["@", "jacob", nil]
|
117
|
+
@rewritten_text.should == "[rewritten]"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end #}}}
|
121
|
+
|
122
|
+
describe "rewrite lists" do #{{{
|
123
|
+
before do
|
124
|
+
@rewritten_text = Twitter::Rewriter.rewrite_usernames_or_lists(original_text, &method(:block))
|
125
|
+
end
|
126
|
+
|
127
|
+
context "slug preceded by a space" do
|
128
|
+
def original_text; "hello @jacob/my-list"; end
|
129
|
+
|
130
|
+
it "should be rewritten" do
|
131
|
+
@block_args.should == ["@", "jacob", "/my-list"]
|
132
|
+
@rewritten_text.should == "hello [rewritten]"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context "username followed by a slash but no list" do
|
137
|
+
def original_text; "hello @jacob/ my-list"; end
|
138
|
+
|
139
|
+
it "should not be rewritten" do
|
140
|
+
@block_args.should == ["@", "jacob", nil]
|
141
|
+
@rewritten_text.should == "hello [rewritten]/ my-list"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "empty username followed by a list" do
|
146
|
+
def original_text; "hello @/my-list"; end
|
147
|
+
|
148
|
+
it "should not be rewritten" do
|
149
|
+
@block_args.should be_nil
|
150
|
+
@rewritten_text.should == "hello @/my-list"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context "list slug at beginning of line" do
|
155
|
+
def original_text; "@jacob/my-list"; end
|
156
|
+
|
157
|
+
it "should be rewritten" do
|
158
|
+
@block_args.should == ["@", "jacob", "/my-list"]
|
159
|
+
@rewritten_text.should == "[rewritten]"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "username preceded by alpha-numeric character" do
|
164
|
+
def original_text; "meet@jacob/my-list"; end
|
165
|
+
|
166
|
+
it "should not be rewritten" do
|
167
|
+
@block_args.should be_nil
|
168
|
+
@rewritten_text.should == "meet@jacob/my-list"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "username preceded by non-word character" do
|
173
|
+
def original_text; "great.@jacob/my-list"; end
|
174
|
+
|
175
|
+
it "should be rewritten" do
|
176
|
+
@block_args.should == ["@", "jacob", "/my-list"]
|
177
|
+
@rewritten_text.should == "great.[rewritten]"
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
context "username containing non-word characters" do
|
182
|
+
def original_text; "@jacob/my-list&^$%^"; end
|
183
|
+
|
184
|
+
it "should be rewritten" do
|
185
|
+
@block_args.should == ["@", "jacob", "/my-list"]
|
186
|
+
@rewritten_text.should == "[rewritten]&^$%^"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context "username over twenty characters" do
|
191
|
+
def original_text
|
192
|
+
@twentyfive_character_list = "a" * 25
|
193
|
+
"@jacob/#{@twentyfive_character_list}12345"
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should be rewritten" do
|
197
|
+
@block_args.should == ["@", "jacob", "/#{@twentyfive_character_list}"]
|
198
|
+
@rewritten_text.should == "[rewritten]12345"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end #}}}
|
202
|
+
|
203
|
+
describe "rewrite hashtags" do #{{{
|
204
|
+
before do
|
205
|
+
@rewritten_text = Twitter::Rewriter.rewrite_hashtags(original_text, &method(:block))
|
206
|
+
end
|
207
|
+
|
208
|
+
context "with an all numeric hashtag" do
|
209
|
+
def original_text; "#123"; end
|
210
|
+
|
211
|
+
it "should not be rewritten" do
|
212
|
+
@block_args.should be_nil
|
213
|
+
@rewritten_text.should == "#123"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
context "with a hashtag with alphanumeric characters" do
|
218
|
+
def original_text; "#ab1d"; end
|
219
|
+
|
220
|
+
it "should be rewritten" do
|
221
|
+
@block_args.should == ["#", "ab1d"]
|
222
|
+
@rewritten_text.should == "[rewritten]"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
context "with a hashtag with underscores" do
|
227
|
+
def original_text; "#a_b_c_d"; end
|
228
|
+
|
229
|
+
it "should be rewritten" do
|
230
|
+
@block_args.should == ["#", "a_b_c_d"]
|
231
|
+
@rewritten_text.should == "[rewritten]"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context "with a hashtag that is preceded by a word character" do
|
236
|
+
def original_text; "ab#cd"; end
|
237
|
+
|
238
|
+
it "should not be rewritten" do
|
239
|
+
@block_args.should be_nil
|
240
|
+
@rewritten_text.should == "ab#cd"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context "with a page anchor in a url" do
|
245
|
+
def original_text; "Here's my url: http://foobar.com/#home"; end
|
246
|
+
|
247
|
+
it "should not link the hashtag" do
|
248
|
+
@block_args.should be_nil
|
249
|
+
@rewritten_text.should == "Here's my url: http://foobar.com/#home"
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
context "with a hashtag that starts with a number but has word characters" do
|
254
|
+
def original_text; "#2ab"; end
|
255
|
+
|
256
|
+
it "should be rewritten" do
|
257
|
+
@block_args.should == ["#", "2ab"]
|
258
|
+
@rewritten_text.should == "[rewritten]"
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
context "with multiple valid hashtags" do
|
263
|
+
def original_text; "I'm frickin' awesome #ab #cd #ef"; end
|
264
|
+
|
265
|
+
it "rewrites each hashtag" do
|
266
|
+
@block_args.should == [["#", "ab"], ["#", "cd"], ["#", "ef"]]
|
267
|
+
@rewritten_text.should == "I'm frickin' awesome [rewritten] [rewritten] [rewritten]"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
context "with a hashtag preceded by a ." do
|
272
|
+
def original_text; "ok, great.#abc"; end
|
273
|
+
|
274
|
+
it "should be rewritten" do
|
275
|
+
@block_args.should == ["#", "abc"]
|
276
|
+
@rewritten_text.should == "ok, great.[rewritten]"
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context "with a hashtag preceded by a &" do
|
281
|
+
def original_text; "&#nbsp;"; end
|
282
|
+
|
283
|
+
it "should not be rewritten" do
|
284
|
+
@block_args.should be_nil
|
285
|
+
@rewritten_text.should == "&#nbsp;"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
context "with a hashtag that ends in an !" do
|
290
|
+
def original_text; "#great!"; end
|
291
|
+
|
292
|
+
it "should be rewritten, but should not include the !" do
|
293
|
+
@block_args.should == ["#", "great"];
|
294
|
+
@rewritten_text.should == "[rewritten]!"
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context "with a hashtag followed by Japanese" do
|
299
|
+
def original_text; "#twj_devの"; end
|
300
|
+
|
301
|
+
it "should be rewritten" do
|
302
|
+
@block_args.should == ["#", "twj_devの"];
|
303
|
+
@rewritten_text.should == "[rewritten]"
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
context "with a hashtag preceded by a full-width space" do
|
308
|
+
def original_text; "#{[0x3000].pack('U')}#twj_dev"; end
|
309
|
+
|
310
|
+
it "should be rewritten" do
|
311
|
+
@block_args.should == ["#", "twj_dev"];
|
312
|
+
@rewritten_text.should == " [rewritten]"
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
context "with a hashtag followed by a full-width space" do
|
317
|
+
def original_text; "#twj_dev#{[0x3000].pack('U')}"; end
|
318
|
+
|
319
|
+
it "should be rewritten" do
|
320
|
+
@block_args.should == ["#", "twj_dev"];
|
321
|
+
@rewritten_text.should == "[rewritten] "
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
context "with a hashtag using full-width hash" do
|
326
|
+
def original_text; "#{[0xFF03].pack('U')}twj_dev"; end
|
327
|
+
|
328
|
+
it "should be rewritten" do
|
329
|
+
@block_args.should == ["#", "twj_dev"];
|
330
|
+
@rewritten_text.should == "[rewritten]"
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
context "with a hashtag containing an accented latin character" do
|
335
|
+
def original_text
|
336
|
+
# the hashtag is #éhashtag
|
337
|
+
"##{[0x00e9].pack('U')}hashtag"
|
338
|
+
end
|
339
|
+
|
340
|
+
it "should be rewritten" do
|
341
|
+
@block_args.should == ["#", "éhashtag"];
|
342
|
+
@rewritten_text.should == "[rewritten]"
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end #}}}
|
346
|
+
|
347
|
+
describe "rewrite urls" do #{{{
|
348
|
+
def url; "http://www.google.com"; end
|
349
|
+
|
350
|
+
before do
|
351
|
+
@rewritten_text = Twitter::Rewriter.rewrite_urls(original_text, &method(:block))
|
352
|
+
end
|
353
|
+
|
354
|
+
context "when embedded in plain text" do
|
355
|
+
def original_text; "On my search engine #{url} I found good links."; end
|
356
|
+
|
357
|
+
it "should be rewritten" do
|
358
|
+
@block_args.should == [url];
|
359
|
+
@rewritten_text.should == "On my search engine [rewritten] I found good links."
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
context "when surrounded by Japanese;" do
|
364
|
+
def original_text; "いまなにしてる#{url}いまなにしてる"; end
|
365
|
+
|
366
|
+
it "should be rewritten" do
|
367
|
+
@block_args.should == [url];
|
368
|
+
@rewritten_text.should == "いまなにしてる[rewritten]いまなにしてる"
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
context "with a path surrounded by parentheses;" do
|
373
|
+
def original_text; "I found a neatness (#{url})"; end
|
374
|
+
|
375
|
+
it "should be rewritten" do
|
376
|
+
@block_args.should == [url];
|
377
|
+
@rewritten_text.should == "I found a neatness ([rewritten])"
|
378
|
+
end
|
379
|
+
|
380
|
+
context "when the URL ends with a slash;" do
|
381
|
+
def url; "http://www.google.com/"; end
|
382
|
+
|
383
|
+
it "should be rewritten" do
|
384
|
+
@block_args.should == [url];
|
385
|
+
@rewritten_text.should == "I found a neatness ([rewritten])"
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
context "when the URL has a path;" do
|
390
|
+
def url; "http://www.google.com/fsdfasdf"; end
|
391
|
+
|
392
|
+
it "should be rewritten" do
|
393
|
+
@block_args.should == [url];
|
394
|
+
@rewritten_text.should == "I found a neatness ([rewritten])"
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
context "when path contains parens" do
|
400
|
+
def original_text; "I found a neatness (#{url})"; end
|
401
|
+
|
402
|
+
it "should be rewritten" do
|
403
|
+
@block_args.should == [url];
|
404
|
+
@rewritten_text.should == "I found a neatness ([rewritten])"
|
405
|
+
end
|
406
|
+
|
407
|
+
context "wikipedia" do
|
408
|
+
def url; "http://en.wikipedia.org/wiki/Madonna_(artist)"; end
|
409
|
+
|
410
|
+
it "should be rewritten" do
|
411
|
+
@block_args.should == [url];
|
412
|
+
@rewritten_text.should == "I found a neatness ([rewritten])"
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
context "IIS session" do
|
417
|
+
def url; "http://msdn.com/S(deadbeef)/page.htm"; end
|
418
|
+
|
419
|
+
it "should be rewritten" do
|
420
|
+
@block_args.should == [url];
|
421
|
+
@rewritten_text.should == "I found a neatness ([rewritten])"
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
context "unbalanced parens" do
|
426
|
+
def url; "http://example.com/i_has_a_("; end
|
427
|
+
|
428
|
+
it "should be rewritten" do
|
429
|
+
@block_args.should == ["http://example.com/i_has_a_"];
|
430
|
+
@rewritten_text.should == "I found a neatness ([rewritten]()"
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
context "balanced parens with a double quote inside" do
|
435
|
+
def url; "http://foo.bar/foo_(\")_bar" end
|
436
|
+
|
437
|
+
it "should be rewritten" do
|
438
|
+
@block_args.should == ["http://foo.bar/foo_"];
|
439
|
+
@rewritten_text.should == "I found a neatness ([rewritten](\")_bar)"
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
context "balanced parens hiding XSS" do
|
444
|
+
def url; 'http://x.xx/("style="color:red"onmouseover="alert(1)' end
|
445
|
+
|
446
|
+
it "should be rewritten" do
|
447
|
+
@block_args.should == ["http://x.xx/"];
|
448
|
+
@rewritten_text.should == 'I found a neatness ([rewritten]("style="color:red"onmouseover="alert(1))'
|
449
|
+
end
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
context "when preceded by a :" do
|
454
|
+
def original_text; "Check this out @hoverbird:#{url}"; end
|
455
|
+
|
456
|
+
it "should be rewritten" do
|
457
|
+
@block_args.should == [url];
|
458
|
+
@rewritten_text.should == "Check this out @hoverbird:[rewritten]"
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
context "with a URL ending in allowed punctuation" do
|
463
|
+
it "does not consume ending punctuation" do
|
464
|
+
%w| ? ! , . : ; ] ) } = \ ' |.each do |char|
|
465
|
+
Twitter::Rewriter.rewrite_urls("#{url}#{char}") do |url|
|
466
|
+
url.should == url; "[rewritten]"
|
467
|
+
end.should == "[rewritten]#{char}"
|
468
|
+
end
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
context "with a URL preceded in forbidden characters" do
|
473
|
+
it "should not be rewritten" do
|
474
|
+
%w| \ ' / ! = |.each do |char|
|
475
|
+
Twitter::Rewriter.rewrite_urls("#{char}#{url}") do |url|
|
476
|
+
"[rewritten]" # should not be called here.
|
477
|
+
end.should == "#{char}#{url}"
|
478
|
+
end
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
context "when embedded in a link tag" do
|
483
|
+
def original_text; "<link rel='true'>#{url}</link>"; end
|
484
|
+
|
485
|
+
it "should be rewritten" do
|
486
|
+
@block_args.should == [url];
|
487
|
+
@rewritten_text.should == "<link rel='true'>[rewritten]</link>"
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
context "with multiple URLs" do
|
492
|
+
def original_text; "http://www.links.org link at start of page, link at end http://www.foo.org"; end
|
493
|
+
|
494
|
+
it "should autolink each one" do
|
495
|
+
@block_args.should == [["http://www.links.org"], ["http://www.foo.org"]];
|
496
|
+
@rewritten_text.should == "[rewritten] link at start of page, link at end [rewritten]"
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
context "with multiple URLs in different formats" do
|
501
|
+
def original_text; "http://foo.com https://bar.com http://mail.foobar.org"; end
|
502
|
+
|
503
|
+
it "should autolink each one, in the proper order" do
|
504
|
+
@block_args.should == [["http://foo.com"], ["https://bar.com"], ["http://mail.foobar.org"]];
|
505
|
+
@rewritten_text.should == "[rewritten] [rewritten] [rewritten]"
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
context "with a URL having a long TLD" do
|
510
|
+
def original_text; "Yahoo integriert Facebook http://golem.mobi/0912/71607.html"; end
|
511
|
+
|
512
|
+
it "should autolink it" do
|
513
|
+
@block_args.should == ["http://golem.mobi/0912/71607.html"]
|
514
|
+
@rewritten_text.should == "Yahoo integriert Facebook [rewritten]"
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
context "with a url lacking the protocol" do
|
519
|
+
def original_text; "I like www.foobar.com dudes"; end
|
520
|
+
|
521
|
+
it "does not link at all" do
|
522
|
+
@block_args.should be_nil
|
523
|
+
@rewritten_text.should == "I like www.foobar.com dudes"
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
context "with a @ in a URL" do
|
528
|
+
context "with XSS attack" do
|
529
|
+
def original_text; 'http://x.xx/@"style="color:pink"onmouseover=alert(1)//'; end
|
530
|
+
|
531
|
+
it "should not allow XSS follwing @" do
|
532
|
+
@block_args.should == ["http://x.xx/"]
|
533
|
+
@rewritten_text.should == '[rewritten]@"style="color:pink"onmouseover=alert(1)//'
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
context "with a username not followed by a /" do
|
538
|
+
def original_text; "http://example.com/@foobar"; end
|
539
|
+
|
540
|
+
it "should link small url and username" do
|
541
|
+
@block_args.should == ["http://example.com/"]
|
542
|
+
@rewritten_text.should == "[rewritten]@foobar"
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
context "with a username followed by a /" do
|
547
|
+
def original_text; "http://example.com/@foobar/"; end
|
548
|
+
|
549
|
+
it "should not link the username but link full url" do
|
550
|
+
@block_args.should == ["http://example.com/@foobar/"]
|
551
|
+
@rewritten_text.should == "[rewritten]"
|
552
|
+
end
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end #}}}
|
556
|
+
end
|
557
|
+
|
558
|
+
# vim: foldmethod=marker
|