twitter 5.4.1 → 5.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +5 -0
- data/CONTRIBUTING.md +6 -8
- data/README.md +8 -0
- data/Rakefile +1 -2
- data/lib/twitter/base.rb +4 -4
- data/lib/twitter/creatable.rb +1 -1
- data/lib/twitter/cursor.rb +3 -3
- data/lib/twitter/direct_message.rb +2 -0
- data/lib/twitter/entities.rb +69 -0
- data/lib/twitter/enumerable.rb +2 -0
- data/lib/twitter/error.rb +4 -3
- data/lib/twitter/null_object.rb +7 -4
- data/lib/twitter/profile.rb +94 -0
- data/lib/twitter/rest/api/direct_messages.rb +1 -1
- data/lib/twitter/rest/api/favorites.rb +1 -1
- data/lib/twitter/rest/api/friends_and_followers.rb +1 -1
- data/lib/twitter/rest/api/spam_reporting.rb +1 -1
- data/lib/twitter/rest/api/tweets.rb +3 -3
- data/lib/twitter/rest/api/users.rb +9 -9
- data/lib/twitter/rest/api/utils.rb +2 -2
- data/lib/twitter/rest/client.rb +2 -2
- data/lib/twitter/search_results.rb +3 -3
- data/lib/twitter/streaming/client.rb +1 -0
- data/lib/twitter/trend_results.rb +1 -1
- data/lib/twitter/tweet.rb +11 -75
- data/lib/twitter/user.rb +8 -87
- data/lib/twitter/utils.rb +7 -8
- data/lib/twitter/version.rb +2 -2
- data/spec/fixtures/direct_message.json +1 -1
- data/spec/twitter/direct_message_spec.rb +142 -0
- data/spec/twitter/null_object_spec.rb +70 -7
- data/spec/twitter/rest/api/direct_messages_spec.rb +12 -12
- data/spec/twitter/tweet_spec.rb +2 -26
- data/twitter.gemspec +9 -9
- metadata +32 -63
- metadata.gz.sig +5 -2
@@ -49,7 +49,7 @@ module Twitter
|
|
49
49
|
# @param path [String]
|
50
50
|
# @param args [Array]
|
51
51
|
# @return [Array<Twitter::User>]
|
52
|
-
def
|
52
|
+
def parallel_user_objects_from_response(request_method, path, args)
|
53
53
|
arguments = Twitter::Arguments.new(args)
|
54
54
|
Twitter::Utils.parallel_map(arguments) do |user|
|
55
55
|
object_from_response(Twitter::User, request_method, path, merge_user(arguments.options, user))
|
@@ -101,7 +101,7 @@ module Twitter
|
|
101
101
|
# @param path [String]
|
102
102
|
# @param args [Array]
|
103
103
|
# @return [Array]
|
104
|
-
def
|
104
|
+
def parallel_objects_from_response(klass, request_method, path, args) # rubocop:disable ParameterLists
|
105
105
|
arguments = Twitter::Arguments.new(args)
|
106
106
|
Twitter::Utils.parallel_map(arguments) do |object|
|
107
107
|
id = extract_id(object)
|
data/lib/twitter/rest/client.rb
CHANGED
@@ -139,8 +139,8 @@ module Twitter
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
response.env
|
142
|
-
rescue Faraday::Error::ClientError, JSON::ParserError
|
143
|
-
raise Twitter::Error
|
142
|
+
rescue Faraday::Error::ClientError, JSON::ParserError => error
|
143
|
+
raise Twitter::Error.new(error) # rubocop:disable RaiseArgs
|
144
144
|
end
|
145
145
|
|
146
146
|
def auth_token(method, path, params = {}, signature_params = params) # rubocop:disable ParameterLists
|
@@ -34,7 +34,7 @@ module Twitter
|
|
34
34
|
@path = path
|
35
35
|
@options = options
|
36
36
|
@collection = []
|
37
|
-
|
37
|
+
self.attrs = attrs
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
@@ -66,10 +66,10 @@ module Twitter
|
|
66
66
|
|
67
67
|
def fetch_next_page
|
68
68
|
response = @client.send(@request_method, @path, next_page)
|
69
|
-
|
69
|
+
self.attrs = response[:body]
|
70
70
|
end
|
71
71
|
|
72
|
-
def
|
72
|
+
def attrs=(attrs)
|
73
73
|
@attrs = attrs
|
74
74
|
Array(@attrs[:statuses]).map do |tweet|
|
75
75
|
@collection << Tweet.new(tweet)
|
@@ -58,6 +58,7 @@ module Twitter
|
|
58
58
|
# @see https://dev.twitter.com/docs/api/1.1/get/site
|
59
59
|
# @see https://dev.twitter.com/docs/streaming-apis/streams/site
|
60
60
|
# @see https://dev.twitter.com/docs/streaming-apis/parameters
|
61
|
+
# @note Site Streams is currently in a limited beta. Access is restricted to whitelisted accounts.
|
61
62
|
# @param follow [Enumerable<Integer, String, Twitter::User>] A list of user IDs, indicating the users to return statuses for in the stream.
|
62
63
|
# @param options [Hash] A customizable set of options.
|
63
64
|
# @option options [String] :with Specifies whether to return information for just the users specified in the follow parameter, or include messages from accounts they follow.
|
data/lib/twitter/tweet.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
require 'twitter/creatable'
|
2
|
+
require 'twitter/entities'
|
3
|
+
require 'twitter/identity'
|
2
4
|
|
3
5
|
module Twitter
|
4
6
|
class Tweet < Twitter::Identity
|
5
7
|
include Twitter::Creatable
|
6
|
-
|
7
|
-
|
8
|
-
:
|
9
|
-
:
|
8
|
+
include Twitter::Entities
|
9
|
+
attr_reader :favorite_count, :favorited, :filter_level,
|
10
|
+
:in_reply_to_screen_name, :in_reply_to_attrs_id,
|
11
|
+
:in_reply_to_status_id, :in_reply_to_user_id, :lang,
|
12
|
+
:retweet_count, :retweeted, :source, :text, :truncated
|
10
13
|
alias_method :favorites_count, :favorite_count
|
11
14
|
alias_method :favoriters_count, :favorite_count
|
12
15
|
alias_method :in_reply_to_tweet_id, :in_reply_to_status_id
|
16
|
+
alias_method :reply?, :in_reply_to_status_id?
|
13
17
|
alias_method :retweeters_count, :retweet_count
|
14
18
|
object_attr_reader :GeoFactory, :geo
|
15
19
|
object_attr_reader :Metadata, :metadata
|
@@ -21,21 +25,10 @@ module Twitter
|
|
21
25
|
alias_method :retweeted_tweet?, :retweeted_status?
|
22
26
|
object_attr_reader :User, :user, :status
|
23
27
|
|
24
|
-
# @return [Boolean]
|
25
|
-
def entities?
|
26
|
-
!@attrs[:entities].nil? && @attrs[:entities].any? { |_, array| !array.empty? }
|
27
|
-
end
|
28
|
-
memoize :entities?
|
29
|
-
|
30
|
-
def filter_level
|
31
|
-
@attrs[:filter_level] || 'none'
|
32
|
-
end
|
33
|
-
memoize :filter_level
|
34
|
-
|
35
|
-
# @return [String]
|
36
28
|
# @note May be > 140 characters.
|
29
|
+
# @return [String]
|
37
30
|
def full_text
|
38
|
-
if
|
31
|
+
if retweet?
|
39
32
|
prefix = text[/\A(RT @[a-z0-9_]{1,20}: )/i, 1]
|
40
33
|
[prefix, retweeted_status.text].compact.join
|
41
34
|
else
|
@@ -44,69 +37,12 @@ module Twitter
|
|
44
37
|
end
|
45
38
|
memoize :full_text
|
46
39
|
|
47
|
-
# @note Must include entities in your request for this method to work
|
48
|
-
# @return [Array<Twitter::Entity::Hashtag>]
|
49
|
-
def hashtags
|
50
|
-
entities(Entity::Hashtag, :hashtags)
|
51
|
-
end
|
52
|
-
memoize :hashtags
|
53
|
-
|
54
|
-
# @note Must include entities in your request for this method to work
|
55
|
-
# @return [Array<Twitter::Media>]
|
56
|
-
def media
|
57
|
-
entities(MediaFactory, :media)
|
58
|
-
end
|
59
|
-
memoize :media
|
60
|
-
|
61
|
-
# @return [Boolean]
|
62
|
-
def reply?
|
63
|
-
!!@attrs[:in_reply_to_status_id]
|
64
|
-
end
|
65
|
-
memoize :reply?
|
66
|
-
|
67
|
-
# @note Must include entities in your request for this method to work
|
68
|
-
# @return [Array<Twitter::Entity::Symbol>]
|
69
|
-
def symbols
|
70
|
-
entities(Entity::Symbol, :symbols)
|
71
|
-
end
|
72
|
-
memoize :symbols
|
73
|
-
|
74
40
|
# @return [String] The URL to the tweet.
|
75
41
|
def uri
|
76
|
-
Addressable::URI.parse("https://twitter.com/#{user.screen_name}/status/#{id}")
|
42
|
+
Addressable::URI.parse("https://twitter.com/#{user.screen_name}/status/#{id}") unless user.nil?
|
77
43
|
end
|
78
44
|
memoize :uri
|
79
45
|
alias_method :url, :uri
|
80
|
-
|
81
|
-
# @note Must include entities in your request for this method to work
|
82
|
-
# @return [Array<Twitter::Entity::URI>]
|
83
|
-
def uris
|
84
|
-
entities(Entity::URI, :urls)
|
85
|
-
end
|
86
|
-
memoize :uris
|
87
|
-
alias_method :urls, :uris
|
88
|
-
|
89
|
-
# @note Must include entities in your request for this method to work
|
90
|
-
# @return [Array<Twitter::Entity::UserMention>]
|
91
|
-
def user_mentions
|
92
|
-
entities(Entity::UserMention, :user_mentions)
|
93
|
-
end
|
94
|
-
memoize :user_mentions
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
# @param klass [Class]
|
99
|
-
# @param key [Symbol]
|
100
|
-
def entities(klass, key)
|
101
|
-
if entities?
|
102
|
-
Array(@attrs[:entities][key.to_sym]).map do |entity|
|
103
|
-
klass.new(entity)
|
104
|
-
end
|
105
|
-
else
|
106
|
-
warn "#{Kernel.caller.first}: To get #{key.to_s.tr('_', ' ')}, you must pass `:include_entities => true` when requesting the #{self.class}."
|
107
|
-
[]
|
108
|
-
end
|
109
|
-
end
|
110
46
|
end
|
111
47
|
Status = Tweet # rubocop:disable ConstantName
|
112
48
|
end
|
data/lib/twitter/user.rb
CHANGED
@@ -1,11 +1,15 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
require 'memoizable'
|
1
3
|
require 'twitter/basic_user'
|
2
4
|
require 'twitter/creatable'
|
5
|
+
require 'twitter/entity/uri'
|
6
|
+
require 'twitter/profile'
|
3
7
|
|
4
8
|
module Twitter
|
5
9
|
class User < Twitter::BasicUser
|
6
|
-
PROFILE_IMAGE_SUFFIX_REGEX = /_normal(\.gif|\.jpe?g|\.png)$/i
|
7
|
-
PREDICATE_URI_METHOD_REGEX = /_uri\?$/
|
8
10
|
include Twitter::Creatable
|
11
|
+
include Twitter::Profile
|
12
|
+
include Memoizable
|
9
13
|
attr_reader :connections, :contributors_enabled, :default_profile,
|
10
14
|
:default_profile_image, :description, :favourites_count,
|
11
15
|
:follow_request_sent, :followers_count, :friends_count,
|
@@ -28,20 +32,6 @@ module Twitter
|
|
28
32
|
alias_method :tweet?, :status?
|
29
33
|
alias_method :tweeted?, :status?
|
30
34
|
|
31
|
-
class << self
|
32
|
-
private
|
33
|
-
|
34
|
-
def alias_predicate_uri_methods(method)
|
35
|
-
%w(_url? _uri_https? _url_https?).each do |replacement|
|
36
|
-
alias_method_sub(method, PREDICATE_URI_METHOD_REGEX, replacement)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def alias_method_sub(method, pattern, replacement)
|
41
|
-
alias_method(method.to_s.sub(pattern, replacement).to_sym, method)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
35
|
# @return [Array<Twitter::Entity::URI>]
|
46
36
|
def description_uris
|
47
37
|
Array(@attrs[:entities][:description][:urls]).map do |entity|
|
@@ -51,71 +41,16 @@ module Twitter
|
|
51
41
|
memoize :description_uris
|
52
42
|
alias_method :description_urls, :description_uris
|
53
43
|
|
54
|
-
# Return the URL to the user's profile banner image
|
55
|
-
#
|
56
|
-
# @param size [String, Symbol] The size of the image. Must be one of: 'mobile', 'mobile_retina', 'web', 'web_retina', 'ipad', or 'ipad_retina'
|
57
|
-
# @return [String]
|
58
|
-
def profile_banner_uri(size = :web)
|
59
|
-
parse_encoded_uri(insecure_uri([@attrs[:profile_banner_url], size].join('/'))) if @attrs[:profile_banner_url]
|
60
|
-
end
|
61
|
-
alias_method :profile_banner_url, :profile_banner_uri
|
62
|
-
|
63
|
-
# Return the secure URL to the user's profile banner image
|
64
|
-
#
|
65
|
-
# @param size [String, Symbol] The size of the image. Must be one of: 'mobile', 'mobile_retina', 'web', 'web_retina', 'ipad', or 'ipad_retina'
|
66
|
-
# @return [String]
|
67
|
-
def profile_banner_uri_https(size = :web)
|
68
|
-
parse_encoded_uri([@attrs[:profile_banner_url], size].join('/')) if @attrs[:profile_banner_url]
|
69
|
-
end
|
70
|
-
alias_method :profile_banner_url_https, :profile_banner_uri_https
|
71
|
-
|
72
|
-
# @return [Boolean]
|
73
|
-
def profile_banner_uri?
|
74
|
-
!!@attrs[:profile_banner_url]
|
75
|
-
end
|
76
|
-
memoize :profile_banner_uri?
|
77
|
-
alias_predicate_uri_methods :profile_banner_uri?
|
78
|
-
|
79
|
-
# Return the URL to the user's profile image
|
80
|
-
#
|
81
|
-
# @param size [String, Symbol] The size of the image. Must be one of: 'mini', 'normal', 'bigger' or 'original'
|
82
|
-
# @return [String]
|
83
|
-
def profile_image_uri(size = :normal)
|
84
|
-
parse_encoded_uri(insecure_uri(profile_image_uri_https(size))) if @attrs[:profile_image_url_https]
|
85
|
-
end
|
86
|
-
alias_method :profile_image_url, :profile_image_uri
|
87
|
-
|
88
|
-
# Return the secure URL to the user's profile image
|
89
|
-
#
|
90
|
-
# @param size [String, Symbol] The size of the image. Must be one of: 'mini', 'normal', 'bigger' or 'original'
|
91
|
-
# @return [String]
|
92
|
-
def profile_image_uri_https(size = :normal)
|
93
|
-
# The profile image URL comes in looking like like this:
|
94
|
-
# https://a0.twimg.com/profile_images/1759857427/image1326743606_normal.png
|
95
|
-
# It can be converted to any of the following sizes:
|
96
|
-
# https://a0.twimg.com/profile_images/1759857427/image1326743606.png
|
97
|
-
# https://a0.twimg.com/profile_images/1759857427/image1326743606_mini.png
|
98
|
-
# https://a0.twimg.com/profile_images/1759857427/image1326743606_bigger.png
|
99
|
-
parse_encoded_uri(@attrs[:profile_image_url_https].sub(PROFILE_IMAGE_SUFFIX_REGEX, profile_image_suffix(size))) if @attrs[:profile_image_url_https]
|
100
|
-
end
|
101
|
-
alias_method :profile_image_url_https, :profile_image_uri_https
|
102
|
-
|
103
|
-
def profile_image_uri?
|
104
|
-
!!@attrs[:profile_image_url_https]
|
105
|
-
end
|
106
|
-
memoize :profile_image_uri?
|
107
|
-
alias_predicate_uri_methods :profile_image_uri?
|
108
|
-
|
109
44
|
# @return [String] The URL to the user.
|
110
45
|
def uri
|
111
|
-
Addressable::URI.parse("https://twitter.com/#{screen_name}")
|
46
|
+
Addressable::URI.parse("https://twitter.com/#{screen_name}") unless screen_name.nil?
|
112
47
|
end
|
113
48
|
memoize :uri
|
114
49
|
alias_method :url, :uri
|
115
50
|
|
116
51
|
# @return [String] The URL to the user's website.
|
117
52
|
def website
|
118
|
-
Addressable::URI.parse(@attrs[:url])
|
53
|
+
Addressable::URI.parse(@attrs[:url]) unless @attrs[:url].nil?
|
119
54
|
end
|
120
55
|
memoize :website
|
121
56
|
|
@@ -123,19 +58,5 @@ module Twitter
|
|
123
58
|
!!@attrs[:url]
|
124
59
|
end
|
125
60
|
memoize :website?
|
126
|
-
|
127
|
-
private
|
128
|
-
|
129
|
-
def parse_encoded_uri(uri)
|
130
|
-
Addressable::URI.parse(URI.encode(uri))
|
131
|
-
end
|
132
|
-
|
133
|
-
def insecure_uri(uri)
|
134
|
-
uri.to_s.sub(/^https/i, 'http')
|
135
|
-
end
|
136
|
-
|
137
|
-
def profile_image_suffix(size)
|
138
|
-
:original == size.to_sym ? '\\1' : "_#{size}\\1"
|
139
|
-
end
|
140
61
|
end
|
141
62
|
end
|
data/lib/twitter/utils.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Twitter
|
2
2
|
module Utils
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
3
|
+
module_function
|
4
|
+
def parallel_map(enumerable)
|
5
|
+
# Don't bother spawning a new thread if there's only one item
|
6
|
+
if enumerable.count == 1
|
7
|
+
enumerable.map { |object| yield object }
|
8
|
+
else
|
9
|
+
enumerable.map { |object| Thread.new { yield object } }.map(&:value)
|
11
10
|
end
|
12
11
|
end
|
13
12
|
end
|
data/lib/twitter/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"
|
1
|
+
{"id":418030038152642560,"id_str":"418030038152642560","text":"My #newride from @PUBLICBikes. Don't you want one? https:\/\/t.co\/7HIwCl68Y8 https:\/\/t.co\/JSSxDPr4Sf","sender":{"id":14471007,"id_str":"14471007","name":"Diana Kimball","screen_name":"dianakimball","location":"Berlin","description":"Community at @SoundCloud. Every now and then, I write a longer letter that I\u2019d love to send to you: http:\/\/t.co\/AZEzTiBwRS","url":"http:\/\/t.co\/tUTbLPD7Yc","entities":{"url":{"urls":[{"url":"http:\/\/t.co\/tUTbLPD7Yc","expanded_url":"http:\/\/blog.dianakimball.com","display_url":"blog.dianakimball.com","indices":[0,22]}]},"description":{"urls":[{"url":"http:\/\/t.co\/AZEzTiBwRS","expanded_url":"http:\/\/expertnovice.com","display_url":"expertnovice.com","indices":[100,122]}]}},"protected":false,"followers_count":4283,"friends_count":684,"listed_count":176,"created_at":"Tue Apr 22 05:14:47 +0000 2008","favourites_count":6773,"utc_offset":-18000,"time_zone":"Quito","geo_enabled":true,"verified":false,"statuses_count":5527,"lang":"en","contributors_enabled":false,"is_translator":false,"profile_background_color":"F4FFFF","profile_background_image_url":"http:\/\/abs.twimg.com\/images\/themes\/theme15\/bg.png","profile_background_image_url_https":"https:\/\/abs.twimg.com\/images\/themes\/theme15\/bg.png","profile_background_tile":false,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/3333204267\/51006fd104a17604e0398359ff5937ba_normal.jpeg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/3333204267\/51006fd104a17604e0398359ff5937ba_normal.jpeg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/14471007\/1359310744","profile_link_color":"8F1864","profile_sidebar_border_color":"FFFFFF","profile_sidebar_fill_color":"C0DFEC","profile_text_color":"333333","profile_use_background_image":false,"default_profile":false,"default_profile_image":false,"following":true,"follow_request_sent":false,"notifications":false},"sender_id":14471007,"sender_id_str":"14471007","sender_screen_name":"dianakimball","recipient":{"id":7505382,"id_str":"7505382","name":"Erik Michaels-Ober","screen_name":"sferik","location":"","description":"Prolonging the inevitable.","url":"https:\/\/t.co\/L2xIBaQPRf","entities":{"url":{"urls":[{"url":"https:\/\/t.co\/L2xIBaQPRf","expanded_url":"https:\/\/github.com\/sferik","display_url":"github.com\/sferik","indices":[0,23]}]},"description":{"urls":[]}},"protected":false,"followers_count":3946,"friends_count":345,"listed_count":205,"created_at":"Mon Jul 16 12:59:01 +0000 2007","favourites_count":8018,"utc_offset":3600,"time_zone":"Berlin","geo_enabled":true,"verified":false,"statuses_count":13011,"lang":"en","contributors_enabled":false,"is_translator":false,"profile_background_color":"000000","profile_background_image_url":"http:\/\/a0.twimg.com\/profile_background_images\/677717672\/bb0b3653dcf0644e344823e0a2eb3382.png","profile_background_image_url_https":"https:\/\/si0.twimg.com\/profile_background_images\/677717672\/bb0b3653dcf0644e344823e0a2eb3382.png","profile_background_tile":false,"profile_image_url":"http:\/\/pbs.twimg.com\/profile_images\/378800000757402331\/d8dfba561e2e94112a737f17e7d138ca_normal.jpeg","profile_image_url_https":"https:\/\/pbs.twimg.com\/profile_images\/378800000757402331\/d8dfba561e2e94112a737f17e7d138ca_normal.jpeg","profile_banner_url":"https:\/\/pbs.twimg.com\/profile_banners\/7505382\/1385736840","profile_link_color":"0084B4","profile_sidebar_border_color":"000000","profile_sidebar_fill_color":"DDEEF6","profile_text_color":"333333","profile_use_background_image":true,"default_profile":false,"default_profile_image":false,"following":false,"follow_request_sent":false,"notifications":false},"recipient_id":7505382,"recipient_id_str":"7505382","recipient_screen_name":"sferik","created_at":"Tue Dec 31 14:45:02 +0000 2013","entities":{"hashtags":[{"text":"newride","indices":[3,11]}],"symbols":[],"urls":[{"url":"https:\/\/t.co\/7HIwCl68Y8","expanded_url":"https:\/\/twitter.com\/PUBLICBikes\/status\/350315569708412929","display_url":"twitter.com\/PUBLICBikes\/st\u2026","indices":[51,74]},{"url":"https:\/\/t.co\/JSSxDPr4Sf","expanded_url":"https:\/\/ton.twitter.com\/1.1\/ton\/data\/dm\/418030038152642560\/418030038161047552\/0cnHqrKV.jpg","display_url":"pic.twitter.com\/JSSxDPr4Sf","indices":[75,98]}],"user_mentions":[{"screen_name":"PUBLICBikes","name":"PUBLIC Bikes","id":30035888,"id_str":"30035888","indices":[17,29]}],"media":[{"id":418030038161047552,"id_str":"418030038161047552","indices":[75,98],"media_url":"https:\/\/ton.twitter.com\/1.1\/ton\/data\/dm\/418030038152642560\/418030038161047552\/0cnHqrKV.jpg","media_url_https":"https:\/\/ton.twitter.com\/1.1\/ton\/data\/dm\/418030038152642560\/418030038161047552\/0cnHqrKV.jpg","url":"https:\/\/t.co\/JSSxDPr4Sf","display_url":"pic.twitter.com\/JSSxDPr4Sf","expanded_url":"https:\/\/ton.twitter.com\/1.1\/ton\/data\/dm\/418030038152642560\/418030038161047552\/0cnHqrKV.jpg","type":"photo","sizes":{"medium":{"w":600,"h":600,"resize":"fit"},"large":{"w":640,"h":640,"resize":"fit"},"thumb":{"w":150,"h":150,"resize":"crop"},"small":{"w":340,"h":340,"resize":"fit"}}}]}}
|
@@ -1,7 +1,17 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
require 'helper'
|
2
3
|
|
3
4
|
describe Twitter::DirectMessage do
|
4
5
|
|
6
|
+
before do
|
7
|
+
@old_stderr = $stderr
|
8
|
+
$stderr = StringIO.new
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
$stderr = @old_stderr
|
13
|
+
end
|
14
|
+
|
5
15
|
describe '#==' do
|
6
16
|
it 'returns true when objects IDs are the same' do
|
7
17
|
direct_message = Twitter::DirectMessage.new(:id => 1, :text => 'foo')
|
@@ -86,4 +96,136 @@ describe Twitter::DirectMessage do
|
|
86
96
|
end
|
87
97
|
end
|
88
98
|
|
99
|
+
describe '#hashtags' do
|
100
|
+
it 'returns an array of Entity::Hashtag when entities are set' do
|
101
|
+
hashtags_array = [
|
102
|
+
{
|
103
|
+
:text => 'twitter',
|
104
|
+
:indices => [10, 33],
|
105
|
+
}
|
106
|
+
]
|
107
|
+
hashtags = Twitter::DirectMessage.new(:id => 28_669_546_014, :entities => {:hashtags => hashtags_array}).hashtags
|
108
|
+
expect(hashtags).to be_an Array
|
109
|
+
expect(hashtags.first).to be_a Twitter::Entity::Hashtag
|
110
|
+
expect(hashtags.first.indices).to eq([10, 33])
|
111
|
+
expect(hashtags.first.text).to eq('twitter')
|
112
|
+
end
|
113
|
+
it 'is empty when not set' do
|
114
|
+
hashtags = Twitter::DirectMessage.new(:id => 28_669_546_014).hashtags
|
115
|
+
expect(hashtags).to be_empty
|
116
|
+
end
|
117
|
+
it 'warns when not set' do
|
118
|
+
Twitter::DirectMessage.new(:id => 28_669_546_014).hashtags
|
119
|
+
expect($stderr.string).to match(/To get hashtags, you must pass `:include_entities => true` when requesting the Twitter::DirectMessage\./)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#media' do
|
124
|
+
it 'returns media' do
|
125
|
+
media = Twitter::DirectMessage.new(:id => 28_669_546_014, :entities => {:media => [{:id => 1, :type => 'photo'}]}).media
|
126
|
+
expect(media).to be_an Array
|
127
|
+
expect(media.first).to be_a Twitter::Media::Photo
|
128
|
+
end
|
129
|
+
it 'is empty when not set' do
|
130
|
+
media = Twitter::DirectMessage.new(:id => 28_669_546_014).media
|
131
|
+
expect(media).to be_empty
|
132
|
+
end
|
133
|
+
it 'warns when not set' do
|
134
|
+
Twitter::DirectMessage.new(:id => 28_669_546_014).media
|
135
|
+
expect($stderr.string).to match(/To get media, you must pass `:include_entities => true` when requesting the Twitter::DirectMessage\./)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#symbols' do
|
140
|
+
it 'returns an array of Entity::Symbol when symbols are set' do
|
141
|
+
symbols_array = [
|
142
|
+
{:text => 'PEP', :indices => [114, 118]},
|
143
|
+
{:text => 'COKE', :indices => [128, 133]}
|
144
|
+
]
|
145
|
+
symbols = Twitter::DirectMessage.new(:id => 28_669_546_014, :entities => {:symbols => symbols_array}).symbols
|
146
|
+
expect(symbols).to be_an Array
|
147
|
+
expect(symbols.size).to eq(2)
|
148
|
+
expect(symbols.first).to be_a Twitter::Entity::Symbol
|
149
|
+
expect(symbols.first.indices).to eq([114, 118])
|
150
|
+
expect(symbols.first.text).to eq('PEP')
|
151
|
+
end
|
152
|
+
it 'is empty when not set' do
|
153
|
+
symbols = Twitter::DirectMessage.new(:id => 28_669_546_014).symbols
|
154
|
+
expect(symbols).to be_empty
|
155
|
+
end
|
156
|
+
it 'warns when not set' do
|
157
|
+
Twitter::DirectMessage.new(:id => 28_669_546_014).symbols
|
158
|
+
expect($stderr.string).to match(/To get symbols, you must pass `:include_entities => true` when requesting the Twitter::DirectMessage\./)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#uris' do
|
163
|
+
it 'returns an array of Entity::URIs when entities are set' do
|
164
|
+
urls_array = [
|
165
|
+
{
|
166
|
+
:url => 'http://example.com/t.co',
|
167
|
+
:expanded_url => 'http://example.com/expanded',
|
168
|
+
:display_url => 'example.com/expanded…',
|
169
|
+
:indices => [10, 33],
|
170
|
+
}
|
171
|
+
]
|
172
|
+
direct_message = Twitter::DirectMessage.new(:id => 28_669_546_014, :entities => {:urls => urls_array})
|
173
|
+
expect(direct_message.uris).to be_an Array
|
174
|
+
expect(direct_message.uris.first).to be_a Twitter::Entity::URI
|
175
|
+
expect(direct_message.uris.first.indices).to eq([10, 33])
|
176
|
+
expect(direct_message.uris.first.display_uri).to be_a String
|
177
|
+
expect(direct_message.uris.first.display_uri).to eq('example.com/expanded…')
|
178
|
+
end
|
179
|
+
it 'is empty when not set' do
|
180
|
+
direct_message = Twitter::DirectMessage.new(:id => 28_669_546_014)
|
181
|
+
expect(direct_message.uris).to be_empty
|
182
|
+
end
|
183
|
+
it 'warns when not set' do
|
184
|
+
Twitter::DirectMessage.new(:id => 28_669_546_014).urls
|
185
|
+
expect($stderr.string).to match(/To get urls, you must pass `:include_entities => true` when requesting the Twitter::DirectMessage\./)
|
186
|
+
end
|
187
|
+
it 'can handle strange urls' do
|
188
|
+
urls_array = [
|
189
|
+
{
|
190
|
+
:url => 'http://with_underscore.example.com/t.co',
|
191
|
+
:expanded_url => 'http://with_underscore.example.com/expanded',
|
192
|
+
:display_url => 'with_underscore.example.com/expanded…',
|
193
|
+
:indices => [10, 33],
|
194
|
+
}
|
195
|
+
]
|
196
|
+
direct_message = Twitter::DirectMessage.new(:id => 28_669_546_014, :entities => {:urls => urls_array})
|
197
|
+
uri = direct_message.uris.first
|
198
|
+
expect { uri.url }.not_to raise_error
|
199
|
+
expect { uri.expanded_url }.not_to raise_error
|
200
|
+
expect { uri.display_url }.not_to raise_error
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe '#user_mentions' do
|
205
|
+
it 'returns an array of Entity::UserMention when entities are set' do
|
206
|
+
user_mentions_array = [
|
207
|
+
{
|
208
|
+
:screen_name => 'sferik',
|
209
|
+
:name => 'Erik Michaels-Ober',
|
210
|
+
:id_str => '7_505_382',
|
211
|
+
:indices => [0, 6],
|
212
|
+
:id => 7_505_382,
|
213
|
+
}
|
214
|
+
]
|
215
|
+
user_mentions = Twitter::DirectMessage.new(:id => 28_669_546_014, :entities => {:user_mentions => user_mentions_array}).user_mentions
|
216
|
+
expect(user_mentions).to be_an Array
|
217
|
+
expect(user_mentions.first).to be_a Twitter::Entity::UserMention
|
218
|
+
expect(user_mentions.first.indices).to eq([0, 6])
|
219
|
+
expect(user_mentions.first.id).to eq(7_505_382)
|
220
|
+
end
|
221
|
+
it 'is empty when not set' do
|
222
|
+
user_mentions = Twitter::DirectMessage.new(:id => 28_669_546_014).user_mentions
|
223
|
+
expect(user_mentions).to be_empty
|
224
|
+
end
|
225
|
+
it 'warns when not set' do
|
226
|
+
Twitter::DirectMessage.new(:id => 28_669_546_014).user_mentions
|
227
|
+
expect($stderr.string).to match(/To get user mentions, you must pass `:include_entities => true` when requesting the Twitter::DirectMessage\./)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
89
231
|
end
|