twitter-multi 0.9.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/History +290 -0
  2. data/License +20 -0
  3. data/Notes +33 -0
  4. data/README.rdoc +19 -0
  5. data/Rakefile +40 -0
  6. data/VERSION.yml +5 -0
  7. data/examples/connect.rb +30 -0
  8. data/examples/friendship_existence.rb +13 -0
  9. data/examples/helpers/config_store.rb +38 -0
  10. data/examples/httpauth.rb +11 -0
  11. data/examples/ids.rb +13 -0
  12. data/examples/lists.rb +11 -0
  13. data/examples/oauth.rb +27 -0
  14. data/examples/search.rb +15 -0
  15. data/examples/timeline.rb +19 -0
  16. data/examples/tumblr.rb +9 -0
  17. data/examples/unauthorized.rb +16 -0
  18. data/examples/update.rb +11 -0
  19. data/examples/user.rb +5 -0
  20. data/lib/twitter/base.rb +390 -0
  21. data/lib/twitter/geo.rb +25 -0
  22. data/lib/twitter/httpauth.rb +53 -0
  23. data/lib/twitter/local_trends.rb +30 -0
  24. data/lib/twitter/oauth.rb +64 -0
  25. data/lib/twitter/request.rb +71 -0
  26. data/lib/twitter/search.rb +163 -0
  27. data/lib/twitter/trends.rb +55 -0
  28. data/lib/twitter.rb +156 -0
  29. data/test/fixtures/blocking.json +1632 -0
  30. data/test/fixtures/firehose.json +1 -0
  31. data/test/fixtures/follower_ids.json +1 -0
  32. data/test/fixtures/followers.json +1 -0
  33. data/test/fixtures/friend_ids.json +1 -0
  34. data/test/fixtures/friends_timeline.json +1 -0
  35. data/test/fixtures/friendship.json +1 -0
  36. data/test/fixtures/friendship_exists.json +1 -0
  37. data/test/fixtures/geo_place.json +1 -0
  38. data/test/fixtures/geo_reverse_geocode.json +1 -0
  39. data/test/fixtures/geo_reverse_geocode_granularity.json +1 -0
  40. data/test/fixtures/geo_reverse_geocode_limit.json +1 -0
  41. data/test/fixtures/geo_search.json +1 -0
  42. data/test/fixtures/geo_search_ip_address.json +1 -0
  43. data/test/fixtures/geo_search_query.json +1 -0
  44. data/test/fixtures/home_timeline.json +1 -0
  45. data/test/fixtures/ids.json +1 -0
  46. data/test/fixtures/list.json +1 -0
  47. data/test/fixtures/list_statuses.json +1 -0
  48. data/test/fixtures/list_statuses_1_1.json +1 -0
  49. data/test/fixtures/list_statuses_2_1.json +1 -0
  50. data/test/fixtures/list_subscriptions.json +1 -0
  51. data/test/fixtures/list_users.json +1 -0
  52. data/test/fixtures/lists.json +1 -0
  53. data/test/fixtures/memberships.json +1 -0
  54. data/test/fixtures/mentions.json +1 -0
  55. data/test/fixtures/not_found.json +1 -0
  56. data/test/fixtures/people_search.json +39 -0
  57. data/test/fixtures/rate_limit_exceeded.json +1 -0
  58. data/test/fixtures/report_spam.json +41 -0
  59. data/test/fixtures/retweet.json +1 -0
  60. data/test/fixtures/retweeted_by_me.json +1 -0
  61. data/test/fixtures/retweeted_to_me.json +1 -0
  62. data/test/fixtures/retweeters_of_tweet.json +166 -0
  63. data/test/fixtures/retweets.json +1 -0
  64. data/test/fixtures/retweets_of_me.json +1 -0
  65. data/test/fixtures/sample-image.png +0 -0
  66. data/test/fixtures/saved_search.json +7 -0
  67. data/test/fixtures/saved_searches.json +16 -0
  68. data/test/fixtures/search.json +1 -0
  69. data/test/fixtures/search_from_jnunemaker.json +1 -0
  70. data/test/fixtures/status.json +1 -0
  71. data/test/fixtures/status_show.json +1 -0
  72. data/test/fixtures/trends_available.json +253 -0
  73. data/test/fixtures/trends_current.json +1 -0
  74. data/test/fixtures/trends_current_exclude.json +1 -0
  75. data/test/fixtures/trends_daily.json +1925 -0
  76. data/test/fixtures/trends_daily_date.json +1 -0
  77. data/test/fixtures/trends_daily_exclude.json +1 -0
  78. data/test/fixtures/trends_location.json +57 -0
  79. data/test/fixtures/trends_weekly.json +1 -0
  80. data/test/fixtures/trends_weekly_date.json +1 -0
  81. data/test/fixtures/trends_weekly_exclude.json +1 -0
  82. data/test/fixtures/unauthorized.json +1 -0
  83. data/test/fixtures/update_profile_background_image.json +1 -0
  84. data/test/fixtures/update_profile_image.json +1 -0
  85. data/test/fixtures/user.json +1 -0
  86. data/test/fixtures/user_timeline.json +710 -0
  87. data/test/fixtures/users.json +1 -0
  88. data/test/test_helper.rb +47 -0
  89. data/test/twitter/base_test.rb +426 -0
  90. data/test/twitter/geo_test.rb +79 -0
  91. data/test/twitter/httpauth_test.rb +86 -0
  92. data/test/twitter/oauth_test.rb +108 -0
  93. data/test/twitter/request_test.rb +217 -0
  94. data/test/twitter/search_test.rb +208 -0
  95. data/test/twitter/trends_test.rb +112 -0
  96. data/test/twitter_test.rb +106 -0
  97. metadata +329 -0
@@ -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
data/lib/twitter.rb ADDED
@@ -0,0 +1,156 @@
1
+ require "forwardable"
2
+ require "oauth"
3
+ require "hashie"
4
+ require "httparty"
5
+ require "multi_json"
6
+
7
+ module Twitter
8
+ include HTTParty
9
+ API_VERSION = "1".freeze
10
+ format :json
11
+
12
+ class TwitterError < StandardError
13
+ attr_reader :data
14
+
15
+ def initialize(data)
16
+ @data = data
17
+ super
18
+ end
19
+ end
20
+
21
+ class RateLimitExceeded < TwitterError; end
22
+ class Unauthorized < TwitterError; end
23
+ class General < TwitterError; end
24
+
25
+ class Unavailable < StandardError; end
26
+ class InformTwitter < StandardError; end
27
+ class NotFound < StandardError; end
28
+
29
+ def self.api_endpoint
30
+ @api_endpoint ||= "api.twitter.com/#{API_VERSION}"
31
+ end
32
+
33
+ def self.api_endpoint=(value)
34
+ @api_endpoint = value
35
+ end
36
+
37
+ def self.firehose(options = {})
38
+ perform_get("/statuses/public_timeline.json")
39
+ end
40
+
41
+ def self.user(id,options={})
42
+ perform_get("/users/show/#{id}.json")
43
+ end
44
+
45
+ def self.status(id,options={})
46
+ perform_get("/statuses/show/#{id}.json")
47
+ end
48
+
49
+ def self.friend_ids(id,options={})
50
+ perform_get("/friends/ids/#{id}.json")
51
+ end
52
+
53
+ def self.follower_ids(id,options={})
54
+ perform_get("/followers/ids/#{id}.json")
55
+ end
56
+
57
+ def self.timeline(id, options={})
58
+ perform_get("/statuses/user_timeline/#{id}.json", :query => options)
59
+ end
60
+
61
+ # :per_page = max number of statues to get at once
62
+ # :page = which page of tweets you wish to get
63
+ def self.list_timeline(list_owner_username, slug, query = {})
64
+ perform_get("/#{list_owner_username}/lists/#{slug}/statuses.json", :query => query)
65
+ end
66
+
67
+ private
68
+
69
+ def self.perform_get(uri, options = {})
70
+ base_uri self.api_endpoint
71
+ make_friendly(get(uri, options))
72
+ end
73
+
74
+ def self.make_friendly(response)
75
+ raise_errors(response)
76
+ data = parse(response)
77
+ # Don't mash arrays of integers
78
+ if data && data.is_a?(Array) && data.first.is_a?(Integer)
79
+ data
80
+ else
81
+ mash(data)
82
+ end
83
+ end
84
+
85
+ def self.raise_errors(response)
86
+ case response.code.to_i
87
+ when 400
88
+ data = parse(response)
89
+ raise RateLimitExceeded.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
90
+ when 401
91
+ data = parse(response)
92
+ raise Unauthorized.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
93
+ when 403
94
+ data = parse(response)
95
+ raise General.new(data), "(#{response.code}): #{response.message} - #{data['error'] if data}"
96
+ when 404
97
+ raise NotFound, "(#{response.code}): #{response.message}"
98
+ when 500
99
+ raise InformTwitter, "Twitter had an internal error. Please let them know in the group. (#{response.code}): #{response.message}"
100
+ when 502..503
101
+ raise Unavailable, "(#{response.code}): #{response.message}"
102
+ end
103
+ end
104
+
105
+ def self.parse(response)
106
+ MultiJson.decode(response.body)
107
+ end
108
+
109
+ def self.mash(obj)
110
+ if obj.is_a?(Array)
111
+ obj.map{|item| make_mash_with_consistent_hash(item)}
112
+ elsif obj.is_a?(Hash)
113
+ make_mash_with_consistent_hash(obj)
114
+ else
115
+ obj
116
+ end
117
+ end
118
+
119
+ # Lame workaround for the fact that mash doesn't hash correctly
120
+ def self.make_mash_with_consistent_hash(obj)
121
+ m = Hashie::Mash.new(obj)
122
+ def m.hash
123
+ inspect.hash
124
+ end
125
+ return m
126
+ end
127
+
128
+ end
129
+
130
+ module Hashie
131
+ class Mash
132
+
133
+ # Converts all of the keys to strings, optionally formatting key name
134
+ def rubyify_keys!
135
+ keys.each{|k|
136
+ v = delete(k)
137
+ new_key = k.to_s.underscore
138
+ self[new_key] = v
139
+ v.rubyify_keys! if v.is_a?(Hash)
140
+ v.each{|p| p.rubyify_keys! if p.is_a?(Hash)} if v.is_a?(Array)
141
+ }
142
+ self
143
+ end
144
+
145
+ end
146
+ end
147
+
148
+ directory = File.expand_path(File.dirname(__FILE__))
149
+
150
+ require File.join(directory, "twitter", "oauth")
151
+ require File.join(directory, "twitter", "httpauth")
152
+ require File.join(directory, "twitter", "request")
153
+ require File.join(directory, "twitter", "base")
154
+ require File.join(directory, "twitter", "search")
155
+ require File.join(directory, "twitter", "trends")
156
+ require File.join(directory, "twitter", "geo")