jlind-twitter 0.9.9
Sign up to get free protection for your applications and to get access to all the features.
- data/History +290 -0
- data/License +20 -0
- data/Notes +33 -0
- data/README.rdoc +19 -0
- data/Rakefile +40 -0
- data/VERSION.yml +5 -0
- data/examples/connect.rb +30 -0
- data/examples/friendship_existence.rb +13 -0
- data/examples/helpers/config_store.rb +38 -0
- data/examples/httpauth.rb +11 -0
- data/examples/ids.rb +13 -0
- data/examples/lists.rb +11 -0
- data/examples/oauth.rb +27 -0
- data/examples/search.rb +15 -0
- data/examples/timeline.rb +19 -0
- data/examples/tumblr.rb +9 -0
- data/examples/unauthorized.rb +16 -0
- data/examples/update.rb +11 -0
- data/examples/user.rb +5 -0
- data/lib/twitter.rb +156 -0
- data/lib/twitter/base.rb +390 -0
- data/lib/twitter/geo.rb +25 -0
- data/lib/twitter/httpauth.rb +53 -0
- data/lib/twitter/local_trends.rb +30 -0
- data/lib/twitter/oauth.rb +85 -0
- data/lib/twitter/request.rb +71 -0
- data/lib/twitter/search.rb +163 -0
- data/lib/twitter/trends.rb +55 -0
- data/test/fixtures/blocking.json +1632 -0
- data/test/fixtures/firehose.json +1 -0
- data/test/fixtures/follower_ids.json +1 -0
- data/test/fixtures/followers.json +1 -0
- data/test/fixtures/friend_ids.json +1 -0
- data/test/fixtures/friends_timeline.json +1 -0
- data/test/fixtures/friendship.json +1 -0
- data/test/fixtures/friendship_exists.json +1 -0
- data/test/fixtures/geo_place.json +1 -0
- data/test/fixtures/geo_reverse_geocode.json +1 -0
- data/test/fixtures/geo_reverse_geocode_granularity.json +1 -0
- data/test/fixtures/geo_reverse_geocode_limit.json +1 -0
- data/test/fixtures/geo_search.json +1 -0
- data/test/fixtures/geo_search_ip_address.json +1 -0
- data/test/fixtures/geo_search_query.json +1 -0
- data/test/fixtures/home_timeline.json +1 -0
- data/test/fixtures/ids.json +1 -0
- data/test/fixtures/list.json +1 -0
- data/test/fixtures/list_statuses.json +1 -0
- data/test/fixtures/list_statuses_1_1.json +1 -0
- data/test/fixtures/list_statuses_2_1.json +1 -0
- data/test/fixtures/list_subscriptions.json +1 -0
- data/test/fixtures/list_users.json +1 -0
- data/test/fixtures/lists.json +1 -0
- data/test/fixtures/memberships.json +1 -0
- data/test/fixtures/mentions.json +1 -0
- data/test/fixtures/not_found.json +1 -0
- data/test/fixtures/people_search.json +39 -0
- data/test/fixtures/rate_limit_exceeded.json +1 -0
- data/test/fixtures/report_spam.json +41 -0
- data/test/fixtures/retweet.json +1 -0
- data/test/fixtures/retweeted_by_me.json +1 -0
- data/test/fixtures/retweeted_to_me.json +1 -0
- data/test/fixtures/retweeters_of_tweet.json +166 -0
- data/test/fixtures/retweets.json +1 -0
- data/test/fixtures/retweets_of_me.json +1 -0
- data/test/fixtures/sample-image.png +0 -0
- data/test/fixtures/saved_search.json +7 -0
- data/test/fixtures/saved_searches.json +16 -0
- data/test/fixtures/search.json +1 -0
- data/test/fixtures/search_from_jnunemaker.json +1 -0
- data/test/fixtures/status.json +1 -0
- data/test/fixtures/status_show.json +1 -0
- data/test/fixtures/trends_available.json +253 -0
- data/test/fixtures/trends_current.json +1 -0
- data/test/fixtures/trends_current_exclude.json +1 -0
- data/test/fixtures/trends_daily.json +1925 -0
- data/test/fixtures/trends_daily_date.json +1 -0
- data/test/fixtures/trends_daily_exclude.json +1 -0
- data/test/fixtures/trends_location.json +57 -0
- data/test/fixtures/trends_weekly.json +1 -0
- data/test/fixtures/trends_weekly_date.json +1 -0
- data/test/fixtures/trends_weekly_exclude.json +1 -0
- data/test/fixtures/unauthorized.json +1 -0
- data/test/fixtures/update_profile_background_image.json +1 -0
- data/test/fixtures/update_profile_image.json +1 -0
- data/test/fixtures/user.json +1 -0
- data/test/fixtures/user_timeline.json +710 -0
- data/test/fixtures/users.json +1 -0
- data/test/test_helper.rb +47 -0
- data/test/twitter/base_test.rb +426 -0
- data/test/twitter/geo_test.rb +79 -0
- data/test/twitter/httpauth_test.rb +86 -0
- data/test/twitter/oauth_test.rb +127 -0
- data/test/twitter/request_test.rb +217 -0
- data/test/twitter/search_test.rb +208 -0
- data/test/twitter/trends_test.rb +112 -0
- data/test/twitter_test.rb +106 -0
- metadata +305 -0
data/lib/twitter/geo.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Twitter
|
2
|
+
class Geo
|
3
|
+
include HTTParty
|
4
|
+
base_uri "api.twitter.com/#{API_VERSION}/geo"
|
5
|
+
format :json
|
6
|
+
|
7
|
+
def self.place(place_id, query={})
|
8
|
+
Twitter.mash(get("/id/#{place_id}.json", :query => query))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.search(query={})
|
12
|
+
mashup(get("/search.json", :query => query))
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.reverse_geocode(query={})
|
16
|
+
mashup(get("/reverse_geocode.json", :query => query))
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def self.mashup(response)
|
22
|
+
response["result"].values.flatten.map{|t| Twitter.mash(t)}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Twitter
|
2
|
+
class HTTPAuth
|
3
|
+
include HTTParty
|
4
|
+
|
5
|
+
format :plain
|
6
|
+
|
7
|
+
attr_reader :username, :password, :options
|
8
|
+
|
9
|
+
def initialize(username, password, options={})
|
10
|
+
|
11
|
+
@username, @password = username, password
|
12
|
+
@options = {:ssl => false}.merge(options)
|
13
|
+
options[:api_endpoint] ||= "api.twitter.com"
|
14
|
+
|
15
|
+
if options[:api_version] == false
|
16
|
+
version_path = ''
|
17
|
+
else
|
18
|
+
options[:api_version] ||= API_VERSION
|
19
|
+
version_path = "/#{options[:api_version]}"
|
20
|
+
end
|
21
|
+
|
22
|
+
self.class.base_uri "http#{'s' if options[:ssl]}://#{options[:api_endpoint]}#{version_path}"
|
23
|
+
self.class.default_timeout options[:timeout] if options[:timeout]
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(uri, headers={})
|
27
|
+
|
28
|
+
self.class.get(uri, :headers => headers, :basic_auth => basic_auth)
|
29
|
+
end
|
30
|
+
|
31
|
+
def post(uri, body={}, headers={})
|
32
|
+
|
33
|
+
self.class.post(uri, :body => body, :headers => headers, :basic_auth => basic_auth)
|
34
|
+
end
|
35
|
+
|
36
|
+
def put(uri, body={}, headers={})
|
37
|
+
|
38
|
+
self.class.put(uri, :body => body, :headers => headers, :basic_auth => basic_auth)
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(uri, body={}, headers={})
|
42
|
+
|
43
|
+
self.class.delete(uri, :body => body, :headers => headers, :basic_auth => basic_auth)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def basic_auth
|
49
|
+
@basic_auth ||= {:username => @username, :password => @password}
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Twitter
|
2
|
+
class LocalTrends
|
3
|
+
include HTTParty
|
4
|
+
base_uri "api.twitter.com/#{API_VERSION}/trends"
|
5
|
+
format :json
|
6
|
+
|
7
|
+
def self.available(query={})
|
8
|
+
before_test(query)
|
9
|
+
query.delete(:api_endpoint)
|
10
|
+
get("/available.json", :query => query).map{|location| Twitter.mash(location)}
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.for_location(woeid,options = {})
|
14
|
+
before_test(options)
|
15
|
+
get("/#{woeid}.json").map{|location| Twitter.mash(location)}
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def self.before_test(options)
|
21
|
+
configure_base_uri(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.configure_base_uri(options)
|
25
|
+
new_base_url = options[:api_endpoint]
|
26
|
+
base_uri "#{new_base_url}/#{API_VERSION}/trends" if new_base_url
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Twitter
|
2
|
+
class OAuth
|
3
|
+
|
4
|
+
def delete(path, headers=nil)
|
5
|
+
access_token.delete(*[api_version + path, headers].compact)
|
6
|
+
end
|
7
|
+
|
8
|
+
def get(path, headers=nil)
|
9
|
+
access_token.get(*[api_version + path, headers].compact)
|
10
|
+
end
|
11
|
+
|
12
|
+
def post(path, data = nil, headers=nil)
|
13
|
+
access_token.post(*[api_version + path, data, headers].compact)
|
14
|
+
end
|
15
|
+
|
16
|
+
def put(path, data = nil, headers=nil)
|
17
|
+
access_token.put(*[api_version + path, data, headers].compact)
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
attr_reader :ctoken, :csecret, :consumer_options, :api_endpoint, :api_version, :signing_endpoint
|
22
|
+
|
23
|
+
# Options
|
24
|
+
# :sign_in => true to just sign in with twitter instead of doing oauth authorization
|
25
|
+
# (http://apiwiki.twitter.com/Sign-in-with-Twitter)
|
26
|
+
def initialize(ctoken, csecret, options={})
|
27
|
+
@ctoken, @csecret, @consumer_options = ctoken, csecret, {}
|
28
|
+
@api_endpoint = options[:api_endpoint] || 'http://api.twitter.com'
|
29
|
+
@signing_endpoint = options[:signing_endpoint] || 'http://api.twitter.com'
|
30
|
+
|
31
|
+
if options[:api_version]
|
32
|
+
@api_version = "/#{options[:api_version].to_s}"
|
33
|
+
else
|
34
|
+
@api_version = ''
|
35
|
+
end
|
36
|
+
|
37
|
+
if options[:sign_in]
|
38
|
+
@consumer_options[:authorize_path] = '/oauth/authenticate'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def consumer
|
43
|
+
@consumer ||= ::OAuth::Consumer.new(@ctoken, @csecret, {:site => api_endpoint}.merge(consumer_options))
|
44
|
+
end
|
45
|
+
|
46
|
+
def signing_consumer
|
47
|
+
@signing_consumer ||= ::OAuth::Consumer.new(@ctoken, @csecret, {:site => signing_endpoint, :request_endpoint => api_endpoint }.merge(consumer_options))
|
48
|
+
end
|
49
|
+
|
50
|
+
def set_callback_url(url)
|
51
|
+
clear_request_token
|
52
|
+
request_token(:oauth_callback => url)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Note: If using oauth with a web app, be sure to provide :oauth_callback.
|
56
|
+
# Options:
|
57
|
+
# :oauth_callback => String, url that twitter should redirect to
|
58
|
+
def request_token(options={})
|
59
|
+
@request_token ||= signing_consumer.get_request_token(options)
|
60
|
+
end
|
61
|
+
|
62
|
+
# For web apps use params[:oauth_verifier], for desktop apps,
|
63
|
+
# use the verifier is the pin that twitter gives users.
|
64
|
+
def authorize_from_request(rtoken, rsecret, verifier_or_pin)
|
65
|
+
request_token = ::OAuth::RequestToken.new(signing_consumer, rtoken, rsecret)
|
66
|
+
access_token = request_token.get_access_token(:oauth_verifier => verifier_or_pin)
|
67
|
+
@atoken, @asecret = access_token.token, access_token.secret
|
68
|
+
end
|
69
|
+
|
70
|
+
def access_token
|
71
|
+
@access_token ||= ::OAuth::AccessToken.new(signing_consumer, @atoken, @asecret)
|
72
|
+
end
|
73
|
+
|
74
|
+
def authorize_from_access(atoken, asecret)
|
75
|
+
@atoken, @asecret = atoken, asecret
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def clear_request_token
|
81
|
+
@request_token = nil
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Twitter
|
2
|
+
class Request
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def self.get(client, path, options={})
|
6
|
+
new(client, :get, path, options).perform
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.post(client, path, options={})
|
10
|
+
new(client, :post, path, options).perform
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.put(client, path, options={})
|
14
|
+
new(client, :put, path, options).perform
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.delete(client, path, options={})
|
18
|
+
new(client, :delete, path, options).perform
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :client, :method, :path, :options
|
22
|
+
|
23
|
+
def_delegators :client, :get, :post, :put, :delete
|
24
|
+
|
25
|
+
def initialize(client, method, path, options={})
|
26
|
+
@client, @method, @path, @options = client, method, path, options
|
27
|
+
end
|
28
|
+
|
29
|
+
def uri
|
30
|
+
@uri ||= begin
|
31
|
+
uri = URI.parse(path)
|
32
|
+
|
33
|
+
if options[:query] && options[:query] != {}
|
34
|
+
uri.query = to_query(options[:query])
|
35
|
+
end
|
36
|
+
|
37
|
+
uri.to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def perform
|
42
|
+
Twitter.make_friendly(send("perform_#{method}"))
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def perform_get
|
48
|
+
get(uri, options[:headers])
|
49
|
+
end
|
50
|
+
|
51
|
+
def perform_post
|
52
|
+
post(uri, options[:body], options[:headers])
|
53
|
+
end
|
54
|
+
|
55
|
+
def perform_put
|
56
|
+
put(uri, options[:body], options[:headers])
|
57
|
+
end
|
58
|
+
|
59
|
+
def perform_delete
|
60
|
+
delete(uri, options[:headers])
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_query(options)
|
64
|
+
options.inject([]) do |collection, opt|
|
65
|
+
collection << "#{opt[0]}=#{opt[1]}"
|
66
|
+
collection
|
67
|
+
end * '&'
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,163 @@
|
|
1
|
+
require 'pp'
|
2
|
+
module Twitter
|
3
|
+
class Search
|
4
|
+
include HTTParty
|
5
|
+
include Enumerable
|
6
|
+
base_uri "search.twitter.com/search"
|
7
|
+
format :json
|
8
|
+
|
9
|
+
attr_reader :result, :query
|
10
|
+
|
11
|
+
def initialize(q=nil, options={})
|
12
|
+
@options = options
|
13
|
+
clear
|
14
|
+
containing(q) if q && q.strip != ""
|
15
|
+
endpoint_url = options[:api_endpoint]
|
16
|
+
endpoint_url = "#{endpoint_url}/search" if endpoint_url && !endpoint_url.include?("/search")
|
17
|
+
self.class.base_uri(endpoint_url) if endpoint_url
|
18
|
+
end
|
19
|
+
|
20
|
+
def user_agent
|
21
|
+
@options[:user_agent] || "Ruby Twitter Gem"
|
22
|
+
end
|
23
|
+
|
24
|
+
def from(user, exclude=false)
|
25
|
+
@query[:q] << "#{exclude ? "-" : ""}from:#{user}"
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
def to(user, exclude=false)
|
30
|
+
@query[:q] << "#{exclude ? "-" : ""}to:#{user}"
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def referencing(user, exclude=false)
|
35
|
+
@query[:q] << "#{exclude ? "-" : ""}@#{user}"
|
36
|
+
self
|
37
|
+
end
|
38
|
+
alias :references :referencing
|
39
|
+
alias :ref :referencing
|
40
|
+
|
41
|
+
def containing(word, exclude=false)
|
42
|
+
@query[:q] << "#{exclude ? "-" : ""}#{word}"
|
43
|
+
self
|
44
|
+
end
|
45
|
+
alias :contains :containing
|
46
|
+
|
47
|
+
# adds filtering based on hash tag ie: #twitter
|
48
|
+
def hashed(tag, exclude=false)
|
49
|
+
@query[:q] << "#{exclude ? "-" : ""}\##{tag}"
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
# Search for a phrase instead of a group of words
|
54
|
+
def phrase(phrase)
|
55
|
+
@query[:phrase] = phrase
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# lang must be ISO 639-1 code ie: en, fr, de, ja, etc.
|
60
|
+
#
|
61
|
+
# when I tried en it limited my results a lot and took
|
62
|
+
# out several tweets that were english so i'd avoid
|
63
|
+
# this unless you really want it
|
64
|
+
def lang(lang)
|
65
|
+
@query[:lang] = lang
|
66
|
+
self
|
67
|
+
end
|
68
|
+
|
69
|
+
# popular|recent
|
70
|
+
def result_type(result_type)
|
71
|
+
@query[:result_type] = result_type
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
# Limits the number of results per page
|
76
|
+
def per_page(num)
|
77
|
+
@query[:rpp] = num
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
# Which page of results to fetch
|
82
|
+
def page(num)
|
83
|
+
@query[:page] = num
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
# Only searches tweets since a given id.
|
88
|
+
# Recommended to use this when possible.
|
89
|
+
def since(since_id)
|
90
|
+
@query[:since_id] = since_id
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
# From the advanced search form, not documented in the API
|
95
|
+
# Format YYYY-MM-DD
|
96
|
+
def since_date(since_date)
|
97
|
+
@query[:since] = since_date
|
98
|
+
self
|
99
|
+
end
|
100
|
+
|
101
|
+
# From the advanced search form, not documented in the API
|
102
|
+
# Format YYYY-MM-DD
|
103
|
+
def until_date(until_date)
|
104
|
+
@query[:until] = until_date
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
# Ranges like 25km and 50mi work.
|
109
|
+
def geocode(lat, long, range)
|
110
|
+
@query[:geocode] = [lat, long, range].join(",")
|
111
|
+
self
|
112
|
+
end
|
113
|
+
|
114
|
+
def max(id)
|
115
|
+
@query[:max_id] = id
|
116
|
+
self
|
117
|
+
end
|
118
|
+
|
119
|
+
# Clears all the query filters to make a new search
|
120
|
+
def clear
|
121
|
+
@fetch = nil
|
122
|
+
@query = {}
|
123
|
+
@query[:q] = []
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
127
|
+
def fetch(force=false)
|
128
|
+
if @fetch.nil? || force
|
129
|
+
query = @query.dup
|
130
|
+
query[:q] = query[:q].join(" ")
|
131
|
+
perform_get(query)
|
132
|
+
end
|
133
|
+
|
134
|
+
@fetch
|
135
|
+
end
|
136
|
+
|
137
|
+
def each
|
138
|
+
results = fetch()['results']
|
139
|
+
return if results.nil?
|
140
|
+
results.each {|r| yield r}
|
141
|
+
end
|
142
|
+
|
143
|
+
def next_page?
|
144
|
+
!!fetch()["next_page"]
|
145
|
+
end
|
146
|
+
|
147
|
+
def fetch_next_page
|
148
|
+
if next_page?
|
149
|
+
s = Search.new(nil, :user_agent => user_agent)
|
150
|
+
s.perform_get(fetch()["next_page"][1..-1])
|
151
|
+
s
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
protected
|
156
|
+
|
157
|
+
def perform_get(query)
|
158
|
+
response = self.class.get("#{self.class.base_uri}.json", :query => query, :format => :json, :headers => {"User-Agent" => user_agent})
|
159
|
+
@fetch = Twitter.mash(response)
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "local_trends")
|
2
|
+
|
3
|
+
module Twitter
|
4
|
+
class Trends
|
5
|
+
include HTTParty
|
6
|
+
format :json
|
7
|
+
|
8
|
+
def self.api_endpoint
|
9
|
+
@api_endpoint ||= "search.twitter.com/trends"
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.api_endpoint=(value)
|
13
|
+
@api_endpoint = value
|
14
|
+
end
|
15
|
+
|
16
|
+
# :exclude => 'hashtags' to exclude hashtags
|
17
|
+
def self.current(options={})
|
18
|
+
get("/current.json", :query => options)
|
19
|
+
end
|
20
|
+
|
21
|
+
# :exclude => 'hashtags' to exclude hashtags
|
22
|
+
# :date => yyyy-mm-dd for specific date
|
23
|
+
def self.daily(options={})
|
24
|
+
get("/daily.json", :query => options)
|
25
|
+
end
|
26
|
+
|
27
|
+
# :exclude => 'hashtags' to exclude hashtags
|
28
|
+
# :date => yyyy-mm-dd for specific date
|
29
|
+
def self.weekly(options={})
|
30
|
+
get("/weekly.json", :query => options)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.available(query={})
|
34
|
+
#checking for api_endpoint in local_trends
|
35
|
+
LocalTrends.available(query)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.for_location(woeid,options={})
|
39
|
+
#checking for api_endpoint in local_trends
|
40
|
+
LocalTrends.for_location(woeid,options)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def self.get(*args)
|
46
|
+
base_uri api_endpoint
|
47
|
+
mashup(super)
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.mashup(response)
|
51
|
+
response["trends"].values.flatten.map{|t| Twitter.mash(t)}
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|