twitter-text 1.2.4 → 1.2.5

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/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ pkg/*
5
+ coverage
6
+ doc
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "test/twitter-text-conformance"]
2
+ path = test/twitter-text-conformance
3
+ url = git://github.com/mzsanford/twitter-text-conformance.git
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=nested
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify the gem's dependencies in twitter-text.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,64 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ twitter-text (1.2.5)
5
+ actionpack
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ abstract (1.0.0)
11
+ actionpack (3.0.1)
12
+ activemodel (= 3.0.1)
13
+ activesupport (= 3.0.1)
14
+ builder (~> 2.1.2)
15
+ erubis (~> 2.6.6)
16
+ i18n (~> 0.4.1)
17
+ rack (~> 1.2.1)
18
+ rack-mount (~> 0.6.12)
19
+ rack-test (~> 0.5.4)
20
+ tzinfo (~> 0.3.23)
21
+ activemodel (3.0.1)
22
+ activesupport (= 3.0.1)
23
+ builder (~> 2.1.2)
24
+ i18n (~> 0.4.1)
25
+ activesupport (3.0.1)
26
+ builder (2.1.2)
27
+ diff-lcs (1.1.2)
28
+ erubis (2.6.6)
29
+ abstract (>= 1.0.0)
30
+ i18n (0.4.2)
31
+ nokogiri (1.4.3.1)
32
+ nokogiri (1.4.3.1-java)
33
+ weakling (>= 0.0.3)
34
+ rack (1.2.1)
35
+ rack-mount (0.6.13)
36
+ rack (>= 1.0.0)
37
+ rack-test (0.5.6)
38
+ rack (>= 1.0)
39
+ rake (0.8.7)
40
+ rspec (2.1.0)
41
+ rspec-core (~> 2.1.0)
42
+ rspec-expectations (~> 2.1.0)
43
+ rspec-mocks (~> 2.1.0)
44
+ rspec-core (2.1.0)
45
+ rspec-expectations (2.1.0)
46
+ diff-lcs (~> 1.1.2)
47
+ rspec-mocks (2.1.0)
48
+ simplecov (0.3.7)
49
+ simplecov-html (>= 0.3.7)
50
+ simplecov-html (0.3.9)
51
+ tzinfo (0.3.23)
52
+ weakling (0.0.4-java)
53
+
54
+ PLATFORMS
55
+ java
56
+ ruby
57
+
58
+ DEPENDENCIES
59
+ actionpack
60
+ nokogiri
61
+ rake
62
+ rspec
63
+ simplecov
64
+ twitter-text!
data/Rakefile CHANGED
@@ -1,50 +1,13 @@
1
- require 'rubygems' unless ENV['NO_RUBYGEMS']
2
- require 'rake/gempackagetask'
3
- require 'rake/rdoctask'
4
- require 'rubygems/specification'
5
- require 'date'
6
-
7
- gem 'rspec'
8
- require 'spec/rake/spectask'
9
- require 'spec/rake/verify_rcov'
10
- require 'digest'
11
-
12
- spec = Gem::Specification.new do |s|
13
- s.name = "twitter-text"
14
- s.version = "1.2.4"
15
- s.authors = ["Matt Sanford", "Patrick Ewing", "Ben Cherry", "Britt Selvitelle", "Raffi Krikorian"]
16
- s.email = ["matt@twitter.com", "patrick.henry.ewing@gmail.com", "bcherry@gmail.com", "bs@brittspace.com", "raffi@twitter.com"]
17
- s.homepage = "http://twitter.com"
18
- s.description = s.summary = "A gem that provides text handling for Twitter"
19
-
20
- s.platform = Gem::Platform::RUBY
21
- s.has_rdoc = true
22
- s.summary = "Twitter text handling library"
23
-
24
- s.add_dependency "actionpack"
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
25
3
 
26
- s.require_path = 'lib'
27
- s.autorequire = ''
28
- s.files = %w(LICENSE README.rdoc Rakefile TODO) + Dir.glob("{lib,spec}/**/*")
29
- end
30
-
31
- task :default => :spec
32
-
33
- desc "Run specs"
34
- Spec::Rake::SpecTask.new do |t|
35
- t.spec_files = FileList['spec/**/*_spec.rb']
36
- t.spec_opts = %w(-fs --color)
37
- t.libs << ["spec", '.']
38
- end
4
+ task :default => ["spec", "test:conformance"]
39
5
 
40
- desc "Run all examples with RCov"
41
- Spec::Rake::SpecTask.new('spec:rcov') do |t|
42
- t.spec_files = FileList['spec/**/*.rb']
43
- t.rcov = true
44
- t.rcov_opts = ['--exclude', 'spec']
45
- end
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new(:spec)
46
8
 
47
9
  def conformance_version(dir)
10
+ require 'digest'
48
11
  Dir[File.join(dir, '*')].inject(Digest::SHA1.new){|digest, file| digest.update(Digest::SHA1.file(file).hexdigest) }
49
12
  end
50
13
 
@@ -85,6 +48,7 @@ namespace :test do
85
48
  end
86
49
  end
87
50
 
51
+ require 'rake/rdoctask'
88
52
  namespace :doc do
89
53
  Rake::RDocTask.new do |rd|
90
54
  rd.main = "README.rdoc"
@@ -93,22 +57,6 @@ namespace :doc do
93
57
  end
94
58
  end
95
59
 
96
- Rake::GemPackageTask.new(spec) do |pkg|
97
- pkg.gem_spec = spec
98
- end
99
-
100
- desc "install the gem locally"
101
- task :install => [:package] do
102
- sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
103
- end
104
-
105
- desc "create a gemspec file"
106
- task :make_spec do
107
- File.open("#{GEM}.gemspec", "w") do |file|
108
- file.puts spec.to_ruby
109
- end
110
- end
111
-
112
- desc "runs cruise control build"
60
+ desc "Run cruise control build"
113
61
  task :cruise => [:spec, 'test:conformance'] do
114
62
  end
data/lib/autolink.rb CHANGED
@@ -1,4 +1,3 @@
1
-
2
1
  module Twitter
3
2
  # A module for including Tweet auto-linking in a class. The primary use of this is for helpers/views so they can auto-link
4
3
  # usernames, lists, hashtags and URLs.
@@ -140,10 +139,17 @@ module Twitter
140
139
 
141
140
  text.gsub(Twitter::Regex[:valid_url]) do
142
141
  all, before, url, protocol, domain, path, query_string = $1, $2, $3, $4, $5, $6, $7
143
- if !protocol.blank? || domain =~ Twitter::Regex[:probable_tld]
142
+ if !protocol.blank? # || domain =~ Twitter::Regex[:probable_tld_domain]
144
143
  html_attrs = tag_options(options.stringify_keys) || ""
145
144
  full_url = ((protocol =~ Twitter::Regex[:www] || protocol.blank?) ? "http://#{url}" : url)
146
145
  "#{before}<a href=\"#{html_escape(full_url)}\"#{html_attrs}>#{html_escape(url)}</a>"
146
+ elsif all =~ Twitter::Regex[:probable_tld_domain]
147
+ before_tld, tld_domain = $1, $2
148
+
149
+ html_attrs = tag_options(options.stringify_keys) || ""
150
+ full_url = "http://#{tld_domain}"
151
+ prefix = (before_tld == before ? before : "#{before}#{before_tld}")
152
+ "#{prefix}<a href=\"#{html_escape(full_url)}\"#{html_attrs}>#{html_escape(tld_domain)}</a>"
147
153
  else
148
154
  all
149
155
  end
@@ -151,4 +157,4 @@ module Twitter
151
157
  end
152
158
 
153
159
  end
154
- end
160
+ end
data/lib/extractor.rb CHANGED
@@ -20,18 +20,23 @@ class String
20
20
  char_array
21
21
  end
22
22
  end
23
+ end
23
24
 
24
- # Helper function to find the index of the <tt>sub_string</tt> in
25
- # <tt>str</tt>. This is needed because with unicode strings, the return
26
- # of index may be incorrect.
27
- def sub_string_search(sub_str, position = 0)
28
- if respond_to? :codepoints
29
- index(sub_str, position)
25
+ # Helper functions to return character offsets instead of byte offsets.
26
+ class MatchData
27
+ def char_begin(n)
28
+ if string.respond_to? :codepoints
29
+ self.begin(n)
30
30
  else
31
- index = to_char_a[position..-1].each_with_index.find do |e|
32
- to_char_a.slice(e.last + position, sub_str.char_length).map{|ci| ci.first }.join == sub_str
33
- end
34
- index.nil? ? -1 : index.last + position
31
+ string[0, self.begin(n)].char_length
32
+ end
33
+ end
34
+
35
+ def char_end(n)
36
+ if string.respond_to? :codepoints
37
+ self.end(n)
38
+ else
39
+ string[0, self.end(n)].char_length
35
40
  end
36
41
  end
37
42
  end
@@ -63,14 +68,14 @@ module Twitter
63
68
  return [] unless text
64
69
 
65
70
  possible_screen_names = []
66
- position = 0
67
71
  text.to_s.scan(Twitter::Regex[:extract_mentions]) do |before, sn, after|
72
+ extract_mentions_match_data = $~
68
73
  unless after =~ Twitter::Regex[:end_screen_name_match]
69
- start_position = text.to_s.sub_string_search(sn, position) - 1
70
- position = start_position + sn.char_length + 1
74
+ start_position = extract_mentions_match_data.char_begin(2) - 1
75
+ end_position = extract_mentions_match_data.char_end(2)
71
76
  possible_screen_names << {
72
77
  :screen_name => sn,
73
- :indices => [start_position, position]
78
+ :indices => [start_position, end_position]
74
79
  }
75
80
  end
76
81
  end
@@ -117,14 +122,22 @@ module Twitter
117
122
  urls = []
118
123
  position = 0
119
124
  text.to_s.scan(Twitter::Regex[:valid_url]) do |all, before, url, protocol, domain, path, query|
120
- if !protocol.blank? || domain =~ Twitter::Regex[:probable_tld]
121
- start_position = text.to_s.sub_string_search(url, position)
122
- end_position = start_position + url.char_length
123
- position = end_position
125
+ valid_url_match_data = $~
126
+ if !protocol.blank?
127
+ start_position = valid_url_match_data.char_begin(3)
128
+ end_position = valid_url_match_data.char_end(3)
124
129
  urls << {
125
130
  :url => ((protocol =~ Twitter::Regex[:www] || protocol.blank?) ? "http://#{url}" : url),
126
131
  :indices => [start_position, end_position]
127
132
  }
133
+ elsif all =~ Twitter::Regex[:probable_tld_domain]
134
+ tld_domain = $2
135
+ start_position = valid_url_match_data.char_begin(1) + $~.char_begin(2)
136
+ end_position = valid_url_match_data.char_begin(1) + $~.char_end(2)
137
+ urls << {
138
+ :url => "http://#{tld_domain}",
139
+ :indices => [start_position, end_position]
140
+ }
128
141
  end
129
142
  end
130
143
  urls.each{|url| yield url[:url], url[:indices].first, url[:indices].last } if block_given?
@@ -153,13 +166,12 @@ module Twitter
153
166
  return [] unless text
154
167
 
155
168
  tags = []
156
- position = 0
157
169
  text.scan(Twitter::Regex[:auto_link_hashtags]) do |before, hash, hash_text|
158
- start_position = text.to_s.sub_string_search(hash + hash_text, position)
159
- position = start_position + hash_text.char_length + 1
170
+ start_position = $~.char_begin(2)
171
+ end_position = $~.char_end(3)
160
172
  tags << {
161
173
  :hashtag => hash_text,
162
- :indices => [start_position, position]
174
+ :indices => [start_position, end_position]
163
175
  }
164
176
  end
165
177
  tags.each{|tag| yield tag[:hashtag], tag[:indices].first, tag[:indices].last } if block_given?
@@ -1,4 +1,3 @@
1
-
2
1
  module Twitter
3
2
  # Module for doing "hit highlighting" on tweets that have been auto-linked already.
4
3
  # Useful with the results returned from the Search API.
data/lib/regex.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  # encoding: utf-8
2
-
3
2
  module Twitter
4
3
  # A collection of regular expressions for parsing Tweet text. The regular expression
5
4
  # list is frozen at load time to ensure immutability. These reular expressions are
@@ -31,15 +30,17 @@ module Twitter
31
30
  REGEXEN[:extract_mentions] = /(^|[^a-zA-Z0-9_])#{REGEXEN[:at_signs]}([a-zA-Z0-9_]{1,20})(?=(.|$))/o
32
31
  REGEXEN[:extract_reply] = /^(?:#{REGEXEN[:spaces]})*#{REGEXEN[:at_signs]}([a-zA-Z0-9_]{1,20})/o
33
32
 
34
- major, minor, patch = RUBY_VERSION.split(/\./)
35
- if major.to_i >= 1 && minor.to_i >= 9
33
+ major, minor, patch = RUBY_VERSION.split('.')
34
+ if major.to_i >= 2 || major.to_i == 1 && minor.to_i >= 9 || (defined?(RUBY_ENGINE) && ["jruby", "rbx"].include?(RUBY_ENGINE))
36
35
  REGEXEN[:list_name] = /[a-zA-Z][a-zA-Z0-9_\-\u0080-\u00ff]{0,24}/
37
36
  else
38
- # This line barfs at compile time in Ruby 1.9.
37
+ # This line barfs at compile time in Ruby 1.9, JRuby, or Rubinius.
39
38
  REGEXEN[:list_name] = eval("/[a-zA-Z][a-zA-Z0-9_\\-\x80-\xff]{0,24}/")
40
39
  end
41
40
 
42
- # Latin accented characters (subtracted 0xD7 from the range, it's a confusable multiplication sign. Looks like "x")
41
+ # Latin accented characters
42
+ # Excludes 0xd7 from the range (the multiplication sign, confusable with "x").
43
+ # Also excludes 0xf7, the division sign
43
44
  LATIN_ACCENTS = [(0xc0..0xd6).to_a, (0xd8..0xf6).to_a, (0xf8..0xff).to_a].flatten.pack('U*').freeze
44
45
  REGEXEN[:latin_accents] = /[#{LATIN_ACCENTS}]+/o
45
46
 
@@ -47,7 +48,7 @@ module Twitter
47
48
 
48
49
  # Characters considered valid in a hashtag but not at the beginning, where only a-z and 0-9 are valid.
49
50
  HASHTAG_CHARACTERS = /[a-z0-9_#{LATIN_ACCENTS}]/io
50
- REGEXEN[:auto_link_hashtags] = /(^|[^0-9A-Z&\/\?]+)(#|#)([0-9A-Z_]*[A-Z_]+#{HASHTAG_CHARACTERS}*)/io
51
+ REGEXEN[:auto_link_hashtags] = /(^|[^0-9A-Z&\/\?]+)(#|#)([0-9a-z_]*[a-z_]+#{HASHTAG_CHARACTERS}*)/io
51
52
  REGEXEN[:auto_link_usernames_or_lists] = /([^a-zA-Z0-9_]|^|RT:?)([@@]+)([a-zA-Z0-9_]{1,20})(\/[a-zA-Z][a-zA-Z0-9_\-]{0,24})?/o
52
53
  REGEXEN[:auto_link_emoticon] = /(8\-\#|8\-E|\+\-\(|\`\@|\`O|\&lt;\|:~\(|\}:o\{|:\-\[|\&gt;o\&lt;|X\-\/|\[:-\]\-I\-|\/\/\/\/Ö\\\\\\\\|\(\|:\|\/\)|∑:\*\)|\( \| \))/
53
54
 
@@ -56,7 +57,7 @@ module Twitter
56
57
  REGEXEN[:valid_domain] = /(?:[^[:punct:]\s][\.-](?=[^[:punct:]\s])|[^[:punct:]\s]){1,}\.[a-z]{2,}(?::[0-9]+)?/i
57
58
 
58
59
  # For protocol-less URLs, we'll accept them if they end in one of a handful of likely TLDs
59
- REGEXEN[:probable_tld] = /\.(?:com|net|org|gov|edu)$/i
60
+ REGEXEN[:probable_tld_domain] = /^(.*?)((?:[a-z0-9_\.\-]+)\.(?:com|net|org|gov|edu))$/i
60
61
 
61
62
  REGEXEN[:www] = /www\./i
62
63
 
data/lib/twitter-text.rb CHANGED
@@ -1,15 +1,12 @@
1
-
2
1
  major, minor, patch = RUBY_VERSION.split('.')
3
2
 
4
- if major == 1 && minor < 9
3
+ if major.to_i == 1 && minor.to_i < 9
5
4
  # Ruby 1.8 KCODE check. Not needed on 1.9 and later.
6
- raise("twitter-text requires the $KCODE variable be set to 'UTF8' or 'u'") unless ['u','UTF8'].include?($KCODE)
5
+ raise("twitter-text requires the $KCODE variable be set to 'UTF8' or 'u'") unless $KCODE[0].chr =~ /u/i
7
6
  end
8
7
 
9
- require 'rubygems'
10
-
11
- # Needed for auto-linking
12
- gem 'actionpack'
8
+ # External libraries required. (for gems, use: ruby -rubygems ...)
9
+ require 'action_pack'
13
10
  require 'action_view'
14
11
 
15
12
  require File.join(File.dirname(__FILE__), 'regex')
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:newgem_simple, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:newgem_simple, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -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
- Hpricot(@autolinked_text).search('a').should be_blank
39
+ Nokogiri::HTML(@autolinked_text).search('a').should be_blank
40
40
  end
41
41
  end
42
42
 
@@ -132,7 +132,7 @@ describe Twitter::Autolink do
132
132
  def original_text; "hello @/my-list"; end
133
133
 
134
134
  it "should NOT be linked" do
135
- Hpricot(@autolinked_text).search('a').should be_blank
135
+ Nokogiri::HTML(@autolinked_text).search('a').should be_blank
136
136
  end
137
137
  end
138
138
 
@@ -148,7 +148,7 @@ describe Twitter::Autolink do
148
148
  def original_text; "meet@the/beach"; end
149
149
 
150
150
  it "should not be linked" do
151
- Hpricot(@autolinked_text).search('a').should be_blank
151
+ Nokogiri::HTML(@autolinked_text).search('a').should be_blank
152
152
  end
153
153
  end
154
154
 
@@ -304,9 +304,9 @@ describe Twitter::Autolink do
304
304
  def original_text; "#{[0xFF03].pack('U')}twj_dev"; end
305
305
 
306
306
  it "should be linked" do
307
- link = Hpricot(@autolinked_text).at('a')
307
+ link = Nokogiri::HTML(@autolinked_text).search('a')
308
308
  (link.inner_text.respond_to?(:force_encoding) ? link.inner_text.force_encoding("utf-8") : link.inner_text).should == "#{[0xFF03].pack('U')}twj_dev"
309
- link['href'].should == 'http://twitter.com/search?q=%23twj_dev'
309
+ link.first['href'].should == 'http://twitter.com/search?q=%23twj_dev'
310
310
  end
311
311
  end
312
312
 
@@ -468,9 +468,9 @@ describe Twitter::Autolink do
468
468
  def original_text; "I like www.foobar.com dudes"; end
469
469
 
470
470
  it "links to the original text with the full href" do
471
- link = Hpricot(@autolinked_text).at('a')
471
+ link = Nokogiri::HTML(@autolinked_text).search('a')
472
472
  link.inner_text.should == 'www.foobar.com'
473
- link['href'].should == 'http://www.foobar.com'
473
+ link.first['href'].should == 'http://www.foobar.com'
474
474
  end
475
475
  end
476
476
 
data/spec/spec_helper.rb CHANGED
@@ -1,21 +1,27 @@
1
1
  $TESTING=true
2
+ $KCODE='u'
2
3
  $:.push File.join(File.dirname(__FILE__), '..', 'lib')
3
4
 
4
- require 'twitter-text'
5
- require 'hpricot'
6
- require 'spec/test_urls'
5
+ require 'nokogiri'
6
+ require 'simplecov'
7
+ SimpleCov.start do
8
+ add_group 'Libraries', 'lib'
9
+ end
10
+
11
+ require File.expand_path('../../lib/twitter-text', __FILE__)
12
+ require File.expand_path('../test_urls', __FILE__)
7
13
 
8
- Spec::Runner.configure do |config|
14
+ RSpec.configure do |config|
9
15
  config.include TestUrls
10
16
  end
11
17
 
12
- Spec::Matchers.define :match_autolink_expression do
18
+ RSpec::Matchers.define :match_autolink_expression do
13
19
  match do |string|
14
20
  Twitter::Regex[:valid_url].match(string)
15
21
  end
16
22
  end
17
23
 
18
- Spec::Matchers.define :match_autolink_expression_in do |text|
24
+ RSpec::Matchers.define :match_autolink_expression_in do |text|
19
25
  match do |url|
20
26
  @match_data = Twitter::Regex[:valid_url].match(text)
21
27
  @match_data && @match_data.to_s.strip == url
@@ -26,9 +32,9 @@ Spec::Matchers.define :match_autolink_expression_in do |text|
26
32
  end
27
33
  end
28
34
 
29
- Spec::Matchers.define :have_autolinked_url do |url|
35
+ RSpec::Matchers.define :have_autolinked_url do |url|
30
36
  match do |text|
31
- @link = Hpricot(text).at("a[@href='#{url}']")
37
+ @link = Nokogiri::HTML(text).search("a[@href='#{url}']")
32
38
  @link &&
33
39
  @link.inner_text &&
34
40
  @link.inner_text == url
@@ -39,10 +45,10 @@ Spec::Matchers.define :have_autolinked_url do |url|
39
45
  end
40
46
  end
41
47
 
42
- Spec::Matchers.define :link_to_screen_name do |screen_name|
48
+ RSpec::Matchers.define :link_to_screen_name do |screen_name|
43
49
  match do |text|
44
- @link = Hpricot(text).at("a.username")
45
- @link && @link.inner_text == screen_name && "http://twitter.com/#{screen_name}".downcase.should == @link['href']
50
+ @link = Nokogiri::HTML(text).search("a.username")
51
+ @link && @link.inner_text == screen_name && "http://twitter.com/#{screen_name}".downcase.should == @link.first['href']
46
52
  end
47
53
 
48
54
  failure_message_for_should do |text|
@@ -58,10 +64,10 @@ Spec::Matchers.define :link_to_screen_name do |screen_name|
58
64
  end
59
65
  end
60
66
 
61
- Spec::Matchers.define :link_to_list_path do |list_path|
67
+ RSpec::Matchers.define :link_to_list_path do |list_path|
62
68
  match do |text|
63
- @link = Hpricot(text).at("a.list-slug")
64
- !@link.nil? && @link.inner_text == list_path && "http://twitter.com/#{list_path}".downcase.should == @link['href']
69
+ @link = Nokogiri::HTML(text).search("a.list-slug")
70
+ !@link.nil? && @link.inner_text == list_path && "http://twitter.com/#{list_path}".downcase.should == @link.first['href']
65
71
  end
66
72
 
67
73
  failure_message_for_should do |text|
@@ -77,9 +83,9 @@ Spec::Matchers.define :link_to_list_path do |list_path|
77
83
  end
78
84
  end
79
85
 
80
- Spec::Matchers.define :have_autolinked_hashtag do |hashtag|
86
+ RSpec::Matchers.define :have_autolinked_hashtag do |hashtag|
81
87
  match do |text|
82
- @link = Hpricot(text).at("a[@href='http://twitter.com/search?q=#{CGI.escape hashtag}']")
88
+ @link = Nokogiri::HTML(text).search("a[@href='http://twitter.com/search?q=#{CGI.escape hashtag}']")
83
89
  @link &&
84
90
  @link.inner_text &&
85
91
  @link.inner_text == hashtag
data/spec/test_urls.rb CHANGED
@@ -23,12 +23,12 @@ module TestUrls
23
23
  "http://x.com/has/one/char/domain",
24
24
  "http://t.co/nwcLTFF",
25
25
  # "t.co/nwcLTFF"
26
- ]
26
+ ] unless defined?(TestUrls::VALID)
27
27
 
28
28
  INVALID = [
29
29
  "http://no-tld",
30
30
  "http://tld-too-short.x",
31
31
  "http://-doman_dash.com"
32
- ]
32
+ ] unless defined?(TestUrls::INVALID)
33
33
 
34
34
  end
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ major, minor, patch = RUBY_VERSION.split('.')
4
+ if major.to_i == 1 && minor.to_i < 9
5
+ describe "base" do
6
+ before do
7
+ $KCODE = 'NONE'
8
+ end
9
+
10
+ after do
11
+ $KCODE = 'u'
12
+ end
13
+
14
+ it "should raise with invalid KCODE on Ruby < 1.9" do
15
+ lambda do
16
+ require 'twitter-text'
17
+ end.should raise_error
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,126 @@
1
+ require 'test/unit'
2
+ require 'yaml'
3
+ $KCODE = 'UTF8'
4
+ require File.dirname(__FILE__) + '/../lib/twitter-text'
5
+
6
+ class ConformanceTest < Test::Unit::TestCase
7
+ include Twitter::Extractor
8
+ include Twitter::Autolink
9
+ include Twitter::HitHighlighter
10
+
11
+ def setup
12
+ @conformance_dir = ENV['CONFORMANCE_DIR'] || File.join(File.dirname(__FILE__), 'twitter-text-conformance')
13
+ end
14
+
15
+ module ExtractorConformance
16
+ def test_replies_extractor_conformance
17
+ run_conformance_test(File.join(@conformance_dir, 'extract.yml'), :replies) do |description, expected, input|
18
+ assert_equal expected, extract_reply_screen_name(input), description
19
+ end
20
+ end
21
+
22
+ def test_mentions_extractor_conformance
23
+ run_conformance_test(File.join(@conformance_dir, 'extract.yml'), :mentions) do |description, expected, input|
24
+ assert_equal expected, extract_mentioned_screen_names(input), description
25
+ end
26
+ end
27
+
28
+ def test_mentions_with_indices_extractor_conformance
29
+ run_conformance_test(File.join(@conformance_dir, 'extract.yml'), :mentions_with_indices) do |description, expected, input|
30
+ expected = expected.map{|elem| elem.symbolize_keys }
31
+ assert_equal expected, extract_mentioned_screen_names_with_indices(input), description
32
+ end
33
+ end
34
+
35
+ def test_url_extractor_conformance
36
+ run_conformance_test(File.join(@conformance_dir, 'extract.yml'), :urls) do |description, expected, input|
37
+ assert_equal expected, extract_urls(input), description
38
+ end
39
+ end
40
+
41
+ def test_urls_with_indices_extractor_conformance
42
+ run_conformance_test(File.join(@conformance_dir, 'extract.yml'), :urls_with_indices) do |description, expected, input|
43
+ expected = expected.map{|elem| elem.symbolize_keys }
44
+ assert_equal expected, extract_urls_with_indices(input), description
45
+ end
46
+ end
47
+
48
+ def test_hashtag_extractor_conformance
49
+ run_conformance_test(File.join(@conformance_dir, 'extract.yml'), :hashtags) do |description, expected, input|
50
+ assert_equal expected, extract_hashtags(input), description
51
+ end
52
+ end
53
+
54
+ def test_hashtags_with_indices_extractor_conformance
55
+ run_conformance_test(File.join(@conformance_dir, 'extract.yml'), :hashtags_with_indices) do |description, expected, input|
56
+ expected = expected.map{|elem| elem.symbolize_keys }
57
+ assert_equal expected, extract_hashtags_with_indices(input), description
58
+ end
59
+ end
60
+ end
61
+ include ExtractorConformance
62
+
63
+ module AutolinkConformance
64
+ def test_users_autolink_conformance
65
+ run_conformance_test(File.join(@conformance_dir, 'autolink.yml'), :usernames) do |description, expected, input|
66
+ assert_equal expected, auto_link_usernames_or_lists(input, :suppress_no_follow => true), description
67
+ end
68
+ end
69
+
70
+ def test_lists_autolink_conformance
71
+ run_conformance_test(File.join(@conformance_dir, 'autolink.yml'), :lists) do |description, expected, input|
72
+ assert_equal expected, auto_link_usernames_or_lists(input, :suppress_no_follow => true), description
73
+ end
74
+ end
75
+
76
+ def test_urls_autolink_conformance
77
+ run_conformance_test(File.join(@conformance_dir, 'autolink.yml'), :urls) do |description, expected, input|
78
+ assert_equal expected, auto_link_urls_custom(input, :suppress_no_follow => true), description
79
+ end
80
+ end
81
+
82
+ def test_hashtags_autolink_conformance
83
+ run_conformance_test(File.join(@conformance_dir, 'autolink.yml'), :hashtags) do |description, expected, input|
84
+ assert_equal expected, auto_link_hashtags(input, :suppress_no_follow => true), description
85
+ end
86
+ end
87
+
88
+ def test_all_autolink_conformance
89
+ run_conformance_test(File.join(@conformance_dir, 'autolink.yml'), :all) do |description, expected, input|
90
+ assert_equal expected, auto_link(input, :suppress_no_follow => true), description
91
+ end
92
+ end
93
+ end
94
+ include AutolinkConformance
95
+
96
+ module HitHighlighterConformance
97
+
98
+ def test_plain_text_conformance
99
+ run_conformance_test(File.join(@conformance_dir, 'hit_highlighting.yml'), :plain_text, true) do |config|
100
+ assert_equal config['expected'], hit_highlight(config['text'], config['hits']), config['description']
101
+ end
102
+ end
103
+
104
+ def test_with_links_conformance
105
+ run_conformance_test(File.join(@conformance_dir, 'hit_highlighting.yml'), :with_links, true) do |config|
106
+ assert_equal config['expected'], hit_highlight(config['text'], config['hits']), config['description']
107
+ end
108
+ end
109
+ end
110
+ include HitHighlighterConformance
111
+
112
+ private
113
+
114
+ def run_conformance_test(file, test_type, hash_config = false, &block)
115
+ yaml = YAML.load_file(file)
116
+ assert yaml["tests"][test_type.to_s], "No such test suite: #{test_type.to_s}"
117
+
118
+ yaml["tests"][test_type.to_s].each do |test_info|
119
+ if hash_config
120
+ yield test_info
121
+ else
122
+ yield test_info['description'], test_info['expected'], test_info['text']
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,23 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = "twitter-text"
3
+ s.version = "1.2.5"
4
+ s.authors = ["Matt Sanford", "Patrick Ewing", "Ben Cherry", "Britt Selvitelle", "Raffi Krikorian"]
5
+ s.email = ["matt@twitter.com", "patrick.henry.ewing@gmail.com", "bcherry@gmail.com", "bs@brittspace.com", "raffi@twitter.com"]
6
+ s.homepage = "http://twitter.com"
7
+ s.description = s.summary = "A gem that provides text handling for Twitter"
8
+
9
+ s.platform = Gem::Platform::RUBY
10
+ s.has_rdoc = true
11
+ s.summary = "Twitter text handling library"
12
+
13
+ s.add_development_dependency "nokogiri"
14
+ s.add_development_dependency "rake"
15
+ s.add_development_dependency "rspec"
16
+ s.add_development_dependency "simplecov"
17
+ s.add_runtime_dependency "actionpack"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
22
+ s.require_paths = ["lib"]
23
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitter-text
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 2
9
- - 4
10
- version: 1.2.4
9
+ - 5
10
+ version: 1.2.5
11
11
  platform: ruby
12
12
  authors:
13
13
  - Matt Sanford
@@ -15,15 +15,15 @@ authors:
15
15
  - Ben Cherry
16
16
  - Britt Selvitelle
17
17
  - Raffi Krikorian
18
- autorequire: ""
18
+ autorequire:
19
19
  bindir: bin
20
20
  cert_chain: []
21
21
 
22
- date: 2010-11-03 00:00:00 -07:00
22
+ date: 2010-11-18 00:00:00 -08:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
26
- name: actionpack
26
+ name: nokogiri
27
27
  prerelease: false
28
28
  requirement: &id001 !ruby/object:Gem::Requirement
29
29
  none: false
@@ -34,8 +34,64 @@ dependencies:
34
34
  segments:
35
35
  - 0
36
36
  version: "0"
37
- type: :runtime
37
+ type: :development
38
38
  version_requirements: *id001
39
+ - !ruby/object:Gem::Dependency
40
+ name: rake
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ hash: 3
48
+ segments:
49
+ - 0
50
+ version: "0"
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: simplecov
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ name: actionpack
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ type: :runtime
94
+ version_requirements: *id005
39
95
  description: A gem that provides text handling for Twitter
40
96
  email:
41
97
  - matt@twitter.com
@@ -50,6 +106,11 @@ extensions: []
50
106
  extra_rdoc_files: []
51
107
 
52
108
  files:
109
+ - .gitignore
110
+ - .gitmodules
111
+ - .rspec
112
+ - Gemfile
113
+ - Gemfile.lock
53
114
  - LICENSE
54
115
  - README.rdoc
55
116
  - Rakefile
@@ -61,14 +122,19 @@ files:
61
122
  - lib/twitter-text.rb
62
123
  - lib/unicode.rb
63
124
  - lib/validation.rb
125
+ - script/destroy
126
+ - script/generate
64
127
  - spec/autolinking_spec.rb
65
128
  - spec/extractor_spec.rb
66
129
  - spec/hithighlighter_spec.rb
67
130
  - spec/regex_spec.rb
68
131
  - spec/spec_helper.rb
69
132
  - spec/test_urls.rb
133
+ - spec/twitter_text_spec.rb
70
134
  - spec/unicode_spec.rb
71
135
  - spec/validation_spec.rb
136
+ - test/conformance_test.rb
137
+ - twitter-text.gemspec
72
138
  has_rdoc: true
73
139
  homepage: http://twitter.com
74
140
  licenses: []
@@ -103,5 +169,14 @@ rubygems_version: 1.3.7
103
169
  signing_key:
104
170
  specification_version: 3
105
171
  summary: Twitter text handling library
106
- test_files: []
107
-
172
+ test_files:
173
+ - spec/autolinking_spec.rb
174
+ - spec/extractor_spec.rb
175
+ - spec/hithighlighter_spec.rb
176
+ - spec/regex_spec.rb
177
+ - spec/spec_helper.rb
178
+ - spec/test_urls.rb
179
+ - spec/twitter_text_spec.rb
180
+ - spec/unicode_spec.rb
181
+ - spec/validation_spec.rb
182
+ - test/conformance_test.rb