oii_twitter_goodies 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.gitignore +17 -0
- data/Gemfile +12 -0
- data/LICENSE.txt +22 -0
- data/README.md +37 -0
- data/Rakefile +1 -0
- data/lib/oii_twitter_goodies/.DS_Store +0 -0
- data/lib/oii_twitter_goodies/extensions/twitter_api_utils.rb +30 -0
- data/lib/oii_twitter_goodies/extensions/twitter_client.rb +17 -0
- data/lib/oii_twitter_goodies/lib/followers_for_users.rb +64 -0
- data/lib/oii_twitter_goodies/lib/streamer.rb +64 -0
- data/lib/oii_twitter_goodies/model/.DS_Store +0 -0
- data/lib/oii_twitter_goodies/model/bounding_box.rb +22 -0
- data/lib/oii_twitter_goodies/model/coordinate.rb +23 -0
- data/lib/oii_twitter_goodies/model/edge.rb +9 -0
- data/lib/oii_twitter_goodies/model/egonet.rb +8 -0
- data/lib/oii_twitter_goodies/model/geo.rb +23 -0
- data/lib/oii_twitter_goodies/model/hashtag.rb +21 -0
- data/lib/oii_twitter_goodies/model/location.rb +44 -0
- data/lib/oii_twitter_goodies/model/media.rb +43 -0
- data/lib/oii_twitter_goodies/model/place.rb +48 -0
- data/lib/oii_twitter_goodies/model/place_attribute.rb +20 -0
- data/lib/oii_twitter_goodies/model/result.rb +8 -0
- data/lib/oii_twitter_goodies/model/sample.rb +4 -0
- data/lib/oii_twitter_goodies/model/size.rb +25 -0
- data/lib/oii_twitter_goodies/model/tweet.rb +112 -0
- data/lib/oii_twitter_goodies/model/twitter_api_call.rb +7 -0
- data/lib/oii_twitter_goodies/model/url.rb +25 -0
- data/lib/oii_twitter_goodies/model/user.rb +106 -0
- data/lib/oii_twitter_goodies/model/user_mention.rb +28 -0
- data/lib/oii_twitter_goodies/version.rb +3 -0
- data/lib/oii_twitter_goodies.rb +20 -0
- data/oii_twitter_goodies.gemspec +29 -0
- metadata +231 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 344af42c7d494fcbf3126d96dbf716f7454790b0
|
4
|
+
data.tar.gz: 318f52d851942f33c8893a9b3c1a0c6438274be5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 35908cc4716bcceded07b1b58ead4994ee7b2357df66f16f48d6d174df3977611d309757de7cac6fdece9e5fa7927f338da8141f757b7b6327731c6e2fef9a3b
|
7
|
+
data.tar.gz: b679c6c0ed1d69859217321e807e05600e262fba553f0cc0af7fb68663755b98b4fb29e34e71fb002714f6fba39a523835a6a080d79b6e4aeaf69b58bbb9776f
|
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Devin Gaffney
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# OII Twitter Goodies
|
2
|
+
|
3
|
+
This set of libraries, functions, and monkey patches to existing Twitter gems aims to make the work that Oxford Internet Institute's various faculty and staff undertakes as simple as possible. Have fun.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'oii_twitter_goodies'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install oii_twitter_goodies
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Although this is *just* a gem, it has a few notable dependencies depending on what you're playing with:
|
22
|
+
|
23
|
+
1. If you're using the OIITwitter class to collect REST API data from Twitter, you're going to need:
|
24
|
+
a. MongoDB installed locally, running on port 27017 (this is the default port). Thankfully, MongoDB is relatively easy to install
|
25
|
+
b. MongoMapper, the Ruby Gem that is responsible for tying between MongoDB's internals and Ruby code (the term for this type of Gem is ORM - may want to read up on that if you're ever bored).
|
26
|
+
c. Twitter and TweetStream (these are the two principle Gems used for Twitter data collection).
|
27
|
+
2. What you get:
|
28
|
+
a. OIITwitter: A library of several functions that cover most of the bases of data collection that any of you guys are going to need (currently supports grabbing sets of tweets, users, follower/friend IDs, and egonets (and caches it!))
|
29
|
+
b. OIITweetStream: A library that wraps TweetStream's streaming API functionality, and sets up a best-practices database for storing data from the stream.
|
30
|
+
|
31
|
+
## Contributing
|
32
|
+
|
33
|
+
1. Fork it
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
35
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
37
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
Binary file
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Twitter
|
2
|
+
module API
|
3
|
+
module Utils
|
4
|
+
def objects_from_response(klass, request_method, path, options={})
|
5
|
+
response = send(request_method.to_sym, path, options)
|
6
|
+
if response.class == Hash && response[:body]
|
7
|
+
response = response[:body]
|
8
|
+
objects_from_array(klass, response)
|
9
|
+
else
|
10
|
+
return response
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def object_from_response(klass, request_method, path, options={})
|
15
|
+
response = send(request_method.to_sym, path, options)
|
16
|
+
return klass.from_response(response) || response
|
17
|
+
end
|
18
|
+
|
19
|
+
def cursor_from_response(collection_name, klass, request_method, path, options, method_name)
|
20
|
+
merge_default_cursor!(options)
|
21
|
+
response = send(request_method.to_sym, path, options)
|
22
|
+
if (response.class == Hash || response.class == BSON::OrderedHash) && !response.keys.include?(:body)
|
23
|
+
Twitter::Cursor.from_response({:body => response}, collection_name.to_sym, klass, self, method_name, options)
|
24
|
+
else
|
25
|
+
Twitter::Cursor.from_response(response, collection_name.to_sym, klass, self, method_name, options)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Twitter
|
2
|
+
class Client
|
3
|
+
def get(path, params={})
|
4
|
+
lookup = TwitterAPICall.first(:url => path.to_s, :params => params)
|
5
|
+
if lookup
|
6
|
+
return lookup.data
|
7
|
+
else
|
8
|
+
response = request(:get, path, params)
|
9
|
+
if response[:status] && response[:status] == 200
|
10
|
+
lookup = TwitterAPICall.new(:url => path.to_s, :params => params, :data => response[:body])
|
11
|
+
lookup.save!
|
12
|
+
end
|
13
|
+
return response
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class FollowersForUsers
|
2
|
+
|
3
|
+
attr_accessor :screen_names, :oauth_token, :oauth_token_secret, :consumer_key, :consumer_secret, :client
|
4
|
+
|
5
|
+
def initialize(opts={})
|
6
|
+
opts = Hashie::Mash[opts]
|
7
|
+
@screen_names = opts[:screen_names] || []
|
8
|
+
@oauth_token = opts[:oauth_token]
|
9
|
+
@oauth_token_secret = opts[:oauth_token_secret]
|
10
|
+
@consumer_key = opts[:consumer_key]
|
11
|
+
@consumer_secret = opts[:consumer_secret]
|
12
|
+
@screen_names = [@screen_names].flatten
|
13
|
+
Twitter.configure do |config|
|
14
|
+
config.consumer_key = @consumer_key
|
15
|
+
config.consumer_secret = @consumer_secret
|
16
|
+
config.oauth_token = @oauth_token
|
17
|
+
config.oauth_token_secret = @oauth_token_secret
|
18
|
+
end
|
19
|
+
@client = Twitter::Client.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def grab_followers
|
23
|
+
results = {}
|
24
|
+
@screen_names.each do |screen_name|
|
25
|
+
puts "Current progress: #{@screen_names.index(screen_name)}/#{@screen_names.length} started"
|
26
|
+
user = user_data_for(screen_name)
|
27
|
+
follower_ids = follower_ids_for(screen_name)
|
28
|
+
user_data = user_data_for(follower_ids)
|
29
|
+
results[user.first.attrs] = user_data
|
30
|
+
puts "Current progress: ##{@screen_names.index(screen_name)}/#{@screen_names.length} complete"
|
31
|
+
end
|
32
|
+
puts "Done!"
|
33
|
+
return results
|
34
|
+
end
|
35
|
+
|
36
|
+
def follower_ids_for(screen_name)
|
37
|
+
return direction_ids_for screen_name, "follower"
|
38
|
+
end
|
39
|
+
|
40
|
+
def friend_ids_for(screen_name)
|
41
|
+
return direction_ids_for screen_name, "friend"
|
42
|
+
end
|
43
|
+
|
44
|
+
def direction_ids_for(screen_name, direction)
|
45
|
+
cursor = -1
|
46
|
+
ids = []
|
47
|
+
while cursor != 0
|
48
|
+
puts cursor
|
49
|
+
data = Hashie::Mash[@client.send(direction+"_ids", screen_name, :cursor => cursor).attrs]
|
50
|
+
ids = ids|data.ids
|
51
|
+
cursor = data["next_cursor"]
|
52
|
+
end
|
53
|
+
return ids
|
54
|
+
end
|
55
|
+
|
56
|
+
def user_data_for(screen_names)
|
57
|
+
screen_names = [screen_names].flatten
|
58
|
+
user_data = []
|
59
|
+
screen_names.each_slice(100) do |screen_name_set|
|
60
|
+
user_data = [user_data|@client.users(screen_name_set)].flatten
|
61
|
+
end
|
62
|
+
user_data
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Streamer
|
2
|
+
attr_accessor :stream_type, :stream_conditions, :oauth_token, :oauth_token_secret, :consumer_key, :consumer_secret
|
3
|
+
|
4
|
+
def initialize(opts={})
|
5
|
+
opts = Hashie::Mash[opts]
|
6
|
+
@stream_type = opts[:stream_type] || "track"
|
7
|
+
@stream_conditions = opts[:stream_conditions] || "lol"
|
8
|
+
@oauth_token = opts[:oauth_token]
|
9
|
+
@oauth_token_secret = opts[:oauth_token_secret]
|
10
|
+
@consumer_key = opts[:consumer_key]
|
11
|
+
@consumer_secret = opts[:consumer_secret]
|
12
|
+
TweetStream.configure do |config|
|
13
|
+
config.consumer_key = @consumer_key
|
14
|
+
config.consumer_secret = @consumer_secret
|
15
|
+
config.oauth_token = @oauth_token
|
16
|
+
config.oauth_token_secret = @oauth_token_secret
|
17
|
+
end
|
18
|
+
@client = TweetStream::Client.new
|
19
|
+
self.send("prepare_#{@stream_type}_variables")
|
20
|
+
end
|
21
|
+
|
22
|
+
def prepare_follow_variables
|
23
|
+
raise "Stream Conditions can't be nil!" if @stream_conditions.nil?
|
24
|
+
raise "Stream Conditions must be a comma-separated string or array!" if ![String, Array].include?(@stream_conditions.class)
|
25
|
+
@stream_conditions = @stream_conditions.split(",") if @stream_conditions.class == String
|
26
|
+
sc_count = @stream_conditions.count
|
27
|
+
@stream_conditions = @stream_conditions.collect(&:to_i)
|
28
|
+
@stream_conditions = @stream_conditions.select{|sc| sc != 0}
|
29
|
+
raise "#{sc_count-@stream_conditions.length} values were dropped from stream conditions as they were not integers. You must specify integers (representing valid user IDs on Twitter) for this to work" if sc_count != @stream_conditions.length
|
30
|
+
raise "Stream conditions are empty!" if @stream_conditions.length == 0
|
31
|
+
@stream_conditions
|
32
|
+
end
|
33
|
+
|
34
|
+
def prepare_track_variables
|
35
|
+
raise "Stream Conditions can't be nil!" if @stream_conditions.nil?
|
36
|
+
raise "Stream Conditions must be a comma-separated string or array!" if ![String, Array].include?(@stream_conditions.class)
|
37
|
+
raise "Stream conditions are empty!" if @stream_conditions.length == 0
|
38
|
+
@stream_conditions = @stream_conditions.split(",") if @stream_conditions.class == String
|
39
|
+
@stream_conditions
|
40
|
+
end
|
41
|
+
|
42
|
+
def prepare_locations_variables
|
43
|
+
new_value = []
|
44
|
+
@stream_conditions.split(",").each_slice(4) do |lat_lon_pair|
|
45
|
+
boundings = lat_lon_pair.collect{|b| b.to_f}
|
46
|
+
raise "Must input two pairs of numbers, separated by commas." if boundings.length!=4
|
47
|
+
raise "Latitudes are out of range (max 90 degrees)" if boundings[1].abs>90 || boundings[3].abs>90
|
48
|
+
raise "Longitudes are out of range (max 180 degrees)" if boundings[0].abs>180 || boundings[2].abs>180
|
49
|
+
new_value << boundings
|
50
|
+
end
|
51
|
+
@stream_conditions = new_value.flatten.collect(&:to_f )
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
def stream(&block)
|
56
|
+
EM.run do
|
57
|
+
@client.on_error {|msg| puts msg }
|
58
|
+
@client.on_limit {|skip_count| puts "limit reached: #{skip_count} skipped"}
|
59
|
+
@client.send(@stream_type, @stream_conditions) do |status|
|
60
|
+
block.call status
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
Binary file
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class BoundingBox
|
2
|
+
include MongoMapper::Document
|
3
|
+
key :type, String, :required => true
|
4
|
+
key :coordinates, Array, :required => true
|
5
|
+
key :place_id, ObjectId
|
6
|
+
belongs_to :place
|
7
|
+
|
8
|
+
def self.example
|
9
|
+
{"type"=>"Polygon", "coordinates"=>[[[4.7289, 52.278227], [5.079207, 52.278227], [5.079207, 52.431229], [4.7289, 52.431229]]]}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new_from_raw(bounding_box, place_id)
|
13
|
+
return nil if bounding_box.nil?
|
14
|
+
bounding_box = Hashie::Mash[bounding_box]
|
15
|
+
obj = self.new
|
16
|
+
obj.type = bounding_box["type"]
|
17
|
+
obj.coordinates = bounding_box["coordinates"]
|
18
|
+
obj.place_id = place_id
|
19
|
+
obj.save!
|
20
|
+
obj
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Coordinate
|
2
|
+
include MongoMapper::Document
|
3
|
+
key :type, String
|
4
|
+
#coordinate coordinates are lon lat - geo coordinates are lat lon.
|
5
|
+
key :coordinates, Array
|
6
|
+
key :tweet_id, ObjectId
|
7
|
+
belongs_to :tweet
|
8
|
+
|
9
|
+
def self.example
|
10
|
+
{"type"=>"Point", "coordinates"=>[4.8930892, 52.37051453]}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.new_from_raw(coordinate, tweet_id)
|
14
|
+
return if coordinate.nil?
|
15
|
+
coordinate = Hashie::Mash[coordinate]
|
16
|
+
obj = self.new
|
17
|
+
obj.type = coordinate["type"]
|
18
|
+
obj.coordinates = coordinate["coordinates"]
|
19
|
+
obj.tweet_id = tweet_id
|
20
|
+
obj.save!
|
21
|
+
obj
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class Geo
|
2
|
+
include MongoMapper::Document
|
3
|
+
key :type, String
|
4
|
+
#coordinate coordinates are lon lat - geo coordinates are lat lon.
|
5
|
+
key :coordinates, Array
|
6
|
+
key :tweet_id, ObjectId
|
7
|
+
belongs_to :tweet
|
8
|
+
|
9
|
+
def self.example
|
10
|
+
{"type"=>"Point", "coordinates"=>[52.37051453, 4.8930892]}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.new_from_raw(geo, tweet_id)
|
14
|
+
return if geo.nil?
|
15
|
+
geo = Hashie::Mash[geo]
|
16
|
+
obj = self.new
|
17
|
+
obj.type = geo["type"]
|
18
|
+
obj.coordinates = geo["coordinates"]
|
19
|
+
obj.tweet_id = tweet_id
|
20
|
+
obj.save!
|
21
|
+
obj
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Hashtag
|
2
|
+
include MongoMapper::Document
|
3
|
+
key :text, String
|
4
|
+
key :indices, Array
|
5
|
+
key :tweet_id, ObjectId
|
6
|
+
belongs_to :tweet
|
7
|
+
|
8
|
+
def self.example
|
9
|
+
{"text"=>"IDMA", "indices"=>[27, 32]}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new_from_raw(entity, tweet_id)
|
13
|
+
entity = Hashie::Mash[entity]
|
14
|
+
obj = self.new
|
15
|
+
obj.text = entity["text"]
|
16
|
+
obj.indices = entity["indices"]
|
17
|
+
obj.tweet_id = tweet_id
|
18
|
+
obj.save!
|
19
|
+
obj
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
class Location
|
3
|
+
include MongoMapper::Document
|
4
|
+
key :term, String
|
5
|
+
key :coordinate_data_yahoo, String
|
6
|
+
key :coordinate_data_google, Hash
|
7
|
+
|
8
|
+
def self.grab(term)
|
9
|
+
term = term || ""
|
10
|
+
if (loc = Location.first(:term => term.downcase))
|
11
|
+
return loc
|
12
|
+
else
|
13
|
+
loc = Location.new(:term => term.downcase)
|
14
|
+
loc.coordinate_data_yahoo = Location.coordinate_data_yahoo(term)
|
15
|
+
loc.coordinate_data_google = Location.coordinate_data_google(term)
|
16
|
+
loc.save!
|
17
|
+
return loc
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.coordinate_data_yahoo(term)
|
22
|
+
return Yahoo.locate(term)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.coordinate_data_google(term)
|
26
|
+
return Google.locate(term).to_hash
|
27
|
+
end
|
28
|
+
|
29
|
+
def google
|
30
|
+
return self.coordinate_data_google if self.coordinate_data_google.nil?
|
31
|
+
if self.coordinate_data_google["success"] && self.coordinate_data_google["success"] == true
|
32
|
+
return {:lat => self.coordinate_data_google["lat"], :lng => self.coordinate_data_google["lng"]}
|
33
|
+
else
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def yahoo
|
39
|
+
return self.coordinate_data_yahoo if self.coordinate_data_yahoo.nil? || self.coordinate_data_yahoo.empty?
|
40
|
+
lat = self.coordinate_data_yahoo.split(",").first.to_f
|
41
|
+
lng = self.coordinate_data_yahoo.split(",").last.to_f
|
42
|
+
return {:lat => lat, :lng => lng}
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'size'
|
2
|
+
|
3
|
+
class Medium
|
4
|
+
include MongoMapper::Document
|
5
|
+
key :display_url, String
|
6
|
+
key :media_url, String
|
7
|
+
key :id_str, String
|
8
|
+
key :media_url_https, String
|
9
|
+
key :expanded_url, String
|
10
|
+
key :url, String
|
11
|
+
key :type, String
|
12
|
+
key :id, Integer
|
13
|
+
key :indices, Array
|
14
|
+
key :size_ids, Array
|
15
|
+
many :sizes, :in => :size_ids
|
16
|
+
key :tweet_id, ObjectId
|
17
|
+
belongs_to :tweet
|
18
|
+
|
19
|
+
def self.example
|
20
|
+
{"display_url"=>"pic.twitter.com/I8kPMVvy", "media_url"=>"http://pbs.twimg.com/media/A9TiOUSCYAArxdM.jpg", "sizes"=>{"thumb"=>{"resize"=>"crop", "h"=>150, "w"=>150}, "large"=>{"resize"=>"fit", "h"=>230, "w"=>632}, "small"=>{"resize"=>"fit", "h"=>124, "w"=>340}, "medium"=>{"resize"=>"fit", "h"=>218, "w"=>600}}, "id_str"=>"276094212766851072", "media_url_https"=>"https://pbs.twimg.com/media/A9TiOUSCYAArxdM.jpg", "expanded_url"=>"http://twitter.com/insomniacevents/status/276094212758462465/photo/1", "url"=>"http://t.co/I8kPMVvy", "type"=>"photo", "id"=>276094212766851072, "indices"=>[118, 138]}
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.new_from_raw(media, tweet_id)
|
24
|
+
media = Hashie::Mash[media]
|
25
|
+
obj = self.new
|
26
|
+
obj.display_url = media["display_url"]
|
27
|
+
obj.media_url = media["media_url"]
|
28
|
+
obj.id_str = media["id_str"]
|
29
|
+
obj.media_url_https = media["media_url_https"]
|
30
|
+
obj.expanded_url = media["expanded_url"]
|
31
|
+
obj.url = media["url"]
|
32
|
+
obj.type = media["type"]
|
33
|
+
obj.id = media["id"]
|
34
|
+
obj.indices = media["indices"]
|
35
|
+
media["sizes"].each_pair do |size_type, size_data|
|
36
|
+
size = Size.new_from_raw(size_type, size_data, obj._id)
|
37
|
+
obj.sizes << size
|
38
|
+
end
|
39
|
+
obj.tweet_id = tweet_id
|
40
|
+
obj.save!
|
41
|
+
obj
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative 'place_attribute'
|
2
|
+
require_relative 'bounding_box'
|
3
|
+
|
4
|
+
class Place
|
5
|
+
include MongoMapper::Document
|
6
|
+
key :twitter_id, Integer
|
7
|
+
key :url, String
|
8
|
+
key :place_type, String
|
9
|
+
key :name, String
|
10
|
+
key :full_name, String
|
11
|
+
key :country_code, String
|
12
|
+
key :country, String
|
13
|
+
key :bounding_box_id, ObjectId
|
14
|
+
key :place_attribute_ids, Array
|
15
|
+
many :place_attributes, :in => :place_attribute_ids
|
16
|
+
key :tweet_id, ObjectId
|
17
|
+
belongs_to :tweet
|
18
|
+
belongs_to :bounding_box
|
19
|
+
|
20
|
+
def self.example
|
21
|
+
{"id"=>"99cdab25eddd6bce", "url"=>"http://api.twitter.com/1/geo/id/99cdab25eddd6bce.json", "place_type"=>"city", "name"=>"Amsterdam", "full_name"=>"Amsterdam, North Holland", "country_code"=>"NL", "country"=>"The Netherlands", "bounding_box"=>{"type"=>"Polygon", "coordinates"=>[[[4.7289, 52.278227], [5.079207, 52.278227], [5.079207, 52.431229], [4.7289, 52.431229]]]}, "attributes"=>{}}
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.new_from_raw(place, tweet_id)
|
25
|
+
return if place.nil?
|
26
|
+
place = Hashie::Mash[place]
|
27
|
+
obj = self.new
|
28
|
+
obj.twitter_id = place["twitter_id"]
|
29
|
+
obj.url = place["url"]
|
30
|
+
obj.place_type = place["place_type"]
|
31
|
+
obj.name = place["name"]
|
32
|
+
obj.full_name = place["full_name"]
|
33
|
+
obj.country_code = place["country_code"]
|
34
|
+
obj.country = place["country"]
|
35
|
+
bounding_box = BoundingBox.new_from_raw(place["bounding_box"], obj._id)
|
36
|
+
if bounding_box
|
37
|
+
obj.bounding_box = bounding_box
|
38
|
+
end
|
39
|
+
|
40
|
+
place["attributes"].each_pair do |key, value|
|
41
|
+
place = PlaceAttribute.new_from_raw(key, value, obj._id)
|
42
|
+
obj.place_attributes << place
|
43
|
+
end
|
44
|
+
obj.tweet_id = tweet_id
|
45
|
+
obj.save!
|
46
|
+
obj
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class PlaceAttribute
|
2
|
+
include MongoMapper::Document
|
3
|
+
key :name, String
|
4
|
+
key :value, String
|
5
|
+
key :place_id, ObjectId
|
6
|
+
belongs_to :place
|
7
|
+
|
8
|
+
def self.example
|
9
|
+
{"street_address"=>"5403 Stevens Creek Blvd"}
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new_from_raw(key, value, place_id)
|
13
|
+
obj = self.new
|
14
|
+
obj.name = key
|
15
|
+
obj.value = value
|
16
|
+
obj.place_id = place_id
|
17
|
+
obj.save!
|
18
|
+
obj
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Size
|
2
|
+
include MongoMapper::Document
|
3
|
+
key :size, String
|
4
|
+
key :resize, String
|
5
|
+
key :h, Integer
|
6
|
+
key :w, Integer
|
7
|
+
key :media_id, ObjectId
|
8
|
+
belongs_to :media
|
9
|
+
|
10
|
+
def self.example
|
11
|
+
{"thumb"=>{"resize"=>"crop", "h"=>150, "w"=>150}}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.new_from_raw(size_type, size_data, media_id)
|
15
|
+
size_data = Hashie::Mash[size_data]
|
16
|
+
obj = self.new
|
17
|
+
obj.size = size_type
|
18
|
+
obj.resize = size_data["resize"]
|
19
|
+
obj.h = size_data["h"]
|
20
|
+
obj.w = size_data["w"]
|
21
|
+
obj.media_id = media_id
|
22
|
+
obj.save!
|
23
|
+
obj
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require_relative 'user_mention'
|
2
|
+
require_relative 'coordinate'
|
3
|
+
require_relative 'hashtag'
|
4
|
+
require_relative 'media'
|
5
|
+
require_relative 'place'
|
6
|
+
require_relative 'geo'
|
7
|
+
require_relative 'url'
|
8
|
+
|
9
|
+
class Tweet
|
10
|
+
include MongoMapper::Document
|
11
|
+
key :created_at, Time, :required => true
|
12
|
+
key :twitter_id, Integer, :required => true
|
13
|
+
key :twitter_id_str, String, :required => true
|
14
|
+
key :text, String, :required => true
|
15
|
+
key :source, String, :required => true
|
16
|
+
key :truncated, Boolean, :default => false, :required => true
|
17
|
+
key :in_reply_to_status_id, Integer
|
18
|
+
key :in_reply_to_status_id_str, String
|
19
|
+
key :in_reply_to_user_id, Integer
|
20
|
+
key :in_reply_to_user_id_str, String
|
21
|
+
key :in_reply_to_screen_name, String
|
22
|
+
key :contributors, Array, :default => []
|
23
|
+
key :retweet_count, Integer, :default => 0, :required => true
|
24
|
+
key :favorited, Boolean, :default => false, :required => true
|
25
|
+
key :retweeted, Boolean, :default => false, :required => true
|
26
|
+
key :possibly_sensitive, Boolean, :default => false, :required => true
|
27
|
+
key :geo_id, ObjectId
|
28
|
+
key :coordinate_id, ObjectId
|
29
|
+
key :place_id, ObjectId
|
30
|
+
key :user_id, ObjectId
|
31
|
+
key :hashtag_ids, Array
|
32
|
+
key :url_ids, Array
|
33
|
+
key :user_mention_ids, Array
|
34
|
+
key :media_ids, Array
|
35
|
+
many :hashtags, :in => :hashtag_ids
|
36
|
+
many :urls, :in => :url_ids
|
37
|
+
many :user_mentions, :in => :user_mention_ids
|
38
|
+
many :media, :in => :media_ids
|
39
|
+
key :user_id, ObjectId
|
40
|
+
belongs_to :geo
|
41
|
+
belongs_to :coordinate
|
42
|
+
belongs_to :place
|
43
|
+
belongs_to :user
|
44
|
+
|
45
|
+
def self.example
|
46
|
+
{"entities"=>{"user_mentions"=>[], "urls"=>[{"display_url"=>"tehelka.com/story_main54.a...", "expanded_url"=>"http://www.tehelka.com/story_main54.asp?filename=Ws041212SPORTS.asp", "url"=>"http://t.co/uZmKgdkO", "indices"=>[120, 140]}], "hashtags"=>[]}, "text"=>"On the day Indian Olympics Association was suspended by IOC, Rahul Mehra says the move gives an opportunity to clean up http://t.co/uZmKgdkO", "retweet_count"=>2, "coordinates"=>nil, "possibly_sensitive"=>false, "in_reply_to_status_id_str"=>nil, "contributors"=>nil, "in_reply_to_user_id_str"=>nil, "id_str"=>"276035961274638336", "in_reply_to_screen_name"=>nil, "retweeted"=>false, "truncated"=>false, "created_at"=>"Tue Dec 04 18:51:16 +0000 2012", "geo"=>nil, "place"=>nil, "in_reply_to_status_id"=>nil, "favorited"=>false, "source"=>"web", "id"=>276035961274638336, "in_reply_to_user_id"=>nil}
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.new_from_raw(tweet, user_id)
|
50
|
+
return if tweet.nil?
|
51
|
+
tweet = Hashie::Mash[tweet]
|
52
|
+
obj = self.new
|
53
|
+
obj.created_at = tweet["created_at"]
|
54
|
+
obj.twitter_id = tweet["id"]
|
55
|
+
obj.twitter_id_str = tweet["id_str"]
|
56
|
+
obj.text = tweet["text"]
|
57
|
+
obj.source = tweet["source"]
|
58
|
+
obj.truncated = tweet["truncated"]
|
59
|
+
obj.in_reply_to_status_id = tweet["in_reply_to_status_id"]
|
60
|
+
obj.in_reply_to_status_id_str = tweet["in_reply_to_status_id_str"]
|
61
|
+
obj.in_reply_to_user_id = tweet["in_reply_to_user_id"]
|
62
|
+
obj.in_reply_to_user_id_str = tweet["in_reply_to_user_id_str"]
|
63
|
+
obj.in_reply_to_screen_name = tweet["in_reply_to_screen_name"]
|
64
|
+
obj.contributors = tweet["contributors"]
|
65
|
+
obj.retweet_count = tweet["retweet_count"]
|
66
|
+
obj.favorited = tweet["favorited"]
|
67
|
+
obj.retweeted = tweet["retweeted"]
|
68
|
+
obj.possibly_sensitive = tweet["possibly_sensitive"]
|
69
|
+
tweet["twitter_id"] = obj.twitter_id
|
70
|
+
if tweet["entities"]
|
71
|
+
tweet["entities"].each_pair do |entity_type, entities|
|
72
|
+
if entity_type == "media"
|
73
|
+
entities.each do |entity|
|
74
|
+
entity = Medium.new_from_raw(entity, obj._id)
|
75
|
+
obj.media << entity
|
76
|
+
end
|
77
|
+
elsif entity_type == "urls"
|
78
|
+
entities.each do |entity|
|
79
|
+
entity = Url.new_from_raw(entity, obj._id)
|
80
|
+
obj.urls << entity
|
81
|
+
end
|
82
|
+
elsif entity_type == "hashtags"
|
83
|
+
entities.each do |entity|
|
84
|
+
entity = Hashtag.new_from_raw(entity, obj._id)
|
85
|
+
obj.hashtags << entity
|
86
|
+
end
|
87
|
+
elsif entity_type == "user_mentions"
|
88
|
+
entities.each do |entity|
|
89
|
+
entity = UserMention.new_from_raw(entity, obj._id)
|
90
|
+
obj.user_mentions << entity
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
place = Place.new_from_raw(tweet["place"], obj._id)
|
96
|
+
if place
|
97
|
+
obj.place = place
|
98
|
+
end
|
99
|
+
geo = Geo.new_from_raw(tweet["geo"], obj._id)
|
100
|
+
if geo
|
101
|
+
obj.geo = geo
|
102
|
+
end
|
103
|
+
coordinate = Coordinate.new_from_raw(tweet["coordinate"], obj._id)
|
104
|
+
if coordinate
|
105
|
+
obj.coordinate = coordinate
|
106
|
+
end
|
107
|
+
obj.user_id = user_id
|
108
|
+
obj.save!
|
109
|
+
obj
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Url
|
2
|
+
include MongoMapper::Document
|
3
|
+
key :url, String
|
4
|
+
key :expanded_url, String
|
5
|
+
key :display_url, String
|
6
|
+
key :indices, Array
|
7
|
+
key :tweet_id, ObjectId
|
8
|
+
belongs_to :tweet
|
9
|
+
|
10
|
+
def self.example
|
11
|
+
{"display_url"=>"bit.ly/SKHqYj", "expanded_url"=>"http://bit.ly/SKHqYj", "url"=>"http://t.co/ZDfXBGCk", "indices"=>[97, 117]}
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.new_from_raw(url, tweet_id)
|
15
|
+
url = Hashie::Mash[url]
|
16
|
+
obj = self.new
|
17
|
+
obj.url = url["url"]
|
18
|
+
obj.expanded_url = url["expanded_url"]
|
19
|
+
obj.display_url = url["display_url"]
|
20
|
+
obj.indices = url["indices"]
|
21
|
+
obj.tweet_id = tweet_id
|
22
|
+
obj.save!
|
23
|
+
obj
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require_relative 'tweet'
|
2
|
+
|
3
|
+
class User
|
4
|
+
include MongoMapper::Document
|
5
|
+
key :twitter_id, Integer, :required => true
|
6
|
+
key :twitter_id_str, String
|
7
|
+
key :name, String
|
8
|
+
key :screen_name, String, :required => true
|
9
|
+
key :location, String
|
10
|
+
key :url, String
|
11
|
+
key :description, String
|
12
|
+
key :protected, Boolean, :default => false, :required => true
|
13
|
+
key :followers_count, Integer, :default => 0, :required => true
|
14
|
+
key :friends_count, Integer, :default => 0, :required => true
|
15
|
+
key :listed_count, Integer, :default => 0, :required => true
|
16
|
+
key :created_at, Time, :required => true
|
17
|
+
key :favourites_count, Integer
|
18
|
+
key :utc_offset, Integer
|
19
|
+
key :time_zone, String
|
20
|
+
key :geo_enabled, Boolean, :default => false, :required => true
|
21
|
+
key :verified, Boolean, :default => false, :required => true
|
22
|
+
key :statuses_count, Integer, :default => 0, :required => true
|
23
|
+
key :lang, String
|
24
|
+
key :contributors_enabled, Boolean, :default => false, :required => true
|
25
|
+
key :is_translator, Boolean, :default => false, :required => true
|
26
|
+
key :profile_background_color, String, :default => "C0DEED", :required => true
|
27
|
+
key :profile_background_image_url, String
|
28
|
+
key :profile_background_image_url_https, String
|
29
|
+
key :profile_background_tile, Boolean, :default => false, :required => true
|
30
|
+
key :profile_image_url, String
|
31
|
+
key :profile_image_url_https, String
|
32
|
+
key :profile_link_color, String, :default => "0084B4", :required => true
|
33
|
+
key :profile_sidebar_border_color, String, :default => "C0DEED", :required => true
|
34
|
+
key :profile_sidebar_fill_color, String, :default => "DDEEF6", :required => true
|
35
|
+
key :profile_text_color, String, :default => "333333", :required => true
|
36
|
+
key :profile_use_background_image, Boolean, :default => true, :required => true
|
37
|
+
key :default_profile, Boolean, :default => false, :required => true
|
38
|
+
key :default_profile_image, Boolean, :default => false, :required => true
|
39
|
+
key :following, Boolean, :default => false, :required => true
|
40
|
+
key :follow_request_sent, Boolean, :default => false, :required => true
|
41
|
+
key :notifications, Boolean, :default => false, :required => true
|
42
|
+
key :tweet_ids, Array
|
43
|
+
many :tweets, :in => :tweet_ids
|
44
|
+
|
45
|
+
def self.example
|
46
|
+
{"created_at"=>"Sat Dec 01 11:01:18 +0000 2012", "id"=>274830526970474496, "id_str"=>"274830526970474496", "text"=>"Getting ready for the #kingsofcode hack battle in Amsterdam! Just got off the plane, running on 2hrs sleep, so will see how this goes!", "source"=>"<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>", "truncated"=>false, "in_reply_to_status_id"=>nil, "in_reply_to_status_id_str"=>nil, "in_reply_to_user_id"=>nil, "in_reply_to_user_id_str"=>nil, "in_reply_to_screen_name"=>nil, "user"=>{"id"=>14447132, "id_str"=>"14447132", "name"=>"Aaron Parecki", "screen_name"=>"aaronpk", "location"=>"Portland, OR", "url"=>"http://aaronparecki.com/", "description"=>"CTO of @esri R&D Center, Portland. Creating my own reality.", "protected"=>false, "followers_count"=>1776, "friends_count"=>619, "listed_count"=>200, "created_at"=>"Sat Apr 19 22:38:15 +0000 2008", "favourites_count"=>1543, "utc_offset"=>-28800, "time_zone"=>"Pacific Time (US & Canada)", "geo_enabled"=>true, "verified"=>false, "statuses_count"=>4331, "lang"=>"en", "contributors_enabled"=>false, "is_translator"=>false, "profile_background_color"=>"7A9AAF", "profile_background_image_url"=>"http://a0.twimg.com/profile_background_images/185835062/4786064324_b7049fbec8_b.jpg", "profile_background_image_url_https"=>"https://si0.twimg.com/profile_background_images/185835062/4786064324_b7049fbec8_b.jpg", "profile_background_tile"=>true, "profile_image_url"=>"http://a0.twimg.com/profile_images/1767475493/aaronpk-glasses_normal.png", "profile_image_url_https"=>"https://si0.twimg.com/profile_images/1767475493/aaronpk-glasses_normal.png", "profile_link_color"=>"0000FF", "profile_sidebar_border_color"=>"87BC44", "profile_sidebar_fill_color"=>"94C8FF", "profile_text_color"=>"000000", "profile_use_background_image"=>true, "default_profile"=>false, "default_profile_image"=>false, "following"=>true, "follow_request_sent"=>false, "notifications"=>nil}, "geo"=>{"type"=>"Point", "coordinates"=>[52.37051453, 4.8930892]}, "coordinates"=>{"type"=>"Point", "coordinates"=>[4.8930892, 52.37051453]}, "place"=>{"id"=>"99cdab25eddd6bce", "url"=>"http://api.twitter.com/1/geo/id/99cdab25eddd6bce.json", "place_type"=>"city", "name"=>"Amsterdam", "full_name"=>"Amsterdam, North Holland", "country_code"=>"NL", "country"=>"The Netherlands", "bounding_box"=>{"type"=>"Polygon", "coordinates"=>[[[4.7289, 52.278227], [5.079207, 52.278227], [5.079207, 52.431229], [4.7289, 52.431229]]]}, "attributes"=>{}}, "contributors"=>nil, "retweet_count"=>0, "favorited"=>false, "retweeted"=>false}
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.new_from_raw(status)
|
50
|
+
status = Hashie::Mash[status]
|
51
|
+
obj = self.new
|
52
|
+
obj.twitter_id = status["user"].nil? ? status["id"] : status["user"]["id"]
|
53
|
+
obj.twitter_id_str = status["user"].nil? ? status["id_str"] : status["user"]["id_str"]
|
54
|
+
obj.name = status["user"].nil? ? status["name"] : status["user"]["name"]
|
55
|
+
obj.screen_name = status["user"].nil? ? status["screen_name"] : status["user"]["screen_name"]
|
56
|
+
obj.location = status["user"].nil? ? status["location"] : status["user"]["location"]
|
57
|
+
obj.url = status["user"].nil? ? status["url"] : status["user"]["url"]
|
58
|
+
obj.description = status["user"].nil? ? status["description"] : status["user"]["description"]
|
59
|
+
obj.protected = status["user"].nil? ? status["protected"] : status["user"]["protected"]
|
60
|
+
obj.followers_count = status["user"].nil? ? status["followers_count"] : status["user"]["followers_count"]
|
61
|
+
obj.friends_count = status["user"].nil? ? status["friends_count"] : status["user"]["friends_count"]
|
62
|
+
obj.listed_count = status["user"].nil? ? status["listed_count"] : status["user"]["listed_count"]
|
63
|
+
obj.created_at = status["user"].nil? ? status["created_at"] : status["user"]["created_at"]
|
64
|
+
obj.favourites_count = status["user"].nil? ? status["favourites_count"] : status["user"]["favourites_count"]
|
65
|
+
obj.utc_offset = status["user"].nil? ? status["utc_offset"] : status["user"]["utc_offset"]
|
66
|
+
obj.time_zone = status["user"].nil? ? status["time_zone"] : status["user"]["time_zone"]
|
67
|
+
obj.geo_enabled = status["user"].nil? ? status["geo_enabled"] : status["user"]["geo_enabled"]
|
68
|
+
obj.verified = status["user"].nil? ? status["verified"] : status["user"]["verified"]
|
69
|
+
obj.statuses_count = status["user"].nil? ? status["statuses_count"] : status["user"]["statuses_count"]
|
70
|
+
obj.lang = status["user"].nil? ? status["lang"] : status["user"]["lang"]
|
71
|
+
obj.contributors_enabled = status["user"].nil? ? status["contributors_enabled"] : status["user"]["contributors_enabled"]
|
72
|
+
obj.is_translator = status["user"].nil? ? status["is_translator"] : status["user"]["is_translator"]
|
73
|
+
obj.profile_background_color = status["user"].nil? ? status["profile_background_color"] : status["user"]["profile_background_color"]
|
74
|
+
obj.profile_background_image_url = status["user"].nil? ? status["profile_background_image_url"] : status["user"]["profile_background_image_url"]
|
75
|
+
obj.profile_background_image_url_https = status["user"].nil? ? status["profile_background_image_url_https"] : status["user"]["profile_background_image_url_https"]
|
76
|
+
obj.profile_background_tile = status["user"].nil? ? status["profile_background_tile"] : status["user"]["profile_background_tile"]
|
77
|
+
obj.profile_image_url = status["user"].nil? ? status["profile_image_url"] : status["user"]["profile_image_url"]
|
78
|
+
obj.profile_image_url_https = status["user"].nil? ? status["profile_image_url_https"] : status["user"]["profile_image_url_https"]
|
79
|
+
obj.profile_link_color = status["user"].nil? ? status["profile_link_color"] : status["user"]["profile_link_color"]
|
80
|
+
obj.profile_sidebar_border_color = status["user"].nil? ? status["profile_sidebar_border_color"] : status["user"]["profile_sidebar_border_color"]
|
81
|
+
obj.profile_sidebar_fill_color = status["user"].nil? ? status["profile_sidebar_fill_color"] : status["user"]["profile_sidebar_fill_color"]
|
82
|
+
obj.profile_text_color = status["user"].nil? ? status["profile_text_color"] : status["user"]["profile_text_color"]
|
83
|
+
obj.profile_use_background_image = status["user"].nil? ? status["profile_use_background_image"] : status["user"]["profile_use_background_image"]
|
84
|
+
obj.default_profile = status["user"].nil? ? status["default_profile"] : status["user"]["default_profile"]
|
85
|
+
obj.default_profile_image = status["user"].nil? ? status["default_profile_image"] : status["user"]["default_profile_image"]
|
86
|
+
obj.following = status["user"].nil? ? status["following"] : status["user"]["following"]
|
87
|
+
obj.follow_request_sent = status["user"].nil? ? status["follow_request_sent"] : status["user"]["follow_request_sent"]
|
88
|
+
obj.notifications = status["user"].nil? ? status["notifications"] : status["user"]["notifications"]
|
89
|
+
if status["text"]
|
90
|
+
tweet = Tweet.new_from_raw(status, obj._id)
|
91
|
+
obj.tweets << tweet
|
92
|
+
end
|
93
|
+
if status["status"]
|
94
|
+
tweet = Tweet.new_from_raw(status["status"], obj._id)
|
95
|
+
obj.tweets << tweet
|
96
|
+
end
|
97
|
+
if status["statuses"]
|
98
|
+
status["statuses"].each do |status|
|
99
|
+
tweet = Tweet.new_from_raw(status, obj._id)
|
100
|
+
obj.tweets << tweet
|
101
|
+
end
|
102
|
+
end
|
103
|
+
obj.save!
|
104
|
+
obj
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class UserMention
|
2
|
+
include MongoMapper::Document
|
3
|
+
key :screen_name, String
|
4
|
+
key :name, String
|
5
|
+
key :twitter_id, Integer
|
6
|
+
key :twitter_id_str, String
|
7
|
+
key :indices, Array
|
8
|
+
key :tweet_id, ObjectId
|
9
|
+
belongs_to :tweet
|
10
|
+
|
11
|
+
def self.example
|
12
|
+
{"name"=>"film.culture360", "id_str"=>"211760188", "id"=>211760188, "indices"=>[3, 19], "screen_name"=>"film_culture360"}
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.new_from_raw(entity, tweet_id)
|
16
|
+
entity = Hashie::Mash[entity]
|
17
|
+
obj = self.new
|
18
|
+
obj.screen_name = entity["screen_name"]
|
19
|
+
obj.name = entity["name"]
|
20
|
+
obj.twitter_id = entity["id"]
|
21
|
+
obj.twitter_id_str = entity["id_str"]
|
22
|
+
obj.indices = entity["indices"]
|
23
|
+
obj.tweet_id = tweet_id
|
24
|
+
obj.save!
|
25
|
+
obj
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'mongo_mapper'
|
3
|
+
require 'oauth'
|
4
|
+
require 'twitter'
|
5
|
+
require 'tweetstream'
|
6
|
+
require 'hashie'
|
7
|
+
require 'typhoeus'
|
8
|
+
require 'json'
|
9
|
+
|
10
|
+
require "oii_twitter_goodies/version"
|
11
|
+
|
12
|
+
Dir[File.dirname(__FILE__) + '/oii_twitter_goodies/extensions/*.rb'].each {|file| require file }
|
13
|
+
Dir[File.dirname(__FILE__) + '/oii_twitter_goodies/lib/*.rb'].each {|file| require file }
|
14
|
+
Dir[File.dirname(__FILE__) + '/oii_twitter_goodies/model/*.rb'].each {|file| require file }
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
module OIITwitterGoodies
|
19
|
+
# Your code goes here...
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'oii_twitter_goodies/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "oii_twitter_goodies"
|
8
|
+
gem.version = OIITwitterGoodies::VERSION
|
9
|
+
gem.authors = ["Devin Gaffney"]
|
10
|
+
gem.email = ["itsme@devingaffney.com"]
|
11
|
+
gem.description = %q{OII Twitter Goodies!}
|
12
|
+
gem.summary = %q{Warm goopy Ruby code for people at OII (or anyone really) to quickly get their hands dirty with Twitter data}
|
13
|
+
gem.homepage = "http://oii.ox.ac.uk"
|
14
|
+
gem.add_development_dependency "bundler", ">= 1.0.0"
|
15
|
+
gem.add_development_dependency "mongo_mapper"
|
16
|
+
gem.add_development_dependency "bcrypt-ruby"
|
17
|
+
gem.add_development_dependency "bson_ext"
|
18
|
+
gem.add_development_dependency "oauth"
|
19
|
+
gem.add_development_dependency "twitter"
|
20
|
+
gem.add_development_dependency "tweetstream"
|
21
|
+
gem.add_development_dependency "minitest"
|
22
|
+
gem.add_development_dependency "hashie"
|
23
|
+
gem.add_development_dependency "typhoeus"
|
24
|
+
gem.add_development_dependency "json"
|
25
|
+
gem.files = `git ls-files`.split($/)
|
26
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
27
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
28
|
+
gem.require_paths = ["lib"]
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oii_twitter_goodies
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Devin Gaffney
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-03-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ! '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mongo_mapper
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bcrypt-ruby
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bson_ext
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: oauth
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: twitter
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ! '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ! '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: tweetstream
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ! '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: hashie
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: typhoeus
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ! '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ! '>='
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: json
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ! '>='
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ! '>='
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description: OII Twitter Goodies!
|
168
|
+
email:
|
169
|
+
- itsme@devingaffney.com
|
170
|
+
executables: []
|
171
|
+
extensions: []
|
172
|
+
extra_rdoc_files: []
|
173
|
+
files:
|
174
|
+
- .DS_Store
|
175
|
+
- .gitignore
|
176
|
+
- Gemfile
|
177
|
+
- LICENSE.txt
|
178
|
+
- README.md
|
179
|
+
- Rakefile
|
180
|
+
- lib/oii_twitter_goodies.rb
|
181
|
+
- lib/oii_twitter_goodies/.DS_Store
|
182
|
+
- lib/oii_twitter_goodies/extensions/twitter_api_utils.rb
|
183
|
+
- lib/oii_twitter_goodies/extensions/twitter_client.rb
|
184
|
+
- lib/oii_twitter_goodies/lib/followers_for_users.rb
|
185
|
+
- lib/oii_twitter_goodies/lib/streamer.rb
|
186
|
+
- lib/oii_twitter_goodies/model/.DS_Store
|
187
|
+
- lib/oii_twitter_goodies/model/bounding_box.rb
|
188
|
+
- lib/oii_twitter_goodies/model/coordinate.rb
|
189
|
+
- lib/oii_twitter_goodies/model/edge.rb
|
190
|
+
- lib/oii_twitter_goodies/model/egonet.rb
|
191
|
+
- lib/oii_twitter_goodies/model/geo.rb
|
192
|
+
- lib/oii_twitter_goodies/model/hashtag.rb
|
193
|
+
- lib/oii_twitter_goodies/model/location.rb
|
194
|
+
- lib/oii_twitter_goodies/model/media.rb
|
195
|
+
- lib/oii_twitter_goodies/model/place.rb
|
196
|
+
- lib/oii_twitter_goodies/model/place_attribute.rb
|
197
|
+
- lib/oii_twitter_goodies/model/result.rb
|
198
|
+
- lib/oii_twitter_goodies/model/sample.rb
|
199
|
+
- lib/oii_twitter_goodies/model/size.rb
|
200
|
+
- lib/oii_twitter_goodies/model/tweet.rb
|
201
|
+
- lib/oii_twitter_goodies/model/twitter_api_call.rb
|
202
|
+
- lib/oii_twitter_goodies/model/url.rb
|
203
|
+
- lib/oii_twitter_goodies/model/user.rb
|
204
|
+
- lib/oii_twitter_goodies/model/user_mention.rb
|
205
|
+
- lib/oii_twitter_goodies/version.rb
|
206
|
+
- oii_twitter_goodies.gemspec
|
207
|
+
homepage: http://oii.ox.ac.uk
|
208
|
+
licenses: []
|
209
|
+
metadata: {}
|
210
|
+
post_install_message:
|
211
|
+
rdoc_options: []
|
212
|
+
require_paths:
|
213
|
+
- lib
|
214
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
215
|
+
requirements:
|
216
|
+
- - ! '>='
|
217
|
+
- !ruby/object:Gem::Version
|
218
|
+
version: '0'
|
219
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
220
|
+
requirements:
|
221
|
+
- - ! '>='
|
222
|
+
- !ruby/object:Gem::Version
|
223
|
+
version: '0'
|
224
|
+
requirements: []
|
225
|
+
rubyforge_project:
|
226
|
+
rubygems_version: 2.0.3
|
227
|
+
signing_key:
|
228
|
+
specification_version: 4
|
229
|
+
summary: Warm goopy Ruby code for people at OII (or anyone really) to quickly get
|
230
|
+
their hands dirty with Twitter data
|
231
|
+
test_files: []
|