twittertype 0.1.0

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/README.rdoc ADDED
@@ -0,0 +1,36 @@
1
+ = Overview
2
+ TwitterType is a basic utility that analyses a Twitter user's tweets and
3
+ determine what type of Tweeter the user is. The set of types identified are:
4
+
5
+ [:+chatter+] most tweets are in response to tweets by other Twitter users
6
+ [:+linker+] most tweets include links to URLs
7
+ [:+retweeter+] most tweets are forwarding on other people's tweets
8
+ [:+originator+] most tweets are original content, not containing links, retweets or responses
9
+ [:+unknown_inconclusive+] no strong trends to base type on.
10
+ [:+unknown_silent+] no tweets found in last 7 days
11
+ [:+unknown_protected_user+] user has not granted public access to tweets
12
+
13
+ = Usage
14
+
15
+ Simply run the twitter_type.rb file passing the Twitter screen name of the person you wish to analyse.
16
+ The analysis of this persons most tweets from the last 7 days will be displayed.
17
+
18
+ For example:
19
+
20
+ ruby twitter_type.rb APlusK
21
+ APlusK: type :linker, #tweets 20, #replies 1, #retweets 5, #links 7
22
+
23
+ To analyse multiple Twitter user's, simply pass each on the command line. For example:
24
+
25
+ ruby twitter_type.rb APlusK BillGates EvaLongoria
26
+ APlusK: type :originator, #tweets 20, #replies 1, #retweets 5, #links 6
27
+ BillGates: type :linker, #tweets 19, #replies 1, #retweets 2, #links 11
28
+ EvaLongoria: type :linker, #tweets 19, #replies 3, #retweets 1, #links 11
29
+
30
+ = Notes
31
+
32
+ * The Twitter screen name parameter is case insensitive.
33
+ * Each tweet will only be classified as one of a link, retweet, reply or original tweet. For example, a retweet containing a link is just a retweet and not both.
34
+
35
+ = Copyright
36
+ Copyright (c) 2010 Andy Marks, released under the MIT license
@@ -0,0 +1,25 @@
1
+ require 'tweeterprofile'
2
+
3
+ module TwitterType
4
+
5
+ class ProfileFactory
6
+
7
+ def initialize(user)
8
+ raise ArgumentError.new("No user name supplied") if user.nil? or !user.is_a?(String)
9
+ @user = user
10
+ end
11
+
12
+ def build(tweets)
13
+ raise ArgumentError.new("No tweets to analyse") if tweets.nil?
14
+ raise ArgumentError.new("Tweets are not enumerable") if !tweets.is_a?(Enumerable)
15
+
16
+ profile = TweeterProfile.new(@user)
17
+ tweets.each do |tweet|
18
+ profile.update_from(tweet)
19
+ end
20
+
21
+ return profile
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,84 @@
1
+ module TwitterType
2
+
3
+ class TweeterProfile
4
+ attr_accessor :screen_name,
5
+ :tweet_count,
6
+ :reply_count,
7
+ :retweet_count,
8
+ :link_count,
9
+ :inferred_type
10
+
11
+ def initialize(screen_name)
12
+ @tweet_count = 0
13
+ @reply_count = 0
14
+ @retweet_count = 0
15
+ @link_count = 0
16
+ @screen_name = screen_name
17
+ end
18
+
19
+ def update_from(tweet)
20
+ begin
21
+ @tweet_count = @tweet_count + 1
22
+
23
+ if tweet.text.slice(0, 1) == '@'
24
+ @reply_count = @reply_count + 1
25
+ return
26
+ end
27
+
28
+ @retweet_count = @retweet_count + 1 if tweet.text.slice(0, 2) == 'RT'
29
+ @link_count = @link_count + 1 if tweet.text.index('http://') != nil
30
+ rescue NoMethodError => root
31
+ raise ArgumentError.new("Missing method responses in tweet structure:" + root.to_s)
32
+ end
33
+ end
34
+
35
+ def to_s
36
+ type_to_s = (@inferred_type ? "type " + @inferred_type.inspect + ", " : "")
37
+ @screen_name + ": " + type_to_s + "#tweets " + @tweet_count.to_s + ", #replies " + @reply_count.to_s + ", #retweets " + @retweet_count.to_s + ", #links " + @link_count.to_s + "\n"
38
+ end
39
+
40
+ def ==(other)
41
+ result = @screen_name == other.screen_name
42
+ result = result && @tweet_count == other.tweet_count
43
+ result = result && @reply_count == other.reply_count
44
+ result = result && @retweet_count == other.retweet_count
45
+ result = result && @link_count == other.link_count
46
+
47
+ return result
48
+ end
49
+
50
+ def infer_type
51
+
52
+ attributes = [@retweet_count, @link_count, @reply_count]
53
+ highest_count = attributes.max
54
+
55
+ raise ArgumentError if @tweet_count < highest_count
56
+
57
+ @inferred_type = set_type(highest_count)
58
+
59
+ return @inferred_type
60
+ end
61
+
62
+ private
63
+ def set_type(highest_count)
64
+ return :unknown_silent if @tweet_count == 0
65
+
66
+ non_original_tweet_count = @retweet_count + @link_count + @reply_count
67
+ original_tweets = @tweet_count - non_original_tweet_count
68
+ return :originator if original_tweets > highest_count
69
+
70
+ return :unknown_inconclusive if equal_highest?(highest_count, @retweet_count, @link_count)
71
+ return :unknown_inconclusive if equal_highest?(highest_count, @retweet_count, @reply_count)
72
+ return :unknown_inconclusive if equal_highest?(highest_count, @link_count, @reply_count)
73
+
74
+ return :retweeter if highest_count == @retweet_count
75
+ return :linker if highest_count == @link_count
76
+ return :chatter if highest_count == @reply_count
77
+ end
78
+
79
+ def equal_highest?(highest_count, first, second)
80
+ highest_count == first and highest_count == second
81
+ end
82
+
83
+ end
84
+ end
@@ -0,0 +1,11 @@
1
+ require 'twittertypeinferrer'
2
+
3
+ module TwitterType
4
+
5
+ inferrer = TwitterType::TypeInferrer.new()
6
+
7
+ ARGV.each do |screen_name|
8
+ inferrer.infer(screen_name)
9
+ print inferrer.profile
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'twitter'
3
+
4
+ module TwitterType
5
+
6
+ class TwitterClient
7
+ def gather_recent_tweets_for (screen_name)
8
+ raise ArgumentError if screen_name.nil? or screen_name.strip.size == 0
9
+
10
+ Twitter::Client.new.timeline_for(:user, :id => screen_name)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'twitterclient'
3
+
4
+ module TwitterType
5
+
6
+ class TwitterClientWrapper < TwitterClient
7
+
8
+ attr_reader :client
9
+
10
+ def initialize(client = TwitterClient.new)
11
+ @client = client
12
+ end
13
+
14
+ def gather_recent_tweets_for (screen_name)
15
+ begin
16
+ @client.gather_recent_tweets_for(screen_name)
17
+ rescue Twitter::RESTError => error
18
+ raise ProtectedUserAccessError.new(error.to_s) if ProtectedUserAccessError.fits(error)
19
+ raise TwitterClientError.new(error.to_s)
20
+ end
21
+ end
22
+ end
23
+
24
+ class TwitterClientError < StandardError
25
+ attr :message
26
+
27
+ def initialize(message)
28
+ @message = message
29
+ end
30
+ end
31
+
32
+ class ProtectedUserAccessError < TwitterClientError
33
+ CODE = "401"
34
+
35
+ def self.fits(error)
36
+ return !error.code.index(CODE).nil?
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ require "twitterclientwrapper"
2
+ require "profilefactory"
3
+
4
+ module TwitterType
5
+
6
+ class TypeInferrer
7
+ attr_writer :client
8
+ attr_reader :profile
9
+
10
+ def initialize()
11
+ @client = TwitterClientWrapper.new
12
+ end
13
+
14
+ def infer(user)
15
+ begin
16
+ tweets = @client.gather_recent_tweets_for(user)
17
+ @profile = ProfileFactory.new(user).build(tweets)
18
+ @profile.infer_type
19
+ rescue TwitterType::ProtectedUserAccessError => error
20
+ @profile = ProfileFactory.new(user).build([])
21
+ @profile.inferred_type = :unknown_protected_user
22
+ end
23
+
24
+ self
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec'
2
+ require 'twittertypeinferrer'
3
+ require 'twitterclient'
4
+
5
+ include TwitterType
6
+
7
+ describe TypeInferrer do
8
+
9
+ it "should pass a basic smoke test" do
10
+ TypeInferrer.new.infer("andee_marks")
11
+ end
12
+ end
@@ -0,0 +1,56 @@
1
+ require "spec"
2
+ require "profilefactory"
3
+ require 'tweeterprofile'
4
+
5
+ describe TwitterType::ProfileFactory do
6
+ before(:each) do
7
+ @empty_profile = TweeterProfile.new("user")
8
+ @factory = TwitterType::ProfileFactory.new(@empty_profile.screen_name)
9
+ end
10
+
11
+ def setup_valid_fields_in_tweet
12
+ mock_valid_tweet = mock()
13
+ mock_valid_tweet.stub!(:to_user).and_return("user")
14
+ mock_valid_tweet.stub!(:text).and_return("RT textm http://www.cool.com")
15
+ mock_valid_tweet.stub!(:id).and_return(12345678)
16
+
17
+ return mock_valid_tweet
18
+ end
19
+
20
+ it "should fail construction without a user" do
21
+ lambda {ProfileFactory.new}.should raise_error(ArgumentError)
22
+ lambda {ProfileFactory.new(nil)}.should raise_error(ArgumentError)
23
+ lambda {ProfileFactory.new(1)}.should raise_error(ArgumentError)
24
+
25
+ ProfileFactory.new("user")
26
+ end
27
+
28
+ it "should fail if it cannot enumerate tweets" do
29
+ lambda {@factory.build()}.should raise_error(ArgumentError)
30
+ lambda {@factory.build(nil)}.should raise_error(ArgumentError)
31
+ lambda {@factory.build("tweets")}.should raise_error(ArgumentError)
32
+ lambda {@factory.build([1, 2, 3])}.should raise_error(ArgumentError)
33
+
34
+ @factory.build(Array.new())
35
+ end
36
+
37
+ it "should return an empty profile if no tweets are supplied" do
38
+ @factory.build(Array.new()).should == @empty_profile
39
+ end
40
+
41
+ it "should take a tweet with a valid set of fields" do
42
+ lambda {@factory.build(Array.new(1, "tweet"))}.should raise_error(ArgumentError)
43
+
44
+ mock_valid_tweet = setup_valid_fields_in_tweet()
45
+
46
+ @factory.build(Array.new(1, mock_valid_tweet))
47
+ end
48
+
49
+ it "needs the tweet text to be a string" do
50
+ tweet_with_non_string_text = mock()
51
+ tweet_with_non_string_text.stub!(:to_user).and_return(nil)
52
+ tweet_with_non_string_text.stub!(:text).and_return(1)
53
+
54
+ lambda {@factory.build(Array.new(1, tweet_with_non_string_text))}.should raise_error(ArgumentError)
55
+ end
56
+ end
@@ -0,0 +1,177 @@
1
+ require 'spec'
2
+ require 'tweeterprofile'
3
+
4
+ describe TwitterType::TweeterProfile, " before update" do
5
+
6
+ before(:each) do
7
+ @profile = TweeterProfile.new("andy")
8
+ end
9
+
10
+ it "should provide a valid string representation for a newly created profile" do
11
+ TweeterProfile.new("andy").to_s.should eql("andy: #tweets 0, #replies 0, #retweets 0, #links 0\n")
12
+ end
13
+
14
+ it "should be equal to another profile with the same values" do
15
+ first = TweeterProfile.new("user")
16
+ first.link_count = 1
17
+ first.retweet_count = 2
18
+ first.reply_count = 3
19
+ first.tweet_count = 4
20
+
21
+ second = TweeterProfile.new(first.screen_name)
22
+ second.link_count = first.link_count
23
+ second.retweet_count = first.retweet_count
24
+ second.reply_count = first.reply_count
25
+ second.tweet_count = first.tweet_count
26
+
27
+ first.equal?(second).should == false
28
+ (first == second).should == true
29
+ end
30
+
31
+ it "should provide a valid string representation for an updated profile" do
32
+ @profile.tweet_count = 1
33
+ @profile.reply_count = 2
34
+ @profile.retweet_count = 3
35
+ @profile.link_count = 4
36
+
37
+ @profile.to_s.should eql("andy: #tweets 1, #replies 2, #retweets 3, #links 4\n")
38
+
39
+ end
40
+
41
+ end
42
+
43
+ describe TwitterType::TweeterProfile, " being updated" do
44
+
45
+ before(:each) do
46
+ @profile = TweeterProfile.new("andy")
47
+ end
48
+
49
+ Tweet = Struct.new(:text, :to_user)
50
+
51
+ it "should fail when asked to update itself from a nil tweet" do
52
+ lambda {@profile.update_from(nil)}.should raise_error(ArgumentError)
53
+ end
54
+
55
+ it "should increase the tweet count for each tweet found" do
56
+ @profile.tweet_count.should == 0
57
+
58
+ @profile.update_from(Tweet.new("text"))
59
+ @profile.tweet_count.should == 1
60
+
61
+ @profile.update_from(Tweet.new("text"))
62
+ @profile.tweet_count.should == 2
63
+
64
+ end
65
+
66
+ it "should increase the reply count for each tweet sent to a user" do
67
+ @profile.reply_count.should == 0
68
+
69
+ @profile.update_from(Tweet.new("@user text"))
70
+ @profile.reply_count.should == 1
71
+
72
+ @profile.update_from(Tweet.new("@user text"))
73
+ @profile.reply_count.should == 2
74
+
75
+ @profile.update_from(Tweet.new("text"))
76
+ @profile.reply_count.should == 2
77
+ end
78
+
79
+ it "should let a reply take precedence over a retweet" do
80
+ @profile.reply_count.should == 0
81
+ @profile.update_from(Tweet.new("@user text"))
82
+ @profile.reply_count.should == 1
83
+ @profile.retweet_count.should == 0
84
+ end
85
+
86
+ it "should increase the retweet count for each tweet forwarded from a user" do
87
+ @profile.retweet_count.should == 0
88
+
89
+ @profile.update_from(Tweet.new("RT text"))
90
+ @profile.retweet_count.should == 1
91
+
92
+ @profile.update_from(Tweet.new("RT text"))
93
+ @profile.retweet_count.should == 2
94
+
95
+ @profile.update_from(Tweet.new("text"))
96
+ @profile.retweet_count.should == 2
97
+ end
98
+
99
+ it "should increase the link count for each tweet mentioning an URL" do
100
+ @profile.link_count.should == 0
101
+
102
+ @profile.update_from(Tweet.new("text http://www.twitter.com", nil))
103
+ @profile.link_count.should == 1
104
+
105
+ @profile.update_from(Tweet.new("text http://www.twitter.com", nil))
106
+ @profile.link_count.should == 2
107
+
108
+ @profile.update_from(Tweet.new("text"))
109
+ @profile.link_count.should == 2
110
+ end
111
+
112
+ end
113
+
114
+ describe TwitterType::TweeterProfile, " inferring a type" do
115
+ before(:each) do
116
+ @cut = TweeterProfile.new("user")
117
+ end
118
+
119
+ it "should fail to infer a profile which has less tweets than possible given other attributes" do
120
+ setup_profile({:retweet_count => 1, :link_count => 0, :reply_count => 0, :tweet_count => 0})
121
+ lambda{@cut.infer_type}.should raise_error(ArgumentError)
122
+
123
+ setup_profile({:retweet_count => 0, :link_count => 1, :reply_count => 0, :tweet_count => 0})
124
+ lambda{@cut.infer_type}.should raise_error(ArgumentError)
125
+
126
+ setup_profile({:retweet_count => 0, :link_count => 0, :reply_count => 1, :tweet_count => 0})
127
+ lambda{@cut.infer_type}.should raise_error(ArgumentError)
128
+ end
129
+
130
+ it "should infer retweeter from a profile with predominantly retweets" do
131
+ setup_profile({:retweet_count => 1, :link_count => 0, :reply_count => 0, :tweet_count => 1})
132
+ @cut.infer_type.should == :retweeter
133
+ end
134
+
135
+ it "should included the inferred type in the string representation" do
136
+ setup_profile({:retweet_count => 1, :link_count => 0, :reply_count => 0, :tweet_count => 1})
137
+ @cut.infer_type
138
+ @cut.to_s.should eql("user: type :retweeter, #tweets 1, #replies 0, #retweets 1, #links 0\n")
139
+ end
140
+
141
+ it "should infer linker from a profile with only links" do
142
+ setup_profile({:retweet_count => 0, :link_count => 1, :reply_count => 0, :tweet_count => 1})
143
+ @cut.infer_type.should == :linker
144
+ end
145
+
146
+ it "should infer linker from a profile with predominantly links" do
147
+ setup_profile({:retweet_count => 0, :link_count => 15, :reply_count => 0, :tweet_count => 20})
148
+ @cut.infer_type.should == :linker
149
+ end
150
+
151
+ it "should infer chatter from a profile with predominantly replies" do
152
+ setup_profile({:retweet_count => 0, :link_count => 0, :reply_count => 1, :tweet_count => 1})
153
+ @cut.infer_type.should == :chatter
154
+ end
155
+
156
+ it "should infer originator from a profile with predominantly original tweets" do
157
+ setup_profile({:retweet_count => 1, :link_count => 1, :reply_count => 1, :tweet_count => 10})
158
+ @cut.infer_type.should == :originator
159
+ end
160
+
161
+ it "should infer no clear type from a profile with no clear trends" do
162
+ setup_profile({:retweet_count => 1, :link_count => 1, :reply_count => 1, :tweet_count => 3})
163
+ @cut.infer_type.should == :unknown_inconclusive
164
+ end
165
+
166
+ it "should infer no clear type from an empty profile" do
167
+ setup_profile({:retweet_count => 0, :link_count => 0, :reply_count => 0, :tweet_count => 0})
168
+ @cut.infer_type.should == :unknown_silent
169
+ end
170
+
171
+ def setup_profile(return_values)
172
+ @cut.retweet_count = return_values[:retweet_count]
173
+ @cut.link_count = return_values[:link_count]
174
+ @cut.reply_count = return_values[:reply_count]
175
+ @cut.tweet_count = return_values[:tweet_count]
176
+ end
177
+ end
@@ -0,0 +1,12 @@
1
+ require "spec"
2
+ require "twitterclient"
3
+
4
+ describe TwitterType::TwitterClient do
5
+
6
+ it "should fail with an empty or nil user name" do
7
+ lambda{TwitterClient.new.gather_recent_tweets_for(nil)}.should raise_error(ArgumentError)
8
+ lambda{TwitterClient.new.gather_recent_tweets_for("")}.should raise_error(ArgumentError)
9
+ lambda{TwitterClient.new.gather_recent_tweets_for(" ")}.should raise_error(ArgumentError)
10
+ lambda{TwitterClient.new.gather_recent_tweets_for(' ')}.should raise_error(ArgumentError)
11
+ end
12
+ end
@@ -0,0 +1,37 @@
1
+ require "spec"
2
+ require "twitterclientwrapper"
3
+
4
+ describe TwitterType::TwitterClientWrapper do
5
+
6
+ it "should subclass TwitterClient" do
7
+ TwitterClientWrapper.superclass.should == TwitterClient
8
+ end
9
+
10
+ it "should allow injection of a TwitterClient" do
11
+ TwitterClientWrapper.new(TwitterClient.new)
12
+ end
13
+
14
+ it "should default the client to a TwitterClient instance" do
15
+ TwitterClientWrapper.new.client.class.should == TwitterClient
16
+ end
17
+
18
+ it "should turn raise a custom exception when an attempt to access a protected user's tweets is made" do
19
+ protected_user_access_error = Twitter::RESTError.new
20
+ protected_user_access_error.code = "401"
21
+
22
+ client = mock
23
+ client.stub!(:gather_recent_tweets_for).with("protected_user").and_raise(protected_user_access_error)
24
+
25
+ lambda{TwitterClientWrapper.new(client).gather_recent_tweets_for("protected_user")}.should raise_error(ProtectedUserAccessError)
26
+ end
27
+
28
+ it "should turn any other exceptiona raised by client into a generci exception" do
29
+ access_error = Twitter::RESTError.new
30
+ access_error.code = "404"
31
+
32
+ client = mock
33
+ client.stub!(:gather_recent_tweets_for).with("dodgy_user").and_raise(access_error)
34
+
35
+ lambda{TwitterClientWrapper.new(client).gather_recent_tweets_for("dodgy_user")}.should raise_error(TwitterClientError)
36
+ end
37
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec'
2
+ require 'twittertypeinferrer'
3
+ require 'twitterclient'
4
+
5
+ include TwitterType
6
+
7
+ describe TypeInferrer do
8
+
9
+ VALID_TWITTER_USER = "andee_marks"
10
+
11
+ Tweet = Struct.new(:text, :to_user)
12
+
13
+ before(:each) do
14
+ @cut = TypeInferrer.new
15
+ @mock_client = mock()
16
+ end
17
+
18
+ it "should fail gracefully if the Twitter client fails in some way" do
19
+ @mock_client.stub!(:gather_recent_tweets_for).with(VALID_TWITTER_USER).and_raise(TwitterClientError.new(nil))
20
+ @cut.client = @mock_client
21
+
22
+ @cut.profile.should == nil
23
+ lambda {@cut.infer(VALID_TWITTER_USER)}.should raise_error(TwitterClientError)
24
+ @cut.profile.should == nil
25
+ end
26
+
27
+ it "should use an unknown_unauthorised type for any protected screen name" do
28
+ @mock_client.stub!(:gather_recent_tweets_for).with(VALID_TWITTER_USER).and_raise(ProtectedUserAccessError.new(nil))
29
+ @cut.client = @mock_client
30
+
31
+ @cut.profile.should == nil
32
+ @cut.infer(VALID_TWITTER_USER)
33
+ @cut.profile.inferred_type.should == :unknown_protected_user
34
+
35
+ end
36
+
37
+ it "should infer a type for a Twitter User" do
38
+ tweets = Array.new(1) {|i| Tweet.new("test", "to user")}
39
+ @mock_client.stub!(:gather_recent_tweets_for).with(VALID_TWITTER_USER).and_return(tweets)
40
+
41
+ @cut.client = @mock_client
42
+
43
+ @cut.profile.should == nil
44
+ @cut.infer(VALID_TWITTER_USER)
45
+ @cut.profile.inferred_type.should_not == :undetermined
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twittertype
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Andy Marks
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-03-01 00:00:00 +11:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: twitter4r
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 3
30
+ - 2
31
+ version: 0.3.2
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description:
35
+ email: andy@corvine.org
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README.rdoc
42
+ files:
43
+ - lib/profilefactory.rb
44
+ - lib/tweeterprofile.rb
45
+ - lib/twitter_type.rb
46
+ - lib/twitterclient.rb
47
+ - lib/twitterclientwrapper.rb
48
+ - lib/twittertypeinferrer.rb
49
+ - README.rdoc
50
+ has_rdoc: true
51
+ homepage: http://github.com/andeemarks/Twitter-Type
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.3.6
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: A utility for analysing Twitter user tweet patterns
80
+ test_files:
81
+ - test/functional/twittertypeinferrer_spec.rb
82
+ - test/unit/profilefactory_spec.rb
83
+ - test/unit/tweeterprofile_spec.rb
84
+ - test/unit/twitterclient_spec.rb
85
+ - test/unit/twitterclientwrapper_spec.rb
86
+ - test/unit/twittertypeinferrer_spec.rb