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.
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