rorra-twitter 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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 +36 -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 +393 -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 +64 -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 +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 +328 -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,64 @@
1
+ module Twitter
2
+ class OAuth
3
+ extend Forwardable
4
+
5
+ def_delegators :access_token, :get, :post, :put, :delete
6
+
7
+ attr_reader :ctoken, :csecret, :consumer_options, :api_endpoint, :signing_endpoint
8
+
9
+ # Options
10
+ # :sign_in => true to just sign in with twitter instead of doing oauth authorization
11
+ # (http://apiwiki.twitter.com/Sign-in-with-Twitter)
12
+ def initialize(ctoken, csecret, options={})
13
+ @ctoken, @csecret, @consumer_options = ctoken, csecret, {}
14
+ @api_endpoint = options[:api_endpoint] || 'http://api.twitter.com'
15
+ @signing_endpoint = options[:signing_endpoint] || 'http://api.twitter.com'
16
+ if options[:sign_in]
17
+ @consumer_options[:authorize_path] = '/oauth/authenticate'
18
+ end
19
+ end
20
+
21
+ def consumer
22
+ @consumer ||= ::OAuth::Consumer.new(@ctoken, @csecret, {:site => api_endpoint}.merge(consumer_options))
23
+ end
24
+
25
+ def signing_consumer
26
+ @signing_consumer ||= ::OAuth::Consumer.new(@ctoken, @csecret, {:site => signing_endpoint, :request_endpoint => api_endpoint }.merge(consumer_options))
27
+ end
28
+
29
+ def set_callback_url(url)
30
+ clear_request_token
31
+ request_token(:oauth_callback => url)
32
+ end
33
+
34
+ # Note: If using oauth with a web app, be sure to provide :oauth_callback.
35
+ # Options:
36
+ # :oauth_callback => String, url that twitter should redirect to
37
+ def request_token(options={})
38
+ @request_token ||= signing_consumer.get_request_token(options)
39
+ end
40
+
41
+ # For web apps use params[:oauth_verifier], for desktop apps,
42
+ # use the verifier is the pin that twitter gives users.
43
+ def authorize_from_request(rtoken, rsecret, verifier_or_pin)
44
+ request_token = ::OAuth::RequestToken.new(signing_consumer, rtoken, rsecret)
45
+ access_token = request_token.get_access_token(:oauth_verifier => verifier_or_pin)
46
+ @atoken, @asecret = access_token.token, access_token.secret
47
+ end
48
+
49
+ def access_token
50
+ @access_token ||= ::OAuth::AccessToken.new(signing_consumer, @atoken, @asecret)
51
+ end
52
+
53
+ def authorize_from_access(atoken, asecret)
54
+ @atoken, @asecret = atoken, asecret
55
+ end
56
+
57
+ private
58
+
59
+ def clear_request_token
60
+ @request_token = nil
61
+ end
62
+
63
+ end
64
+ 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