Skip to content

Commit

Permalink
Allow user to pass a Tweet IDs, URIs, or objects
Browse files Browse the repository at this point in the history
  • Loading branch information
sferik committed Jul 20, 2013
1 parent 9ed417c commit 721de1e
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 65 deletions.
30 changes: 16 additions & 14 deletions lib/twitter/api/favorites.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ def favorites(*args)
# @authentication Requires user context
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Array<Twitter::Tweet>] The un-favorited Tweets.
# @overload unfavorite(*ids)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload unfavorite(*tweets)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @example Un-favorite the tweet with the ID 25938088801
# Twitter.unfavorite(25938088801)
# @overload unfavorite(*ids, options)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload unfavorite(*tweets, options)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @param options [Hash] A customizable set of options.
def unfavorite(*args)
threaded_object_from_response(Twitter::Tweet, :post, "/1.1/favorites/destroy.json", args)
Expand All @@ -69,16 +69,17 @@ def unfavorite(*args)
# @authentication Requires user context
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Array<Twitter::Tweet>] The favorited Tweets.
# @overload favorite(*ids)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload favorite(*tweets)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @example Favorite the Tweet with the ID 25938088801
# Twitter.favorite(25938088801)
# @overload favorite(*ids, options)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload favorite(*tweets, options)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @param options [Hash] A customizable set of options.
def favorite(*args)
arguments = Twitter::API::Arguments.new(args)
arguments.flatten.threaded_map do |id|
arguments.flatten.threaded_map do |tweet|
id = extract_id(tweet)
begin
object_from_response(Twitter::Tweet, :post, "/1.1/favorites/create.json", arguments.options.merge(:id => id))
rescue Twitter::Error::Forbidden => error
Expand All @@ -99,16 +100,17 @@ def favorite(*args)
# @raise [Twitter::Error::AlreadyFavorited] Error raised when tweet has already been favorited.
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Array<Twitter::Tweet>] The favorited Tweets.
# @overload favorite(*ids)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload favorite(*tweets)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @example Favorite the Tweet with the ID 25938088801
# Twitter.favorite(25938088801)
# @overload favorite(*ids, options)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload favorite(*tweets, options)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @param options [Hash] A customizable set of options.
def favorite!(*args)
arguments = Twitter::API::Arguments.new(args)
arguments.flatten.threaded_map do |id|
arguments.flatten.threaded_map do |tweet|
id = extract_id(tweet)
begin
object_from_response(Twitter::Tweet, :post, "/1.1/favorites/create.json", arguments.options.merge(:id => id))
rescue Twitter::Error::Forbidden => error
Expand Down
81 changes: 34 additions & 47 deletions lib/twitter/api/tweets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module Tweets
# @example Return up to 100 of the first retweets of the Tweet with the ID 28561922516
# Twitter.retweets(28561922516)
def retweets(tweet, options={})
id = extract_tweet_id(tweet)
id = extract_id(tweet)
objects_from_response(Twitter::Tweet, :get, "/1.1/statuses/retweets/#{id}.json", options)
end

Expand Down Expand Up @@ -66,7 +66,7 @@ def retweeters_of(tweet, options={})
# @example Return the Tweet with the ID 25938088801
# Twitter.status(25938088801)
def status(tweet, options={})
id = extract_tweet_id(tweet)
id = extract_id(tweet)
object_from_response(Twitter::Tweet, :get, "/1.1/statuses/show/#{id}.json", options)
end

Expand All @@ -77,12 +77,12 @@ def status(tweet, options={})
# @authentication Requires user context
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Array<Twitter::Tweet>] The requested Tweets.
# @overload statuses(*ids)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload statuses(*tweets)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @example Return the Tweet with the ID 25938088801
# Twitter.statuses(25938088801)
# @overload statuses(*ids, options)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload statuses(*tweets, options)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @param options [Hash] A customizable set of options.
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
def statuses(*args)
Expand All @@ -97,12 +97,12 @@ def statuses(*args)
# @authentication Requires user context
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Array<Twitter::Tweet>] The deleted Tweets.
# @overload status_destroy(*ids)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload status_destroy(*tweets)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @example Destroy the Tweet with the ID 25938088801
# Twitter.status_destroy(25938088801)
# @overload status_destroy(*ids, options)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload status_destroy(*tweets, options)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @param options [Hash] A customizable set of options.
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
def status_destroy(*args)
Expand Down Expand Up @@ -139,17 +139,18 @@ def update(status, options={})
# @authentication Requires user context
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Array<Twitter::Tweet>] The original tweets with retweet details embedded.
# @overload retweet(*ids)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload retweet(*tweets)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @example Retweet the Tweet with the ID 28561922516
# Twitter.retweet(28561922516)
# @overload retweet(*ids, options)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload retweet(*tweets, options)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @param options [Hash] A customizable set of options.
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
def retweet(*args)
arguments = Twitter::API::Arguments.new(args)
arguments.flatten.threaded_map do |id|
arguments.flatten.threaded_map do |tweet|
id = extract_id(tweet)
begin
post_retweet(id, arguments.options)
rescue Twitter::Error::Forbidden => error
Expand All @@ -166,17 +167,18 @@ def retweet(*args)
# @raise [Twitter::Error::AlreadyRetweeted] Error raised when tweet has already been retweeted.
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Array<Twitter::Tweet>] The original tweets with retweet details embedded.
# @overload retweet!(*ids)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload retweet!(*tweets)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @example Retweet the Tweet with the ID 28561922516
# Twitter.retweet!(28561922516)
# @overload retweet!(*ids, options)
# @param ids [Enumerable<Integer>] A collection of Tweet IDs.
# @overload retweet!(*tweets, options)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @param options [Hash] A customizable set of options.
# @option options [Boolean, String, Integer] :trim_user Each tweet returned in a timeline will include a user object with only the author's numerical ID when set to true, 't' or 1.
def retweet!(*args)
arguments = Twitter::API::Arguments.new(args)
arguments.flatten.threaded_map do |id|
arguments.flatten.threaded_map do |tweet|
id = extract_id(tweet)
begin
post_retweet(id, arguments.options)
rescue Twitter::Error::Forbidden => error
Expand Down Expand Up @@ -227,7 +229,7 @@ def update_with_media(status, media, options={})
# @example Return oEmbeds for Tweet with the ID 25938088801
# Twitter.status_with_activity(25938088801)
def oembed(tweet, options={})
options[:id] = extract_tweet_id(tweet)
options[:id] = extract_id(tweet)
object_from_response(Twitter::OEmbed, :get, "/1.1/statuses/oembed.json", options)
end

Expand All @@ -238,12 +240,12 @@ def oembed(tweet, options={})
# @authentication Requires user context
# @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
# @return [Array<Twitter::OEmbed>] OEmbeds for the requested Tweets.
# @overload oembed(*ids_or_urls)
# @param ids_or_urls [Enumerable<Integer, String>] A collection of Tweet IDs or URLs.
# @overload oembed(*tweets)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @example Return oEmbeds for Tweets with the ID 25938088801
# Twitter.status_with_activity(25938088801)
# @overload oembed(*ids_or_urls, options)
# @param ids_or_urls [Enumerable<Integer, String>] A collection of Tweet IDs or URLs.
# @overload oembed(*tweets, options)
# @param tweets [Enumerable<Integer, String, URI, Twitter::Tweet>] A collection of Tweet IDs, URIs, or objects.
# @param options [Hash] A customizable set of options.
# @option options [Integer] :maxwidth The maximum width in pixels that the embed should be rendered at. This value is constrained to be between 250 and 550 pixels.
# @option options [Boolean, String, Integer] :hide_media Specifies whether the embedded Tweet should automatically expand images which were uploaded via {https://dev.twitter.com/docs/api/1.1/post/statuses/update_with_media POST statuses/update_with_media}. When set to either true, t or 1 images will not be expanded. Defaults to false.
Expand All @@ -254,8 +256,9 @@ def oembed(tweet, options={})
# @option options [String] :lang Language code for the rendered embed. This will affect the text and localization of the rendered HTML.
def oembeds(*args)
arguments = Twitter::API::Arguments.new(args)
arguments.flatten.threaded_map do |id_or_url|
oembed(id_or_url, arguments.options)
arguments.flatten.threaded_map do |tweet|
id = extract_id(tweet)
oembed(id, arguments.options)
end
end

Expand All @@ -277,42 +280,26 @@ def oembeds(*args)
# Twitter.retweeters_ids(25938088801)
def retweeters_ids(*args)
arguments = Twitter::API::Arguments.new(args)
arguments.options[:id] ||= extract_tweet_id(arguments.first)
arguments.options[:id] ||= extract_id(arguments.first)
cursor_from_response(:ids, nil, :get, "/1.1/statuses/retweeters/ids.json", arguments.options, :retweeters_ids)
end

private

# Take a URI string or Tweet object and convert it to an id.
#
# @param tweet [Integer, String, URI, Twitter::Tweet] A Tweet ID, URI, or object.
# @return [Integer]
def extract_tweet_id(tweet)
case tweet
when Integer
tweet
when String
tweet.split('/').last.to_i
when URI
tweet.path.split('/').last.to_i
when Twitter::Tweet
tweet.id
end
end

# @param request_method [Symbol]
# @param path [String]
# @param args [Array]
# @return [Array<Twitter::Tweet>]
def threaded_tweets_from_response(request_method, path, args)
arguments = Twitter::API::Arguments.new(args)
arguments.flatten.threaded_map do |id|
arguments.flatten.threaded_map do |tweet|
id = extract_id(tweet)
object_from_response(Twitter::Tweet, request_method, path + "/#{id}.json", arguments.options)
end
end

def post_retweet(tweet, options)
id = extract_tweet_id(tweet)
id = extract_id(tweet)
response = post("/1.1/statuses/retweet/#{id}.json", options)
retweeted_status = response.dup
retweeted_status[:body] = response[:body].delete(:retweeted_status)
Expand Down
20 changes: 19 additions & 1 deletion lib/twitter/api/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,23 @@ module Utils

private

# Take a URI string or Twitter::Identity object and return its ID
#
# @param object [Integer, String, URI, Twitter::Identity] An ID, URI, or object.
# @return [Integer]
def extract_id(object)
case object
when Integer
object
when String
object.split('/').last.to_i
when URI
object.path.split('/').last.to_i
when Twitter::Identity
object.id
end
end

# @param request_method [Symbol]
# @param path [String]
# @param args [Array]
Expand Down Expand Up @@ -69,7 +86,8 @@ def objects_from_array(klass, array)
# @return [Array]
def threaded_object_from_response(klass, request_method, path, args)
arguments = Twitter::API::Arguments.new(args)
arguments.flatten.threaded_map do |id|
arguments.flatten.threaded_map do |object|
id = extract_id(object)
object_from_response(klass, request_method, path, arguments.options.merge(:id => id))
end
end
Expand Down
60 changes: 60 additions & 0 deletions spec/twitter/api/favorites_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,26 @@
expect(tweets.first).to be_a Twitter::Tweet
expect(tweets.first.text).to eq "The problem with your code is that it's doing exactly what you told it to do."
end
context "with a URI object passed" do
it "requests the correct resource" do
tweet = URI.parse("https://twitter.com/sferik/status/25938088801")
@client.unfavorite(tweet)
expect(a_post("/1.1/favorites/destroy.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
context "with a URI string passed" do
it "requests the correct resource" do
@client.unfavorite("https://twitter.com/sferik/status/25938088801")
expect(a_post("/1.1/favorites/destroy.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
context "with a Tweet passed" do
it "requests the correct resource" do
tweet = Twitter::Tweet.new(:id => 25938088801)
@client.unfavorite(tweet)
expect(a_post("/1.1/favorites/destroy.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
end

describe "#favorite" do
Expand All @@ -77,6 +97,26 @@
expect{@client.favorite(25938088801)}.not_to raise_error
end
end
context "with a URI object passed" do
it "requests the correct resource" do
tweet = URI.parse("https://twitter.com/sferik/status/25938088801")
@client.favorite(tweet)
expect(a_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
context "with a URI string passed" do
it "requests the correct resource" do
@client.favorite("https://twitter.com/sferik/status/25938088801")
expect(a_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
context "with a Tweet passed" do
it "requests the correct resource" do
tweet = Twitter::Tweet.new(:id => 25938088801)
@client.favorite(tweet)
expect(a_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
end

describe "#favorite!" do
Expand Down Expand Up @@ -109,6 +149,26 @@
expect{@client.favorite!(25938088801)}.to raise_error Twitter::Error::AlreadyFavorited
end
end
context "with a URI object passed" do
it "requests the correct resource" do
tweet = URI.parse("https://twitter.com/sferik/status/25938088801")
@client.favorite!(tweet)
expect(a_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
context "with a URI string passed" do
it "requests the correct resource" do
@client.favorite!("https://twitter.com/sferik/status/25938088801")
expect(a_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
context "with a Tweet passed" do
it "requests the correct resource" do
tweet = Twitter::Tweet.new(:id => 25938088801)
@client.favorite!(tweet)
expect(a_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"})).to have_been_made
end
end
end

end
Loading

0 comments on commit 721de1e

Please sign in to comment.