pork_sandwich 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/lib/pork/saver.rb ADDED
@@ -0,0 +1,211 @@
1
+ # Variations within the saver class:
2
+ # - Type of object being saved (tweets, userinfo, followers, followees)
3
+ # - Which tag(s) to use
4
+ # - Whether to save, update, or not save
5
+ #
6
+ # Similarities within the saver class:
7
+ # - all recieve an object
8
+ # - all receive a rule set
9
+ module Pork
10
+ class Saver
11
+ attr_accessor :rules
12
+
13
+ def initialize(rules = {})
14
+ @rules = rules
15
+ end
16
+
17
+ def save(to_save, &save_type)
18
+ save_type.call(to_save, rules)
19
+ end
20
+ end
21
+ end
22
+ TWEET_SAVE = lambda do |tweet_to_save, rules|
23
+ $LOG.debug "TWEET SAVE"
24
+ tweet = Tweet.new(:text => tweet_to_save.text,
25
+ :time_of_tweet => tweet_to_save.created_at,
26
+ :to_user_id_search => tweet_to_save.to_user_id,
27
+ :iso_language_code => tweet_to_save.iso_language_code,
28
+ :source => tweet_to_save.source,
29
+ :profile_image_url => tweet_to_save.profile_image_url,
30
+ :from_user_id_search => tweet_to_save.from_user_id,
31
+ :to_user => tweet_to_save.to_user,
32
+ :from_user => tweet_to_save.from_user,
33
+ :status_id => tweet_to_save.status_id
34
+ )
35
+
36
+ unless rules['tags'].nil?
37
+ rules['tags'].each do |tag_name, tag_value|
38
+ tweet.tag_list << tag_value
39
+ end
40
+ end
41
+
42
+ tweet.save
43
+ tweet
44
+ #If not in DB
45
+ #Active record save
46
+ #According to rules
47
+ #save associations
48
+
49
+ end
50
+
51
+ USER_TWEET_SAVE = lambda do |tweet_to_save, rules|
52
+ $LOG.debug "USER TWEET SAVE"
53
+ tweet = Tweet.new(:text => tweet_to_save.text,
54
+ :time_of_tweet => tweet_to_save.created_at,
55
+ :to_user_id => tweet_to_save.in_reply_to_user_id,
56
+ :source => tweet_to_save.source,
57
+ :profile_image_url => tweet_to_save.user.profile_image_url,
58
+ :to_user => tweet_to_save.in_reply_to_screen_name,
59
+ :from_user => tweet_to_save.user.screen_name,
60
+ :twitter_account_id => tweet_to_save.user.id,
61
+ :status_id => tweet_to_save.id,
62
+ :truncated => tweet_to_save.truncated
63
+ )
64
+
65
+ unless rules['tags'].nil?
66
+ rules['tags'].each do |tag_name, tag_value|
67
+ tweet.tag_list << tag_value
68
+ end
69
+ end
70
+
71
+ tweet.save
72
+ tweet
73
+ end
74
+ TWITTER_ACCOUNT_SAVE = lambda do |twitter_account_to_save, rules|
75
+ $LOG.debug "TWITTER ACCOUNT SAVE"
76
+ if twitter_account_to_save.class == Pork::TwitterUser
77
+ twitter_account_attribute_hash = {:twitter_id => twitter_account_to_save.twitter_id,
78
+ :screen_name => twitter_account_to_save.twitter_screen_name}
79
+ twitter_account = TwitterAccount.new(twitter_account_attribute_hash)
80
+
81
+ twitter_account_from_find = TwitterAccount.find(twitter_account.twitter_id) rescue nil
82
+
83
+ else
84
+ twitter_account_attribute_hash = {:twitter_id => twitter_account_to_save.id,
85
+ :name => twitter_account_to_save.name,
86
+ :screen_name => twitter_account_to_save.screen_name,
87
+ :description => twitter_account_to_save.description,
88
+ :location => twitter_account_to_save.location,
89
+ :profile_image_url => twitter_account_to_save.profile_image_url,
90
+ :url => twitter_account_to_save.url,
91
+ :protected => twitter_account_to_save.protected,
92
+ :followers_count => twitter_account_to_save.followers_count,
93
+ :statuses_count => twitter_account_to_save.statuses_count,
94
+ :friends_count => twitter_account_to_save.friends_count,
95
+ :profile_background_image_url => twitter_account_to_save.profile_background_image_url,
96
+ :profile_background_tile => twitter_account_to_save.profile_background_tile,
97
+ :favourites_count => twitter_account_to_save.favourites_count,
98
+ :time_zone => twitter_account_to_save.time_zone,
99
+ :utc_offset => twitter_account_to_save.utc_offset,
100
+ :time_of_user_creation => twitter_account_to_save.created_at,
101
+ :profile_background_color => twitter_account_to_save.profile_background_color,
102
+ :profile_text_color => twitter_account_to_save.profile_text_color,
103
+ :profile_link_color => twitter_account_to_save.profile_link_color,
104
+ :profile_sidebar_fill_color => twitter_account_to_save.profile_sidebar_fill_color,
105
+ :profile_sidebar_border_color => twitter_account_to_save.profile_sidebar_border_color,
106
+ :notifications => twitter_account_to_save.notifications,
107
+ :verified => twitter_account_to_save.verified,
108
+ :twitter_id_for_search => twitter_account_to_save.twitter_id_for_search}
109
+ twitter_account = TwitterAccount.new(twitter_account_attribute_hash)
110
+
111
+ twitter_account_from_find = TwitterAccount.find_by_screen_name(twitter_account.screen_name)
112
+
113
+ end
114
+
115
+
116
+ if twitter_account_from_find
117
+
118
+ twitter_account = twitter_account_from_find
119
+ unless rules['tags'].nil?
120
+ rules['tags'].each do |tag_name, tag_value|
121
+ twitter_account.tag_list << tag_value
122
+ end
123
+ end
124
+ twitter_account.update_attributes(twitter_account_attribute_hash)
125
+ else
126
+ unless rules['tags'].nil?
127
+ rules['tags'].each do |tag_name, tag_value|
128
+ twitter_account.tag_list << tag_value
129
+ end
130
+ end
131
+ twitter_account.save
132
+ end
133
+
134
+ twitter_account
135
+
136
+ end
137
+ CALL_SAVE = lambda do |call_to_save, rules|
138
+ $LOG.debug "CALL SAVE"
139
+ call = Call.new(:query => call_to_save.query,
140
+ :completed_in => call_to_save.completed_in,
141
+ :since_id => call_to_save.since_id,
142
+ :max_id => call_to_save.max_id,
143
+ :refresh_url => call_to_save.refresh_url,
144
+ :results_per_page => call_to_save.results_per_page,
145
+ :next_page => call_to_save.next_page,
146
+ :page => call_to_save.page,
147
+ :api => call_to_save.api_id)
148
+ unless rules['tags'].nil?
149
+ rules['tags'].each do |tag_name, tag_value|
150
+ call.tag_list << tag_value
151
+ end
152
+ end
153
+ call.save
154
+ call
155
+ end
156
+
157
+ RELATIONSHIP_SAVE = lambda do |users_to_save, rules|
158
+ $LOG.debug "RELATIONSHIP SAVE"
159
+ follower = users_to_save[:follower]
160
+ friend = users_to_save[:friend]
161
+
162
+ twitter_relationship = TwitterRelationship.new(:follower_id => follower.db_object.id, :friend_id => friend.db_object.id, :current => true)
163
+ if rules[:complete_friend_set]
164
+ twitter_relationship[:complete_friend_set] = rules[:complete_friend_set]
165
+ end
166
+ if rules[:complete_follower_set]
167
+ twitter_relationship[:complete_follower_set] = rules[:complete_follower_set]
168
+ end
169
+
170
+ unless rules['tags'].nil?
171
+ rules['tags'].each do |tag_name, tag_value|
172
+ twitter_relationship.tag_list << tag_value
173
+ end
174
+ end
175
+ twitter_relationship.save
176
+ twitter_relationship
177
+ end
178
+
179
+
180
+
181
+ REACTION_SAVE = lambda do |reaction_to_save, rules|
182
+ $LOG.debug "REACTION SAVE"
183
+
184
+
185
+ initiator = reaction_to_save[:initiator]
186
+ responder = reaction_to_save[:responder]
187
+ tweet = reaction_to_save[:tweet]
188
+ reaction_type = reaction_to_save[:type]
189
+
190
+ tweet_reaction = TweetReaction.new(:tweet_id => tweet.id,
191
+ :reaction_id => Reaction.find_by_reaction_type(reaction_type).id,
192
+ :initiator_id => initiator.id,
193
+ :responder_id => responder.id)
194
+
195
+
196
+
197
+ unless rules['tags'].nil?
198
+ rules['tags'].each do |tag_name, tag_value|
199
+ tweet_reaction.tag_list << tag_value
200
+ end
201
+ end
202
+
203
+ tweet_reaction.save
204
+ tweet_reaction
205
+ end
206
+
207
+ TREND_SAVE = lambda do |trend_to_save, rules|
208
+ trend = Trend.new(:name => trend_to_save[:name], :query => trend_to_save[:query])
209
+ trend.save
210
+ trend
211
+ end
@@ -0,0 +1,69 @@
1
+ module Pork
2
+ class Search
3
+ attr_reader :query, :db_ids_created, :desired_count, :from_user, :current_count
4
+
5
+ def initialize(query, options = {})
6
+ @query = query
7
+ @desired_count = options[:desired_count] #if nil, will pull as far back as the Search API allows
8
+ @current_count = 0
9
+ @from_user = options[:from_user]
10
+ @db_ids_created = []
11
+ @collect_users = options[:collect_users]
12
+ end
13
+
14
+ def historical_pull
15
+ @search_params = Twitter::Search.new(@query).per_page(100)
16
+ @search_params.from(@from_user) if @from_user
17
+ begin
18
+ loop do
19
+ @tweets_pulled = @search_params.dup.fetch.results
20
+ @tweets_pulled.each do |tweet|
21
+ tweet.status_id = tweet.id
22
+ @db_ids_created << $SAVER.save(tweet, &TWEET_SAVE).id
23
+ $CRAWLER.append(tweet.from_user) if @collect_users
24
+ @current_count += 1
25
+ if reached_desired_count?
26
+ break
27
+ end
28
+ end
29
+ if reached_desired_count? or @search_params.query[:max_id] == @tweets_pulled.last.id
30
+ break
31
+ else
32
+ @search_params.query[:max_id] = @tweets_pulled.last.id
33
+ end
34
+ end
35
+ rescue Twitter::Unavailable
36
+ p "ERROR: Twitter unavailable, trying in 60"
37
+ sleep 60
38
+ retry
39
+ rescue Twitter::NotFound
40
+ p "ERROR: Info target not found, trying to skip"
41
+ rescue Crack::ParseError
42
+ p "Error: JSON Parsing error, trying to skip past problem tweet"
43
+ @search_params.query[:max_id] -= 1000
44
+ rescue Errno::ETIMEDOUT
45
+ $LOG.error "ERROR: Puller timed out, retrying in 10"
46
+ sleep 10
47
+ retry
48
+ rescue Twitter::InformTwitter
49
+ $LOG.error "ERROR: Twitter internal error, retrying in 30"
50
+ sleep 30
51
+ retry
52
+ # rescue NoMethodError
53
+ # p "Rate limited; holding off for a bit then trying again"
54
+ # sleep 600
55
+ # retry
56
+ end
57
+ return true
58
+ end
59
+
60
+ def reached_desired_count?
61
+ if @desired_count
62
+ return @current_count >= @desired_count
63
+ else
64
+ return false
65
+ end
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,83 @@
1
+ module Pork
2
+ class TwitterUser
3
+ attr_accessor :twitter_id, :twitter_screen_name, :crawled, :user_info, :db_object, :puller, :desired_follower_count, :desired_friend_count
4
+ attr_reader :tweet_db_ids, :follower_relationship_db_ids, :friend_relationship_db_ids
5
+
6
+
7
+ def initialize(opts)
8
+ @twitter_id = sanitize_id(opts[:twitter_id])
9
+ @twitter_screen_name = opts[:twitter_screen_name]
10
+ @crawled = opts[:crawled]
11
+ @user_info = opts[:user_info]
12
+ @db_object = opts[:db_object]
13
+ @puller = nil
14
+ @tweet_db_ids = nil
15
+ @follower_relationship_db_ids = nil
16
+ @friend_relationship_db_ids = nil
17
+ @desired_follower_count = opts[:desired_follower_count]
18
+ @desired_friend_count = opts[:desired_friend_count]
19
+ end
20
+
21
+ def crawled?
22
+ @crawled
23
+ end
24
+
25
+ def search
26
+ twitter_id ? twitter_id : twitter_screen_name
27
+ end
28
+
29
+ def sanitize_id(id)
30
+ id.nil? ? nil : id.to_i
31
+ end
32
+
33
+ def pull_tweets
34
+ pull_result = self.puller.pull(self, &TWEETS)
35
+ @tweet_db_ids = pull_result[:db_ids]
36
+ return true
37
+ end
38
+
39
+ def pull_account_info
40
+ unless @user_info && @db_object
41
+ self.update_account_info
42
+ end
43
+ end
44
+
45
+ def update_account_info
46
+ pull_result = self.puller.pull(self, &ACCOUNT_INFO)
47
+ @user_info, @db_object, @twitter_id, @twitter_screen_name = pull_result[:pull_data], pull_result[:db_object], pull_result[:db_object].twitter_id, pull_result[:db_object].screen_name
48
+ return true
49
+ end
50
+
51
+ def pull_followers
52
+ pull_result = self.puller.pull(self, &FOLLOWERS)
53
+ @follower_relationship_db_ids = pull_result[:follower_relationship_db_ids]
54
+ end
55
+
56
+ def pull_friends
57
+ pull_result = self.puller.pull(self, &FRIENDS)
58
+ @friend_relationship_db_ids = pull_result[:friend_relationship_db_ids]
59
+ end
60
+
61
+ def pull_follower_ids
62
+ pull_result = self.puller.pull(self, &FOLLOWER_IDS)
63
+ @follower_relationship_db_ids = pull_result[:follower_relationship_db_ids]
64
+ end
65
+
66
+ def pull_friend_ids
67
+ pull_result = self.puller.pull(self, &FRIEND_IDS)
68
+ @friend_relationship_db_ids = pull_result[:friend_relationship_db_ids]
69
+ end
70
+
71
+ def puller
72
+ unless @puller
73
+ @puller = Pork::Puller.new($AUTH)
74
+ end
75
+ @puller
76
+ end
77
+
78
+
79
+
80
+
81
+
82
+ end
83
+ end
data/lib/pork.rb ADDED
@@ -0,0 +1,28 @@
1
+ require "#{File.dirname(__FILE__)}/pork/twitter_user"
2
+ require "#{File.dirname(__FILE__)}/pork/puller"
3
+ require "#{File.dirname(__FILE__)}/pork/crawler"
4
+ require "#{File.dirname(__FILE__)}/pork/saver"
5
+ require "#{File.dirname(__FILE__)}/pork/reaction_processor"
6
+ require "#{File.dirname(__FILE__)}/pork/auth"
7
+ require "#{File.dirname(__FILE__)}/pork/log"
8
+ require "#{File.dirname(__FILE__)}/pork/search"
9
+
10
+ require "#{File.dirname(__FILE__)}/pork/table_classes/reaction"
11
+ require "#{File.dirname(__FILE__)}/pork/table_classes/trend"
12
+ require "#{File.dirname(__FILE__)}/pork/table_classes/tweet"
13
+ require "#{File.dirname(__FILE__)}/pork/table_classes/tweet_reaction"
14
+ require "#{File.dirname(__FILE__)}/pork/table_classes/twitter_account"
15
+ require "#{File.dirname(__FILE__)}/pork/table_classes/twitter_relationship"
16
+
17
+ module Pork
18
+ #Object.send :undef_method, :id
19
+
20
+
21
+ ActiveRecord::Base.send :include, ActiveRecord::Acts::TaggableOn
22
+ ActiveRecord::Base.send :include, ActiveRecord::Acts::Tagger
23
+
24
+ end
25
+
26
+
27
+
28
+
data/test/auth_test.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "#{File.dirname(__FILE__)}/test_helper"
2
+
3
+ class AuthTest < Test::Unit::TestCase
4
+ context "An Auth object" do
5
+ setup do
6
+ @auth = Pork::Auth.new("username", "password", "user_agent")
7
+ end
8
+
9
+ should "be able to be created" do
10
+ assert_equal "username", @auth.auth.client.username
11
+ assert_equal "password", @auth.auth.client.password
12
+ assert_equal "user_agent", @auth.auth.client.options[:user_agent]
13
+ end
14
+ end
15
+
16
+ end
@@ -0,0 +1,52 @@
1
+ # require "#{File.dirname(__FILE__)}/test_helper"
2
+ #
3
+ #
4
+ # class CrawlerTest < Test::Unit::TestCase
5
+ # context "A crawler initialized with a user array" do
6
+ # setup do
7
+ # $CRAWLER = Pork::Crawler.new([Pork::TwitterUser.new(:twitter_id => 15019521, :crawled => false)], 2, &FOLLOWERS_CRAWL)
8
+ # $PULLER = Pork::Puller.new($AUTH)
9
+ # $TWITERATOR = Pork::Twiterator.new()
10
+ # $SAVER = Pork::Saver.new
11
+ # $LOG = Logger.new(STDOUT)
12
+ # $LOG.level = Logger::INFO
13
+ # end
14
+ # # should "convert the array into a hash" do
15
+ # # assert_same_elements $CRAWLER.users, {15019521 => 'uncrawled'}
16
+ # # end
17
+ # # should "be able to append new and not new users" do
18
+ # # $CRAWLER.append('user3')
19
+ # # $CRAWLER.append(15019521)
20
+ # # assert_same_elements $CRAWLER.users , {15019521 => 'uncrawled','user3' => 'uncrawled'}
21
+ # # end
22
+ # # should "return the initial users when called to a depth of 0" do
23
+ # # $CRAWLER.depth = 0
24
+ # # assert_same_elements [15019521], $CRAWLER.crawl()
25
+ # # end
26
+ # # should "be able to crawl 2 depths of follower ids" do
27
+ # # $CRAWLER.crawl_type = FOLLOWER_IDS_CRAWL
28
+ # # assert_same_elements [15019521, 55555, 4444, 333, 22, 1], $CRAWLER.crawl()
29
+ # # end
30
+ # # should "be able to crawl 2 depths of friend ids" do
31
+ # # $CRAWLER.crawl_type = FRIEND_IDS_CRAWL
32
+ # # assert_same_elements [15019521, 55555, 4444, 333, 22, 1], $CRAWLER.crawl()
33
+ # # end
34
+ # should "be able to gather users from a twitter search" do
35
+ # $CRAWLER.users = []
36
+ # $CRAWLER.depth = 0
37
+ # $CRAWLER.crawl_type = SEARCH_CRAWL
38
+ # @test_result = $CRAWLER.crawl('test').map do |u| u.twitter_screen_name end
39
+ # assert_same_elements ["SamIsMarth", "MarthIsGreat", "EvanIsLucas", "LucasIsCheap"], @test_result
40
+ # end
41
+ # # should "be able to crawl 2 depths of followers" do
42
+ # # $CRAWLER.crawl_type = FOLLOWERS_CRAWL
43
+ # # assert_same_elements [55555,4444,333,22,1,15019521], $CRAWLER.crawl()
44
+ # # end
45
+ # # should "be able to crawl 2 depths of friends" do
46
+ # # $CRAWLER.crawl_type = FRIENDS_CRAWL
47
+ # # assert_same_elements [55555,4444,333,22,1,15019521], $CRAWLER.crawl()
48
+ # # end
49
+ # end
50
+ #
51
+ #
52
+ # end
data/test/factories.rb ADDED
@@ -0,0 +1,56 @@
1
+ Factory.sequence :status_id do |n|
2
+ "1432#{n}".to_i
3
+ end
4
+
5
+ Factory.define :tweet do |t|
6
+ t.text "Someting to tweet about"
7
+ t.from_user "aplusk"
8
+ t.status_id {Factory.next(:status_id)}
9
+ end
10
+
11
+ Factory.define :retweet1_tweet, :parent => :tweet do |t|
12
+ t.text "RT @username blah blah blah"
13
+ end
14
+
15
+ Factory.define :retweet2_tweet, :parent => :tweet do |t|
16
+ t.text "Someting to tweet about RT @username blah blah blah"
17
+ end
18
+
19
+ Factory.define :mention_tweet, :parent => :tweet do |t|
20
+ t.text "Someting to @username tweet about"
21
+ end
22
+
23
+ Factory.define :reply_tweet, :parent => :tweet do |t|
24
+ t.text "@username Someting to tweet about"
25
+ end
26
+
27
+ Factory.define :double_mention_tweet, :parent => :tweet do |t|
28
+ t.text "Someting @username1 to @username2 tweet about"
29
+ end
30
+
31
+ Factory.sequence :screen_name do |n|
32
+ "User#{n}"
33
+ end
34
+
35
+ Factory.sequence :twitter_id do |n|
36
+ "11#{n}".to_i
37
+ end
38
+
39
+ Factory.define :twitter_account do |tw|
40
+ tw.screen_name {Factory.next(:screen_name)}
41
+ tw.twitter_id {Factory.next(:twitter_id)}
42
+ end
43
+
44
+
45
+ Factory.define :tweet_reaction do |tr|
46
+ tr.reaction {Factory.create(:reaction)}
47
+ tr.tweet {Factory.create(:tweet)}
48
+ tr.responder {Factory.create(:twitter_account)}
49
+ tr.initiator {Factory.create(:twitter_account)}
50
+ end
51
+
52
+ Factory.define :reaction do |r|
53
+ r.reaction_type "at mention"
54
+ r.value 0.6
55
+ end
56
+