jlind-twitter 0.9.9

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.rb +156 -0
  21. data/lib/twitter/base.rb +390 -0
  22. data/lib/twitter/geo.rb +25 -0
  23. data/lib/twitter/httpauth.rb +53 -0
  24. data/lib/twitter/local_trends.rb +30 -0
  25. data/lib/twitter/oauth.rb +85 -0
  26. data/lib/twitter/request.rb +71 -0
  27. data/lib/twitter/search.rb +163 -0
  28. data/lib/twitter/trends.rb +55 -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 +127 -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 +305 -0
@@ -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