twitter 4.3.0 → 4.4.0

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 (60) hide show
  1. data/.yardopts +10 -0
  2. data/CHANGELOG.md +123 -110
  3. data/CONTRIBUTING.md +51 -0
  4. data/README.md +17 -2
  5. data/lib/twitter/api/direct_messages.rb +3 -6
  6. data/lib/twitter/api/favorites.rb +6 -13
  7. data/lib/twitter/api/friends_and_followers.rb +76 -8
  8. data/lib/twitter/api/lists.rb +65 -36
  9. data/lib/twitter/api/places_and_geo.rb +3 -3
  10. data/lib/twitter/api/saved_searches.rb +2 -2
  11. data/lib/twitter/api/spam_reporting.rb +2 -2
  12. data/lib/twitter/api/suggested_users.rb +1 -1
  13. data/lib/twitter/api/timelines.rb +12 -8
  14. data/lib/twitter/api/tweets.rb +8 -12
  15. data/lib/twitter/api/undocumented.rb +3 -3
  16. data/lib/twitter/api/users.rb +16 -10
  17. data/lib/twitter/api/utils.rb +109 -30
  18. data/lib/twitter/base.rb +15 -5
  19. data/lib/twitter/basic_user.rb +0 -1
  20. data/lib/twitter/client.rb +16 -37
  21. data/lib/twitter/core_ext/enumerable.rb +2 -2
  22. data/lib/twitter/default.rb +5 -8
  23. data/lib/twitter/exceptable.rb +36 -0
  24. data/lib/twitter/factory.rb +4 -4
  25. data/lib/twitter/list.rb +0 -1
  26. data/lib/twitter/request/multipart_with_file.rb +5 -7
  27. data/lib/twitter/search_results.rb +10 -6
  28. data/lib/twitter/settings.rb +0 -1
  29. data/lib/twitter/source_user.rb +0 -7
  30. data/lib/twitter/target_user.rb +0 -1
  31. data/lib/twitter/tweet.rb +15 -17
  32. data/lib/twitter/user.rb +4 -14
  33. data/lib/twitter/version.rb +4 -4
  34. data/spec/fixtures/followers_list.json +1 -0
  35. data/spec/fixtures/friends_list.json +1 -0
  36. data/spec/fixtures/ids_list.json +1 -1
  37. data/spec/fixtures/ids_list2.json +1 -1
  38. data/spec/helper.rb +9 -8
  39. data/spec/twitter/action_factory_spec.rb +1 -1
  40. data/spec/twitter/api/favorites_spec.rb +2 -2
  41. data/spec/twitter/api/friends_and_followers_spec.rb +102 -2
  42. data/spec/twitter/api/spam_reporting_spec.rb +2 -2
  43. data/spec/twitter/api/tweets_spec.rb +2 -2
  44. data/spec/twitter/api/users_spec.rb +107 -49
  45. data/spec/twitter/base_spec.rb +1 -1
  46. data/spec/twitter/client_spec.rb +4 -4
  47. data/spec/twitter/cursor_spec.rb +2 -2
  48. data/spec/twitter/error/client_error_spec.rb +16 -5
  49. data/spec/twitter/error/server_error_spec.rb +1 -1
  50. data/spec/twitter/error_spec.rb +2 -2
  51. data/spec/twitter/geo_factory_spec.rb +1 -1
  52. data/spec/twitter/identifiable_spec.rb +2 -2
  53. data/spec/twitter/media_factory_spec.rb +1 -1
  54. data/spec/twitter/search_results_spec.rb +11 -0
  55. data/spec/twitter/tweet_spec.rb +11 -0
  56. data/twitter.gemspec +3 -2
  57. metadata +190 -173
  58. data/lib/twitter/core_ext/array.rb +0 -7
  59. data/lib/twitter/core_ext/hash.rb +0 -100
  60. data/lib/twitter/core_ext/string.rb +0 -10
@@ -3,7 +3,6 @@ require 'twitter/identity'
3
3
  module Twitter
4
4
  class BasicUser < Twitter::Identity
5
5
  attr_reader :following, :screen_name
6
- alias following? following
7
6
  alias handle screen_name
8
7
  alias username screen_name
9
8
  alias user_name screen_name
@@ -27,7 +27,6 @@ module Twitter
27
27
  # @note All methods have been separated into modules and follow the same grouping used in {http://dev.twitter.com/doc the Twitter API Documentation}.
28
28
  # @see http://dev.twitter.com/pages/every_developer
29
29
  class Client
30
- include Twitter::API
31
30
  include Twitter::API::DirectMessages
32
31
  include Twitter::API::Favorites
33
32
  include Twitter::API::FriendsAndFollowers
@@ -67,57 +66,37 @@ module Twitter
67
66
 
68
67
  # Perform an HTTP POST request
69
68
  def post(path, params={})
70
- request(:post, path, params)
69
+ signature_params = params.values.any?{|value| value.respond_to?(:to_io)} ? {} : params
70
+ request(:post, path, params, signature_params)
71
71
  end
72
72
 
73
- # Perform an HTTP UPDATE request
73
+ # Perform an HTTP PUT request
74
74
  def put(path, params={})
75
75
  request(:put, path, params)
76
76
  end
77
77
 
78
78
  private
79
79
 
80
- # Returns a Faraday::Connection object
81
- #
82
- # @return [Faraday::Connection]
83
- def connection
84
- @connection ||= Faraday.new(@endpoint, @connection_options.merge(:builder => @middleware))
85
- end
86
-
87
- # Perform an HTTP request
88
- #
89
- # @raise [Twitter::Error::ClientError, Twitter::Error::DecodeError]
90
- def request(method, path, params={})
91
- uri = URI(@endpoint) unless uri.respond_to?(:host)
92
- uri += path
93
- request_headers = {}
94
- if credentials?
95
- authorization = auth_header(method, uri, params)
96
- request_headers[:authorization] = authorization.to_s
97
- end
98
- connection.url_prefix = @endpoint
99
- response = connection.run_request(method.to_sym, path, nil, request_headers) do |request|
100
- unless params.empty?
101
- case request.method
102
- when :post, :put
103
- request.body = params
104
- else
105
- request.params.update(params)
106
- end
107
- end
108
- yield request if block_given?
80
+ def request(method, path, params={}, signature_params=params)
81
+ connection.send(method.to_sym, path, params) do |request|
82
+ request.headers[:authorization] = auth_header(method.to_sym, path, signature_params).to_s
109
83
  end.env
110
- response
111
84
  rescue Faraday::Error::ClientError
112
85
  raise Twitter::Error::ClientError
113
86
  rescue MultiJson::DecodeError
114
87
  raise Twitter::Error::DecodeError
115
88
  end
116
89
 
117
- def auth_header(method, uri, params={})
118
- # When posting a file, don't sign any params
119
- signature_params = [:post, :put].include?(method.to_sym) && params.values.any?{|value| value.respond_to?(:to_io)} ? {} : params
120
- SimpleOAuth::Header.new(method, uri, signature_params, credentials)
90
+ # Returns a Faraday::Connection object
91
+ #
92
+ # @return [Faraday::Connection]
93
+ def connection
94
+ @connection ||= Faraday.new(@endpoint, @connection_options.merge(:builder => @middleware))
95
+ end
96
+
97
+ def auth_header(method, path, params={})
98
+ uri = URI(@endpoint + path)
99
+ SimpleOAuth::Header.new(method, uri, params, credentials)
121
100
  end
122
101
 
123
102
  end
@@ -15,9 +15,9 @@ private
15
15
  def abort_on_exception
16
16
  initial_abort_on_exception = Thread.abort_on_exception
17
17
  Thread.abort_on_exception ||= true
18
- value = yield
18
+ yield
19
+ ensure
19
20
  Thread.abort_on_exception = initial_abort_on_exception
20
- value
21
21
  end
22
22
 
23
23
  end
@@ -2,7 +2,6 @@ require 'faraday'
2
2
  require 'twitter/configurable'
3
3
  require 'twitter/error/client_error'
4
4
  require 'twitter/error/server_error'
5
- require 'twitter/identity_map'
6
5
  require 'twitter/request/multipart_with_file'
7
6
  require 'twitter/response/parse_json'
8
7
  require 'twitter/response/raise_error'
@@ -10,7 +9,7 @@ require 'twitter/version'
10
9
 
11
10
  module Twitter
12
11
  module Default
13
- ENDPOINT = 'https://api.twitter.com' unless defined? ENDPOINT
12
+ ENDPOINT = 'https://api.twitter.com' unless defined? Twitter::Default::ENDPOINT
14
13
  CONNECTION_OPTIONS = {
15
14
  :headers => {
16
15
  :accept => 'application/json',
@@ -20,8 +19,8 @@ module Twitter
20
19
  :raw => true,
21
20
  :ssl => {:verify => false},
22
21
  :timeout => 10,
23
- } unless defined? CONNECTION_OPTIONS
24
- IDENTITY_MAP = false unless defined? IDENTITY_MAP
22
+ } unless defined? Twitter::Default::CONNECTION_OPTIONS
23
+ IDENTITY_MAP = false unless defined? Twitter::Default::IDENTITY_MAP
25
24
  MIDDLEWARE = Faraday::Builder.new do |builder|
26
25
  # Convert file uploads to Faraday::UploadIO objects
27
26
  builder.use Twitter::Request::MultipartWithFile
@@ -37,7 +36,7 @@ module Twitter
37
36
  builder.use Twitter::Response::RaiseError, Twitter::Error::ServerError
38
37
  # Set Faraday's HTTP adapter
39
38
  builder.adapter Faraday.default_adapter
40
- end
39
+ end unless defined? Twitter::Default::MIDDLEWARE
41
40
 
42
41
  class << self
43
42
 
@@ -66,7 +65,7 @@ module Twitter
66
65
  ENV['TWITTER_OAUTH_TOKEN_SECRET']
67
66
  end
68
67
 
69
- # @note This is configurable in case you want to use HTTP instead of HTTPS or use a Twitter-compatible endpoint.
68
+ # @note This is configurable in case you want to use a Twitter-compatible endpoint.
70
69
  # @see http://status.net/wiki/Twitter-compatible_API
71
70
  # @see http://en.blog.wordpress.com/2009/12/12/twitter-api/
72
71
  # @see http://staff.tumblr.com/post/287703110/api
@@ -76,12 +75,10 @@ module Twitter
76
75
  ENDPOINT
77
76
  end
78
77
 
79
- # @return [Hash]
80
78
  def connection_options
81
79
  CONNECTION_OPTIONS
82
80
  end
83
81
 
84
- # @return [Twitter::IdentityMap]
85
82
  def identity_map
86
83
  IDENTITY_MAP
87
84
  end
@@ -0,0 +1,36 @@
1
+ module Twitter
2
+ module Exceptable
3
+
4
+ private
5
+
6
+ # Return a hash that includes everything but the given keys.
7
+ #
8
+ # @param klass [Class]
9
+ # @param hash [Hash]
10
+ # @param key1 [Symbol]
11
+ # @param key2 [Symbol]
12
+ def fetch_or_new_without_self(klass, hash, key1, key2)
13
+ klass.fetch_or_new(hash.dup[key1].merge(key2 => except(hash, key1))) unless hash[key1].nil?
14
+ end
15
+
16
+ # Return a hash that includes everything but the given keys.
17
+ #
18
+ # @param hash [Hash]
19
+ # @param key [Symbol]
20
+ # @return [Hash]
21
+ def except(hash, key)
22
+ except!(hash.dup, key)
23
+ end
24
+
25
+ # Replaces the hash without the given keys.
26
+ #
27
+ # @param hash [Hash]
28
+ # @param key [Symbol]
29
+ # @return [Hash]
30
+ def except!(hash, key)
31
+ hash.delete(key)
32
+ hash
33
+ end
34
+
35
+ end
36
+ end
@@ -1,5 +1,3 @@
1
- require 'twitter/core_ext/string'
2
-
3
1
  module Twitter
4
2
  class Factory
5
3
 
@@ -10,8 +8,10 @@ module Twitter
10
8
  # @return [Twitter::Action::Favorite, Twitter::Action::Follow, Twitter::Action::ListMemberAdded, Twitter::Action::Mention, Twitter::Action::Reply, Twitter::Action::Retweet]
11
9
  def self.fetch_or_new(method, klass, attrs={})
12
10
  return unless attrs
13
- if type = attrs.delete(method.to_sym)
14
- klass.const_get(type.camelize.to_sym).fetch_or_new(attrs)
11
+ type = attrs.delete(method.to_sym)
12
+ if type
13
+ const_name = type.gsub(/\/(.?)/){"::#{$1.upcase}"}.gsub(/(?:^|_)(.)/){$1.upcase}
14
+ klass.const_get(const_name.to_sym).fetch_or_new(attrs)
15
15
  else
16
16
  raise ArgumentError, "argument must have :#{method} key"
17
17
  end
@@ -7,7 +7,6 @@ module Twitter
7
7
  include Twitter::Creatable
8
8
  attr_reader :description, :following, :full_name, :member_count,
9
9
  :mode, :name, :slug, :subscriber_count, :uri
10
- alias following? following
11
10
 
12
11
  # @return [Twitter::User]
13
12
  def user
@@ -10,14 +10,12 @@ module Twitter
10
10
  end
11
11
 
12
12
  def call(env)
13
- if env[:body].is_a?(Hash)
14
- env[:body].each do |key, value|
15
- if value.respond_to?(:to_io)
16
- env[:body][key] = Faraday::UploadIO.new(value, mime_type(value.path), value.path)
17
- env[:request_headers][CONTENT_TYPE] = self.class.mime_type
18
- end
13
+ env[:body].each do |key, value|
14
+ if value.respond_to?(:to_io)
15
+ env[:body][key] = Faraday::UploadIO.new(value, mime_type(value.path), value.path)
16
+ env[:request_headers][CONTENT_TYPE] = self.class.mime_type
19
17
  end
20
- end
18
+ end if env[:body].is_a?(::Hash)
21
19
  @app.call(env)
22
20
  end
23
21
 
@@ -15,33 +15,37 @@ module Twitter
15
15
 
16
16
  # @return [Float]
17
17
  def completed_in
18
- @attrs[:search_metadata][:completed_in] unless @attrs[:search_metadata].nil?
18
+ @attrs[:search_metadata][:completed_in] if search_metadata?
19
19
  end
20
20
 
21
21
  # @return [Integer]
22
22
  def max_id
23
- @attrs[:search_metadata][:max_id] unless @attrs[:search_metadata].nil?
23
+ @attrs[:search_metadata][:max_id] if search_metadata?
24
24
  end
25
25
 
26
26
  # @return [Integer]
27
27
  def page
28
- @attrs[:search_metadata][:page] unless @attrs[:search_metadata].nil?
28
+ @attrs[:search_metadata][:page] if search_metadata?
29
29
  end
30
30
 
31
31
  # @return [String]
32
32
  def query
33
- @attrs[:search_metadata][:query] unless @attrs[:search_metadata].nil?
33
+ @attrs[:search_metadata][:query] if search_metadata?
34
34
  end
35
35
 
36
36
  # @return [Integer]
37
37
  def results_per_page
38
- @attrs[:search_metadata][:results_per_page] unless @attrs[:search_metadata].nil?
38
+ @attrs[:search_metadata][:results_per_page] if search_metadata?
39
39
  end
40
40
  alias rpp results_per_page
41
41
 
42
+ def search_metadata?
43
+ !@attrs[:search_metadata].nil?
44
+ end
45
+
42
46
  # @return [Integer]
43
47
  def since_id
44
- @attrs[:search_metadata][:since_id] unless @attrs[:search_metadata].nil?
48
+ @attrs[:search_metadata][:since_id] if search_metadata?
45
49
  end
46
50
 
47
51
  end
@@ -6,7 +6,6 @@ module Twitter
6
6
  attr_reader :always_use_https, :discoverable_by_email, :geo_enabled,
7
7
  :language, :protected, :screen_name, :show_all_inline_media, :sleep_time,
8
8
  :time_zone
9
- alias protected? protected
10
9
 
11
10
  # @return [Twitter::Place]
12
11
  def trend_location
@@ -4,12 +4,5 @@ module Twitter
4
4
  class SourceUser < Twitter::BasicUser
5
5
  attr_reader :all_replies, :blocking, :can_dm, :followed_by, :marked_spam,
6
6
  :notifications_enabled, :want_retweets
7
- alias all_replies? all_replies
8
- alias blocking? blocking
9
- alias can_dm? can_dm
10
- alias followed_by? followed_by
11
- alias marked_spam? marked_spam
12
- alias notifications_enabled? notifications_enabled
13
- alias want_retweets? want_retweets
14
7
  end
15
8
  end
@@ -3,6 +3,5 @@ require 'twitter/basic_user'
3
3
  module Twitter
4
4
  class TargetUser < Twitter::BasicUser
5
5
  attr_reader :followed_by
6
- alias followed_by? followed_by
7
6
  end
8
7
  end
@@ -1,8 +1,8 @@
1
- require 'twitter/core_ext/hash'
2
1
  require 'twitter/creatable'
3
2
  require 'twitter/entity/hashtag'
4
3
  require 'twitter/entity/url'
5
4
  require 'twitter/entity/user_mention'
5
+ require 'twitter/exceptable'
6
6
  require 'twitter/geo_factory'
7
7
  require 'twitter/identity'
8
8
  require 'twitter/media_factory'
@@ -13,18 +13,21 @@ require 'twitter/user'
13
13
  module Twitter
14
14
  class Tweet < Twitter::Identity
15
15
  include Twitter::Creatable
16
+ include Twitter::Exceptable
16
17
  attr_reader :favorited, :favoriters, :from_user_id, :from_user_name,
17
18
  :in_reply_to_screen_name, :in_reply_to_attrs_id, :in_reply_to_status_id,
18
19
  :in_reply_to_user_id, :iso_language_code, :profile_image_url,
19
20
  :profile_image_url_https, :repliers, :retweeted, :retweeters, :source,
20
21
  :text, :to_user, :to_user_id, :to_user_name, :truncated
21
22
  alias in_reply_to_tweet_id in_reply_to_status_id
22
- alias favorited? favorited
23
23
  alias favourited favorited
24
- alias favourited? favorited
24
+ alias favourited? favorited?
25
25
  alias favouriters favoriters
26
- alias retweeted? retweeted
27
- alias truncated? truncated
26
+
27
+ # @return [Boolean]
28
+ def entities?
29
+ !@attrs[:entities].nil?
30
+ end
28
31
 
29
32
  # @return [Integer]
30
33
  def favoriters_count
@@ -121,7 +124,7 @@ module Twitter
121
124
 
122
125
  # @return [Twitter::User]
123
126
  def user
124
- @user ||= Twitter::User.fetch_or_new(@attrs.dup[:user].merge(:status => @attrs.except(:user))) if user?
127
+ @user ||= fetch_or_new_without_self(Twitter::User, @attrs, :user, :status)
125
128
  end
126
129
 
127
130
  # @note Must include entities in your request for this method to work
@@ -130,30 +133,25 @@ module Twitter
130
133
  @user_mentions ||= entities(Twitter::Entity::UserMention, :user_mentions)
131
134
  end
132
135
 
133
- # @return [Boolean]
134
- def entities?
135
- !@attrs[:entities].nil?
136
+ def user?
137
+ !@attrs[:user].nil?
136
138
  end
137
139
 
138
140
  private
139
141
 
140
142
  # @param klass [Class]
141
- # @param method [Symbol]
142
- def entities(klass, method)
143
+ # @param key [Symbol]
144
+ def entities(klass, key)
143
145
  if entities?
144
- Array(@attrs[:entities][method.to_sym]).map do |user_mention|
146
+ Array(@attrs[:entities][key.to_sym]).map do |user_mention|
145
147
  klass.fetch_or_new(user_mention)
146
148
  end
147
149
  else
148
- warn "#{Kernel.caller.first}: To get #{method.to_s.tr('_', ' ')}, you must pass `:include_entities => true` when requesting the #{self.class.name}."
150
+ warn "#{Kernel.caller.first}: To get #{key.to_s.tr('_', ' ')}, you must pass `:include_entities => true` when requesting the #{self.class.name}."
149
151
  []
150
152
  end
151
153
  end
152
154
 
153
- def user?
154
- !@attrs[:user].nil?
155
- end
156
-
157
155
  end
158
156
 
159
157
  Status = Tweet
@@ -1,12 +1,13 @@
1
1
  require 'twitter/basic_user'
2
- require 'twitter/core_ext/hash'
3
2
  require 'twitter/creatable'
3
+ require 'twitter/exceptable'
4
4
  require 'twitter/tweet'
5
5
 
6
6
  module Twitter
7
7
  class User < Twitter::BasicUser
8
8
  PROFILE_IMAGE_SUFFIX_REGEX = /_normal(\.gif|\.jpe?g|\.png)$/
9
9
  include Twitter::Creatable
10
+ include Twitter::Exceptable
10
11
  attr_reader :connections, :contributors_enabled, :default_profile,
11
12
  :default_profile_image, :description, :favourites_count,
12
13
  :follow_request_sent, :followers_count, :friends_count, :geo_enabled,
@@ -17,10 +18,6 @@ module Twitter
17
18
  :profile_sidebar_fill_color, :profile_text_color,
18
19
  :profile_use_background_image, :protected, :statuses_count, :time_zone,
19
20
  :url, :utc_offset, :verified
20
- alias contributors_enabled? contributors_enabled
21
- alias default_profile? default_profile
22
- alias default_profile_image? default_profile_image
23
- alias follow_request_sent? follow_request_sent
24
21
  alias favorite_count favourites_count
25
22
  alias favoriters_count favourites_count
26
23
  alias favorites_count favourites_count
@@ -28,20 +25,13 @@ module Twitter
28
25
  alias favouriters_count favourites_count
29
26
  alias follower_count followers_count
30
27
  alias friend_count friends_count
31
- alias geo_enabled? geo_enabled
32
- alias is_translator? is_translator
33
- alias notifications? notifications
34
- alias profile_background_tile? profile_background_tile
35
- alias profile_use_background_image? profile_use_background_image
36
- alias protected? protected
37
28
  alias status_count statuses_count
38
29
  alias translator is_translator
39
- alias translator? is_translator
30
+ alias translator? is_translator?
40
31
  alias tweet_count statuses_count
41
32
  alias tweets_count statuses_count
42
33
  alias update_count statuses_count
43
34
  alias updates_count statuses_count
44
- alias verified? verified
45
35
 
46
36
  # Return the URL to the user's profile banner image
47
37
  #
@@ -93,7 +83,7 @@ module Twitter
93
83
 
94
84
  # @return [Twitter::Tweet]
95
85
  def status
96
- @status ||= Twitter::Tweet.fetch_or_new(@attrs.dup[:status].merge(:user => @attrs.except(:status))) if status?
86
+ @status ||= fetch_or_new_without_self(Twitter::Tweet, @attrs, :status, :user)
97
87
  end
98
88
 
99
89
  def status?