twitter 5.0.0.rc.1 → 5.0.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.
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +7 -1
- data/CONTRIBUTING.md +13 -15
- data/README.md +53 -33
- data/Rakefile +6 -0
- data/lib/twitter/arguments.rb +3 -0
- data/lib/twitter/base.rb +88 -89
- data/lib/twitter/client.rb +5 -41
- data/lib/twitter/configuration.rb +4 -5
- data/lib/twitter/core_ext/kernel.rb +5 -1
- data/lib/twitter/creatable.rb +6 -1
- data/lib/twitter/cursor.rb +16 -12
- data/lib/twitter/entity/uri.rb +2 -1
- data/lib/twitter/enumerable.rb +1 -1
- data/lib/twitter/error.rb +42 -39
- data/lib/twitter/factory.rb +12 -5
- data/lib/twitter/geo.rb +2 -7
- data/lib/twitter/geo_factory.rb +11 -7
- data/lib/twitter/geo_results.rb +12 -8
- data/lib/twitter/identity.rb +4 -12
- data/lib/twitter/list.rb +6 -3
- data/lib/twitter/media/photo.rb +5 -3
- data/lib/twitter/media_factory.rb +11 -7
- data/lib/twitter/null_object.rb +4 -3
- data/lib/twitter/place.rb +10 -16
- data/lib/twitter/profile_banner.rb +4 -5
- data/lib/twitter/rate_limit.rb +3 -0
- data/lib/twitter/relationship.rb +0 -9
- data/lib/twitter/rest/api/direct_messages.rb +9 -6
- data/lib/twitter/rest/api/favorites.rb +6 -11
- data/lib/twitter/rest/api/friends_and_followers.rb +6 -9
- data/lib/twitter/rest/api/lists.rb +27 -20
- data/lib/twitter/rest/api/oauth.rb +17 -0
- data/lib/twitter/rest/api/places_and_geo.rb +0 -18
- data/lib/twitter/rest/api/saved_searches.rb +6 -4
- data/lib/twitter/rest/api/suggested_users.rb +2 -2
- data/lib/twitter/rest/api/tweets.rb +7 -9
- data/lib/twitter/rest/api/users.rb +6 -6
- data/lib/twitter/rest/api/utils.rb +44 -17
- data/lib/twitter/rest/client.rb +25 -43
- data/lib/twitter/rest/response/parse_error_json.rb +15 -0
- data/lib/twitter/rest/response/parse_json.rb +5 -1
- data/lib/twitter/search_results.rb +12 -8
- data/lib/twitter/size.rb +2 -15
- data/lib/twitter/streaming/client.rb +23 -11
- data/lib/twitter/streaming/event.rb +35 -0
- data/lib/twitter/streaming/friend_list.rb +13 -0
- data/lib/twitter/streaming/message_parser.rb +18 -0
- data/lib/twitter/streaming/response.rb +4 -0
- data/lib/twitter/suggestion.rb +5 -10
- data/lib/twitter/token.rb +3 -1
- data/lib/twitter/trend.rb +2 -7
- data/lib/twitter/trend_results.rb +20 -14
- data/lib/twitter/tweet.rb +18 -23
- data/lib/twitter/user.rb +34 -19
- data/lib/twitter/version.rb +1 -1
- data/spec/fixtures/request_token.txt +6 -0
- data/spec/fixtures/track_streaming_user.json +5 -0
- data/spec/twitter/base_spec.rb +0 -16
- data/spec/twitter/basic_user_spec.rb +3 -3
- data/spec/twitter/cursor_spec.rb +4 -4
- data/spec/twitter/direct_message_spec.rb +9 -9
- data/spec/twitter/entity/uri_spec.rb +12 -11
- data/spec/twitter/geo/point_spec.rb +5 -5
- data/spec/twitter/geo/polygon_spec.rb +5 -5
- data/spec/twitter/geo_factory_spec.rb +2 -2
- data/spec/twitter/geo_spec.rb +6 -6
- data/spec/twitter/identifiable_spec.rb +5 -5
- data/spec/twitter/list_spec.rb +7 -7
- data/spec/twitter/media/photo_spec.rb +19 -18
- data/spec/twitter/media_factory_spec.rb +2 -2
- data/spec/twitter/null_object_spec.rb +7 -6
- data/spec/twitter/oembed_spec.rb +6 -6
- data/spec/twitter/place_spec.rb +37 -37
- data/spec/twitter/rate_limit_spec.rb +0 -17
- data/spec/twitter/relationship_spec.rb +4 -12
- data/spec/twitter/rest/api/direct_messages_spec.rb +8 -8
- data/spec/twitter/rest/api/friends_and_followers_spec.rb +50 -120
- data/spec/twitter/rest/api/geo_spec.rb +0 -14
- data/spec/twitter/rest/api/lists_spec.rb +39 -39
- data/spec/twitter/rest/api/oauth_spec.rb +15 -4
- data/spec/twitter/rest/api/saved_searches_spec.rb +6 -6
- data/spec/twitter/rest/api/tweets_spec.rb +6 -6
- data/spec/twitter/rest/api/users_spec.rb +4 -4
- data/spec/twitter/rest/client_spec.rb +9 -9
- data/spec/twitter/saved_search_spec.rb +5 -5
- data/spec/twitter/search_results_spec.rb +3 -3
- data/spec/twitter/settings_spec.rb +2 -2
- data/spec/twitter/size_spec.rb +5 -15
- data/spec/twitter/source_user_spec.rb +3 -3
- data/spec/twitter/streaming/client_spec.rb +33 -16
- data/spec/twitter/streaming/event_spec.rb +45 -0
- data/spec/twitter/suggestion_spec.rb +5 -15
- data/spec/twitter/target_user_spec.rb +3 -3
- data/spec/twitter/token_spec.rb +2 -2
- data/spec/twitter/trend_results_spec.rb +6 -6
- data/spec/twitter/trend_spec.rb +7 -17
- data/spec/twitter/tweet_spec.rb +31 -25
- data/spec/twitter/user_spec.rb +16 -16
- data/twitter.gemspec +5 -2
- metadata +67 -15
- metadata.gz.sig +0 -0
data/lib/twitter/client.rb
CHANGED
@@ -4,15 +4,16 @@ require 'uri'
|
|
4
4
|
|
5
5
|
module Twitter
|
6
6
|
class Client
|
7
|
-
|
8
|
-
|
7
|
+
attr_accessor :access_token, :access_token_secret, :consumer_key, :consumer_secret
|
8
|
+
alias oauth_token access_token
|
9
9
|
alias oauth_token= access_token=
|
10
|
+
alias oauth_token_secret access_token_secret
|
10
11
|
alias oauth_token_secret= access_token_secret=
|
11
12
|
|
12
13
|
# Initializes a new Client object
|
13
14
|
#
|
14
15
|
# @param options [Hash]
|
15
|
-
# @return [Twitter::
|
16
|
+
# @return [Twitter::Client]
|
16
17
|
def initialize(options={})
|
17
18
|
options.each do |key, value|
|
18
19
|
send(:"#{key}=", value)
|
@@ -21,49 +22,12 @@ module Twitter
|
|
21
22
|
validate_credential_type!
|
22
23
|
end
|
23
24
|
|
24
|
-
# @return [String]
|
25
|
-
def consumer_key
|
26
|
-
if instance_variable_defined?(:@consumer_key)
|
27
|
-
@consumer_key
|
28
|
-
else
|
29
|
-
ENV['TWITTER_CONSUMER_KEY']
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
# @return [String]
|
34
|
-
def consumer_secret
|
35
|
-
if instance_variable_defined?(:@consumer_secret)
|
36
|
-
@consumer_secret
|
37
|
-
else
|
38
|
-
ENV['TWITTER_CONSUMER_SECRET']
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# @return [String]
|
43
|
-
def access_token
|
44
|
-
if instance_variable_defined?(:@access_token)
|
45
|
-
@access_token
|
46
|
-
else
|
47
|
-
ENV['TWITTER_ACCESS_TOKEN'] || ENV['TWITTER_OAUTH_TOKEN']
|
48
|
-
end
|
49
|
-
end
|
50
|
-
alias oauth_token access_token
|
51
|
-
|
52
|
-
# @return [String]
|
53
|
-
def access_token_secret
|
54
|
-
if instance_variable_defined?(:@access_token_secret)
|
55
|
-
@access_token_secret
|
56
|
-
else
|
57
|
-
ENV['TWITTER_ACCESS_TOKEN_SECRET'] || ENV['TWITTER_OAUTH_TOKEN_SECRET']
|
58
|
-
end
|
59
|
-
end
|
60
|
-
alias oauth_token_secret access_token_secret
|
61
|
-
|
62
25
|
# @return [Boolean]
|
63
26
|
def user_token?
|
64
27
|
!!(access_token && access_token_secret)
|
65
28
|
end
|
66
29
|
|
30
|
+
# @return [String]
|
67
31
|
def user_agent
|
68
32
|
@user_agent ||= "Twitter Ruby Gem #{Twitter::Version}"
|
69
33
|
end
|
@@ -11,13 +11,12 @@ module Twitter
|
|
11
11
|
#
|
12
12
|
# @return [Array<Twitter::Size>]
|
13
13
|
def photo_sizes
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
object
|
18
|
-
end
|
14
|
+
Array(@attrs[:photo_sizes]).inject({}) do |object, (key, value)|
|
15
|
+
object[key] = Size.new(value)
|
16
|
+
object
|
19
17
|
end
|
20
18
|
end
|
19
|
+
memoize :photo_sizes
|
21
20
|
|
22
21
|
end
|
23
22
|
end
|
@@ -1,6 +1,10 @@
|
|
1
1
|
module Kernel
|
2
2
|
|
3
3
|
# Returns the object's singleton class (exists in Ruby 1.9.2)
|
4
|
-
def singleton_class
|
4
|
+
def singleton_class
|
5
|
+
class << self
|
6
|
+
self
|
7
|
+
end
|
8
|
+
end unless method_defined?(:singleton_class)
|
5
9
|
|
6
10
|
end
|
data/lib/twitter/creatable.rb
CHANGED
@@ -1,18 +1,23 @@
|
|
1
1
|
require 'time'
|
2
|
+
require 'memoizable'
|
2
3
|
|
3
4
|
module Twitter
|
4
5
|
module Creatable
|
6
|
+
include Memoizable
|
5
7
|
|
6
8
|
# Time when the object was created on Twitter
|
7
9
|
#
|
8
10
|
# @return [Time]
|
9
11
|
def created_at
|
10
|
-
|
12
|
+
Time.parse(@attrs[:created_at]) if @attrs[:created_at]
|
11
13
|
end
|
14
|
+
memoize :created_at
|
12
15
|
|
16
|
+
# @return [Boolean]
|
13
17
|
def created?
|
14
18
|
!!@attrs[:created_at]
|
15
19
|
end
|
20
|
+
memoize :created?
|
16
21
|
|
17
22
|
end
|
18
23
|
end
|
data/lib/twitter/cursor.rb
CHANGED
@@ -8,18 +8,22 @@ module Twitter
|
|
8
8
|
alias to_hash attrs
|
9
9
|
alias to_hsh attrs
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# Construct a new Cursor object from a response hash
|
14
|
+
#
|
15
|
+
# @param response [Hash]
|
16
|
+
# @param key [String, Symbol] The key to fetch the data from the response
|
17
|
+
# @param klass [Class] The class to instantiate objects in the response
|
18
|
+
# @param client [Twitter::REST::Client]
|
19
|
+
# @param request_method [String, Symbol]
|
20
|
+
# @param path [String]
|
21
|
+
# @param options [Hash]
|
22
|
+
# @return [Twitter::Cursor]
|
23
|
+
def from_response(response, key, klass, client, request_method, path, options)
|
24
|
+
new(response[:body], key, klass, client, request_method, path, options)
|
25
|
+
end
|
26
|
+
|
23
27
|
end
|
24
28
|
|
25
29
|
# Initializes a new Cursor
|
data/lib/twitter/entity/uri.rb
CHANGED
data/lib/twitter/enumerable.rb
CHANGED
data/lib/twitter/error.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
require 'descendants_tracker'
|
1
2
|
require 'twitter/rate_limit'
|
2
3
|
|
3
4
|
module Twitter
|
4
5
|
# Custom error class for rescuing from all Twitter errors
|
5
6
|
class Error < StandardError
|
7
|
+
extend DescendantsTracker
|
6
8
|
attr_reader :rate_limit, :wrapped_exception, :code
|
7
9
|
|
8
10
|
# If error code is missing see https://dev.twitter.com/docs/error-codes-responses
|
@@ -16,36 +18,54 @@ module Twitter
|
|
16
18
|
OVER_CAPACITY = 130
|
17
19
|
INTERNAL_ERROR = 131
|
18
20
|
OAUTH_TIMESTAMP_OUT_OF_RANGE = 135
|
21
|
+
FOLLOW_LIMIT_EXCEEDED = 161
|
22
|
+
PROTECTED_STATUS = 179
|
19
23
|
DUPLICATE_STATUS = 187
|
20
24
|
BAD_AUTHENTICATION_DATA = 215
|
21
25
|
LOGIN_VERIFICATION_NEEDED = 231
|
26
|
+
ENDPOINT_RETIRED = 251
|
22
27
|
end
|
23
28
|
|
24
|
-
|
25
|
-
#
|
26
|
-
# @param response [Hash]
|
27
|
-
# @return [Twitter::Error]
|
28
|
-
def self.from_response(response={})
|
29
|
-
error, code = parse_error(response[:body])
|
30
|
-
new(error, response[:response_headers], code)
|
31
|
-
end
|
29
|
+
class << self
|
32
30
|
|
33
|
-
|
34
|
-
|
35
|
-
@
|
36
|
-
|
37
|
-
|
31
|
+
# Create a new error from an HTTP response
|
32
|
+
#
|
33
|
+
# @param response [Hash]
|
34
|
+
# @return [Twitter::Error]
|
35
|
+
def from_response(response={})
|
36
|
+
error, code = parse_error(response[:body])
|
37
|
+
new(error, response[:response_headers], code)
|
38
38
|
end
|
39
|
-
end
|
40
39
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
# @return [Hash]
|
41
|
+
def errors
|
42
|
+
@errors ||= descendants.inject({}) do |hash, klass|
|
43
|
+
hash[klass::HTTP_STATUS_CODE] = klass
|
44
|
+
hash
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def parse_error(body)
|
51
|
+
if body.nil?
|
52
|
+
['', nil]
|
53
|
+
elsif body[:error]
|
54
|
+
[body[:error], nil]
|
55
|
+
elsif body[:errors]
|
56
|
+
extract_message_from_errors(body)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def extract_message_from_errors(body)
|
61
|
+
first = Array(body[:errors]).first
|
62
|
+
if first.is_a?(Hash)
|
63
|
+
[first[:message].chomp, first[:code]]
|
64
|
+
else
|
65
|
+
[first.chomp, nil]
|
66
|
+
end
|
67
|
+
end
|
45
68
|
|
46
|
-
# @return [Array]
|
47
|
-
def self.inherited(descendant)
|
48
|
-
descendants << descendant
|
49
69
|
end
|
50
70
|
|
51
71
|
# Initializes a new Error object
|
@@ -55,28 +75,11 @@ module Twitter
|
|
55
75
|
# @param code [Integer]
|
56
76
|
# @return [Twitter::Error]
|
57
77
|
def initialize(exception=$!, response_headers={}, code=nil)
|
58
|
-
@rate_limit =
|
78
|
+
@rate_limit = RateLimit.new(response_headers)
|
59
79
|
@wrapped_exception = exception
|
60
80
|
@code = code
|
61
81
|
exception.respond_to?(:message) ? super(exception.message) : super(exception.to_s)
|
62
82
|
end
|
63
83
|
|
64
|
-
private
|
65
|
-
|
66
|
-
def self.parse_error(body)
|
67
|
-
if body.nil?
|
68
|
-
['', nil]
|
69
|
-
elsif body[:error]
|
70
|
-
[body[:error], nil]
|
71
|
-
elsif body[:errors]
|
72
|
-
first = Array(body[:errors]).first
|
73
|
-
if first.is_a?(Hash)
|
74
|
-
[first[:message].chomp, first[:code]]
|
75
|
-
else
|
76
|
-
[first.chomp, nil]
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
84
|
end
|
82
85
|
end
|
data/lib/twitter/factory.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
module Twitter
|
2
2
|
class Factory
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# Construct a new object
|
7
|
+
#
|
8
|
+
# @param method [Symbol]
|
9
|
+
# @param klass [Class]
|
10
|
+
# @param attrs [Hash]
|
11
|
+
# @raise [IndexError] Error raised when supplied argument is missing a key.
|
12
|
+
# @return [Twitter::Base]
|
13
|
+
def new(method, klass, attrs={})
|
14
|
+
type = attrs.fetch(method.to_sym)
|
7
15
|
const_name = type.gsub(/\/(.?)/){"::#{$1.upcase}"}.gsub(/(?:^|_)(.)/){$1.upcase}
|
8
16
|
klass.const_get(const_name.to_sym).new(attrs)
|
9
|
-
else
|
10
|
-
raise ArgumentError, "argument must have :#{method} key"
|
11
17
|
end
|
18
|
+
|
12
19
|
end
|
13
20
|
|
14
21
|
end
|
data/lib/twitter/geo.rb
CHANGED
@@ -1,15 +1,10 @@
|
|
1
|
+
require 'equalizer'
|
1
2
|
require 'twitter/base'
|
2
3
|
|
3
4
|
module Twitter
|
4
5
|
class Geo < Twitter::Base
|
6
|
+
include Equalizer.new(:coordinates)
|
5
7
|
attr_reader :coordinates
|
6
8
|
alias coords coordinates
|
7
|
-
|
8
|
-
# @param other [Twitter::Geo]
|
9
|
-
# @return [Boolean]
|
10
|
-
def ==(other)
|
11
|
-
super || attr_equal(:coordinates, other) || attrs_equal(other)
|
12
|
-
end
|
13
|
-
|
14
9
|
end
|
15
10
|
end
|
data/lib/twitter/geo_factory.rb
CHANGED
@@ -5,13 +5,17 @@ require 'twitter/geo/polygon'
|
|
5
5
|
module Twitter
|
6
6
|
class GeoFactory < Twitter::Factory
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# Construct a new geo object
|
11
|
+
#
|
12
|
+
# @param attrs [Hash]
|
13
|
+
# @raise [IndexError] Error raised when supplied argument is missing a :type key.
|
14
|
+
# @return [Twitter::Geo]
|
15
|
+
def new(attrs={})
|
16
|
+
super(:type, Geo, attrs)
|
17
|
+
end
|
18
|
+
|
15
19
|
end
|
16
20
|
|
17
21
|
end
|
data/lib/twitter/geo_results.rb
CHANGED
@@ -8,22 +8,26 @@ module Twitter
|
|
8
8
|
alias to_hash attrs
|
9
9
|
alias to_hsh attrs
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# Construct a new GeoResults object from a response hash
|
14
|
+
#
|
15
|
+
# @param response [Hash]
|
16
|
+
# @return [Twitter::Base]
|
17
|
+
def from_response(response={})
|
18
|
+
new(response[:body])
|
19
|
+
end
|
20
|
+
|
17
21
|
end
|
18
22
|
|
19
|
-
# Initializes a new
|
23
|
+
# Initializes a new GeoResults object
|
20
24
|
#
|
21
25
|
# @param attrs [Hash]
|
22
26
|
# @return [Twitter::GeoResults]
|
23
27
|
def initialize(attrs={})
|
24
28
|
@attrs = attrs
|
25
29
|
@collection = Array(@attrs[:result][:places]).map do |place|
|
26
|
-
|
30
|
+
Place.new(place)
|
27
31
|
end
|
28
32
|
end
|
29
33
|
|
data/lib/twitter/identity.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
require 'equalizer'
|
1
2
|
require 'twitter/base'
|
2
3
|
|
3
4
|
module Twitter
|
4
5
|
class Identity < Twitter::Base
|
6
|
+
include Equalizer.new(:id)
|
7
|
+
attr_reader :id
|
5
8
|
|
6
9
|
# Initializes a new object
|
7
10
|
#
|
@@ -9,19 +12,8 @@ module Twitter
|
|
9
12
|
# @raise [ArgumentError] Error raised when supplied argument is missing an :id key.
|
10
13
|
# @return [Twitter::Identity]
|
11
14
|
def initialize(attrs={})
|
15
|
+
attrs.fetch(:id)
|
12
16
|
super
|
13
|
-
raise ArgumentError, "argument must have an :id key" unless id
|
14
|
-
end
|
15
|
-
|
16
|
-
# @param other [Twitter::Identity]
|
17
|
-
# @return [Boolean]
|
18
|
-
def ==(other)
|
19
|
-
super || attr_equal(:id, other) || attrs_equal(other)
|
20
|
-
end
|
21
|
-
|
22
|
-
# @return [Integer]
|
23
|
-
def id
|
24
|
-
@attrs[:id]
|
25
17
|
end
|
26
18
|
|
27
19
|
end
|
data/lib/twitter/list.rb
CHANGED
@@ -10,20 +10,23 @@ module Twitter
|
|
10
10
|
|
11
11
|
# @return [URI] The URI to the list members.
|
12
12
|
def members_uri
|
13
|
-
|
13
|
+
URI.parse("https://twitter.com/#{user.screen_name}/#{slug}/members")
|
14
14
|
end
|
15
|
+
memoize :members_uri
|
15
16
|
alias members_url members_uri
|
16
17
|
|
17
18
|
# @return [URI] The URI to the list subscribers.
|
18
19
|
def subscribers_uri
|
19
|
-
|
20
|
+
URI.parse("https://twitter.com/#{user.screen_name}/#{slug}/subscribers")
|
20
21
|
end
|
22
|
+
memoize :subscribers_uri
|
21
23
|
alias subscribers_url subscribers_uri
|
22
24
|
|
23
25
|
# @return [URI] The URI to the list.
|
24
26
|
def uri
|
25
|
-
|
27
|
+
URI.parse("https://twitter.com/#{user.screen_name}/#{slug}")
|
26
28
|
end
|
29
|
+
memoize :uri
|
27
30
|
alias url uri
|
28
31
|
|
29
32
|
end
|