twitter 5.0.0.rc.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data.tar.gz.sig +0 -0
  2. data/CHANGELOG.md +7 -1
  3. data/CONTRIBUTING.md +13 -15
  4. data/README.md +53 -33
  5. data/Rakefile +6 -0
  6. data/lib/twitter/arguments.rb +3 -0
  7. data/lib/twitter/base.rb +88 -89
  8. data/lib/twitter/client.rb +5 -41
  9. data/lib/twitter/configuration.rb +4 -5
  10. data/lib/twitter/core_ext/kernel.rb +5 -1
  11. data/lib/twitter/creatable.rb +6 -1
  12. data/lib/twitter/cursor.rb +16 -12
  13. data/lib/twitter/entity/uri.rb +2 -1
  14. data/lib/twitter/enumerable.rb +1 -1
  15. data/lib/twitter/error.rb +42 -39
  16. data/lib/twitter/factory.rb +12 -5
  17. data/lib/twitter/geo.rb +2 -7
  18. data/lib/twitter/geo_factory.rb +11 -7
  19. data/lib/twitter/geo_results.rb +12 -8
  20. data/lib/twitter/identity.rb +4 -12
  21. data/lib/twitter/list.rb +6 -3
  22. data/lib/twitter/media/photo.rb +5 -3
  23. data/lib/twitter/media_factory.rb +11 -7
  24. data/lib/twitter/null_object.rb +4 -3
  25. data/lib/twitter/place.rb +10 -16
  26. data/lib/twitter/profile_banner.rb +4 -5
  27. data/lib/twitter/rate_limit.rb +3 -0
  28. data/lib/twitter/relationship.rb +0 -9
  29. data/lib/twitter/rest/api/direct_messages.rb +9 -6
  30. data/lib/twitter/rest/api/favorites.rb +6 -11
  31. data/lib/twitter/rest/api/friends_and_followers.rb +6 -9
  32. data/lib/twitter/rest/api/lists.rb +27 -20
  33. data/lib/twitter/rest/api/oauth.rb +17 -0
  34. data/lib/twitter/rest/api/places_and_geo.rb +0 -18
  35. data/lib/twitter/rest/api/saved_searches.rb +6 -4
  36. data/lib/twitter/rest/api/suggested_users.rb +2 -2
  37. data/lib/twitter/rest/api/tweets.rb +7 -9
  38. data/lib/twitter/rest/api/users.rb +6 -6
  39. data/lib/twitter/rest/api/utils.rb +44 -17
  40. data/lib/twitter/rest/client.rb +25 -43
  41. data/lib/twitter/rest/response/parse_error_json.rb +15 -0
  42. data/lib/twitter/rest/response/parse_json.rb +5 -1
  43. data/lib/twitter/search_results.rb +12 -8
  44. data/lib/twitter/size.rb +2 -15
  45. data/lib/twitter/streaming/client.rb +23 -11
  46. data/lib/twitter/streaming/event.rb +35 -0
  47. data/lib/twitter/streaming/friend_list.rb +13 -0
  48. data/lib/twitter/streaming/message_parser.rb +18 -0
  49. data/lib/twitter/streaming/response.rb +4 -0
  50. data/lib/twitter/suggestion.rb +5 -10
  51. data/lib/twitter/token.rb +3 -1
  52. data/lib/twitter/trend.rb +2 -7
  53. data/lib/twitter/trend_results.rb +20 -14
  54. data/lib/twitter/tweet.rb +18 -23
  55. data/lib/twitter/user.rb +34 -19
  56. data/lib/twitter/version.rb +1 -1
  57. data/spec/fixtures/request_token.txt +6 -0
  58. data/spec/fixtures/track_streaming_user.json +5 -0
  59. data/spec/twitter/base_spec.rb +0 -16
  60. data/spec/twitter/basic_user_spec.rb +3 -3
  61. data/spec/twitter/cursor_spec.rb +4 -4
  62. data/spec/twitter/direct_message_spec.rb +9 -9
  63. data/spec/twitter/entity/uri_spec.rb +12 -11
  64. data/spec/twitter/geo/point_spec.rb +5 -5
  65. data/spec/twitter/geo/polygon_spec.rb +5 -5
  66. data/spec/twitter/geo_factory_spec.rb +2 -2
  67. data/spec/twitter/geo_spec.rb +6 -6
  68. data/spec/twitter/identifiable_spec.rb +5 -5
  69. data/spec/twitter/list_spec.rb +7 -7
  70. data/spec/twitter/media/photo_spec.rb +19 -18
  71. data/spec/twitter/media_factory_spec.rb +2 -2
  72. data/spec/twitter/null_object_spec.rb +7 -6
  73. data/spec/twitter/oembed_spec.rb +6 -6
  74. data/spec/twitter/place_spec.rb +37 -37
  75. data/spec/twitter/rate_limit_spec.rb +0 -17
  76. data/spec/twitter/relationship_spec.rb +4 -12
  77. data/spec/twitter/rest/api/direct_messages_spec.rb +8 -8
  78. data/spec/twitter/rest/api/friends_and_followers_spec.rb +50 -120
  79. data/spec/twitter/rest/api/geo_spec.rb +0 -14
  80. data/spec/twitter/rest/api/lists_spec.rb +39 -39
  81. data/spec/twitter/rest/api/oauth_spec.rb +15 -4
  82. data/spec/twitter/rest/api/saved_searches_spec.rb +6 -6
  83. data/spec/twitter/rest/api/tweets_spec.rb +6 -6
  84. data/spec/twitter/rest/api/users_spec.rb +4 -4
  85. data/spec/twitter/rest/client_spec.rb +9 -9
  86. data/spec/twitter/saved_search_spec.rb +5 -5
  87. data/spec/twitter/search_results_spec.rb +3 -3
  88. data/spec/twitter/settings_spec.rb +2 -2
  89. data/spec/twitter/size_spec.rb +5 -15
  90. data/spec/twitter/source_user_spec.rb +3 -3
  91. data/spec/twitter/streaming/client_spec.rb +33 -16
  92. data/spec/twitter/streaming/event_spec.rb +45 -0
  93. data/spec/twitter/suggestion_spec.rb +5 -15
  94. data/spec/twitter/target_user_spec.rb +3 -3
  95. data/spec/twitter/token_spec.rb +2 -2
  96. data/spec/twitter/trend_results_spec.rb +6 -6
  97. data/spec/twitter/trend_spec.rb +7 -17
  98. data/spec/twitter/tweet_spec.rb +31 -25
  99. data/spec/twitter/user_spec.rb +16 -16
  100. data/twitter.gemspec +5 -2
  101. metadata +67 -15
  102. metadata.gz.sig +0 -0
@@ -4,15 +4,16 @@ require 'uri'
4
4
 
5
5
  module Twitter
6
6
  class Client
7
- attr_writer :access_token, :access_token_secret, :consumer_key,
8
- :consumer_secret, :user_agent
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::REST::Client]
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
- memoize(:photo_sizes) do
15
- Array(@attrs[:photo_sizes]).inject({}) do |object, (key, value)|
16
- object[key] = Twitter::Size.new(value)
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; class << self; self; end; end unless method_defined?(: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
@@ -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
- @created_at ||= Time.parse(@attrs[:created_at]) if @attrs[:created_at]
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
@@ -8,18 +8,22 @@ module Twitter
8
8
  alias to_hash attrs
9
9
  alias to_hsh attrs
10
10
 
11
- # Construct a new Cursor object from a response hash
12
- #
13
- # @param response [Hash]
14
- # @param key [String, Symbol] The key to fetch the data from the response
15
- # @param klass [Class] The class to instantiate objects in the response
16
- # @param client [Twitter::REST::Client]
17
- # @param request_method [String, Symbol]
18
- # @param path [String]
19
- # @param options [Hash]
20
- # @return [Twitter::Cursor]
21
- def self.from_response(response, key, klass, client, request_method, path, options)
22
- new(response[:body], key, klass, client, request_method, path, options)
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
@@ -3,7 +3,8 @@ require 'twitter/entity'
3
3
  module Twitter
4
4
  class Entity
5
5
  class URI < Twitter::Entity
6
- uri_attr_reader :display_uri, :expanded_uri, :uri
6
+ display_uri_attr_reader
7
+ uri_attr_reader :expanded_uri, :uri
7
8
  end
8
9
 
9
10
  Uri = URI
@@ -3,7 +3,7 @@ module Twitter
3
3
  include ::Enumerable
4
4
 
5
5
  # @return [Enumerator]
6
- def each(start = 0, &block)
6
+ def each(start=0, &block)
7
7
  return to_enum(:each) unless block_given?
8
8
  Array(@collection[start..-1]).each do |element|
9
9
  yield element
@@ -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
- # Create a new error from an HTTP response
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
- # @return [Hash]
34
- def self.errors
35
- @errors ||= descendants.inject({}) do |hash, klass|
36
- hash[klass::HTTP_STATUS_CODE] = klass
37
- hash
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
- # @return [Array]
42
- def self.descendants
43
- @descendants ||= []
44
- end
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 = Twitter::RateLimit.new(response_headers)
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
@@ -1,14 +1,21 @@
1
1
  module Twitter
2
2
  class Factory
3
3
 
4
- def self.new(method, klass, attrs={})
5
- type = attrs.delete(method.to_sym)
6
- if type
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
@@ -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
@@ -5,13 +5,17 @@ require 'twitter/geo/polygon'
5
5
  module Twitter
6
6
  class GeoFactory < Twitter::Factory
7
7
 
8
- # Construct a new geo object
9
- #
10
- # @param attrs [Hash]
11
- # @raise [ArgumentError] Error raised when supplied argument is missing a :type key.
12
- # @return [Twitter::Geo]
13
- def self.new(attrs={})
14
- super(:type, Twitter::Geo, attrs)
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
@@ -8,22 +8,26 @@ module Twitter
8
8
  alias to_hash attrs
9
9
  alias to_hsh attrs
10
10
 
11
- # Construct a new SearchResults object from a response hash
12
- #
13
- # @param response [Hash]
14
- # @return [Twitter::Base]
15
- def self.from_response(response={})
16
- new(response[:body])
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 SearchResults object
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
- Twitter::Place.new(place)
30
+ Place.new(place)
27
31
  end
28
32
  end
29
33
 
@@ -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
@@ -10,20 +10,23 @@ module Twitter
10
10
 
11
11
  # @return [URI] The URI to the list members.
12
12
  def members_uri
13
- @members_uri ||= ::URI.parse("https://twitter.com/#{user.screen_name}/#{slug}/members")
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
- @subscribers_uri ||= ::URI.parse("https://twitter.com/#{user.screen_name}/#{slug}/subscribers")
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
- @uri ||= ::URI.parse("https://twitter.com/#{user.screen_name}/#{slug}")
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