brookr-tootils 0.1.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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README +69 -0
- data/Rakefile +56 -0
- data/VERSION +1 -0
- data/lib/tootils.rb +115 -0
- data/test/test_helper.rb +11 -0
- data/test/tootils_test.rb +11 -0
- metadata +63 -0
data/.document
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Jack Danger Canty
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
Description:
|
2
|
+
A collection of useful Twitter Utilities
|
3
|
+
Tools:
|
4
|
+
Of primary interest is the graphing tool. It will determine if a
|
5
|
+
Twitter user has another user in thier 1st, 2nd or
|
6
|
+
3rd degree of connections
|
7
|
+
Limitations:
|
8
|
+
Running 3rd degree checks on users that have a lot of followers/friends
|
9
|
+
will result in using all your available API hit. Twitter developer
|
10
|
+
account recommended!
|
11
|
+
|
12
|
+
Result: the graph method returns a hash of arrays, keyed off the degree of
|
13
|
+
separation. The value for each key an array of all the connections that exist
|
14
|
+
at that level. Each connection is described by a series of Twitter IDs
|
15
|
+
that are ordered by the flow of the connection.
|
16
|
+
|
17
|
+
Example:
|
18
|
+
tootil = Tootils.new(user, pass)
|
19
|
+
tootil.graph(sarahr, brookr)
|
20
|
+
- {1=>[[11146212, 11136022]], 2=>[], 3=>[]}
|
21
|
+
tootil.graph(sarahr, whitscott)
|
22
|
+
- {1=>[],
|
23
|
+
- 2=>
|
24
|
+
- [[11146212, 11136022, 9338922],
|
25
|
+
- [11146212, 14864296, 9338922],
|
26
|
+
- [11146212, 17785160, 9338922],
|
27
|
+
- [11146212, 6602252, 9338922],
|
28
|
+
- [11146212, 11136252, 9338922]],
|
29
|
+
- 3=>[]}
|
30
|
+
|
31
|
+
tootil.graph(sarahr, pop17)
|
32
|
+
- {1=>[],
|
33
|
+
- 2=>[],
|
34
|
+
- 3=>
|
35
|
+
- [[11146212, 11136022, 9338922, 74673],
|
36
|
+
- [11146212, 11136022, 813286, 74673],
|
37
|
+
- [11146212, 11136022, 5997662, 74673],
|
38
|
+
- [11146212, 11136022, 2874, 74673],
|
39
|
+
- [11146212, 11136022, 734493, 74673],
|
40
|
+
- [11146212, 14864296, 9338922, 74673],
|
41
|
+
- ...}
|
42
|
+
|
43
|
+
Author:
|
44
|
+
Brook Riggio
|
45
|
+
http://twitter.com/brookr
|
46
|
+
|
47
|
+
History:
|
48
|
+
2009-07-16:
|
49
|
+
Version 0.1.1: "Gemified!"
|
50
|
+
– Thanks to @jackdanger for using technicalpickles-jeweler to set up the gem
|
51
|
+
2009-07-15:
|
52
|
+
Version 0.1.0: "Layout the API"
|
53
|
+
– Renamed project Tootils, to make space for other utilities
|
54
|
+
– Totally refactored
|
55
|
+
– Graph now shows all connections between two users
|
56
|
+
– Consistent internal API
|
57
|
+
– Renamed links_to to graph
|
58
|
+
– Better data structure for graph results
|
59
|
+
2009-05-26:
|
60
|
+
Version 0.0.2: "We might have something here"
|
61
|
+
– Now checks the 3rd degree as intended
|
62
|
+
– Various optimizations to reduce API hits
|
63
|
+
– Refactorings!
|
64
|
+
|
65
|
+
2009-02-20:
|
66
|
+
Version 0.0.1: "Proof of concept"
|
67
|
+
– Checks first and second degree
|
68
|
+
– Uses lots of API hits
|
69
|
+
– But keeps track of those API hits used!
|
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "tootils"
|
8
|
+
gem.summary = %Q{Twitter Utilities}
|
9
|
+
gem.email = "gitcommit@6brand.com"
|
10
|
+
gem.homepage = "http://github.com/JackDanger/tootils"
|
11
|
+
gem.authors = ["Jack Danger Canty"]
|
12
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
13
|
+
end
|
14
|
+
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
21
|
+
test.libs << 'lib' << 'test'
|
22
|
+
test.pattern = 'test/**/*_test.rb'
|
23
|
+
test.verbose = true
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'rcov/rcovtask'
|
28
|
+
Rcov::RcovTask.new do |test|
|
29
|
+
test.libs << 'test'
|
30
|
+
test.pattern = 'test/**/*_test.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
rescue LoadError
|
34
|
+
task :rcov do
|
35
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
task :default => :test
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
if File.exist?('VERSION.yml')
|
45
|
+
config = YAML.load(File.read('VERSION.yml'))
|
46
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
47
|
+
else
|
48
|
+
version = ""
|
49
|
+
end
|
50
|
+
|
51
|
+
rdoc.rdoc_dir = 'rdoc'
|
52
|
+
rdoc.title = "tootils #{version}"
|
53
|
+
rdoc.rdoc_files.include('README*')
|
54
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
55
|
+
end
|
56
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
data/lib/tootils.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# See README for version history and usage
|
2
|
+
#
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'httparty'
|
6
|
+
require 'pp'
|
7
|
+
config = YAML::load(File.read(File.join(ENV['HOME'], '.twitter')))
|
8
|
+
|
9
|
+
module Tootils
|
10
|
+
class Tools
|
11
|
+
include HTTParty
|
12
|
+
base_uri 'twitter.com'
|
13
|
+
format :json
|
14
|
+
|
15
|
+
def initialize(user, pass)
|
16
|
+
@auth = {:username => user, :password => pass}
|
17
|
+
end
|
18
|
+
|
19
|
+
def options
|
20
|
+
options = { :basic_auth => @auth }
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.remaining_hits
|
24
|
+
options = { :basic_auth => @auth }
|
25
|
+
get("/account/rate_limit_status.json", options)['remaining_hits']
|
26
|
+
end
|
27
|
+
|
28
|
+
def check_limit
|
29
|
+
if self.class.remaining_hits > 1
|
30
|
+
true
|
31
|
+
else
|
32
|
+
raise 'Over API rate limit!'
|
33
|
+
exit 2
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def friends(user)
|
39
|
+
friends = self.class.get("/friends/ids/#{user.to_s}.json", options)
|
40
|
+
if friends["error"]
|
41
|
+
pp friends
|
42
|
+
return []
|
43
|
+
end unless friends.class == Array
|
44
|
+
friends
|
45
|
+
end
|
46
|
+
|
47
|
+
def followers(user)
|
48
|
+
followers = self.class.get("/followers/ids/#{user.to_s}.json", options)
|
49
|
+
if followers["error"]
|
50
|
+
pp followers
|
51
|
+
return []
|
52
|
+
end unless followers.class == Array
|
53
|
+
followers
|
54
|
+
end
|
55
|
+
|
56
|
+
def info(user)
|
57
|
+
info = self.class.get("/users/show/#{user.to_s}.json", options)
|
58
|
+
if info["error"]
|
59
|
+
pp info
|
60
|
+
return {}
|
61
|
+
end
|
62
|
+
info
|
63
|
+
end
|
64
|
+
|
65
|
+
# Our first twitter tool: Graphing connections from the first user to the second.
|
66
|
+
# This will check the first 3 degrees for links, and return a hash of connections
|
67
|
+
# found in each degree.
|
68
|
+
# Once any degree has a connection in it, additional degrees are not checked.
|
69
|
+
def graph(twit1, twit2)
|
70
|
+
twit1_id = info(twit1)['id']
|
71
|
+
twit1_friends = friends(twit1)
|
72
|
+
twit2_id = info(twit2)['id']
|
73
|
+
twit2_followers = followers(twit2)
|
74
|
+
# Start assuming there are no connections
|
75
|
+
graph = { 1 => [], 2 => [], 3 => [] }
|
76
|
+
|
77
|
+
if twit2_followers.include?(twit1_id)
|
78
|
+
graph[1] = [[twit1_id, twit2_id]]
|
79
|
+
end
|
80
|
+
|
81
|
+
return graph unless graph[1].empty?
|
82
|
+
|
83
|
+
# Check second degree: Are there friends of twit1 who are followers of twit2?
|
84
|
+
# Get an array of all connections.
|
85
|
+
for friend in (twit1_friends & twit2_followers)
|
86
|
+
graph[2] << [twit1_id, friend, twit2_id]
|
87
|
+
end
|
88
|
+
return graph unless graph[2].empty?
|
89
|
+
|
90
|
+
# Check the 3rd degree: This is where we really burn through API calls.
|
91
|
+
# We need to check friends of friends, or the followers of followers,
|
92
|
+
# which ever is fewer to save API hits
|
93
|
+
if twit1_friends.length < twit2_followers.length
|
94
|
+
for friend in twit1_friends
|
95
|
+
friends_of_friend = friends(friend)
|
96
|
+
deg3 = friends_of_friend & twit2_followers
|
97
|
+
# Add a connection for each friend of a friend who is a follower of twit2
|
98
|
+
for fof in deg3
|
99
|
+
graph[3] << [twit1_id, friend, fof, twit2_id]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
else
|
103
|
+
for follower in twit2_followers
|
104
|
+
followers_of_follower = followers(follower)
|
105
|
+
deg3 = twit1_friends & followers_of_follower
|
106
|
+
# Add a connection for each follower of a follower who is a friend of twit1
|
107
|
+
for fof in deg3
|
108
|
+
graph[3] << [twit1_id, fof, follower, twit2_id]
|
109
|
+
end rescue pp "Can't get followers for #{follower}: #{info(follower)}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
return graph
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TootilsTest < Test::Unit::TestCase
|
4
|
+
should "build auth hash" do
|
5
|
+
assert !Tootils::Tools.new('user', 'pass').options.empty?
|
6
|
+
end
|
7
|
+
|
8
|
+
should "find first degree connections" do
|
9
|
+
assert !Tootils::Tools.new('user', 'pass').graph('brookr', 'jackdanger')[1].empty?
|
10
|
+
end
|
11
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: brookr-tootils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brook Riggio
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-16 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: brookr@brookr.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- LICENSE
|
24
|
+
- README
|
25
|
+
files:
|
26
|
+
- .document
|
27
|
+
- .gitignore
|
28
|
+
- LICENSE
|
29
|
+
- README
|
30
|
+
- Rakefile
|
31
|
+
- VERSION
|
32
|
+
- lib/tootils.rb
|
33
|
+
- test/test_helper.rb
|
34
|
+
- test/tootils_test.rb
|
35
|
+
has_rdoc: false
|
36
|
+
homepage: http://github.com/brookr/tootils
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options:
|
39
|
+
- --charset=UTF-8
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "0"
|
47
|
+
version:
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.2.0
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: Twitter Utilities
|
61
|
+
test_files:
|
62
|
+
- test/test_helper.rb
|
63
|
+
- test/tootils_test.rb
|