twitter 4.1.2 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,14 @@
1
+ 4.2.0
2
+ -----
3
+ * [Use new resource for `Twitter::API#retweets_of_me`](https://github.com/sferik/twitter/commit/d88ca1e91af06e748c31dcda287326028cf28258)
4
+ * [`Twitter::API#favorite` no longer raises `Twitter::Error::Forbidden`](https://github.com/sferik/twitter/commit/65c01133a96106a6b0c61bc16cb2ffec38fa5e25)
5
+ * [`Twitter::API#retweet` no longer raises `Twitter::Error::Forbidden`](https://github.com/sferik/twitter/commit/f1322ab12c573229ea3dc8decda2e2ea8b36fc31)
6
+ * [Add `Twitter::Error::AlreadyFavorited`](https://github.com/sferik/twitter/commit/34710927e00d4dc5abc049bfc198bdd337fba1bd)
7
+ * [Add `Twitter::Error::AlreadyRetweeted`](https://github.com/sferik/twitter/commit/2a231a0888dcd65dbef2dc92571e06d50f845cca)
8
+
1
9
  4.1.2
2
10
  -----
3
- * [Add abort_on_exception to threaded_map](https://github.com/sferik/twitter/commit/15c9a7c221f24226c1003b76b287d2b2ed9306cb)
11
+ * [Add abort_on_exception to `Enumerable#threaded_map`](https://github.com/sferik/twitter/commit/15c9a7c221f24226c1003b76b287d2b2ed9306cb) ([@aheaven87](http://twitter.com/aheaven87))
4
12
 
5
13
  4.1.1
6
14
  -----
data/README.md CHANGED
@@ -216,7 +216,7 @@ Twitter.update("I'm tweeting with @gem!")
216
216
  Applications that make requests on behalf of multiple Twitter users should
217
217
  avoid using global configuration. In this case, you may still specify the
218
218
  `consumer_key` and `consumer_secret` globally. (In a Rails application, this
219
- could go in `config/initiliazers/twitter.rb`.)
219
+ could go in `config/initializers/twitter.rb`.)
220
220
 
221
221
  ```ruby
222
222
  Twitter.configure do |config|
@@ -6,6 +6,8 @@ require 'twitter/core_ext/hash'
6
6
  require 'twitter/core_ext/kernel'
7
7
  require 'twitter/cursor'
8
8
  require 'twitter/direct_message'
9
+ require 'twitter/error/already_favorited'
10
+ require 'twitter/error/already_retweeted'
9
11
  require 'twitter/error/forbidden'
10
12
  require 'twitter/error/not_found'
11
13
  require 'twitter/language'
@@ -1372,7 +1374,7 @@ module Twitter
1372
1374
  # @option options [String] :until Optional. Returns tweets generated before the given date. Date should be formatted as YYYY-MM-DD.
1373
1375
  # @option options [Integer] :since_id Returns results with an ID greater than (that is, more recent than) the specified ID. There are limits to the number of Tweets which can be accessed through the API. If the limit of Tweets has occured since the since_id, the since_id will be forced to the oldest ID available.
1374
1376
  # @option options [Integer] :max_id Returns results with an ID less than (that is, older than) or equal to the specified ID.
1375
- # @option options [Boolean, String, Integer] :include_entities Specifies that each tweet should include an 'entities' node including metadata about the tweet such as: user_mentions, urls, and hashtags.
1377
+ # @option options [Boolean, String, Integer] :include_entities The tweet entities node will be disincluded when set to false.
1376
1378
  # @return [Twitter::SearchResults] Return tweets that match a specified query with search metadata
1377
1379
  # @example Returns tweets related to twitter
1378
1380
  # Twitter.search('twitter')
@@ -1443,13 +1445,50 @@ module Twitter
1443
1445
  def favorite(*args)
1444
1446
  options = args.extract_options!
1445
1447
  args.flatten.threaded_map do |id|
1446
- object_from_response(Twitter::Tweet, :post, "/1.1/favorites/create.json", options.merge(:id => id))
1447
- end
1448
+ begin
1449
+ object_from_response(Twitter::Tweet, :post, "/1.1/favorites/create.json", options.merge(:id => id))
1450
+ rescue Twitter::Error::Forbidden => error
1451
+ raise unless error.message == Twitter::Error::AlreadyFavorited::MESSAGE
1452
+ end
1453
+ end.compact
1448
1454
  end
1449
1455
  alias fav favorite
1450
1456
  alias fave favorite
1451
1457
  alias favorite_create favorite
1452
1458
 
1459
+ # Favorites the specified Tweets as the authenticating user and raises an error if one has already been favorited
1460
+ #
1461
+ # @see https://dev.twitter.com/docs/api/1.1/post/favorites/create
1462
+ # @rate_limited No
1463
+ # @authentication_required Requires user context
1464
+ # @raise [Twitter::Error::AlreadyFavorited] Error raised when tweet has already been favorited.
1465
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
1466
+ # @return [Array<Twitter::Tweet>] The favorited Tweets.
1467
+ # @overload favorite(*ids)
1468
+ # @param ids [Array<Integer>, Set<Integer>] An array of Tweet IDs.
1469
+ # @example Favorite the Tweet with the ID 25938088801
1470
+ # Twitter.favorite(25938088801)
1471
+ # @overload favorite(*ids, options)
1472
+ # @param ids [Array<Integer>, Set<Integer>] An array of Tweet IDs.
1473
+ # @param options [Hash] A customizable set of options.
1474
+ def favorite!(*args)
1475
+ options = args.extract_options!
1476
+ args.flatten.threaded_map do |id|
1477
+ begin
1478
+ object_from_response(Twitter::Tweet, :post, "/1.1/favorites/create.json", options.merge(:id => id))
1479
+ rescue Twitter::Error::Forbidden => error
1480
+ if error.message == "You have already favorited this status"
1481
+ raise Twitter::Error::AlreadyFavorited.new("Tweet with the ID #{id} has already been favorited by the authenticated user.")
1482
+ else
1483
+ raise
1484
+ end
1485
+ end
1486
+ end
1487
+ end
1488
+ alias fav! favorite!
1489
+ alias fave! favorite!
1490
+ alias favorite_create! favorite!
1491
+
1453
1492
  # Un-favorites the specified Tweets as the authenticating user
1454
1493
  #
1455
1494
  # @see https://dev.twitter.com/docs/api/1.1/post/favorites/destroy
@@ -1488,7 +1527,7 @@ module Twitter
1488
1527
  # @option options [Boolean, String, Integer] :exclude_replies This parameter will prevent replies from appearing in the returned timeline. Using exclude_replies with the count parameter will mean you will receive up-to count tweets - this is because the count parameter retrieves that many tweets before filtering out retweets and replies.
1489
1528
  # @option options [Boolean, String, Integer] :include_rts Specifies that the timeline should include native retweets in addition to regular tweets. Note: If you're using the trim_user parameter in conjunction with include_rts, the retweets will no longer contain a full user object.
1490
1529
  # @option options [Boolean, String, Integer] :contributor_details Specifies that the contributors element should be enhanced to include the screen_name of the contributor.
1491
- # @option options [Boolean, String, Integer] :include_entities Specifies that each tweet should include an 'entities' node including metadata about the tweet such as: user_mentions, urls, and hashtags.
1530
+ # @option options [Boolean, String, Integer] :include_entities The tweet entities node will be disincluded when set to false.
1492
1531
  # @example Return the 20 most recent Tweets, including retweets if they exist, posted by the authenticating user and the users they follow
1493
1532
  # Twitter.home_timeline
1494
1533
  def home_timeline(options={})
@@ -1583,7 +1622,7 @@ module Twitter
1583
1622
  # @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.
1584
1623
  # @option options [Boolean, String, Integer] :exclude_replies This parameter will prevent replies from appearing in the returned timeline. Using exclude_replies with the count parameter will mean you will receive up-to count tweets - this is because the count parameter retrieves that many tweets before filtering out retweets and replies.
1585
1624
  # @option options [Boolean, String, Integer] :contributor_details Specifies that the contributors element should be enhanced to include the screen_name of the contributor.
1586
- # @option options [Boolean, String, Integer] :include_entities Specifies that each tweet should include an 'entities' node including metadata about the tweet such as: user_mentions, urls, and hashtags.
1625
+ # @option options [Boolean, String, Integer] :include_entities The tweet entities node will be disincluded when set to false.
1587
1626
  # @example Return the 20 most recent retweets posted by users followed by the authenticating user
1588
1627
  # Twitter.retweeted_to_me
1589
1628
  def retweeted_to_me(options={})
@@ -1596,27 +1635,22 @@ module Twitter
1596
1635
 
1597
1636
  # Returns the 20 most recent tweets of the authenticated user that have been retweeted by others
1598
1637
  #
1599
- # @see https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
1600
- # @note This method can only return up to 3,200 Tweets.
1638
+ # @see https://dev.twitter.com/docs/api/1.1/get/statuses/retweets_of_me
1601
1639
  # @rate_limited Yes
1602
1640
  # @authentication_required Requires user context
1603
1641
  # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
1604
1642
  # @return [Array<Twitter::Tweet>]
1605
1643
  # @param options [Hash] A customizable set of options.
1644
+ # @option options [Integer] :count Specifies the number of records to retrieve. Must be less than or equal to 200.
1606
1645
  # @option options [Integer] :since_id Returns results with an ID greater than (that is, more recent than) the specified ID.
1607
1646
  # @option options [Integer] :max_id Returns results with an ID less than (that is, older than) or equal to the specified ID.
1608
- # @option options [Integer] :count Specifies the number of records to retrieve. Must be less than or equal to 200.
1609
1647
  # @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.
1610
- # @option options [Boolean, String, Integer] :exclude_replies This parameter will prevent replies from appearing in the returned timeline. Using exclude_replies with the count parameter will mean you will receive up-to count tweets - this is because the count parameter retrieves that many tweets before filtering out retweets and replies.
1611
- # @option options [Boolean, String, Integer] :contributor_details Specifies that the contributors element should be enhanced to include the screen_name of the contributor.
1648
+ # @option options [Boolean, String, Integer] :include_entities The tweet entities node will be disincluded when set to false.
1649
+ # @option options [Boolean, String, Integer] :include_user_entities The user entities node will be disincluded when set to false.
1612
1650
  # @example Return the 20 most recent tweets of the authenticated user that have been retweeted by others
1613
1651
  # Twitter.retweets_of_me
1614
1652
  def retweets_of_me(options={})
1615
- options[:include_rts] = false
1616
- count = options[:count] || DEFAULT_TWEETS_PER_REQUEST
1617
- collect_with_count(count) do |count_options|
1618
- user_timeline(options.merge(count_options)).select{|tweet| tweet.retweet_count.to_i > 0}
1619
- end
1653
+ collection_from_response(Twitter::Tweet, :get, "/1.1/statuses/retweets_of_me.json", options)
1620
1654
  end
1621
1655
 
1622
1656
  # Returns the 20 most recent Tweets posted by the specified user
@@ -1847,12 +1881,11 @@ module Twitter
1847
1881
  end
1848
1882
  alias tweet_destroy status_destroy
1849
1883
 
1850
- # Retweets tweets
1884
+ # Retweets the specified Tweets as the authenticating user
1851
1885
  #
1852
1886
  # @see https://dev.twitter.com/docs/api/1.1/post/statuses/retweet/:id
1853
1887
  # @rate_limited Yes
1854
1888
  # @authentication_required Requires user context
1855
- # @raise [Twitter::Error::Forbidden] Error raised when tweet has already been retweeted.
1856
1889
  # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
1857
1890
  # @return [Array<Twitter::Tweet>] The original tweets with retweet details embedded.
1858
1891
  # @overload retweet(*ids)
@@ -1866,12 +1899,51 @@ module Twitter
1866
1899
  def retweet(*args)
1867
1900
  options = args.extract_options!
1868
1901
  args.flatten.threaded_map do |id|
1869
- response = post("/1.1/statuses/retweet/#{id}.json", options)
1870
- retweeted_status = response.dup
1871
- retweeted_status[:body] = response[:body].delete(:retweeted_status)
1872
- retweeted_status[:body][:retweeted_status] = response[:body]
1873
- Twitter::Tweet.from_response(retweeted_status)
1874
- end
1902
+ begin
1903
+ response = post("/1.1/statuses/retweet/#{id}.json", options)
1904
+ retweeted_status = response.dup
1905
+ retweeted_status[:body] = response[:body].delete(:retweeted_status)
1906
+ retweeted_status[:body][:retweeted_status] = response[:body]
1907
+ Twitter::Tweet.from_response(retweeted_status)
1908
+ rescue Twitter::Error::Forbidden => error
1909
+ raise unless error.message == Twitter::Error::AlreadyRetweeted::MESSAGE
1910
+ end
1911
+ end.compact
1912
+ end
1913
+
1914
+ # Retweets the specified Tweets as the authenticating user and raises an error if one has already been retweeted
1915
+ #
1916
+ # @see https://dev.twitter.com/docs/api/1.1/post/statuses/retweet/:id
1917
+ # @rate_limited Yes
1918
+ # @authentication_required Requires user context
1919
+ # @raise [Twitter::Error::AlreadyRetweeted] Error raised when tweet has already been retweeted.
1920
+ # @raise [Twitter::Error::Unauthorized] Error raised when supplied user credentials are not valid.
1921
+ # @return [Array<Twitter::Tweet>] The original tweets with retweet details embedded.
1922
+ # @overload retweet(*ids)
1923
+ # @param ids [Array<Integer>, Set<Integer>] An array of Tweet IDs.
1924
+ # @example Retweet the Tweet with the ID 28561922516
1925
+ # Twitter.retweet(28561922516)
1926
+ # @overload retweet(*ids, options)
1927
+ # @param ids [Array<Integer>, Set<Integer>] An array of Tweet IDs.
1928
+ # @param options [Hash] A customizable set of options.
1929
+ # @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.
1930
+ def retweet!(*args)
1931
+ options = args.extract_options!
1932
+ args.flatten.threaded_map do |id|
1933
+ begin
1934
+ response = post("/1.1/statuses/retweet/#{id}.json", options)
1935
+ retweeted_status = response.dup
1936
+ retweeted_status[:body] = response[:body].delete(:retweeted_status)
1937
+ retweeted_status[:body][:retweeted_status] = response[:body]
1938
+ Twitter::Tweet.from_response(retweeted_status)
1939
+ rescue Twitter::Error::Forbidden => error
1940
+ if error.message == "sharing is not permissible for this status (Share validations failed)"
1941
+ raise Twitter::Error::AlreadyRetweeted.new("Tweet with the ID #{id} has already been retweeted by the authenticated user.")
1942
+ else
1943
+ raise
1944
+ end
1945
+ end
1946
+ end.compact
1875
1947
  end
1876
1948
 
1877
1949
  # Updates the authenticating user's status
@@ -4,5 +4,8 @@ module Twitter
4
4
  class BasicUser < Twitter::Identity
5
5
  attr_reader :following, :screen_name
6
6
  alias following? following
7
+ alias handle screen_name
8
+ alias username screen_name
9
+ alias user_name screen_name
7
10
  end
8
11
  end
@@ -1,15 +1,23 @@
1
1
  module Enumerable
2
2
 
3
3
  def threaded_map
4
+ abort_on_exception do
5
+ threads = []
6
+ each do |object|
7
+ threads << Thread.new { yield object }
8
+ end
9
+ threads.map(&:value)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def abort_on_exception
4
16
  initial_abort_on_exception = Thread.abort_on_exception
5
17
  Thread.abort_on_exception ||= true
6
- threads = []
7
- each do |object|
8
- threads << Thread.new { yield object }
9
- end
10
- values = threads.map(&:value)
18
+ value = yield
11
19
  Thread.abort_on_exception = initial_abort_on_exception
12
- values
20
+ value
13
21
  end
14
22
 
15
23
  end
@@ -0,0 +1,10 @@
1
+ require 'twitter/error/forbidden'
2
+
3
+ module Twitter
4
+ class Error
5
+ # Raised when a Tweet has already been favorited
6
+ class AlreadyFavorited < Twitter::Error::Forbidden
7
+ MESSAGE = "You have already favorited this status"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'twitter/error/forbidden'
2
+
3
+ module Twitter
4
+ class Error
5
+ # Raised when a Tweet has already been retweeted
6
+ class AlreadyRetweeted < Twitter::Error::Forbidden
7
+ MESSAGE = "sharing is not permissible for this status (Share validations failed)"
8
+ end
9
+ end
10
+ end
@@ -1,8 +1,8 @@
1
1
  module Twitter
2
2
  class Version
3
3
  MAJOR = 4 unless defined? Twitter::MAJOR
4
- MINOR = 1 unless defined? Twitter::MINOR
5
- PATCH = 2 unless defined? Twitter::PATCH
4
+ MINOR = 2 unless defined? Twitter::MINOR
5
+ PATCH = 0 unless defined? Twitter::PATCH
6
6
  PRE = nil unless defined? Twitter::PRE
7
7
 
8
8
  class << self
@@ -0,0 +1 @@
1
+ {"errors":[{"message":"You have already favorited this status","code":139}]}
@@ -0,0 +1 @@
1
+ {"errors":"sharing is not permissible for this status (Share validations failed)"}
@@ -53,6 +53,46 @@ describe Twitter::API do
53
53
  expect(tweets.first).to be_a Twitter::Tweet
54
54
  expect(tweets.first.text).to eq "The problem with your code is that it's doing exactly what you told it to do."
55
55
  end
56
+ context "already favorited" do
57
+ before do
58
+ stub_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"}).to_return(:status => 403, :body => fixture("already_favorited.json"), :headers => {:content_type => "application/json; charset=utf-8"})
59
+ end
60
+ it "does not raises an error" do
61
+ expect{@client.favorite(25938088801)}.not_to raise_error
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#favorite!" do
67
+ before do
68
+ stub_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"}).to_return(:body => fixture("status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
69
+ end
70
+ it "requests the correct resource" do
71
+ @client.favorite!(25938088801)
72
+ expect(a_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"})).to have_been_made
73
+ end
74
+ it "returns an array of favorited Tweets" do
75
+ tweets = @client.favorite!(25938088801)
76
+ expect(tweets).to be_an Array
77
+ expect(tweets.first).to be_a Twitter::Tweet
78
+ expect(tweets.first.text).to eq "The problem with your code is that it's doing exactly what you told it to do."
79
+ end
80
+ context "forbidden" do
81
+ before do
82
+ stub_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"}).to_return(:status => 403, :headers => {:content_type => "application/json; charset=utf-8"})
83
+ end
84
+ it "raises a Forbidden error" do
85
+ expect{@client.favorite!(25938088801)}.to raise_error(Twitter::Error::Forbidden)
86
+ end
87
+ end
88
+ context "already favorited" do
89
+ before do
90
+ stub_post("/1.1/favorites/create.json").with(:body => {:id => "25938088801"}).to_return(:status => 403, :body => fixture("already_favorited.json"), :headers => {:content_type => "application/json; charset=utf-8"})
91
+ end
92
+ it "raises an AlreadyFavorited error" do
93
+ expect{@client.favorite!(25938088801)}.to raise_error(Twitter::Error::AlreadyFavorited, "Tweet with the ID 25938088801 has already been favorited by the authenticated user.")
94
+ end
95
+ end
56
96
  end
57
97
 
58
98
  describe "#unfavorite" do
@@ -159,19 +199,17 @@ describe Twitter::API do
159
199
 
160
200
  describe "#retweets_of_me" do
161
201
  before do
162
- stub_get("/1.1/statuses/user_timeline.json").with(:query => {:include_rts => "false", :count => "200"}).to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
163
- stub_get("/1.1/statuses/user_timeline.json").with(:query => {:include_rts => "false", :count => "200", :max_id => "244102490646278145"}).to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
202
+ stub_get("/1.1/statuses/retweets_of_me.json").to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
164
203
  end
165
204
  it "requests the correct resource" do
166
205
  @client.retweets_of_me
167
- expect(a_get("/1.1/statuses/user_timeline.json").with(:query => {:include_rts => "false", :count => "200"})).to have_been_made
168
- expect(a_get("/1.1/statuses/user_timeline.json").with(:query => {:include_rts => "false", :count => "200", :max_id => "244102490646278145"})).to have_been_made
206
+ expect(a_get("/1.1/statuses/retweets_of_me.json")).to have_been_made
169
207
  end
170
208
  it "returns the 20 most recent tweets of the authenticated user that have been retweeted by others" do
171
209
  tweets = @client.retweets_of_me
172
210
  expect(tweets).to be_an Array
173
211
  expect(tweets.first).to be_a Twitter::Tweet
174
- expect(tweets.first.text).to eq "RT @olivercameron: Mosaic looks cool: http://t.co/A8013C9k"
212
+ expect(tweets.first.text).to eq "Happy Birthday @imdane. Watch out for those @rally pranksters!"
175
213
  end
176
214
  end
177
215
 
@@ -371,6 +409,48 @@ describe Twitter::API do
371
409
  expect(tweets.first.retweeted_tweet.text).to eq "RT @gruber: As for the Series, I'm for the Giants. Fuck Texas, fuck Nolan Ryan, fuck George Bush."
372
410
  expect(tweets.first.retweeted_tweet.id).not_to eq tweets.first.id
373
411
  end
412
+ context "already retweeted" do
413
+ before do
414
+ stub_post("/1.1/statuses/retweet/28561922516.json").to_return(:status => 403, :body => fixture("already_retweeted.json"), :headers => {:content_type => "application/json; charset=utf-8"})
415
+ end
416
+ it "does not raise an error" do
417
+ expect{@client.retweet(28561922516)}.not_to raise_error
418
+ end
419
+ end
420
+ end
421
+
422
+ describe "#retweet!" do
423
+ before do
424
+ stub_post("/1.1/statuses/retweet/28561922516.json").to_return(:body => fixture("retweet.json"), :headers => {:content_type => "application/json; charset=utf-8"})
425
+ end
426
+ it "requests the correct resource" do
427
+ @client.retweet!(28561922516)
428
+ expect(a_post("/1.1/statuses/retweet/28561922516.json")).to have_been_made
429
+ end
430
+ it "returns an array of Tweets with retweet details embedded" do
431
+ tweets = @client.retweet!(28561922516)
432
+ expect(tweets).to be_an Array
433
+ expect(tweets.first).to be_a Twitter::Tweet
434
+ expect(tweets.first.text).to eq "As for the Series, I'm for the Giants. Fuck Texas, fuck Nolan Ryan, fuck George Bush."
435
+ expect(tweets.first.retweeted_tweet.text).to eq "RT @gruber: As for the Series, I'm for the Giants. Fuck Texas, fuck Nolan Ryan, fuck George Bush."
436
+ expect(tweets.first.retweeted_tweet.id).not_to eq tweets.first.id
437
+ end
438
+ context "fobidden" do
439
+ before do
440
+ stub_post("/1.1/statuses/retweet/28561922516.json").to_return(:status => 403, :headers => {:content_type => "application/json; charset=utf-8"})
441
+ end
442
+ it "raises a Forbidden error" do
443
+ expect{@client.retweet!(28561922516)}.to raise_error(Twitter::Error::Forbidden)
444
+ end
445
+ end
446
+ context "already retweeted" do
447
+ before do
448
+ stub_post("/1.1/statuses/retweet/28561922516.json").to_return(:status => 403, :body => fixture("already_retweeted.json"), :headers => {:content_type => "application/json; charset=utf-8"})
449
+ end
450
+ it "raises an AlreadyRetweeted error" do
451
+ expect{@client.retweet!(28561922516)}.to raise_error(Twitter::Error::AlreadyRetweeted, "Tweet with the ID 28561922516 has already been retweeted by the authenticated user.")
452
+ end
453
+ end
374
454
  end
375
455
 
376
456
  describe "#tweet" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twitter
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.2
4
+ version: 4.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-10-20 00:00:00.000000000 Z
15
+ date: 2012-10-30 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: faraday
@@ -248,6 +248,8 @@ files:
248
248
  - lib/twitter/entity/url.rb
249
249
  - lib/twitter/entity/user_mention.rb
250
250
  - lib/twitter/entity.rb
251
+ - lib/twitter/error/already_favorited.rb
252
+ - lib/twitter/error/already_retweeted.rb
251
253
  - lib/twitter/error/bad_gateway.rb
252
254
  - lib/twitter/error/bad_request.rb
253
255
  - lib/twitter/error/client_error.rb
@@ -298,6 +300,8 @@ files:
298
300
  - spec/fixtures/about_me.json
299
301
  - spec/fixtures/activity_summary.json
300
302
  - spec/fixtures/all.json
303
+ - spec/fixtures/already_favorited.json
304
+ - spec/fixtures/already_retweeted.json
301
305
  - spec/fixtures/bad_gateway.json
302
306
  - spec/fixtures/bad_request.json
303
307
  - spec/fixtures/by_friends.json
@@ -457,6 +461,8 @@ test_files:
457
461
  - spec/fixtures/about_me.json
458
462
  - spec/fixtures/activity_summary.json
459
463
  - spec/fixtures/all.json
464
+ - spec/fixtures/already_favorited.json
465
+ - spec/fixtures/already_retweeted.json
460
466
  - spec/fixtures/bad_gateway.json
461
467
  - spec/fixtures/bad_request.json
462
468
  - spec/fixtures/by_friends.json