t 0.4.0 → 0.5.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.
data/lib/t/collectable.rb CHANGED
@@ -4,7 +4,7 @@ module T
4
4
  def collect_with_cursor(collection=[], cursor=-1, &block)
5
5
  object = yield cursor
6
6
  collection += object.collection
7
- object.next_cursor.zero? ? collection : collect_with_cursor(collection, object.next_cursor)
7
+ object.last? ? collection : collect_with_cursor(collection, object.next_cursor, &block)
8
8
  end
9
9
 
10
10
  end
data/lib/t/delete.rb ADDED
@@ -0,0 +1,84 @@
1
+ require 't/core_ext/string'
2
+ require 't/rcfile'
3
+ require 't/requestable'
4
+ require 'thor'
5
+
6
+ module T
7
+ class Delete < Thor
8
+ include T::Requestable
9
+
10
+ check_unknown_options!
11
+
12
+ def initialize(*)
13
+ super
14
+ @rcfile = RCFile.instance
15
+ end
16
+
17
+ desc "block SCREEN_NAME [SCREEN_NAME...]", "Unblock users."
18
+ def block(screen_name, *screen_names)
19
+ screen_names.unshift(screen_name)
20
+ screen_names.threaded_each do |screen_name|
21
+ screen_name.strip_at
22
+ retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
23
+ client.unblock(screen_name, :include_entities => false)
24
+ end
25
+ end
26
+ say "@#{@rcfile.default_profile[0]} unblocked @#{screen_names.join(' ')}."
27
+ say
28
+ say "Run `#{File.basename($0)} block #{screen_names.join(' ')}` to block."
29
+ end
30
+
31
+ desc "dm", "Delete the last Direct Message sent."
32
+ def dm
33
+ direct_message = client.direct_messages_sent(:count => 1, :include_entities => false).first
34
+ if direct_message
35
+ unless parent_options['force']
36
+ return unless yes? "Are you sure you want to permanently delete the direct message to @#{direct_message.recipient.screen_name}: \"#{direct_message.text}\"? [y/N]"
37
+ end
38
+ direct_message = client.direct_message_destroy(direct_message.id, :include_entities => false)
39
+ say "@#{direct_message.sender.screen_name} deleted the direct message sent to @#{direct_message.recipient.screen_name}: \"#{direct_message.text}\""
40
+ else
41
+ raise Thor::Error, "Direct Message not found"
42
+ end
43
+ end
44
+ map %w(m) => :dm
45
+
46
+ desc "favorite STATUS_ID [STATUS_ID...]", "Delete favorites."
47
+ def favorite(status_id, *status_ids)
48
+ status_ids.unshift(status_id)
49
+ status_ids.each do |status_id|
50
+ unless parent_options['force']
51
+ status = client.status(status_id, :include_entities => false, :include_my_retweet => false, :trim_user => true)
52
+ return unless yes? "Are you sure you want to delete the favorite of @#{status.user.screen_name}'s status: \"#{status.text}\"? [y/N]"
53
+ end
54
+ status = client.unfavorite(status_id, :include_entities => false)
55
+ say "@#{@rcfile.default_profile[0]} unfavorited @#{status.user.screen_name}'s status: \"#{status.text}\""
56
+ end
57
+ end
58
+ map %w(post tweet update) => :status
59
+
60
+ desc "list LIST_NAME", "Delete a list."
61
+ def list(list_name)
62
+ unless parent_options['force']
63
+ return unless yes? "Are you sure you want to permanently delete the list \"#{list_name}\"? [y/N]"
64
+ end
65
+ status = client.list_destroy(list_name)
66
+ say "@#{@rcfile.default_profile[0]} deleted the list \"#{list_name}\"."
67
+ end
68
+
69
+ desc "status STATUS_ID [STATUS_ID...]", "Delete Tweets."
70
+ def status(status_id, *status_ids)
71
+ status_ids.unshift(status_id)
72
+ status_ids.each do |status_id|
73
+ unless parent_options['force']
74
+ status = client.status(status_id, :include_entities => false, :include_my_retweet => false, :trim_user => true)
75
+ return unless yes? "Are you sure you want to permanently delete @#{status.user.screen_name}'s status: \"#{status.text}\"? [y/N]"
76
+ end
77
+ status = client.status_destroy(status_id, :include_entities => false, :trim_user => true)
78
+ say "@#{@rcfile.default_profile[0]} deleted the status: \"#{status.text}\""
79
+ end
80
+ end
81
+ map %w(post tweet update) => :status
82
+
83
+ end
84
+ end
data/lib/t/list.rb ADDED
@@ -0,0 +1,103 @@
1
+ require 'action_view'
2
+ require 'active_support/core_ext/array/grouping'
3
+ require 'retryable'
4
+ require 't/core_ext/enumerable'
5
+ require 't/core_ext/string'
6
+ require 't/rcfile'
7
+ require 't/requestable'
8
+ require 'thor'
9
+
10
+ module T
11
+ class List < Thor
12
+ include ActionView::Helpers::DateHelper
13
+ include T::Requestable
14
+
15
+ DEFAULT_NUM_RESULTS = 20
16
+ MAX_SCREEN_NAME_SIZE = 20
17
+ MAX_USERS_PER_LIST = 500
18
+ MAX_USERS_PER_REQUEST = 100
19
+
20
+ check_unknown_options!
21
+
22
+ def initialize(*)
23
+ super
24
+ @rcfile = RCFile.instance
25
+ end
26
+
27
+ desc "add LIST_NAME SCREEN_NAME [SCREEN_NAME...]", "Add users to a list."
28
+ def add(list_name, screen_name, *screen_names)
29
+ screen_names.unshift(screen_name)
30
+ screen_names.map!(&:strip_at)
31
+ screen_names.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
32
+ retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
33
+ client.list_add_members(list_name, user_id_group)
34
+ end
35
+ end
36
+ number = screen_names.length
37
+ say "@#{@rcfile.default_profile[0]} added #{number} #{number == 1 ? 'user' : 'users'} to the list \"#{list_name}\"."
38
+ say
39
+ say "Run `#{File.basename($0)} list remove users #{list_name} #{screen_names.join(' ')}` to undo."
40
+ end
41
+
42
+ desc "create LIST_NAME [DESCRIPTION]", "Create a new list."
43
+ method_option :private, :aliases => "-p", :type => :boolean
44
+ def create(list_name, description="")
45
+ opts = description.blank? ? {} : {:description => description}
46
+ opts.merge!(:mode => 'private') if options['private']
47
+ client.list_create(list_name, opts)
48
+ say "@#{@rcfile.default_profile[0]} created the list \"#{list_name}\"."
49
+ end
50
+
51
+ # Remove
52
+ desc "remove LIST_NAME SCREEN_NAME [SCREEN_NAME...]", "Remove users from a list."
53
+ def remove(list_name, screen_name, *screen_names)
54
+ screen_names.unshift(screen_name)
55
+ screen_names.map!(&:strip_at)
56
+ screen_names.in_groups_of(MAX_USERS_PER_REQUEST, false).threaded_each do |user_id_group|
57
+ retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
58
+ client.list_remove_members(list_name, user_id_group)
59
+ end
60
+ end
61
+ number = screen_names.length
62
+ say "@#{@rcfile.default_profile[0]} removed #{number} #{number == 1 ? 'user' : 'users'} from the list \"#{list_name}\"."
63
+ say
64
+ say "Run `#{File.basename($0)} list add users #{list_name} #{screen_names.join(' ')}` to undo."
65
+ end
66
+
67
+ desc "timeline [SCREEN_NAME] LIST_NAME", "Show tweet timeline for members of the specified list."
68
+ method_option :created, :aliases => "-c", :type => :boolean, :default => false, :desc => "Sort by the time when Twitter acount was created."
69
+ method_option :friends, :aliases => "-d", :type => :boolean, :default => false, :desc => "Sort by total number of friends."
70
+ method_option :followers, :aliases => "-f", :type => :boolean, :default => false, :desc => "Sort by total number of followers."
71
+ method_option :listed, :aliases => "-i", :type => :boolean, :default => false, :desc => "Sort by number of list memberships."
72
+ method_option :long, :aliases => "-l", :type => :boolean, :default => false, :desc => "List in long format."
73
+ method_option :number, :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS
74
+ method_option :reverse, :aliases => "-r", :type => :boolean, :default => false, :desc => "Reverse the order of the sort."
75
+ method_option :tweets, :aliases => "-t", :type => :boolean, :default => false, :desc => "Sort by total number of Tweets."
76
+ method_option :unsorted, :aliases => "-u", :type => :boolean, :default => false, :desc => "Output is not sorted."
77
+ method_option :favorites, :aliases => "-v", :type => :boolean, :default => false, :desc => "Sort by total number of favorites."
78
+ def timeline(*args)
79
+ list = args.pop
80
+ owner = args.pop || @rcfile.default_profile[0]
81
+ per_page = options['number'] || DEFAULT_NUM_RESULTS
82
+ statuses = client.list_timeline(owner, list, :include_entities => false, :per_page => per_page)
83
+ statuses.reverse! if options['reverse']
84
+ if options['long']
85
+ array = statuses.map do |status|
86
+ created_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
87
+ [status.id.to_s, created_at, status.user.screen_name, status.text.gsub(/\n+/, ' ')]
88
+ end
89
+ if STDOUT.tty?
90
+ headings = ["ID", "Created at", "Screen name", "Text"]
91
+ array.unshift(headings)
92
+ end
93
+ print_table(array)
94
+ else
95
+ statuses.each do |status|
96
+ say "#{status.user.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text.gsub(/\n+/, ' ')} (#{time_ago_in_words(status.created_at)} ago)"
97
+ end
98
+ end
99
+ end
100
+ map %w(tl) => :timeline
101
+
102
+ end
103
+ end
data/lib/t/search.rb ADDED
@@ -0,0 +1,133 @@
1
+ require 'action_view'
2
+ require 'retryable'
3
+ require 't/core_ext/enumerable'
4
+ require 't/rcfile'
5
+ require 't/requestable'
6
+ require 'thor'
7
+
8
+ module T
9
+ class Search < Thor
10
+ include ActionView::Helpers::DateHelper
11
+ include T::Requestable
12
+
13
+ DEFAULT_NUM_RESULTS = 20
14
+ MAX_PAGES = 16
15
+ MAX_NUM_RESULTS = 200
16
+ MAX_SCREEN_NAME_SIZE = 20
17
+
18
+ check_unknown_options!
19
+
20
+ def initialize(*)
21
+ super
22
+ @rcfile = RCFile.instance
23
+ end
24
+
25
+ desc "all QUERY", "Returns the #{DEFAULT_NUM_RESULTS} most recent Tweets that match a specified query."
26
+ method_option :number, :aliases => "-n", :type => :numeric, :default => DEFAULT_NUM_RESULTS
27
+ def all(query)
28
+ rpp = options['number'] || DEFAULT_NUM_RESULTS
29
+ statuses = client.search(query, :include_entities => false, :rpp => rpp)
30
+ if parent_options['long']
31
+ array = statuses.map do |status|
32
+ created_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
33
+ [status.id.to_s, created_at, status.from_user, status.text.gsub(/\n+/, ' ')]
34
+ end
35
+ if STDOUT.tty?
36
+ headings = ["ID", "Created at", "Screen name", "Text"]
37
+ array.unshift(headings)
38
+ end
39
+ print_table(array)
40
+ else
41
+ statuses.each do |status|
42
+ say "#{status.from_user.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text.gsub(/\n+/, ' ')} (#{time_ago_in_words(status.created_at)} ago)"
43
+ end
44
+ end
45
+ end
46
+
47
+ desc "favorites QUERY", "Returns Tweets you've favorited that mach a specified query."
48
+ def favorites(query)
49
+ statuses = 1.upto(MAX_PAGES).threaded_map do |page|
50
+ retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
51
+ client.favorites(:page => page, :count => MAX_NUM_RESULTS).select do |status|
52
+ /#{query}/i.match(status.text)
53
+ end
54
+ end
55
+ end.flatten.compact
56
+ print_status_list(statuses)
57
+ end
58
+ map %w(faves) => :favorites
59
+
60
+ desc "mentions QUERY", "Returns Tweets mentioning you that mach a specified query."
61
+ def mentions(query)
62
+ statuses = 1.upto(MAX_PAGES).threaded_map do |page|
63
+ retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
64
+ client.mentions(:page => page, :count => MAX_NUM_RESULTS).select do |status|
65
+ /#{query}/i.match(status.text)
66
+ end
67
+ end
68
+ end.flatten.compact
69
+ print_status_list(statuses)
70
+ end
71
+ map %w(replies) => :mentions
72
+
73
+ desc "retweets QUERY", "Returns Tweets you've retweeted that mach a specified query."
74
+ def retweets(query)
75
+ statuses = 1.upto(MAX_PAGES).threaded_map do |page|
76
+ retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
77
+ client.retweeted_by(:page => page, :count => MAX_NUM_RESULTS).select do |status|
78
+ /#{query}/i.match(status.text)
79
+ end
80
+ end
81
+ end.flatten.compact
82
+ print_status_list(statuses)
83
+ end
84
+ map %w(rts) => :retweets
85
+
86
+ desc "timeline QUERY", "Returns Tweets in your timeline that match a specified query."
87
+ def timeline(query)
88
+ statuses = 1.upto(MAX_PAGES).threaded_map do |page|
89
+ retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
90
+ client.home_timeline(:page => page, :count => MAX_NUM_RESULTS).select do |status|
91
+ /#{query}/i.match(status.text)
92
+ end
93
+ end
94
+ end.flatten.compact
95
+ print_status_list(statuses)
96
+ end
97
+ map %w(tl) => :timeline
98
+
99
+ desc "user SCREEN_NAME QUERY", "Returns Tweets in a user's timeline that match a specified query."
100
+ def user(screen_name, query)
101
+ screen_name = screen_name.strip_at
102
+ statuses = 1.upto(MAX_PAGES).threaded_map do |page|
103
+ retryable(:tries => 3, :on => Twitter::Error::ServerError, :sleep => 0) do
104
+ client.user_timeline(screen_name, :page => page, :count => MAX_NUM_RESULTS).select do |status|
105
+ /#{query}/i.match(status.text)
106
+ end
107
+ end
108
+ end.flatten.compact
109
+ print_status_list(statuses)
110
+ end
111
+
112
+ private
113
+
114
+ def print_status_list(statuses)
115
+ if parent_options['long']
116
+ array = statuses.map do |status|
117
+ created_at = status.created_at > 6.months.ago ? status.created_at.strftime("%b %e %H:%M") : status.created_at.strftime("%b %e %Y")
118
+ [status.id.to_s, created_at, status.user.screen_name, status.text.gsub(/\n+/, ' ')]
119
+ end
120
+ if STDOUT.tty?
121
+ headings = ["ID", "Created at", "Screen name", "Text"]
122
+ array.unshift(headings)
123
+ end
124
+ print_table(array)
125
+ else
126
+ statuses.each do |status|
127
+ say "#{status.user.screen_name.rjust(MAX_SCREEN_NAME_SIZE)}: #{status.text.gsub(/\n+/, ' ')} (#{time_ago_in_words(status.created_at)} ago)"
128
+ end
129
+ end
130
+ end
131
+
132
+ end
133
+ end
data/lib/t/set.rb ADDED
@@ -0,0 +1,57 @@
1
+ require 't/core_ext/string'
2
+ require 't/rcfile'
3
+ require 't/requestable'
4
+ require 'thor'
5
+
6
+ module T
7
+ class Set < Thor
8
+ include T::Requestable
9
+
10
+ check_unknown_options!
11
+
12
+ def initialize(*)
13
+ super
14
+ @rcfile = RCFile.instance
15
+ end
16
+
17
+ desc "bio DESCRIPTION", "Edits your Bio information on your Twitter profile."
18
+ def bio(description)
19
+ client.update_profile(:description => description, :include_entities => false)
20
+ say "@#{@rcfile.default_profile[0]}'s bio has been updated."
21
+ end
22
+
23
+ desc "default SCREEN_NAME [CONSUMER_KEY]", "Set your default account."
24
+ def default(screen_name, consumer_key=nil)
25
+ screen_name = screen_name.strip_at
26
+ @rcfile.path = parent_options['profile'] if parent_options['profile']
27
+ consumer_key = @rcfile[screen_name].keys.last if consumer_key.nil?
28
+ @rcfile.default_profile = {'username' => screen_name, 'consumer_key' => consumer_key}
29
+ say "Default account has been updated."
30
+ end
31
+
32
+ desc "language LANGUAGE_NAME", "Selects the language you'd like to receive notifications in."
33
+ def language(language_name)
34
+ client.settings(:lang => language_name)
35
+ say "@#{@rcfile.default_profile[0]}'s language has been updated."
36
+ end
37
+
38
+ desc "location PLACE_NAME", "Updates the location field in your profile."
39
+ def location(place_name)
40
+ client.update_profile(:location => place_name, :include_entities => false)
41
+ say "@#{@rcfile.default_profile[0]}'s location has been updated."
42
+ end
43
+
44
+ desc "name NAME", "Sets the name field on your Twitter profile."
45
+ def name(name)
46
+ client.update_profile(:name => name, :include_entities => false)
47
+ say "@#{@rcfile.default_profile[0]}'s name has been updated."
48
+ end
49
+
50
+ desc "url URL", "Sets the URL field on your profile."
51
+ def url(url)
52
+ client.update_profile(:url => url, :include_entities => false)
53
+ say "@#{@rcfile.default_profile[0]}'s URL has been updated."
54
+ end
55
+
56
+ end
57
+ end
data/lib/t/version.rb CHANGED
@@ -8,7 +8,7 @@ module T
8
8
 
9
9
  # @return [Integer]
10
10
  def self.minor
11
- 4
11
+ 5
12
12
  end
13
13
 
14
14
  # @return [Integer]
data/spec/cli_spec.rb CHANGED
@@ -89,13 +89,13 @@ describe T::CLI do
89
89
  describe "#direct_messages" do
90
90
  before do
91
91
  stub_get("/1/direct_messages.json").
92
- with(:query => {:include_entities => "false"}).
92
+ with(:query => {:count => "20", :include_entities => "false"}).
93
93
  to_return(:body => fixture("direct_messages.json"), :headers => {:content_type => "application/json; charset=utf-8"})
94
94
  end
95
95
  it "should request the correct resource" do
96
96
  @t.direct_messages
97
97
  a_get("/1/direct_messages.json").
98
- with(:query => {:include_entities => "false"}).
98
+ with(:query => {:count => "20", :include_entities => "false"}).
99
99
  should have_been_made
100
100
  end
101
101
  it "should have the correct output" do
@@ -125,6 +125,45 @@ describe T::CLI do
125
125
  end
126
126
  end
127
127
 
128
+ describe "#direct_messages_sent" do
129
+ before do
130
+ stub_get("/1/direct_messages/sent.json").
131
+ with(:query => {:count => "20", :include_entities => "false"}).
132
+ to_return(:body => fixture("direct_messages.json"), :headers => {:content_type => "application/json; charset=utf-8"})
133
+ end
134
+ it "should request the correct resource" do
135
+ @t.direct_messages_sent
136
+ a_get("/1/direct_messages/sent.json").
137
+ with(:query => {:count => "20", :include_entities => "false"}).
138
+ should have_been_made
139
+ end
140
+ it "should have the correct output" do
141
+ @t.direct_messages_sent
142
+ $stdout.string.should == <<-eos.gsub(/^/, ' ' * 3)
143
+ hurrycane: Sounds good. Meeting Tuesday is fine. (about 1 year ago)
144
+ technoweenie: if you want to add me to your GroupMe group, my phone number is 415-312-2382 (about 1 year ago)
145
+ hurrycane: That's great news! Let's plan to chat around 8 AM tomorrow Pacific time. Does that work for you? (about 1 year ago)
146
+ hurrycane: I asked Yehuda about the stipend. I believe it has already been sent. Glad you're feeling better. (about 1 year ago)
147
+ hurrycane: Just checking in. How's everything going? (about 1 year ago)
148
+ hurrycane: Any luck completing graphs this weekend? There have been lots of commits to RailsAdmin since summer ended but none from you. How's it going? (about 1 year ago)
149
+ hurrycane: Not sure about the payment. Feel free to ask Leah or Yehuda directly. Think you'll be able to finish up your work on graphs this weekend? (about 1 year ago)
150
+ hurrycane: Looks good to me. I'm going to pull in the change now. My only concern is that we don't have any tests for auth. (about 1 year ago)
151
+ hurrycane: How are the graph enhancements coming? (about 1 year ago)
152
+ hurrycane: Changes pushed. You should pull and re-bundle when you have a minute. (about 1 year ago)
153
+ hurrycane: Glad to hear the new graphs are coming along. Can't wait to see them! (about 1 year ago)
154
+ hurrycane: I figured out what was wrong with the tests: I accidentally unbundled webrat. The problem had nothing to do with rspec-rails. (about 1 year ago)
155
+ hurrycane: After the upgrade 54/80 specs are failing. I'm working on fixing them now. (about 1 year ago)
156
+ hurrycane: a new version of rspec-rails just shipped with some nice features and fixes http://github.com/rspec/rspec-rails/blob/master/History.md (about 1 year ago)
157
+ hurrycane: How are the graphs coming? I'm really looking forward to seeing what you do with Raphaël. (about 1 year ago)
158
+ hurrycane: Awesome! Any luck duplicating the Gemfile.lock error with Ruby 1.9.2 final? (about 1 year ago)
159
+ hurrycane: I just committed a bunch of cleanup and fixes to RailsAdmin that touched many of files. Make sure you pull to avoid conflicts. (about 1 year ago)
160
+ hurrycane: Can you try upgrading to 1.9.2 final, re-installing Bundler 1.0.0.rc.6 (don't remove 1.0.0) and see if you can reproduce the problem? (about 1 year ago)
161
+ hurrycane: I'm trying to debug the issue you were having with the Bundler Gemfile.lock shortref. What version of Ruby and RubyGems are you running? (about 1 year ago)
162
+ hurrycane: Let's try to debug that problem during our session in 1.5 hours. In the mean time, try working on the graphs or internationalization. (about 1 year ago)
163
+ eos
164
+ end
165
+ end
166
+
128
167
  describe "#dm" do
129
168
  before do
130
169
  @t.options = @t.options.merge(:profile => fixture_path + "/.trc")
@@ -140,84 +179,37 @@ describe T::CLI do
140
179
  end
141
180
  it "should have the correct output" do
142
181
  @t.dm("pengwynn", "Creating a fixture for the Twitter gem")
143
- $stdout.string.chomp.should == "Direct Message sent from @testcli to @pengwynn (about 1 year ago)"
182
+ $stdout.string.chomp.should == "Direct Message sent from @testcli to @pengwynn (about 1 year ago)."
144
183
  end
145
184
  end
146
185
 
147
186
  describe "#favorite" do
148
187
  before do
149
188
  @t.options = @t.options.merge(:profile => fixture_path + "/.trc")
189
+ stub_post("/1/favorites/create/26755176471724032.json").
190
+ to_return(:body => fixture("status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
150
191
  end
151
- context "not found" do
152
- before do
153
- stub_get("/1/users/show.json").
154
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
155
- to_return(:body => '{}', :headers => {:content_type => "application/json; charset=utf-8"})
156
- end
157
- it "should exit" do
158
- lambda do
159
- @t.favorite("sferik")
160
- end.should raise_error(Thor::Error, "Tweet not found")
161
- end
162
- end
163
- context "forbidden" do
164
- before do
165
- stub_get("/1/users/show.json").
166
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
167
- to_return(:body => '{"error":"Forbidden"}', :headers => {:content_type => "application/json; charset=utf-8"}, :status => 403)
168
- end
169
- it "should exit" do
170
- lambda do
171
- @t.favorite("sferik")
172
- end.should raise_error(Twitter::Error::Forbidden, "Forbidden")
173
- end
174
- end
175
- context "duplicate" do
176
- before do
177
- stub_get("/1/users/show.json").
178
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
179
- to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
180
- stub_post("/1/favorites/create/26755176471724032.json").
181
- to_return(:body => '{"error":"You have already favorited this status."}', :headers => {:content_type => "application/json; charset=utf-8"}, :status => 403)
182
- end
183
- it "should have the correct output" do
184
- @t.favorite("sferik")
185
- $stdout.string.should =~ /^@testcli favorited @sferik's latest status: "RT @tenderlove: \[ANN\] sqlite3-ruby =&gt; sqlite3"$/
186
- end
192
+ it "should request the correct resource" do
193
+ @t.favorite("26755176471724032")
194
+ a_post("/1/favorites/create/26755176471724032.json").
195
+ should have_been_made
187
196
  end
188
- context "found" do
189
- before do
190
- stub_get("/1/users/show.json").
191
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
192
- to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
193
- stub_post("/1/favorites/create/26755176471724032.json").
194
- to_return(:body => fixture("status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
195
- end
196
- it "should request the correct resource" do
197
- @t.favorite("sferik")
198
- a_get("/1/users/show.json").
199
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
200
- should have_been_made
201
- a_post("/1/favorites/create/26755176471724032.json").
202
- should have_been_made
203
- end
204
- it "should have the correct output" do
205
- @t.favorite("sferik")
206
- $stdout.string.should =~ /^@testcli favorited @sferik's latest status: "RT @tenderlove: \[ANN\] sqlite3-ruby =&gt; sqlite3"$/
207
- end
197
+ it "should have the correct output" do
198
+ @t.favorite("26755176471724032")
199
+ $stdout.string.should =~ /^@testcli favorited @sferik's status: "@noradio working on implementing #NewTwitter API methods in the twitter gem\. Twurl is making it easy\. Thank you!"$/
208
200
  end
209
201
  end
210
202
 
211
203
  describe "#favorites" do
212
204
  before do
213
205
  stub_get("/1/favorites.json").
214
- with(:query => {:include_entities => "false"}).
206
+ with(:query => {:count => "20", :include_entities => "false"}).
215
207
  to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
216
208
  end
217
209
  it "should request the correct resource" do
218
210
  @t.favorites
219
211
  a_get("/1/favorites.json").
220
- with(:query => {:include_entities => "false"}).
212
+ with(:query => {:count => "20", :include_entities => "false"}).
221
213
  should have_been_made
222
214
  end
223
215
  it "should have the correct output" do
@@ -246,16 +238,180 @@ describe T::CLI do
246
238
  end
247
239
  end
248
240
 
241
+ describe "#follow" do
242
+ before do
243
+ @t.options = @t.options.merge(:profile => fixture_path + "/.trc")
244
+ end
245
+ context "no users" do
246
+ it "should exit" do
247
+ lambda do
248
+ @t.follow
249
+ end.should raise_error
250
+ end
251
+ end
252
+ context "one user" do
253
+ it "should request the correct resource" do
254
+ stub_post("/1/friendships/create.json").
255
+ with(:body => {:screen_name => "sferik", :include_entities => "false"}).
256
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
257
+ @t.follow("sferik")
258
+ a_post("/1/friendships/create.json").
259
+ with(:body => {:screen_name => "sferik", :include_entities => "false"}).
260
+ should have_been_made
261
+ end
262
+ it "should have the correct output" do
263
+ stub_post("/1/friendships/create.json").
264
+ with(:body => {:screen_name => "sferik", :include_entities => "false"}).
265
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
266
+ @t.follow("sferik")
267
+ $stdout.string.should =~ /^@testcli is now following 1 more user\.$/
268
+ end
269
+ context "Twitter is down" do
270
+ it "should retry 3 times and then raise an error" do
271
+ stub_post("/1/friendships/create.json").
272
+ with(:body => {:screen_name => "sferik", :include_entities => "false"}).
273
+ to_return(:status => 502)
274
+ lambda do
275
+ @t.follow("sferik")
276
+ end.should raise_error("Twitter is down or being upgraded.")
277
+ a_post("/1/friendships/create.json").
278
+ with(:body => {:screen_name => "sferik", :include_entities => "false"}).
279
+ should have_been_made.times(3)
280
+ end
281
+ end
282
+ end
283
+ end
284
+
285
+ describe "#followings" do
286
+ before do
287
+ stub_get("/1/friends/ids.json").
288
+ with(:query => {:cursor => "-1"}).
289
+ to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
290
+ stub_get("/1/users/lookup.json").
291
+ with(:query => {:user_id => "7505382", :include_entities => "false"}).
292
+ to_return(:body => fixture("users.json"), :headers => {:content_type => "application/json; charset=utf-8"})
293
+ end
294
+ it "should request the correct resource" do
295
+ @t.followings
296
+ a_get("/1/friends/ids.json").
297
+ with(:query => {:cursor => "-1"}).
298
+ should have_been_made
299
+ a_get("/1/users/lookup.json").
300
+ with(:query => {:user_id => "7505382", :include_entities => "false"}).
301
+ should have_been_made
302
+ end
303
+ it "should have the correct output" do
304
+ @t.followings
305
+ $stdout.string.chomp.rstrip.should == "pengwynn sferik"
306
+ end
307
+ end
308
+
309
+ describe "#followers" do
310
+ before do
311
+ stub_get("/1/followers/ids.json").
312
+ with(:query => {:cursor => "-1"}).
313
+ to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
314
+ stub_get("/1/users/lookup.json").
315
+ with(:query => {:user_id => "7505382", :include_entities => "false"}).
316
+ to_return(:body => fixture("users.json"), :headers => {:content_type => "application/json; charset=utf-8"})
317
+ end
318
+ it "should request the correct resource" do
319
+ @t.followers
320
+ a_get("/1/followers/ids.json").
321
+ with(:query => {:cursor => "-1"}).
322
+ should have_been_made
323
+ a_get("/1/users/lookup.json").
324
+ with(:query => {:user_id => "7505382", :include_entities => "false"}).
325
+ should have_been_made
326
+ end
327
+ it "should have the correct output" do
328
+ @t.followers
329
+ $stdout.string.chomp.rstrip.should == "pengwynn sferik"
330
+ end
331
+ end
332
+
333
+ describe "#friends" do
334
+ before do
335
+ stub_get("/1/friends/ids.json").
336
+ with(:query => {:cursor => "-1"}).
337
+ to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
338
+ stub_get("/1/followers/ids.json").
339
+ with(:query => {:cursor => "-1"}).
340
+ to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
341
+ stub_get("/1/users/lookup.json").
342
+ with(:query => {:user_id => "7505382", :include_entities => "false"}).
343
+ to_return(:body => fixture("users.json"), :headers => {:content_type => "application/json; charset=utf-8"})
344
+ end
345
+ it "should request the correct resource" do
346
+ @t.friends
347
+ a_get("/1/friends/ids.json").
348
+ with(:query => {:cursor => "-1"}).
349
+ should have_been_made
350
+ a_get("/1/followers/ids.json").
351
+ with(:query => {:cursor => "-1"}).
352
+ should have_been_made
353
+ a_get("/1/users/lookup.json").
354
+ with(:query => {:user_id => "7505382", :include_entities => "false"}).
355
+ should have_been_made
356
+ end
357
+ it "should have the correct output" do
358
+ @t.friends
359
+ $stdout.string.chomp.rstrip.should == "pengwynn sferik"
360
+ end
361
+ end
362
+
363
+ describe "#leaders" do
364
+ before do
365
+ stub_get("/1/friends/ids.json").
366
+ with(:query => {:cursor => "-1"}).
367
+ to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
368
+ stub_get("/1/followers/ids.json").
369
+ with(:query => {:cursor => "-1"}).
370
+ to_return(:body => fixture("friends_ids.json"), :headers => {:content_type => "application/json; charset=utf-8"})
371
+ end
372
+ it "should request the correct resource" do
373
+ @t.leaders
374
+ a_get("/1/friends/ids.json").
375
+ with(:query => {:cursor => "-1"}).
376
+ should have_been_made
377
+ a_get("/1/followers/ids.json").
378
+ with(:query => {:cursor => "-1"}).
379
+ should have_been_made
380
+ end
381
+ it "should have the correct output" do
382
+ @t.leaders
383
+ $stdout.string.chomp.rstrip.should == ""
384
+ end
385
+ end
386
+
387
+ describe "#members" do
388
+ before do
389
+ stub_get("/1/lists/members.json").
390
+ with(:query => {:cursor => "-1", :include_entities => "false", :owner_screen_name => "sferik", :skip_status => "true", :slug => "presidents"}).
391
+ to_return(:body => fixture("empty_cursor.json"), :headers => {:content_type => "application/json; charset=utf-8"})
392
+ end
393
+ it "should request the correct resource" do
394
+ @t.members("sferik", "presidents")
395
+ a_get("/1/lists/members.json").
396
+ with(:query => {:cursor => "-1", :include_entities => "false", :owner_screen_name => "sferik", :skip_status => "true", :slug => "presidents"}).
397
+ should have_been_made
398
+ end
399
+ it "should have the correct output" do
400
+ @t.members("sferik", "presidents")
401
+ $stdout.string.chomp.should == ""
402
+ end
403
+ end
404
+
249
405
  describe "#mentions" do
250
406
  before do
251
407
  stub_get("/1/statuses/mentions.json").
252
- with(:query => {:include_entities => "false"}).
408
+ with(:query => {:count => "20", :include_entities => "false"}).
253
409
  to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
254
410
  end
255
411
  it "should request the correct resource" do
256
412
  @t.mentions
257
413
  a_get("/1/statuses/mentions.json").
258
- with(:query => {:include_entities => "false"}).
414
+ with(:query => {:count => "20", :include_entities => "false"}).
259
415
  should have_been_made
260
416
  end
261
417
  it "should have the correct output" do
@@ -298,11 +454,11 @@ describe T::CLI do
298
454
  describe "#reply" do
299
455
  before do
300
456
  @t.options = @t.options.merge(:profile => fixture_path + "/.trc", :location => true)
301
- stub_get("/1/users/show.json").
302
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
303
- to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
457
+ stub_get("/1/statuses/show/25938088801.json").
458
+ with(:query => {:include_entities => "false", :include_my_retweet => "false", :trim_user => "true"}).
459
+ to_return(:body => fixture("status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
304
460
  stub_post("/1/statuses/update.json").
305
- with(:body => {:in_reply_to_status_id => "26755176471724032", :status => "@sferik Testing", :lat => "37.76969909668", :long => "-122.39330291748", :include_entities => "false", :trim_user => "true"}).
461
+ with(:body => {:in_reply_to_status_id => "25938088801", :status => "@sferik Testing", :lat => "37.76969909668", :long => "-122.39330291748", :include_entities => "false", :trim_user => "true"}).
306
462
  to_return(:body => fixture("status.json"), :headers => {:content_type => "application/json; charset=utf-8"})
307
463
  stub_request(:get, "http://checkip.dyndns.org/").
308
464
  to_return(:body => fixture("checkip.html"), :headers => {:content_type => "text/html"})
@@ -310,12 +466,12 @@ describe T::CLI do
310
466
  to_return(:body => fixture("xml.gp"), :headers => {:content_type => "application/xml"})
311
467
  end
312
468
  it "should request the correct resource" do
313
- @t.reply("sferik", "Testing")
314
- a_get("/1/users/show.json").
315
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
469
+ @t.reply("25938088801", "Testing")
470
+ a_get("/1/statuses/show/25938088801.json").
471
+ with(:query => {:include_entities => "false", :include_my_retweet => "false", :trim_user => "true"}).
316
472
  should have_been_made
317
473
  a_post("/1/statuses/update.json").
318
- with(:body => {:in_reply_to_status_id => "26755176471724032", :status => "@sferik Testing", :lat => "37.76969909668", :long => "-122.39330291748", :include_entities => "false", :trim_user => "true"}).
474
+ with(:body => {:in_reply_to_status_id => "25938088801", :status => "@sferik Testing", :lat => "37.76969909668", :long => "-122.39330291748", :include_entities => "false", :trim_user => "true"}).
319
475
  should have_been_made
320
476
  a_request(:get, "http://checkip.dyndns.org/").
321
477
  should have_been_made
@@ -323,72 +479,44 @@ describe T::CLI do
323
479
  should have_been_made
324
480
  end
325
481
  it "should have the correct output" do
326
- @t.reply("sferik", "Testing")
327
- $stdout.string.should =~ /^Reply created by @testcli to @sferik \(about 1 year ago\)$/
482
+ @t.reply("25938088801", "Testing")
483
+ $stdout.string.should =~ /^Reply created by @testcli to @sferik \(about 1 year ago\)\.$/
328
484
  end
329
485
  end
330
486
 
331
- describe "#retweet" do
487
+ describe "#report_spam" do
332
488
  before do
333
489
  @t.options = @t.options.merge(:profile => fixture_path + "/.trc")
490
+ stub_post("/1/report_spam.json").
491
+ with(:body => {:screen_name => "sferik", :include_entities => "false"}).
492
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
334
493
  end
335
- context "not found" do
336
- before do
337
- stub_get("/1/users/show.json").
338
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
339
- to_return(:body => '{}', :headers => {:content_type => "application/json; charset=utf-8"})
340
- end
341
- it "should exit" do
342
- lambda do
343
- @t.retweet("sferik")
344
- end.should raise_error(Thor::Error, "Tweet not found")
345
- end
494
+ it "should request the correct resource" do
495
+ @t.report_spam("sferik")
496
+ a_post("/1/report_spam.json").
497
+ with(:body => {:screen_name => "sferik", :include_entities => "false"}).
498
+ should have_been_made
346
499
  end
347
- context "forbidden" do
348
- before do
349
- stub_get("/1/users/show.json").
350
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
351
- to_return(:body => '{"error":"Forbidden"}', :headers => {:content_type => "application/json; charset=utf-8"}, :status => 403)
352
- end
353
- it "should exit" do
354
- lambda do
355
- @t.retweet("sferik")
356
- end.should raise_error(Twitter::Error::Forbidden, "Forbidden")
357
- end
500
+ it "should have the correct output" do
501
+ @t.report_spam("sferik")
502
+ $stdout.string.should =~ /^@testcli reported @sferik/
358
503
  end
359
- context "duplicate" do
360
- before do
361
- stub_get("/1/users/show.json").
362
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
363
- to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
364
- stub_post("/1/statuses/retweet/26755176471724032.json").
365
- to_return(:body => '{"error":"sharing is not permissable for this status (Share validations failed)"}', :headers => {:content_type => "application/json; charset=utf-8"}, :status => 403)
366
- end
367
- it "should have the correct output" do
368
- @t.retweet("sferik")
369
- $stdout.string.should =~ /^@testcli retweeted @sferik's latest status: "RT @tenderlove: \[ANN\] sqlite3-ruby =&gt; sqlite3"$/
370
- end
504
+ end
505
+
506
+ describe "#retweet" do
507
+ before do
508
+ @t.options = @t.options.merge(:profile => fixture_path + "/.trc")
509
+ stub_post("/1/statuses/retweet/26755176471724032.json").
510
+ to_return(:body => fixture("retweet.json"), :headers => {:content_type => "application/json; charset=utf-8"})
371
511
  end
372
- context "found" do
373
- before do
374
- stub_get("/1/users/show.json").
375
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
376
- to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
377
- stub_post("/1/statuses/retweet/26755176471724032.json").
378
- to_return(:body => fixture("retweet.json"), :headers => {:content_type => "application/json; charset=utf-8"})
379
- end
380
- it "should request the correct resource" do
381
- @t.retweet("sferik")
382
- a_get("/1/users/show.json").
383
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
384
- should have_been_made
385
- a_post("/1/statuses/retweet/26755176471724032.json").
386
- should have_been_made
387
- end
388
- it "should have the correct output" do
389
- @t.retweet("sferik")
390
- $stdout.string.should =~ /^@testcli retweeted @sferik's latest status: "RT @tenderlove: \[ANN\] sqlite3-ruby =&gt; sqlite3"$/
391
- end
512
+ it "should request the correct resource" do
513
+ @t.retweet("26755176471724032")
514
+ a_post("/1/statuses/retweet/26755176471724032.json").
515
+ should have_been_made
516
+ end
517
+ it "should have the correct output" do
518
+ @t.retweet("26755176471724032")
519
+ $stdout.string.should =~ /^@testcli retweeted @gruber's status: "As for the Series, I'm for the Giants\. Fuck Texas, fuck Nolan Ryan, fuck George Bush\."$/
392
520
  end
393
521
  end
394
522
 
@@ -396,13 +524,13 @@ describe T::CLI do
396
524
  context "without arguments" do
397
525
  before do
398
526
  stub_get("/1/statuses/retweeted_by_me.json").
399
- with(:query => {:include_entities => "false"}).
527
+ with(:query => {:count => "20", :include_entities => "false"}).
400
528
  to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
401
529
  end
402
530
  it "should request the correct resource" do
403
531
  @t.retweets
404
532
  a_get("/1/statuses/retweeted_by_me.json").
405
- with(:query => {:include_entities => "false"}).
533
+ with(:query => {:count => "20", :include_entities => "false"}).
406
534
  should have_been_made
407
535
  end
408
536
  it "should have the correct output" do
@@ -433,13 +561,13 @@ describe T::CLI do
433
561
  context "with a screen name passed" do
434
562
  before do
435
563
  stub_get("/1/statuses/retweeted_by_user.json").
436
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
564
+ with(:query => {:count => "20", :include_entities => "false", :screen_name => "sferik"}).
437
565
  to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
438
566
  end
439
567
  it "should request the correct resource" do
440
568
  @t.retweets("sferik")
441
569
  a_get("/1/statuses/retweeted_by_user.json").
442
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
570
+ with(:query => {:count => "20", :include_entities => "false", :screen_name => "sferik"}).
443
571
  should have_been_made
444
572
  end
445
573
  it "should have the correct output" do
@@ -469,67 +597,6 @@ describe T::CLI do
469
597
  end
470
598
  end
471
599
 
472
- describe "#sent_messages" do
473
- before do
474
- stub_get("/1/direct_messages/sent.json").
475
- with(:query => {:include_entities => "false"}).
476
- to_return(:body => fixture("direct_messages.json"), :headers => {:content_type => "application/json; charset=utf-8"})
477
- end
478
- it "should request the correct resource" do
479
- @t.sent_messages
480
- a_get("/1/direct_messages/sent.json").
481
- with(:query => {:include_entities => "false"}).
482
- should have_been_made
483
- end
484
- it "should have the correct output" do
485
- @t.sent_messages
486
- $stdout.string.should == <<-eos.gsub(/^/, ' ' * 3)
487
- hurrycane: Sounds good. Meeting Tuesday is fine. (about 1 year ago)
488
- technoweenie: if you want to add me to your GroupMe group, my phone number is 415-312-2382 (about 1 year ago)
489
- hurrycane: That's great news! Let's plan to chat around 8 AM tomorrow Pacific time. Does that work for you? (about 1 year ago)
490
- hurrycane: I asked Yehuda about the stipend. I believe it has already been sent. Glad you're feeling better. (about 1 year ago)
491
- hurrycane: Just checking in. How's everything going? (about 1 year ago)
492
- hurrycane: Any luck completing graphs this weekend? There have been lots of commits to RailsAdmin since summer ended but none from you. How's it going? (about 1 year ago)
493
- hurrycane: Not sure about the payment. Feel free to ask Leah or Yehuda directly. Think you'll be able to finish up your work on graphs this weekend? (about 1 year ago)
494
- hurrycane: Looks good to me. I'm going to pull in the change now. My only concern is that we don't have any tests for auth. (about 1 year ago)
495
- hurrycane: How are the graph enhancements coming? (about 1 year ago)
496
- hurrycane: Changes pushed. You should pull and re-bundle when you have a minute. (about 1 year ago)
497
- hurrycane: Glad to hear the new graphs are coming along. Can't wait to see them! (about 1 year ago)
498
- hurrycane: I figured out what was wrong with the tests: I accidentally unbundled webrat. The problem had nothing to do with rspec-rails. (about 1 year ago)
499
- hurrycane: After the upgrade 54/80 specs are failing. I'm working on fixing them now. (about 1 year ago)
500
- hurrycane: a new version of rspec-rails just shipped with some nice features and fixes http://github.com/rspec/rspec-rails/blob/master/History.md (about 1 year ago)
501
- hurrycane: How are the graphs coming? I'm really looking forward to seeing what you do with Raphaël. (about 1 year ago)
502
- hurrycane: Awesome! Any luck duplicating the Gemfile.lock error with Ruby 1.9.2 final? (about 1 year ago)
503
- hurrycane: I just committed a bunch of cleanup and fixes to RailsAdmin that touched many of files. Make sure you pull to avoid conflicts. (about 1 year ago)
504
- hurrycane: Can you try upgrading to 1.9.2 final, re-installing Bundler 1.0.0.rc.6 (don't remove 1.0.0) and see if you can reproduce the problem? (about 1 year ago)
505
- hurrycane: I'm trying to debug the issue you were having with the Bundler Gemfile.lock shortref. What version of Ruby and RubyGems are you running? (about 1 year ago)
506
- hurrycane: Let's try to debug that problem during our session in 1.5 hours. In the mean time, try working on the graphs or internationalization. (about 1 year ago)
507
- eos
508
- end
509
- end
510
-
511
- describe "#stats" do
512
- before do
513
- stub_get("/1/users/show.json").
514
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
515
- to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
516
- end
517
- it "should request the correct resource" do
518
- @t.stats("sferik")
519
- a_get("/1/users/show.json").
520
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
521
- should have_been_made
522
- end
523
- it "should have the correct output" do
524
- @t.stats("sferik")
525
- $stdout.string.should =~ /^Tweets: 3,479$/
526
- $stdout.string.should =~ /^Following: 197$/
527
- $stdout.string.should =~ /^Followers: 1,048$/
528
- $stdout.string.should =~ /^Favorites: 1,040$/
529
- $stdout.string.should =~ /^Listed: 41$/
530
- end
531
- end
532
-
533
600
  describe "#status" do
534
601
  before do
535
602
  @t.options = @t.options.merge(:profile => fixture_path + "/.trc", :location => true)
@@ -553,25 +620,25 @@ describe T::CLI do
553
620
  end
554
621
  it "should have the correct output" do
555
622
  @t.status("Testing")
556
- $stdout.string.should =~ /^Tweet created by @testcli \(about 1 year ago\)$/
623
+ $stdout.string.should =~ /^Tweet created by @testcli \(about 1 year ago\)\.$/
557
624
  end
558
625
  end
559
626
 
560
627
  describe "#suggest" do
561
628
  before do
562
629
  stub_get("/1/users/recommendations.json").
563
- with(:query => {:limit => "1", :include_entities => "false"}).
630
+ with(:query => {:limit => "20", :include_entities => "false"}).
564
631
  to_return(:body => fixture("recommendations.json"), :headers => {:content_type => "application/json; charset=utf-8"})
565
632
  end
566
633
  it "should request the correct resource" do
567
634
  @t.suggest
568
635
  a_get("/1/users/recommendations.json").
569
- with(:query => {:limit => "1", :include_entities => "false"}).
636
+ with(:query => {:limit => "20", :include_entities => "false"}).
570
637
  should have_been_made
571
638
  end
572
639
  it "should have the correct output" do
573
640
  @t.suggest
574
- $stdout.string.should =~ /^Try following @jtrupiano\.$/
641
+ $stdout.string.chomp.rstrip.should == "antpires jtrupiano maccman mlroach stuntmann82"
575
642
  end
576
643
  end
577
644
 
@@ -579,13 +646,13 @@ describe T::CLI do
579
646
  context "without user" do
580
647
  before do
581
648
  stub_get("/1/statuses/home_timeline.json").
582
- with(:query => {:include_entities => "false"}).
649
+ with(:query => {:count => "20", :include_entities => "false"}).
583
650
  to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
584
651
  end
585
652
  it "should request the correct resource" do
586
653
  @t.timeline
587
654
  a_get("/1/statuses/home_timeline.json").
588
- with(:query => {:include_entities => "false"}).
655
+ with(:query => {:count => "20", :include_entities => "false"}).
589
656
  should have_been_made
590
657
  end
591
658
  it "should have the correct output" do
@@ -616,13 +683,13 @@ describe T::CLI do
616
683
  context "with user" do
617
684
  before do
618
685
  stub_get("/1/statuses/user_timeline.json").
619
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
686
+ with(:query => {:count => "20", :include_entities => "false", :screen_name => "sferik"}).
620
687
  to_return(:body => fixture("statuses.json"), :headers => {:content_type => "application/json; charset=utf-8"})
621
688
  end
622
689
  it "should request the correct resource" do
623
690
  @t.timeline("sferik")
624
691
  a_get("/1/statuses/user_timeline.json").
625
- with(:query => {:screen_name => "sferik", :include_entities => "false"}).
692
+ with(:query => {:count => "20", :include_entities => "false", :screen_name => "sferik"}).
626
693
  should have_been_made
627
694
  end
628
695
  it "should have the correct output" do
@@ -652,6 +719,68 @@ describe T::CLI do
652
719
  end
653
720
  end
654
721
 
722
+ describe "#unfollow" do
723
+ before do
724
+ @t.options = @t.options.merge(:profile => fixture_path + "/.trc")
725
+ end
726
+ context "no users" do
727
+ it "should exit" do
728
+ lambda do
729
+ @t.unfollow
730
+ end.should raise_error
731
+ end
732
+ end
733
+ context "one user" do
734
+ it "should request the correct resource" do
735
+ stub_delete("/1/friendships/destroy.json").
736
+ with(:query => {:screen_name => "sferik", :include_entities => "false"}).
737
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
738
+ @t.unfollow("sferik")
739
+ a_delete("/1/friendships/destroy.json").
740
+ with(:query => {:screen_name => "sferik", :include_entities => "false"}).
741
+ should have_been_made
742
+ end
743
+ it "should have the correct output" do
744
+ stub_delete("/1/friendships/destroy.json").
745
+ with(:query => {:screen_name => "sferik", :include_entities => "false"}).
746
+ to_return(:body => fixture("sferik.json"), :headers => {:content_type => "application/json; charset=utf-8"})
747
+ @t.unfollow("sferik")
748
+ $stdout.string.should =~ /^@testcli is no longer following 1 user\.$/
749
+ end
750
+ context "Twitter is down" do
751
+ it "should retry 3 times and then raise an error" do
752
+ stub_delete("/1/friendships/destroy.json").
753
+ with(:query => {:screen_name => "sferik", :include_entities => "false"}).
754
+ to_return(:status => 502)
755
+ lambda do
756
+ @t.unfollow("sferik")
757
+ end.should raise_error("Twitter is down or being upgraded.")
758
+ a_delete("/1/friendships/destroy.json").
759
+ with(:query => {:screen_name => "sferik", :include_entities => "false"}).
760
+ should have_been_made.times(3)
761
+ end
762
+ end
763
+ end
764
+ end
765
+
766
+ describe "#users" do
767
+ before do
768
+ stub_get("/1/users/lookup.json").
769
+ with(:query => {:screen_name => "sferik", :include_entities => "false"}).
770
+ to_return(:body => fixture("users.json"), :headers => {:content_type => "application/json; charset=utf-8"})
771
+ end
772
+ it "should request the correct resource" do
773
+ @t.users("sferik")
774
+ a_get("/1/users/lookup.json").
775
+ with(:query => {:screen_name => "sferik", :include_entities => "false"}).
776
+ should have_been_made
777
+ end
778
+ it "should have the correct output" do
779
+ @t.users("sferik")
780
+ $stdout.string.chomp.rstrip.should == "pengwynn sferik"
781
+ end
782
+ end
783
+
655
784
  describe "#version" do
656
785
  it "should have the correct output" do
657
786
  @t.version