tweetwine 0.2.5 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG.rdoc +30 -17
  2. data/README.rdoc +16 -17
  3. data/Rakefile +2 -0
  4. data/bin/tweetwine +3 -68
  5. data/example/example_helper.rb +31 -41
  6. data/example/fixtures/{statuses.json → home.json} +0 -0
  7. data/example/fixtures/mentions.json +1 -0
  8. data/example/fixtures/search.json +1 -0
  9. data/example/fixtures/update.json +1 -0
  10. data/example/fixtures/user.json +1 -0
  11. data/example/fixtures/users.json +1 -0
  12. data/example/search_statuses_example.rb +36 -0
  13. data/example/show_followers_example.rb +23 -0
  14. data/example/show_friends_example.rb +23 -0
  15. data/example/show_home_example.rb +51 -0
  16. data/example/show_mentions_example.rb +23 -0
  17. data/example/show_metadata_example.rb +54 -7
  18. data/example/show_user_example.rb +37 -0
  19. data/example/update_status_example.rb +65 -0
  20. data/lib/tweetwine/cli.rb +241 -0
  21. data/lib/tweetwine/client.rb +94 -57
  22. data/lib/tweetwine/io.rb +39 -28
  23. data/lib/tweetwine/meta.rb +1 -1
  24. data/lib/tweetwine/retrying_http.rb +93 -0
  25. data/lib/tweetwine/startup_config.rb +14 -15
  26. data/lib/tweetwine/url_shortener.rb +13 -8
  27. data/lib/tweetwine/util.rb +14 -0
  28. data/lib/tweetwine.rb +2 -1
  29. data/test/cli_test.rb +16 -0
  30. data/test/client_test.rb +275 -205
  31. data/test/fixtures/test_config.yaml +2 -1
  32. data/test/io_test.rb +89 -62
  33. data/test/retrying_http_test.rb +127 -0
  34. data/test/startup_config_test.rb +52 -27
  35. data/test/test_helper.rb +32 -17
  36. data/test/url_shortener_test.rb +18 -18
  37. data/test/util_test.rb +145 -47
  38. metadata +20 -7
  39. data/example/show_latest_statuses_example.rb +0 -45
  40. data/lib/tweetwine/rest_client_wrapper.rb +0 -37
  41. data/test/rest_client_wrapper_test.rb +0 -68
data/CHANGELOG.rdoc CHANGED
@@ -1,15 +1,28 @@
1
+ === 0.2.7 released 2009-12-22
2
+
3
+ * Formatted help texts so that they do not exceed 80 chars in width.
4
+
5
+ === 0.2.6 released 2009-12-22
6
+
7
+ * Command <tt>search</tt> allows searching statuses.
8
+ * Renamed option <tt>--colorize</tt> to <tt>--colors</tt>.
9
+ * Command <tt>home</tt> shows home timeline instead of friends timeline.
10
+ * Command <tt>help</tt> accepts argument for showing help about a command.
11
+ * Acceptance tests in <tt>example</tt> directory cover all commands.
12
+ * Reimplemented how application starts executing a specific command.
13
+
1
14
  === 0.2.5 released 2009-10-14
2
15
 
3
16
  * Improved username highlighting for colorization. For example, email
4
17
  addresses are not highlighted as usernames anymore.
5
- * Command line option "--no-colorize" to (temporarily) disable colors from the
6
- output.
18
+ * Command line option <tt>--no-colorize</tt> to (temporarily) disable colors
19
+ from the output.
7
20
  * Added first set of acceptance tests under "example" directory.
8
21
 
9
22
  === 0.2.4 released 2009-09-16
10
23
 
11
24
  * Retry connection upon connection reset, trying maximum of three times.
12
- * Display proper version info on Ruby 1.8 when using option "-v".
25
+ * Display proper version info on Ruby 1.8 when using option <tt>-v</tt>.
13
26
  * Minor code cleanups.
14
27
  * Release 0.2.3 is skipped due to my error in tagging the wrong commit.
15
28
 
@@ -25,7 +38,7 @@
25
38
 
26
39
  === 0.2.1 released 2009-08-17
27
40
 
28
- * Command line option "-v" show version information.
41
+ * Command line option <tt>-v</tt> shows version information.
29
42
  * Slight implementation code cleaning.
30
43
 
31
44
  === 0.2.0 released 2009-08-17
@@ -44,8 +57,8 @@
44
57
 
45
58
  === 0.1.9 released 2009-07-15
46
59
 
47
- * Added commands "friends" and "followers"
48
- * Removed dependency to the "json" gem. It is included in Ruby 1.9.
60
+ * Added commands <tt>friends</tt> and <tt>followers</tt>.
61
+ * Removed dependency to the json gem. It is included in Ruby 1.9.
49
62
 
50
63
  === 0.1.8 released 2009-07-01
51
64
 
@@ -67,26 +80,26 @@
67
80
 
68
81
  === 0.1.4 released 2009-05-12
69
82
 
70
- * Command line option "--page N" fetches a specific status page
83
+ * Command line option <tt>--page N</tt> fetches a specific status page.
71
84
 
72
85
  === 0.1.3 released 2009-05-05
73
86
 
74
- * Empty status update indicates cancellation of the command
75
- * Other minor improvements
87
+ * Empty status update indicates cancellation of the command.
88
+ * Other minor improvements.
76
89
 
77
90
  === 0.1.2 released 2009-05-04
78
91
 
79
- * Renamed command "friends" to "home"
80
- * Added command "mentions"
81
- * When showing a status, indicate if it is a reply
82
- * Improved command line argument and configuration file parsing
92
+ * Renamed command <tt>friends</tt> to <tt>home</tt>.
93
+ * Added command <tt>mentions</tt>.
94
+ * When showing a status, indicate if it is a reply.
95
+ * Improved command line argument and configuration file parsing.
83
96
 
84
97
  === 0.1.1 released 2009-04-23
85
98
 
86
- * Renamed command "msg" to "update"
87
- * If status update if longer than 140 characters, warn about it
99
+ * Renamed command <tt>msg</tt> to <tt>update</tt>.
100
+ * If status update if longer than 140 characters, warn about it.
88
101
 
89
102
  === 0.1.0 released 2009-04-22
90
103
 
91
- * Initial release with minimal functionality
92
- * Usable for quickly checking friends' statuses and sending status updates
104
+ * Initial release with minimal functionality.
105
+ * Usable for quickly checking friends' statuses and sending status updates.
data/README.rdoc CHANGED
@@ -4,18 +4,19 @@ A simple but tasty Twitter agent for command line use, made for fun.
4
4
 
5
5
  == Installation
6
6
 
7
- Install Tweetwine as a RubyGem from GitHub:
7
+ Install Tweetwine as a RubyGem from Gemcutter[http://gemcutter.org/]:
8
8
 
9
- $ sudo gem install tuomas-tweetwine --source http://gems.github.com
9
+ $ sudo gem install tweetwine --source http://gemcutter.org
10
10
 
11
- The program is compatible with Ruby 1.9.1, and it requires <b>rest_client</b>
12
- gem to be installed. In addition, <b>json</b> gem is needed for Ruby 1.8.6.
11
+ The program is compatible with both Ruby 1.8 and 1.9.
12
+
13
+ The program requires <b>rest_client</b> gem to be installed. In addition, the program needs <b>json</b> gem on Ruby 1.8.
13
14
 
14
15
  == Usage
15
16
 
16
17
  In the command line, run the program by entering
17
18
 
18
- $ tweetwine [options...] [command]
19
+ $ tweetwine [global_options...] [command] [command_options...]
19
20
 
20
21
  The program needs the user's username and password for authentication. This
21
22
  information can be supplied either via a configuration file or as an option
@@ -27,22 +28,20 @@ program recognizes the following basic settings:
27
28
 
28
29
  username: <your_username>
29
30
  password: <your_password>
30
- colorize: true|false
31
+ colors: true|false
31
32
 
32
- When invoking the program, the supported commands are
33
+ The program supports showing the home timeline of the authenticated user, the
34
+ latest statuses of friends and followers, and the latest statuses that mention
35
+ the user. If that's not enough, statuses can be searched with arbitrary terms.
36
+ In addition, new statuses can be sent.
33
37
 
34
- <tt>home</tt>:: Fetch friends' latest statuses (the contents of the authenticated user's home).
35
- <tt>mentions</tt>:: Fetch latest mentions for the authenticated user.
36
- <tt>user [name]</tt>:: Fetch a specific user's latest statuses, identified by the argument; if given no argument, fetch the statuses of the authenticated user.
37
- <tt>update [status]</tt>:: Send a status update, but confirm the action first before actually sending. The status update can either be given as an argument or via STDIN if no argument is given.
38
- <tt>friends</tt>:: Fetch friends and their latest statuses.
39
- <tt>followers</tt>:: Fetch followers and their latest statuses.
38
+ For all the global options and commands, see:
40
39
 
41
- If no <tt>[command]</tt> is given, the default action is <tt>home</tt>.
40
+ $ tweetwine help
42
41
 
43
- For all the options, see:
42
+ For information about a specific command and its options, use:
44
43
 
45
- $ tweetwine -h
44
+ $ tweetwine help command
46
45
 
47
46
  === URL shortening for status update
48
47
 
@@ -53,7 +52,7 @@ example:
53
52
 
54
53
  username: spoonman
55
54
  password: withyourhands
56
- colorize: true
55
+ colors: true
57
56
  shorten_urls:
58
57
  enable: true
59
58
  service_url: http://is.gd/create.php
data/Rakefile CHANGED
@@ -45,10 +45,12 @@ task :gemspec do
45
45
  end
46
46
  end
47
47
 
48
+ desc "Install the software as a gem"
48
49
  task :install => [:package] do
49
50
  sh %{sudo gem install pkg/#{name}-#{version}.gem}
50
51
  end
51
52
 
53
+ desc "Uninstall the gem"
52
54
  task :uninstall => [:clean] do
53
55
  sh %{sudo gem uninstall #{name}}
54
56
  end
data/bin/tweetwine CHANGED
@@ -1,80 +1,15 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- EXIT_HELP = 1
4
- EXIT_VERSION = 2
5
3
  EXIT_SIGINT = 6
6
- EXIT_ERROR = 64
7
4
 
8
5
  trap("INT") do
9
6
  puts "\nAbort"
10
7
  exit(EXIT_SIGINT)
11
8
  end
12
9
 
13
- require "optparse"
14
10
  require "tweetwine"
15
11
 
16
- include Tweetwine
12
+ exec_name = File.basename($0)
13
+ config_file = ENV["HOME"] + "/.#{exec_name}"
17
14
 
18
- cmd_parser = lambda do |args|
19
- options = {}
20
- begin
21
- OptionParser.new do |opt|
22
- executable_name = File.basename($0)
23
-
24
- opt.banner =<<-END
25
- Usage: #{executable_name} [options...] [command]
26
-
27
- Commands: #{Client::COMMANDS.join(", ")}
28
-
29
- Options:
30
-
31
- END
32
- opt.on("-a", "--auth USERNAME:PASSWORD", "Authentication") do |arg|
33
- options[:username], options[:password] = arg.split(":", 2)
34
- end
35
- opt.on("-c", "--colorize", "Colorize output with ANSI escape codes") do
36
- options[:colorize] = true
37
- end
38
- opt.on("-n", "--num N", Integer, "The number of statuses to fetch, defaults to #{Client::DEFAULT_NUM_STATUSES}") do |arg|
39
- options[:num_statuses] = arg
40
- end
41
- opt.on("--no-colorize", "Do not colorize output with ANSI escape codes") do
42
- options[:colorize] = false
43
- end
44
- opt.on("--no-url-shorten", "Do not shorten URLs for status update") do
45
- options[:shorten_urls] = { :enable => false }
46
- end
47
- opt.on("-p", "--page N", Integer, "The page number of the statuses to fetch, defaults to #{Client::DEFAULT_PAGE_NUM}") do |arg|
48
- options[:page_num] = arg
49
- end
50
- opt.on("-v", "--version", "Show version information and exit") do
51
- puts "#{executable_name} #{Tweetwine::VERSION}"
52
- exit(EXIT_VERSION)
53
- end
54
- opt.on_tail("-h", "--help", "Show this help message and exit") do
55
- puts opt
56
- exit(EXIT_HELP)
57
- end
58
- end.parse!(args)
59
- rescue OptionParser::ParseError => e
60
- raise ArgumentError, e.message
61
- end
62
- options
63
- end
64
-
65
- def create_dependencies(options)
66
- io = Tweetwine::IO.new(options)
67
- rest_client = RestClientWrapper.new(io)
68
- url_shortener = lambda { |opts| UrlShortener.new(rest_client, opts) }
69
- Client::Dependencies.new io, rest_client, url_shortener
70
- end
71
-
72
- begin
73
- config = StartupConfig.new(Client::COMMANDS)
74
- config.parse(ARGV, ENV["HOME"] + "/.tweetwine", &cmd_parser)
75
- client = Client.new(create_dependencies(config.options), config.options)
76
- client.send(config.command, *config.args)
77
- rescue ArgumentError, ClientError => e
78
- puts "Error: #{e.message}"
79
- exit(EXIT_ERROR)
80
- end
15
+ Tweetwine::CLI.launch(ARGV, exec_name, config_file)
@@ -1,59 +1,49 @@
1
- require "coulda"
2
- require "matchy"
3
- require "open4"
4
- require "tweetwine"
1
+ %w{
2
+ coulda
3
+ matchy
4
+ fakeweb
5
+ open4
6
+ stringio
7
+ time
8
+ timecop
9
+ }.each { |lib| require lib }
5
10
 
6
- module Tweetwine
7
- module ExampleHelpers
8
- DEFAULT_INJECTION =<<-END
9
- require "fakeweb"
10
11
  FakeWeb.allow_net_connect = false
11
-
12
- require "date"
13
- require "time"
14
- require "timecop"
15
12
  Timecop.freeze(Time.parse("2009-10-14 01:56:15 +0300"))
16
13
 
17
- def fixture(filename)
18
- contents = nil
19
- filepath = File.dirname(__FILE__) << "/example/fixtures/" << filename
20
- File.open(filepath) do |f|
21
- contents = f.readlines.join("\n")
22
- end
23
- contents
24
- end
25
- END
14
+ require "tweetwine"
26
15
 
27
- def launch_app(args, injection_code = "", &blk)
16
+ module Tweetwine
17
+ module ExampleHelpers
18
+ TEST_USER = "fooman"
19
+ TEST_PASSWD = "barpwd"
20
+ TEST_AUTH = "#{TEST_USER}:#{TEST_PASSWD}"
21
+
22
+ def launch_app(args, &blk)
28
23
  lib = File.dirname(__FILE__) << "/../lib"
29
24
  executable = File.dirname(__FILE__) << "/../bin/tweetwine"
30
- code =<<-END
31
- #{escape_injection_for_shell(DEFAULT_INJECTION)}
32
- #{escape_injection_for_shell(injection_code)}
33
- `cat #{executable}`
34
- END
35
- launch_cmd = "ruby -rubygems -I#{lib} -e \"#{code}\" -- #{args}"
25
+ launch_cmd = "ruby -rubygems -I#{lib} -- #{executable} #{args}"
36
26
  Open4::popen4(launch_cmd, &blk)
37
27
  end
38
28
 
39
- private
40
-
41
- def escape_injection_for_shell(code)
42
- code_dup = code.dup
43
- code_dup.gsub!('\'', '\\\'')
44
- code_dup.gsub!('"', '\\"')
45
- code_dup
29
+ def launch_cli(args, *input)
30
+ input, output = StringIO.new(input.join("\n")), StringIO.new
31
+ extra_opts = { :input => input, :output => output }
32
+ CLI.launch(args, "test", nil, extra_opts)
33
+ output.string.split("\n")
46
34
  end
47
- end
48
- end
49
35
 
50
- module Test
51
- module Unit
52
- class TestCase
53
- include Tweetwine::ExampleHelpers
36
+ def fixture(filename)
37
+ contents = nil
38
+ filepath = File.dirname(__FILE__) << "/fixtures/" << filename
39
+ File.open(filepath) do |f|
40
+ contents = f.readlines.join("\n")
41
+ end
42
+ contents
54
43
  end
55
44
  end
56
45
  end
57
46
 
58
47
  include Coulda
59
48
  include Tweetwine
49
+ include Tweetwine::ExampleHelpers
File without changes
@@ -0,0 +1 @@
1
+ [{"in_reply_to_screen_name":"fooman","geo":null,"in_reply_to_user_id":29706667,"in_reply_to_status_id":5917716667,"source":"<a href=\"http://apiwiki.twitter.com/\" rel=\"nofollow\">API</a>","user":{"profile_sidebar_fill_color":"ccf5cd","followers_count":32768,"description":null,"following":false,"time_zone":"GMT","friends_count":2,"profile_sidebar_border_color":"e0ffee","notifications":false,"favourites_count":0,"profile_text_color":"000000","url":null,"statuses_count":42,"profile_background_image_url":null,"profile_link_color":"1f6603","protected":false,"geo_enabled":false,"profile_background_tile":false,"created_at":"Fri Jul 24 15:18:06 +0000 2009","profile_image_url":null,"location":"Spain","name":"Jill Valentine","profile_background_color":"ffffff","id":59804598,"verified":false,"utc_offset":0,"screen_name":"jillv"},"truncated":false,"created_at":"Sat Oct 10 22:36:25 +0000 2009","id":5930046667,"favorited":false,"text":"@fooman, did you see their eyes glow yellow after sunset?"},{"in_reply_to_screen_name":"fooman","geo":null,"in_reply_to_user_id":29706667,"in_reply_to_status_id":5917726667,"source":"<a href=\"http://apiwiki.twitter.com/\" rel=\"nofollow\">API</a>","user":{"profile_sidebar_fill_color":"ccf5cd","followers_count":327,"description":null,"following":false,"time_zone":"GMT","friends_count":22,"profile_sidebar_border_color":"e0ffee","notifications":false,"favourites_count":0,"profile_text_color":"000000","url":null,"statuses_count":42,"profile_background_image_url":null,"profile_link_color":"1f6603","protected":false,"geo_enabled":false,"profile_background_tile":false,"created_at":"Fri Jul 25 15:18:06 +0000 2009","profile_image_url":null,"location":"Spain","name":"Chris Redfield","profile_background_color":"ffffff","id":59804333,"verified":false,"utc_offset":0,"screen_name":"redfield"},"truncated":false,"created_at":"Thu Oct 8 22:36:25 +0000 2009","id":5930056667,"favorited":false,"text":"sometimes it is just best to run, just like @fooman"}]
@@ -0,0 +1 @@
1
+ {"results":[{"profile_image_url":"","created_at":"Tue, 13 Oct 2009 18:18:44 +0000","from_user":"thatswhatshesaid","to_user_id":52166667,"text":"@hatguy braid, perhaps the best indie game of 2009","id":6900986667,"from_user_id":1216667,"to_user":"hatguy","geo":null,"iso_language_code":"en","source":""},{"profile_image_url":"","created_at":"Tue, 13 Oct 2009 11:44:27 +0000","from_user":"jillv","to_user_id":null,"text":"braid is even better than of the games i'm in, expect re4","id":6891036667,"from_user_id":3486667,"geo":null,"iso_language_code":"en","source":""}],"max_id":6902086667,"since_id":0,"refresh_url":"?since_id=6902084185&q=braid+game","next_page":"?page=2&max_id=6902084185&rpp=2&q=braid+game","results_per_page":2,"page":1,"completed_in":0.020717,"query":"braid+game"}
@@ -0,0 +1 @@
1
+ {"favorited":false,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://apiwiki.twitter.com/\" rel=\"nofollow\">API</a>","in_reply_to_user_id":null,"in_reply_to_status_id":null,"user":{"profile_background_tile":false,"description":"just testing","verified":false,"profile_background_color":"1a1b1f","following":false,"profile_sidebar_fill_color":"24252b","profile_image_url":"","followers_count":0,"statuses_count":1,"time_zone":"Helsinki","profile_sidebar_border_color":"1a1b1f","url":"http://www.twitter.com/fooman","screen_name":"fooman","friends_count":0,"protected":false,"notifications":false,"favourites_count":0,"created_at":"Wed Oct 10 12:00:00 +0000 2009","profile_text_color":"6b6b6b","location":"Finland","name":"Fooman","profile_background_image_url":"http://s.twimg.com/a/1258674567/images/themes/theme5/bg.gif","id":29700570,"geo_enabled":false,"utc_offset":7200,"profile_link_color":"0070cc"},"created_at":"Sat Oct 13 14:23:41 +0000 2009","truncated":false,"id":5919326888,"text":"bored. going to sleep."}
@@ -0,0 +1 @@
1
+ [{"geo":null,"source":"web","truncated":false,"favorited":false,"user":{"profile_background_image_url":null,"description":"","profile_link_color":"0070cc","profile_background_tile":false,"statuses_count":2,"profile_background_color":"1a1b1f","following":false,"followers_count":2,"profile_sidebar_fill_color":"24252b","friends_count":2,"time_zone":null,"profile_sidebar_border_color":"1a1b1f","protected":false,"url":null,"notifications":false,"favourites_count":0,"profile_image_url":null,"location":null,"name":"Jill Valentine","id":29706667,"verified":false,"geo_enabled":false,"utc_offset":0,"created_at":"Wed Apr 08 12:12:22 +0000 2009","profile_text_color":"6b6b6b","screen_name":"jillv"},"in_reply_to_user_id":15506667,"in_reply_to_status_id":null,"in_reply_to_screen_name":"chris","id":679006667,"text":"@chris wait me until the garden","created_at":"Wed Oct 14 07:57:00 +0000 2009"},{"geo":null,"source":"web","truncated":false,"favorited":false,"user":{"profile_background_image_url":null,"description":"","profile_link_color":"0070cc","profile_background_tile":false,"statuses_count":2,"profile_background_color":"1a1b1f","following":false,"followers_count":2,"profile_sidebar_fill_color":"24252b","friends_count":2,"time_zone":null,"profile_sidebar_border_color":"1a1b1f","protected":false,"url":null,"notifications":false,"favourites_count":0,"profile_image_url":null,"location":null,"name":"Jill Valentine","id":29706667,"verified":false,"geo_enabled":false,"utc_offset":0,"created_at":"Wed Apr 08 12:12:22 +0000 2009","profile_text_color":"6b6b6b","screen_name":"jillv"},"in_reply_to_user_id":null,"in_reply_to_status_id":null,"in_reply_to_screen_name":null,"id":6766566667,"text":"so boring to wait","created_at":"Sat Oct 10 15:39:16 +0000 2009"}]
@@ -0,0 +1 @@
1
+ [{"profile_background_image_url":null,"description":"","profile_link_color":"1F98C7","status":{"source":"web","truncated":false,"favorited":false,"in_reply_to_user_id":null,"in_reply_to_status_id":null,"in_reply_to_screen_name":null,"id":6626773208,"text":"choosing next target","created_at":"Sun Oct 13 11:22:34 +0000 2009"},"profile_background_tile":false,"statuses_count":1,"profile_background_color":"C6E2EE","following":true,"followers_count":1,"profile_sidebar_fill_color":"DAECF4","friends_count":2,"time_zone":null,"profile_sidebar_border_color":"C6E2EE","protected":false,"url":null,"notifications":false,"favourites_count":0,"profile_image_url":null,"location":null,"name":"Jill Valentine","id":85386667,"verified":false,"geo_enabled":false,"utc_offset":0,"created_at":"Thu Oct 1 18:43:52 +0000 2009","profile_text_color":"663B12","screen_name":"jillv"},{"profile_background_image_url":null,"description":"","verified":false,"profile_link_color":"990000","status":{"source":"web","truncated":false,"favorited":false,"in_reply_to_user_id":null,"in_reply_to_status_id":null,"in_reply_to_screen_name":null,"id":689686667,"text":null,"created_at":null},"profile_background_tile":false,"profile_background_color":"EBEBEB","following":true,"statuses_count":0,"profile_sidebar_fill_color":"F3F3F3","followers_count":1,"time_zone":null,"profile_sidebar_border_color":"DFDFDF","protected":false,"url":null,"friends_count":1,"profile_image_url":null,"location":null,"name":"ham","id":15506667,"geo_enabled":false,"notifications":false,"utc_offset":7200,"favourites_count":0,"created_at":"Fri Oct 2 20:41:17 +0000 2008","profile_text_color":"333333","screen_name":"ham"}]
@@ -0,0 +1,36 @@
1
+ require "example_helper"
2
+
3
+ FakeWeb.register_uri(:get, "http://search.twitter.com/search.json?q=braid%20game&rpp=2&page=1", :body => fixture("search.json"))
4
+
5
+ Feature "search statuses" do
6
+ in_order_to "search statuses"
7
+ as_a "any user"
8
+ i_want_to "see latest statuses that match the search"
9
+
10
+ Scenario "see statuses that match the search" do
11
+ When "application is launched 'search' command and search words as extra arguments" do
12
+ @output = launch_cli(%W{-a anyuser:anypwd --no-colors -n 2 search braid game})
13
+ end
14
+
15
+ Then "the latest statuses that match the search are shown" do
16
+ @output[0].should == "thatswhatshesaid, in reply to hatguy, 5 hours ago:"
17
+ @output[1].should == "@hatguy braid, perhaps the best indie game of 2009"
18
+ @output[2].should == ""
19
+ @output[3].should == "jillv, 11 hours ago:"
20
+ @output[4].should == "braid is even better than of the games i'm in, expect re4"
21
+ end
22
+ end
23
+
24
+ Scenario "attempt searching without specifying search word" do
25
+ When "application is launched 'search' command without extra arguments" do
26
+ @status = launch_app("-a anyuser:anypwd --no-colors -n 2 search") do |pid, stdin, stdout|
27
+ @output = stdout.readlines
28
+ end
29
+ end
30
+
31
+ Then "the latest statuses that match the search are shown" do
32
+ @output[0].should == "Error: No search word\n"
33
+ @status.exitstatus.should == CLI::EXIT_ERROR
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,23 @@
1
+ require "example_helper"
2
+
3
+ FakeWeb.register_uri(:get, "https://#{TEST_AUTH}@twitter.com/statuses/followers/#{TEST_USER}.json", :body => fixture("users.json"))
4
+
5
+ Feature "show followers and their latest statuses" do
6
+ in_order_to "to see who follows me"
7
+ as_a "authenticated user"
8
+ i_want_to "see my followers and their latest statuses, if any"
9
+
10
+ Scenario "see followers and their latest statuses" do
11
+ When "application is launched 'followers' command" do
12
+ @output = launch_cli(%W{-a #{TEST_AUTH} --no-colors followers})
13
+ end
14
+
15
+ Then "my followers and their latest statuses are shown" do
16
+ @output[0].should == "jillv, 12 hours ago:"
17
+ @output[1].should == "choosing next target"
18
+ @output[2].should == ""
19
+ @output[3].should == "ham"
20
+ @output[4].should == nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ require "example_helper"
2
+
3
+ FakeWeb.register_uri(:get, "https://#{TEST_AUTH}@twitter.com/statuses/friends/#{TEST_USER}.json", :body => fixture("users.json"))
4
+
5
+ Feature "show friends and their latest statuses" do
6
+ in_order_to "to see who I follow"
7
+ as_a "authenticated user"
8
+ i_want_to "see my friends and their latest statuses, if any"
9
+
10
+ Scenario "see friends and their latest statuses" do
11
+ When "application is launched 'friends' command" do
12
+ @output = launch_cli(%W{-a #{TEST_AUTH} --no-colors friends})
13
+ end
14
+
15
+ Then "my friends and their latest statuses are shown" do
16
+ @output[0].should == "jillv, 12 hours ago:"
17
+ @output[1].should == "choosing next target"
18
+ @output[2].should == ""
19
+ @output[3].should == "ham"
20
+ @output[4].should == nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ require "example_helper"
2
+
3
+ FakeWeb.register_uri(:get, "https://#{TEST_AUTH}@twitter.com/statuses/home_timeline.json?count=20&page=1", :body => fixture("home.json"))
4
+
5
+ Feature "show the latest statuses in the home timeline for the user" do
6
+ in_order_to "stay up-to-date"
7
+ as_a "authenticated user"
8
+ i_want_to "see the latest statuses in the home view"
9
+
10
+ Scenario "see home with colorization disabled" do
11
+ When "application is launched with no command" do
12
+ @output = launch_cli(%W{-a #{TEST_AUTH} --no-colors})
13
+ end
14
+
15
+ Then "the latest statuses in the home view are shown" do
16
+ @output[0].should == "pelit, 11 days ago:"
17
+ @output[1].should == "F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ"
18
+ @output[2].should == ""
19
+ @output[58].should == "radar, 15 days ago:"
20
+ @output[59].should == "Four short links: 29 September 2009 http://bit.ly/dYxay"
21
+ end
22
+ end
23
+
24
+ Scenario "see home with colorization enabled" do
25
+ When "application is launched with no command" do
26
+ @output = launch_cli(%W{-a #{TEST_AUTH} --colors})
27
+ end
28
+
29
+ Then "the latest statuses in the home view are shown" do
30
+ @output[0].should == "\e[32mpelit\e[0m, 11 days ago:"
31
+ @output[1].should == "F1-kausi alkaa marraskuussa \e[36mhttp://bit.ly/1qQwjQ\e[0m"
32
+ @output[2].should == ""
33
+ @output[58].should == "\e[32mradar\e[0m, 15 days ago:"
34
+ @output[59].should == "Four short links: 29 September 2009 \e[36mhttp://bit.ly/dYxay\e[0m"
35
+ end
36
+ end
37
+
38
+ Scenario "the command for showing the home view is the default command" do
39
+ When "application is launched with 'home' command" do
40
+ @output = launch_cli(%W{-a #{TEST_AUTH} --no-colors home})
41
+ end
42
+
43
+ Then "the latest statuses in the home view are shown" do
44
+ @output[0].should == "pelit, 11 days ago:"
45
+ @output[1].should == "F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ"
46
+ @output[2].should == ""
47
+ @output[58].should == "radar, 15 days ago:"
48
+ @output[59].should == "Four short links: 29 September 2009 http://bit.ly/dYxay"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,23 @@
1
+ require "example_helper"
2
+
3
+ FakeWeb.register_uri(:get, "https://#{TEST_AUTH}@twitter.com/statuses/mentions.json?count=20&page=1", :body => fixture("mentions.json"))
4
+
5
+ Feature "show the latest statuses mentioning the user" do
6
+ in_order_to "know if someone has mention me"
7
+ as_a "authenticated user"
8
+ i_want_to "see the latest statuses that mention me"
9
+
10
+ Scenario "see the latest statuses that mention me" do
11
+ When "application is launched with 'mentions' command" do
12
+ @output = launch_cli(%W{-a #{TEST_AUTH} --no-colors mentions})
13
+ end
14
+
15
+ Then "the latest statuses that mention me are shown" do
16
+ @output[0].should == "jillv, in reply to fooman, 3 days ago:"
17
+ @output[1].should == "@fooman, did you see their eyes glow yellow after sunset?"
18
+ @output[2].should == ""
19
+ @output[3].should == "redfield, in reply to fooman, 5 days ago:"
20
+ @output[4].should == "sometimes it is just best to run, just like @fooman"
21
+ end
22
+ end
23
+ end
@@ -5,7 +5,7 @@ Feature "show metadata" do
5
5
  as_a "user"
6
6
  i_want_to "see application metadata"
7
7
 
8
- Scenario "see version" do
8
+ Scenario "see version with designated exit status" do
9
9
  When "application is launched with -v" do
10
10
  @status = launch_app("-v") do |pid, stdin, stdout|
11
11
  @output = stdout.gets
@@ -14,11 +14,11 @@ Feature "show metadata" do
14
14
 
15
15
  Then "version is shown" do
16
16
  @output.should =~ /\d\.\d\.\d$/
17
- @status.exitstatus.should == 2
17
+ @status.exitstatus.should == CLI::EXIT_VERSION
18
18
  end
19
19
  end
20
20
 
21
- Scenario "see help" do
21
+ Scenario "see help with designated exit status" do
22
22
  When "application is launched with -h" do
23
23
  @status = launch_app("-h") do |pid, stdin, stdout|
24
24
  @output = stdout.readlines
@@ -26,10 +26,57 @@ Feature "show metadata" do
26
26
  end
27
27
 
28
28
  Then "help is shown" do
29
- @output[0].should =~ /^Usage:.* \[options\.\.\.\] \[command\]/
30
- @output[2].should =~ /Commands: #{Client::COMMANDS.join(", ")}/
31
- @output[4].should =~ /Options:$/
32
- @status.exitstatus.should == 1
29
+ @output.join.should == <<-END
30
+ A simple but tasty Twitter agent for command line use, made for fun.
31
+
32
+ Usage: tweetwine [global_options...] [command] [command_options...]
33
+
34
+ [command] is one of
35
+ * followers,
36
+ * friends,
37
+ * home,
38
+ * mentions,
39
+ * search,
40
+ * update, or
41
+ * user.
42
+
43
+ The default command is home.
44
+
45
+ [global_options]:
46
+ -a, --auth USERNAME:PASSWORD Authentication
47
+ -c, --colors Colorize output with ANSI escape codes
48
+ -n, --num N The number of statuses in page, default 20
49
+ --no-colors Do not use ANSI colors
50
+ --no-url-shorten Do not shorten URLs for status update
51
+ -p, --page N The page number for statuses, default 1
52
+ -v, --version Show version information and exit
53
+ -h, --help Show this help message and exit
54
+ END
55
+ @status.exitstatus.should == CLI::EXIT_HELP
56
+ end
57
+ end
58
+
59
+ Scenario "upon invalid option, use designated exit status" do
60
+ When "application is launched with -X" do
61
+ @status = launch_app("-X") do |pid, stdin, stdout|
62
+ @output = stdout.readlines
63
+ end
64
+ end
65
+
66
+ Then "designated exit status is returned" do
67
+ @status.exitstatus.should == CLI::EXIT_ERROR
68
+ end
69
+ end
70
+
71
+ Scenario "upon invalid command, use designated exit status" do
72
+ When "application is launched with 'unknown'" do
73
+ @status = launch_app("unknown") do |pid, stdin, stdout|
74
+ @output = stdout.readlines
75
+ end
76
+ end
77
+
78
+ Then "designated exit status is returned" do
79
+ @status.exitstatus.should == CLI::EXIT_ERROR
33
80
  end
34
81
  end
35
82
  end