tweetwine 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +8 -0
- data/Rakefile +10 -2
- data/bin/tweetwine +8 -7
- data/example/example_helper.rb +59 -0
- data/example/fixtures/statuses.json +1 -0
- data/example/show_latest_statuses_example.rb +45 -0
- data/example/show_metadata_example.rb +35 -0
- data/lib/tweetwine/client.rb +5 -3
- data/lib/tweetwine/io.rb +8 -4
- data/lib/tweetwine/meta.rb +1 -1
- data/lib/tweetwine/util.rb +27 -0
- data/test/client_test.rb +1 -5
- data/test/{test_config.yaml → fixtures/test_config.yaml} +0 -0
- data/test/io_test.rb +34 -12
- data/test/startup_config_test.rb +1 -1
- data/test/util_test.rb +31 -0
- metadata +12 -7
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 0.2.5 released 2009-10-14
|
2
|
+
|
3
|
+
* Improved username highlighting for colorization. For example, email
|
4
|
+
addresses are not highlighted as usernames anymore.
|
5
|
+
* Command line option "--no-colorize" to (temporarily) disable colors from the
|
6
|
+
output.
|
7
|
+
* Added first set of acceptance tests under "example" directory.
|
8
|
+
|
1
9
|
=== 0.2.4 released 2009-09-16
|
2
10
|
|
3
11
|
* Retry connection upon connection reset, trying maximum of three times.
|
data/Rakefile
CHANGED
@@ -20,7 +20,7 @@ spec = Gem::Specification.new do |s|
|
|
20
20
|
s.email = "tkareine@gmail.com"
|
21
21
|
|
22
22
|
s.platform = Gem::Platform::RUBY
|
23
|
-
s.files = FileList["Rakefile", "MIT-LICENSE.txt", "*.rdoc", "bin/**/*", "lib/**/*", "test/**/*"].to_a
|
23
|
+
s.files = FileList["Rakefile", "MIT-LICENSE.txt", "*.rdoc", "bin/**/*", "example/**/*", "lib/**/*", "test/**/*"].to_a
|
24
24
|
s.executables = ["tweetwine"]
|
25
25
|
|
26
26
|
s.add_dependency("rest-client", ">= 1.0.0")
|
@@ -73,6 +73,14 @@ Rake::TestTask.new(:test) do |t|
|
|
73
73
|
t.libs << "test"
|
74
74
|
end
|
75
75
|
|
76
|
+
Rake::TestTask.new(:example) do |t|
|
77
|
+
t.test_files = FileList["example/**/*_example.rb"]
|
78
|
+
t.verbose = true
|
79
|
+
t.warning = false
|
80
|
+
t.ruby_opts << "-rrubygems"
|
81
|
+
t.libs << "example"
|
82
|
+
end
|
83
|
+
|
76
84
|
desc "Find code smells"
|
77
85
|
task :roodi do
|
78
86
|
sh %{roodi "**/*.rb"}
|
@@ -83,4 +91,4 @@ task :todo do
|
|
83
91
|
FileList["**/*.rb", "**/*.rdoc", "**/*.txt"].egrep /(TODO|FIXME)/
|
84
92
|
end
|
85
93
|
|
86
|
-
task :default => :test
|
94
|
+
task :default => [:test, :example]
|
data/bin/tweetwine
CHANGED
@@ -19,8 +19,10 @@ cmd_parser = lambda do |args|
|
|
19
19
|
options = {}
|
20
20
|
begin
|
21
21
|
OptionParser.new do |opt|
|
22
|
+
executable_name = File.basename($0)
|
23
|
+
|
22
24
|
opt.banner =<<-END
|
23
|
-
Usage:
|
25
|
+
Usage: #{executable_name} [options...] [command]
|
24
26
|
|
25
27
|
Commands: #{Client::COMMANDS.join(", ")}
|
26
28
|
|
@@ -36,6 +38,9 @@ Usage: tweetwine [options...] [command]
|
|
36
38
|
opt.on("-n", "--num N", Integer, "The number of statuses to fetch, defaults to #{Client::DEFAULT_NUM_STATUSES}") do |arg|
|
37
39
|
options[:num_statuses] = arg
|
38
40
|
end
|
41
|
+
opt.on("--no-colorize", "Do not colorize output with ANSI escape codes") do
|
42
|
+
options[:colorize] = false
|
43
|
+
end
|
39
44
|
opt.on("--no-url-shorten", "Do not shorten URLs for status update") do
|
40
45
|
options[:shorten_urls] = { :enable => false }
|
41
46
|
end
|
@@ -43,7 +48,7 @@ Usage: tweetwine [options...] [command]
|
|
43
48
|
options[:page_num] = arg
|
44
49
|
end
|
45
50
|
opt.on("-v", "--version", "Show version information and exit") do
|
46
|
-
puts "#{
|
51
|
+
puts "#{executable_name} #{Tweetwine::VERSION}"
|
47
52
|
exit(EXIT_VERSION)
|
48
53
|
end
|
49
54
|
opt.on_tail("-h", "--help", "Show this help message and exit") do
|
@@ -61,11 +66,7 @@ def create_dependencies(options)
|
|
61
66
|
io = Tweetwine::IO.new(options)
|
62
67
|
rest_client = RestClientWrapper.new(io)
|
63
68
|
url_shortener = lambda { |opts| UrlShortener.new(rest_client, opts) }
|
64
|
-
|
65
|
-
:io => io,
|
66
|
-
:rest_client => rest_client,
|
67
|
-
:url_shortener => url_shortener
|
68
|
-
}
|
69
|
+
Client::Dependencies.new io, rest_client, url_shortener
|
69
70
|
end
|
70
71
|
|
71
72
|
begin
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "coulda"
|
2
|
+
require "matchy"
|
3
|
+
require "open4"
|
4
|
+
require "tweetwine"
|
5
|
+
|
6
|
+
module Tweetwine
|
7
|
+
module ExampleHelpers
|
8
|
+
DEFAULT_INJECTION =<<-END
|
9
|
+
require "fakeweb"
|
10
|
+
FakeWeb.allow_net_connect = false
|
11
|
+
|
12
|
+
require "date"
|
13
|
+
require "time"
|
14
|
+
require "timecop"
|
15
|
+
Timecop.freeze(Time.parse("2009-10-14 01:56:15 +0300"))
|
16
|
+
|
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
|
26
|
+
|
27
|
+
def launch_app(args, injection_code = "", &blk)
|
28
|
+
lib = File.dirname(__FILE__) << "/../lib"
|
29
|
+
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}"
|
36
|
+
Open4::popen4(launch_cmd, &blk)
|
37
|
+
end
|
38
|
+
|
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
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
module Test
|
51
|
+
module Unit
|
52
|
+
class TestCase
|
53
|
+
include Tweetwine::ExampleHelpers
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
include Coulda
|
59
|
+
include Tweetwine
|
@@ -0,0 +1 @@
|
|
1
|
+
[{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Fri Oct 02 11:47:12 +0000 2009","truncated":false,"user":{"verified":false,"profile_background_tile":false,"description":"Suomen suurin pelilehti.","friends_count":27,"profile_background_color":"9ae4e8","notifications":false,"profile_image_url":"http://a1.twimg.com/profile_images/67613662/pelittw_normal.jpg","favourites_count":0,"profile_sidebar_fill_color":"e0ff92","url":"http://www.pelit.fi","following":true,"screen_name":"pelit","profile_sidebar_border_color":"87bc44","geo_enabled":false,"created_at":"Sat Nov 22 13:23:32 +0000 2008","statuses_count":391,"time_zone":"Greenland","protected":false,"profile_text_color":"000000","location":"Finland","name":"Pelit","profile_background_image_url":"http://s.twimg.com/a/1255039715/images/themes/theme1/bg.png","id":17556985,"utc_offset":-10800,"profile_link_color":"0000ff","followers_count":70},"in_reply_to_status_id":null,"id":4550677399,"text":"F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ"},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Fri Oct 02 10:42:43 +0000 2009","truncated":false,"user":{"geo_enabled":false,"statuses_count":576,"profile_background_tile":false,"followers_count":6571,"description":"O'Reilly Media's group blog about emerging technologies including Web 2.0, location, open source, ambient computing, mobile, web operations, and more.","profile_background_color":"9ae4e8","friends_count":6,"profile_image_url":"http://a3.twimg.com/profile_images/55297199/iphone_icon_radar_normal.png","profile_sidebar_fill_color":"e0ff92","url":"http://radar.oreilly.com","following":true,"favourites_count":0,"screen_name":"radar","verified":false,"profile_sidebar_border_color":"87bc44","created_at":"Mon Jun 02 19:45:48 +0000 2008","time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"Sebastopol, CA","name":"O'Reilly Radar","notifications":false,"profile_background_image_url":"http://s.twimg.com/a/1255384803/images/themes/theme1/bg.png","id":14984090,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4549851544,"text":"Four short links: 2 October 2009 http://bit.ly/9sbgV"},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://www.atebits.com/\" rel=\"nofollow\">Tweetie</a>","created_at":"Fri Oct 02 09:28:10 +0000 2009","truncated":false,"user":{"notifications":false,"statuses_count":1490,"profile_background_tile":false,"description":"jQuery/Merb/DM FTW","profile_background_color":"333333","geo_enabled":false,"followers_count":3007,"profile_image_url":"http://a1.twimg.com/profile_images/427781590/yehuda_normal.jpg","profile_sidebar_fill_color":"a8caa0","url":"http://www.yehudakatz.com","following":false,"friends_count":117,"screen_name":"wycats","profile_sidebar_border_color":"87bc44","favourites_count":3,"created_at":"Thu Aug 30 04:07:52 +0000 2007","verified":false,"time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"iPhone: 37.786461,-122.394867","name":"wycats","profile_background_image_url":"http://a3.twimg.com/profile_background_images/12633131/Twit3.gif","id":8526432,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4549018421,"text":"Enjoyed giving a less technical talk about how Rails makes it easier to get your app in your users' hands quickly and easily."},{"favorited":false,"in_reply_to_user_id":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://www.atebits.com/\" rel=\"nofollow\">Tweetie</a>","created_at":"Fri Oct 02 01:01:20 +0000 2009","geo":null,"user":{"profile_background_tile":false,"favourites_count":3,"profile_image_url":"http://a1.twimg.com/profile_images/427781590/yehuda_normal.jpg","description":"jQuery/Merb/DM FTW","statuses_count":1478,"profile_background_color":"333333","url":"http://www.yehudakatz.com","following":true,"time_zone":"Pacific Time (US & Canada)","screen_name":"wycats","verified":false,"profile_sidebar_fill_color":"a8caa0","created_at":"Thu Aug 30 04:07:52 +0000 2007","profile_sidebar_border_color":"87bc44","notifications":false,"followers_count":2978,"protected":false,"profile_text_color":"000000","location":"iPhone: 37.786461,-122.394867","name":"wycats","geo_enabled":false,"profile_background_image_url":"http://a3.twimg.com/profile_background_images/12633131/Twit3.gif","friends_count":117,"id":8526432,"utc_offset":-28800,"profile_link_color":"0000ff"},"truncated":false,"id":4540204389,"in_reply_to_status_id":null,"text":"Ruby is like steroids for programmers. It should be considered cheating :P"},{"in_reply_to_screen_name":null,"geo":null,"source":"<a href=\"http://adium.im\" rel=\"nofollow\">Adium</a>","created_at":"Thu Oct 01 18:08:19 +0000 2009","truncated":false,"in_reply_to_status_id":null,"user":{"verified":false,"profile_sidebar_fill_color":"a290ea","description":"","url":"http://pragdave.pragprog.com","following":true,"notifications":false,"profile_sidebar_border_color":"783a4e","followers_count":4718,"created_at":"Mon May 21 00:21:44 +0000 2007","friends_count":37,"profile_text_color":"1160a2","geo_enabled":false,"profile_background_image_url":"http://a1.twimg.com/profile_background_images/3232584/303213676_b1a058e6a3.jpg","statuses_count":971,"favourites_count":0,"profile_link_color":"06066f","protected":false,"profile_image_url":"http://a3.twimg.com/profile_images/62575979/dave_notepaper_small_normal.png","profile_background_tile":false,"location":"Southlake, Texas","name":"Dave Thomas","profile_background_color":"051d7f","screen_name":"pragdave","id":6186692,"time_zone":"Central Time (US & Canada)","utc_offset":-21600},"favorited":false,"id":4530763642,"in_reply_to_user_id":null,"text":"It's royalty check day. I love getting them all out."},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Thu Oct 01 14:13:18 +0000 2009","truncated":false,"user":{"geo_enabled":false,"statuses_count":576,"profile_background_tile":false,"followers_count":6571,"description":"O'Reilly Media's group blog about emerging technologies including Web 2.0, location, open source, ambient computing, mobile, web operations, and more.","profile_background_color":"9ae4e8","friends_count":6,"profile_image_url":"http://a3.twimg.com/profile_images/55297199/iphone_icon_radar_normal.png","profile_sidebar_fill_color":"e0ff92","url":"http://radar.oreilly.com","following":true,"favourites_count":0,"screen_name":"radar","verified":false,"profile_sidebar_border_color":"87bc44","created_at":"Mon Jun 02 19:45:48 +0000 2008","time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"Sebastopol, CA","name":"O'Reilly Radar","notifications":false,"profile_background_image_url":"http://s.twimg.com/a/1255384803/images/themes/theme1/bg.png","id":14984090,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4525352423,"text":"More on how web performance impacts revenue... http://bit.ly/tEpMP"},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Thu Oct 01 12:46:07 +0000 2009","truncated":false,"user":{"verified":false,"profile_background_tile":false,"description":"Suomen suurin pelilehti.","friends_count":27,"profile_background_color":"9ae4e8","notifications":false,"profile_image_url":"http://a1.twimg.com/profile_images/67613662/pelittw_normal.jpg","favourites_count":0,"profile_sidebar_fill_color":"e0ff92","url":"http://www.pelit.fi","following":true,"screen_name":"pelit","profile_sidebar_border_color":"87bc44","geo_enabled":false,"created_at":"Sat Nov 22 13:23:32 +0000 2008","statuses_count":391,"time_zone":"Greenland","protected":false,"profile_text_color":"000000","location":"Finland","name":"Pelit","profile_background_image_url":"http://s.twimg.com/a/1255039715/images/themes/theme1/bg.png","id":17556985,"utc_offset":-10800,"profile_link_color":"0000ff","followers_count":70},"in_reply_to_status_id":null,"id":4523641304,"text":"PSPgo kaupoissa http://bit.ly/2n7evK"},{"geo":null,"truncated":false,"source":"web","created_at":"Thu Oct 01 11:37:47 +0000 2009","in_reply_to_status_id":null,"favorited":false,"user":{"geo_enabled":false,"profile_background_image_url":"http://s.twimg.com/a/1254344155/images/themes/theme1/bg.png","description":"","statuses_count":45,"profile_link_color":"0000ff","url":"http://minigore.blogspot.com","following":null,"profile_background_tile":false,"profile_background_color":"9ae4e8","time_zone":"Helsinki","created_at":"Fri Jun 26 10:09:29 +0000 2009","followers_count":1495,"verified":false,"profile_sidebar_fill_color":"e0ff92","friends_count":9,"profile_sidebar_border_color":"87bc44","protected":false,"profile_image_url":"http://a1.twimg.com/profile_images/423903314/SwayGoreAvatar_normal.jpg","favourites_count":0,"location":"Finland","name":"Mountain Sheep","notifications":null,"screen_name":"minigore","id":51000682,"utc_offset":7200,"profile_text_color":"000000"},"in_reply_to_user_id":null,"in_reply_to_screen_name":null,"id":4522561867,"text":"We have picked a bit over 60 new beta testers so far. Last chance to send those applications in! http://bit.ly/3sVIAb"},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Thu Oct 01 10:42:46 +0000 2009","truncated":false,"user":{"geo_enabled":false,"statuses_count":576,"profile_background_tile":false,"followers_count":6571,"description":"O'Reilly Media's group blog about emerging technologies including Web 2.0, location, open source, ambient computing, mobile, web operations, and more.","profile_background_color":"9ae4e8","friends_count":6,"profile_image_url":"http://a3.twimg.com/profile_images/55297199/iphone_icon_radar_normal.png","profile_sidebar_fill_color":"e0ff92","url":"http://radar.oreilly.com","following":true,"favourites_count":0,"screen_name":"radar","verified":false,"profile_sidebar_border_color":"87bc44","created_at":"Mon Jun 02 19:45:48 +0000 2008","time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"Sebastopol, CA","name":"O'Reilly Radar","notifications":false,"profile_background_image_url":"http://s.twimg.com/a/1255384803/images/themes/theme1/bg.png","id":14984090,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4521842026,"text":"Four short links: 1 October 2009 http://bit.ly/UisfL"},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://www.atebits.com/\" rel=\"nofollow\">Tweetie</a>","created_at":"Thu Oct 01 01:56:01 +0000 2009","truncated":false,"user":{"notifications":false,"statuses_count":1490,"profile_background_tile":false,"description":"jQuery/Merb/DM FTW","profile_background_color":"333333","geo_enabled":false,"followers_count":3007,"profile_image_url":"http://a1.twimg.com/profile_images/427781590/yehuda_normal.jpg","profile_sidebar_fill_color":"a8caa0","url":"http://www.yehudakatz.com","following":false,"friends_count":117,"screen_name":"wycats","profile_sidebar_border_color":"87bc44","favourites_count":3,"created_at":"Thu Aug 30 04:07:52 +0000 2007","verified":false,"time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"iPhone: 37.786461,-122.394867","name":"wycats","profile_background_image_url":"http://a3.twimg.com/profile_background_images/12633131/Twit3.gif","id":8526432,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4513811464,"text":"There's a picture of a mac next to the \"universal\" laptop charger available on the flight. Cruel."},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://www.atebits.com/\" rel=\"nofollow\">Tweetie</a>","created_at":"Thu Oct 01 00:56:13 +0000 2009","truncated":false,"user":{"notifications":false,"statuses_count":1490,"profile_background_tile":false,"description":"jQuery/Merb/DM FTW","profile_background_color":"333333","geo_enabled":false,"followers_count":3007,"profile_image_url":"http://a1.twimg.com/profile_images/427781590/yehuda_normal.jpg","profile_sidebar_fill_color":"a8caa0","url":"http://www.yehudakatz.com","following":false,"friends_count":117,"screen_name":"wycats","profile_sidebar_border_color":"87bc44","favourites_count":3,"created_at":"Thu Aug 30 04:07:52 +0000 2007","verified":false,"time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"iPhone: 37.786461,-122.394867","name":"wycats","profile_background_image_url":"http://a3.twimg.com/profile_background_images/12633131/Twit3.gif","id":8526432,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4512344880,"text":"Is there someplace to buy apple power cord in SFO International terminal?"},{"text":"http://yfrog.com/0lvi6j\nAwesome seats for the cubs game. Thanks Kenny and DRW","created_at":"Thu Oct 01 00:05:04 +0000 2009","truncated":false,"in_reply_to_status_id":null,"source":"<a href=\"http://twitterrific.com\" rel=\"nofollow\">Twitterrific</a>","user":{"favourites_count":0,"profile_background_color":"EBEBEB","verified":false,"utc_offset":-21600,"created_at":"Mon Apr 21 00:02:22 +0000 2008","screen_name":"jaycfields","profile_sidebar_fill_color":"F3F3F3","profile_sidebar_border_color":"DFDFDF","notifications":false,"location":"Chicago, IL","time_zone":"Central Time (US & Canada)","geo_enabled":false,"profile_text_color":"333333","followers_count":560,"protected":false,"statuses_count":1296,"profile_background_image_url":"http://s.twimg.com/a/1255039715/images/themes/theme7/bg.gif","name":"Jay Fields","friends_count":33,"profile_link_color":"990000","url":"http://www.jayfields.com","id":14456381,"following":true,"profile_background_tile":false,"profile_image_url":"http://a1.twimg.com/profile_images/54137880/JayFields_normal.jpg","description":"Programmer, Alcoholic, Gambler"},"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"id":4511163054},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://www.atebits.com/\" rel=\"nofollow\">Tweetie</a>","created_at":"Wed Sep 30 21:08:03 +0000 2009","truncated":false,"user":{"notifications":false,"statuses_count":1490,"profile_background_tile":false,"description":"jQuery/Merb/DM FTW","profile_background_color":"333333","geo_enabled":false,"followers_count":3007,"profile_image_url":"http://a1.twimg.com/profile_images/427781590/yehuda_normal.jpg","profile_sidebar_fill_color":"a8caa0","url":"http://www.yehudakatz.com","following":false,"friends_count":117,"screen_name":"wycats","profile_sidebar_border_color":"87bc44","favourites_count":3,"created_at":"Thu Aug 30 04:07:52 +0000 2007","verified":false,"time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"iPhone: 37.786461,-122.394867","name":"wycats","profile_background_image_url":"http://a3.twimg.com/profile_background_images/12633131/Twit3.gif","id":8526432,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4507179861,"text":"Looking forward to my FOWA talk. \"Rails 3 and the Future of Agile\""},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Wed Sep 30 10:42:39 +0000 2009","truncated":false,"user":{"geo_enabled":false,"statuses_count":576,"profile_background_tile":false,"followers_count":6571,"description":"O'Reilly Media's group blog about emerging technologies including Web 2.0, location, open source, ambient computing, mobile, web operations, and more.","profile_background_color":"9ae4e8","friends_count":6,"profile_image_url":"http://a3.twimg.com/profile_images/55297199/iphone_icon_radar_normal.png","profile_sidebar_fill_color":"e0ff92","url":"http://radar.oreilly.com","following":true,"favourites_count":0,"screen_name":"radar","verified":false,"profile_sidebar_border_color":"87bc44","created_at":"Mon Jun 02 19:45:48 +0000 2008","time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"Sebastopol, CA","name":"O'Reilly Radar","notifications":false,"profile_background_image_url":"http://s.twimg.com/a/1255384803/images/themes/theme1/bg.png","id":14984090,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4494333077,"text":"Four short links: 30 September 2009 http://bit.ly/hQHat"},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Wed Sep 30 07:15:59 +0000 2009","truncated":false,"user":{"verified":false,"profile_background_tile":false,"description":"Suomen suurin pelilehti.","friends_count":27,"profile_background_color":"9ae4e8","notifications":false,"profile_image_url":"http://a1.twimg.com/profile_images/67613662/pelittw_normal.jpg","favourites_count":0,"profile_sidebar_fill_color":"e0ff92","url":"http://www.pelit.fi","following":true,"screen_name":"pelit","profile_sidebar_border_color":"87bc44","geo_enabled":false,"created_at":"Sat Nov 22 13:23:32 +0000 2008","statuses_count":391,"time_zone":"Greenland","protected":false,"profile_text_color":"000000","location":"Finland","name":"Pelit","profile_background_image_url":"http://s.twimg.com/a/1255039715/images/themes/theme1/bg.png","id":17556985,"utc_offset":-10800,"profile_link_color":"0000ff","followers_count":70},"in_reply_to_status_id":null,"id":4492072996,"text":"Left 4 Dead laajeni http://bit.ly/aPmwY"},{"text":"Mexican for dinner with Shane Harvie. Then a cigar on my balcony solo. A nice peaceful evening.","created_at":"Wed Sep 30 03:25:53 +0000 2009","truncated":false,"in_reply_to_status_id":null,"source":"<a href=\"http://twitterrific.com\" rel=\"nofollow\">Twitterrific</a>","user":{"favourites_count":0,"profile_background_color":"EBEBEB","verified":false,"utc_offset":-21600,"created_at":"Mon Apr 21 00:02:22 +0000 2008","screen_name":"jaycfields","profile_sidebar_fill_color":"F3F3F3","profile_sidebar_border_color":"DFDFDF","notifications":false,"location":"Chicago, IL","time_zone":"Central Time (US & Canada)","geo_enabled":false,"profile_text_color":"333333","followers_count":560,"protected":false,"statuses_count":1296,"profile_background_image_url":"http://s.twimg.com/a/1255039715/images/themes/theme7/bg.gif","name":"Jay Fields","friends_count":33,"profile_link_color":"990000","url":"http://www.jayfields.com","id":14456381,"following":true,"profile_background_tile":false,"profile_image_url":"http://a1.twimg.com/profile_images/54137880/JayFields_normal.jpg","description":"Programmer, Alcoholic, Gambler"},"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"id":4488550494},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Wed Sep 30 02:42:57 +0000 2009","truncated":false,"user":{"geo_enabled":false,"statuses_count":576,"profile_background_tile":false,"followers_count":6571,"description":"O'Reilly Media's group blog about emerging technologies including Web 2.0, location, open source, ambient computing, mobile, web operations, and more.","profile_background_color":"9ae4e8","friends_count":6,"profile_image_url":"http://a3.twimg.com/profile_images/55297199/iphone_icon_radar_normal.png","profile_sidebar_fill_color":"e0ff92","url":"http://radar.oreilly.com","following":true,"favourites_count":0,"screen_name":"radar","verified":false,"profile_sidebar_border_color":"87bc44","created_at":"Mon Jun 02 19:45:48 +0000 2008","time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"Sebastopol, CA","name":"O'Reilly Radar","notifications":false,"profile_background_image_url":"http://s.twimg.com/a/1255384803/images/themes/theme1/bg.png","id":14984090,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4487612897,"text":"Review of Guobin Yang's \"Power of the Internet in China\" http://bit.ly/19jf69"},{"truncated":false,"source":"<a href=\"http://www.atebits.com/\" rel=\"nofollow\">Tweetie</a>","created_at":"Wed Sep 30 01:11:13 +0000 2009","in_reply_to_status_id":null,"favorited":false,"user":{"profile_sidebar_border_color":"86A4A6","description":"","verified":false,"url":"http://blog.fallingsnow.net","following":true,"notifications":true,"profile_text_color":"333333","followers_count":1321,"profile_image_url":"http://a3.twimg.com/profile_images/52576575/DSCN0363_2_normal.JPG","profile_background_image_url":"http://s.twimg.com/a/1253743961/images/themes/theme6/bg.gif","created_at":"Mon Apr 23 20:51:19 +0000 2007","friends_count":130,"profile_link_color":"FF3300","screen_name":"evanphx","profile_background_tile":false,"favourites_count":1,"profile_background_color":"709397","protected":false,"statuses_count":1253,"time_zone":"Pacific Time (US & Canada)","location":"Los Angeles, California","name":"Evan Phoenix","profile_sidebar_fill_color":"A0C5C7","id":5444392,"utc_offset":-28800},"in_reply_to_user_id":null,"in_reply_to_screen_name":null,"id":4485439470,"text":"Thanks to @malafortune, a little elbow grease, and a lot of specs, Rubinius is now largely updated to ruby 1.8.7!"},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Tue Sep 29 14:42:51 +0000 2009","truncated":false,"user":{"geo_enabled":false,"statuses_count":576,"profile_background_tile":false,"followers_count":6571,"description":"O'Reilly Media's group blog about emerging technologies including Web 2.0, location, open source, ambient computing, mobile, web operations, and more.","profile_background_color":"9ae4e8","friends_count":6,"profile_image_url":"http://a3.twimg.com/profile_images/55297199/iphone_icon_radar_normal.png","profile_sidebar_fill_color":"e0ff92","url":"http://radar.oreilly.com","following":true,"favourites_count":0,"screen_name":"radar","verified":false,"profile_sidebar_border_color":"87bc44","created_at":"Mon Jun 02 19:45:48 +0000 2008","time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"Sebastopol, CA","name":"O'Reilly Radar","notifications":false,"profile_background_image_url":"http://s.twimg.com/a/1255384803/images/themes/theme1/bg.png","id":14984090,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4471331911,"text":"David Hoover's Top 5 Tips for Apprentices http://bit.ly/ZOgVm"},{"favorited":false,"in_reply_to_user_id":null,"geo":null,"in_reply_to_screen_name":null,"source":"<a href=\"http://twitterfeed.com\" rel=\"nofollow\">twitterfeed</a>","created_at":"Tue Sep 29 10:42:45 +0000 2009","truncated":false,"user":{"geo_enabled":false,"statuses_count":576,"profile_background_tile":false,"followers_count":6571,"description":"O'Reilly Media's group blog about emerging technologies including Web 2.0, location, open source, ambient computing, mobile, web operations, and more.","profile_background_color":"9ae4e8","friends_count":6,"profile_image_url":"http://a3.twimg.com/profile_images/55297199/iphone_icon_radar_normal.png","profile_sidebar_fill_color":"e0ff92","url":"http://radar.oreilly.com","following":true,"favourites_count":0,"screen_name":"radar","verified":false,"profile_sidebar_border_color":"87bc44","created_at":"Mon Jun 02 19:45:48 +0000 2008","time_zone":"Pacific Time (US & Canada)","protected":false,"profile_text_color":"000000","location":"Sebastopol, CA","name":"O'Reilly Radar","notifications":false,"profile_background_image_url":"http://s.twimg.com/a/1255384803/images/themes/theme1/bg.png","id":14984090,"utc_offset":-28800,"profile_link_color":"0000ff"},"in_reply_to_status_id":null,"id":4467285671,"text":"Four short links: 29 September 2009 http://bit.ly/dYxay"}]
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "example_helper"
|
2
|
+
|
3
|
+
Feature "show the latest statuses" do
|
4
|
+
in_order_to "stay up-to-date"
|
5
|
+
as_a "user"
|
6
|
+
i_want_to "see the latest statuses"
|
7
|
+
|
8
|
+
INJECTION = 'FakeWeb.register_uri(:get, "https://foouser:barpwd@twitter.com/statuses/friends_timeline.json?count=20&page=1", :body => fixture("statuses.json"))'
|
9
|
+
|
10
|
+
Scenario "see the latest statuses with colorization disabled" do
|
11
|
+
When "application is launched with command 'home'" do
|
12
|
+
@status = launch_app("-a foouser:barpwd --no-colorize", INJECTION) do |pid, stdin, stdout|
|
13
|
+
@output = stdout.readlines
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Then "the latest statuses are shown" do
|
18
|
+
@output[0].should == "pelit, 11 days ago:\n"
|
19
|
+
@output[1].should == "F1-kausi alkaa marraskuussa http://bit.ly/1qQwjQ\n"
|
20
|
+
@output[2].should == "\n"
|
21
|
+
@output[58].should == "radar, 15 days ago:\n"
|
22
|
+
@output[59].should == "Four short links: 29 September 2009 http://bit.ly/dYxay\n"
|
23
|
+
@output[60].should == "\n"
|
24
|
+
@status.exitstatus.should == 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Scenario "see the latest statuses with colorization enabled" do
|
29
|
+
When "application is launched with command 'home'" do
|
30
|
+
@status = launch_app("-a foouser:barpwd --colorize", INJECTION) do |pid, stdin, stdout|
|
31
|
+
@output = stdout.readlines
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Then "the latest statuses are shown" do
|
36
|
+
@output[0].should == "\e[32mpelit\e[0m, 11 days ago:\n"
|
37
|
+
@output[1].should == "F1-kausi alkaa marraskuussa \e[36mhttp://bit.ly/1qQwjQ\e[0m\n"
|
38
|
+
@output[2].should == "\n"
|
39
|
+
@output[58].should == "\e[32mradar\e[0m, 15 days ago:\n"
|
40
|
+
@output[59].should == "Four short links: 29 September 2009 \e[36mhttp://bit.ly/dYxay\e[0m\n"
|
41
|
+
@output[60].should == "\n"
|
42
|
+
@status.exitstatus.should == 0
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "example_helper"
|
2
|
+
|
3
|
+
Feature "show metadata" do
|
4
|
+
in_order_to "know about the application"
|
5
|
+
as_a "user"
|
6
|
+
i_want_to "see application metadata"
|
7
|
+
|
8
|
+
Scenario "see version" do
|
9
|
+
When "application is launched with -v" do
|
10
|
+
@status = launch_app("-v") do |pid, stdin, stdout|
|
11
|
+
@output = stdout.gets
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Then "version is shown" do
|
16
|
+
@output.should =~ /\d\.\d\.\d$/
|
17
|
+
@status.exitstatus.should == 2
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
Scenario "see help" do
|
22
|
+
When "application is launched with -h" do
|
23
|
+
@status = launch_app("-h") do |pid, stdin, stdout|
|
24
|
+
@output = stdout.readlines
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
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
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/tweetwine/client.rb
CHANGED
@@ -3,6 +3,8 @@ require "uri"
|
|
3
3
|
|
4
4
|
module Tweetwine
|
5
5
|
class Client
|
6
|
+
Dependencies = Struct.new :io, :rest_client, :url_shortener
|
7
|
+
|
6
8
|
attr_reader :num_statuses, :page_num
|
7
9
|
|
8
10
|
COMMANDS = [:home, :mentions, :user, :update, :friends, :followers]
|
@@ -12,15 +14,15 @@ module Tweetwine
|
|
12
14
|
MAX_STATUS_LENGTH = 140
|
13
15
|
|
14
16
|
def initialize(dependencies, options)
|
15
|
-
@io = dependencies
|
16
|
-
@rest_client = dependencies
|
17
|
+
@io = dependencies.io
|
18
|
+
@rest_client = dependencies.rest_client
|
17
19
|
@username = options[:username].to_s
|
18
20
|
raise ArgumentError, "No authentication data given" if @username.empty?
|
19
21
|
@base_url = "https://#{@username}:#{options[:password]}@twitter.com/"
|
20
22
|
@num_statuses = Util.parse_int_gt(options[:num_statuses], DEFAULT_NUM_STATUSES, 1, "number of statuses_to_show")
|
21
23
|
@page_num = Util.parse_int_gt(options[:page_num], DEFAULT_PAGE_NUM, 1, "page number")
|
22
24
|
@url_shortener = if options[:shorten_urls] && options[:shorten_urls][:enable]
|
23
|
-
dependencies
|
25
|
+
dependencies.url_shortener.call(options[:shorten_urls])
|
24
26
|
else
|
25
27
|
nil
|
26
28
|
end
|
data/lib/tweetwine/io.rb
CHANGED
@@ -10,7 +10,7 @@ module Tweetwine
|
|
10
10
|
}
|
11
11
|
|
12
12
|
HASHTAG_REGEX = /#[\w-]+/
|
13
|
-
USERNAME_REGEX =
|
13
|
+
USERNAME_REGEX = /^(@\w+)|\s+(@\w+)/
|
14
14
|
|
15
15
|
def initialize(options)
|
16
16
|
@input = options[:input] || $stdin
|
@@ -79,8 +79,8 @@ module Tweetwine
|
|
79
79
|
def format_status(status)
|
80
80
|
status = status.dup
|
81
81
|
if @colorize
|
82
|
-
|
83
|
-
|
82
|
+
colorize_all_by_group!(:yellow, status, USERNAME_REGEX)
|
83
|
+
colorize_all_by_group!(:magenta, status, HASHTAG_REGEX)
|
84
84
|
URI.extract(status, ["http", "https"]).uniq.each do |url|
|
85
85
|
colorize_all!(:cyan, status, url)
|
86
86
|
end
|
@@ -106,12 +106,16 @@ module Tweetwine
|
|
106
106
|
str.gsub!(pattern) { |s| colorize_str(COLOR_CODES[color.to_sym], s) }
|
107
107
|
end
|
108
108
|
|
109
|
+
def colorize_all_by_group!(color, str, pattern)
|
110
|
+
str.replace Util.str_gsub_by_group(str, pattern) { |s| colorize_str(COLOR_CODES[color.to_sym], s) }
|
111
|
+
end
|
112
|
+
|
109
113
|
def colorize!(color, str)
|
110
114
|
str.replace colorize_str(COLOR_CODES[color.to_sym], str)
|
111
115
|
end
|
112
116
|
|
113
117
|
def colorize_str(color_code, str)
|
114
|
-
"\
|
118
|
+
"\e[#{color_code}m#{str}\e[0m"
|
115
119
|
end
|
116
120
|
end
|
117
121
|
end
|
data/lib/tweetwine/meta.rb
CHANGED
data/lib/tweetwine/util.rb
CHANGED
@@ -40,6 +40,25 @@ module Tweetwine
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
def self.str_gsub_by_group(str, regexp)
|
44
|
+
dup_str = str.dup
|
45
|
+
index, dup_index = 0, 0
|
46
|
+
while index < str.size && (match_data = regexp.match(str[index..-1]))
|
47
|
+
matching_group_indexes = indexes_of_filled_matches(match_data)
|
48
|
+
|
49
|
+
matching_group_indexes.each do |i|
|
50
|
+
replacement = (yield match_data[i]).to_s
|
51
|
+
dup_str[dup_index + match_data.begin(i), match_data[i].size] = replacement
|
52
|
+
replacement_delta = replacement.size - match_data[i].size
|
53
|
+
dup_index += replacement_delta
|
54
|
+
end
|
55
|
+
skip_delta = match_data.end(0)
|
56
|
+
index += skip_delta
|
57
|
+
dup_index += skip_delta
|
58
|
+
end
|
59
|
+
dup_str
|
60
|
+
end
|
61
|
+
|
43
62
|
private
|
44
63
|
|
45
64
|
def self.pluralize_unit(value, unit)
|
@@ -48,5 +67,13 @@ module Tweetwine
|
|
48
67
|
end
|
49
68
|
unit
|
50
69
|
end
|
70
|
+
|
71
|
+
def self.indexes_of_filled_matches(match_data)
|
72
|
+
if match_data.size > 1
|
73
|
+
(1...match_data.size).to_a.reject { |i| match_data[i].nil? }
|
74
|
+
else
|
75
|
+
[0]
|
76
|
+
end
|
77
|
+
end
|
51
78
|
end
|
52
79
|
end
|
data/test/client_test.rb
CHANGED
@@ -12,11 +12,7 @@ class ClientTest < Test::Unit::TestCase
|
|
12
12
|
@rest_client = mock()
|
13
13
|
@url_shortener = mock()
|
14
14
|
url_shortener = lambda { |options| @url_shortener }
|
15
|
-
@deps =
|
16
|
-
:io => @io,
|
17
|
-
:rest_client => @rest_client,
|
18
|
-
:url_shortener => url_shortener
|
19
|
-
}
|
15
|
+
@deps = Client::Dependencies.new @io, @rest_client, url_shortener
|
20
16
|
end
|
21
17
|
|
22
18
|
context "upon initialization" do
|
File without changes
|
data/test/io_test.rb
CHANGED
@@ -118,7 +118,7 @@ barman, in reply to fooman, 2 secs ago:
|
|
118
118
|
should "output a record as user info when no status is given" do
|
119
119
|
record = { :user => "fooman" }
|
120
120
|
@output.expects(:puts).with(<<-END
|
121
|
-
\
|
121
|
+
\e[32mfooman\e[0m
|
122
122
|
|
123
123
|
END
|
124
124
|
)
|
@@ -135,7 +135,7 @@ barman, in reply to fooman, 2 secs ago:
|
|
135
135
|
}
|
136
136
|
Util.expects(:humanize_time_diff).returns([2, "secs"])
|
137
137
|
@output.expects(:puts).with(<<-END
|
138
|
-
\
|
138
|
+
\e[32mfooman\e[0m, 2 secs ago:
|
139
139
|
Wondering the meaning of life.
|
140
140
|
|
141
141
|
END
|
@@ -154,8 +154,8 @@ Wondering the meaning of life.
|
|
154
154
|
}
|
155
155
|
Util.expects(:humanize_time_diff).returns([2, "secs"])
|
156
156
|
@output.expects(:puts).with(<<-END
|
157
|
-
\
|
158
|
-
Hi, \
|
157
|
+
\e[32mbarman\e[0m, in reply to \e[32mfooman\e[0m, 2 secs ago:
|
158
|
+
Hi, \e[33m@fooman\e[0m! How are you doing? \e[35m#hellos\e[0m
|
159
159
|
|
160
160
|
END
|
161
161
|
)
|
@@ -166,7 +166,7 @@ Hi, \033[33m@fooman\033[0m! How are you doing? \033[35m#hellos\033[0m
|
|
166
166
|
status = "@nick, check http://bit.ly/18rU_Vx"
|
167
167
|
@output.expects(:puts).with(<<-END
|
168
168
|
|
169
|
-
\
|
169
|
+
\e[33m@nick\e[0m, check \e[36mhttp://bit.ly/18rU_Vx\e[0m
|
170
170
|
|
171
171
|
END
|
172
172
|
)
|
@@ -183,8 +183,8 @@ Hi, \033[33m@fooman\033[0m! How are you doing? \033[35m#hellos\033[0m
|
|
183
183
|
}
|
184
184
|
Util.expects(:humanize_time_diff).returns([2, "secs"])
|
185
185
|
@output.expects(:puts).with(<<-END
|
186
|
-
\
|
187
|
-
Three links: \
|
186
|
+
\e[32mbarman\e[0m, 2 secs ago:
|
187
|
+
Three links: \e[36mhttp://bit.ly/18rU_Vx\e[0m \e[36mhttp://is.gd/1qLk3\e[0m and \e[36mhttps://is.gd/2rLk4\e[0m
|
188
188
|
|
189
189
|
END
|
190
190
|
)
|
@@ -201,8 +201,8 @@ Three links: \033[36mhttp://bit.ly/18rU_Vx\033[0m \033[36mhttp://is.gd/1qLk3\033
|
|
201
201
|
}
|
202
202
|
Util.expects(:humanize_time_diff).returns([2, "secs"])
|
203
203
|
@output.expects(:puts).with(<<-END
|
204
|
-
\
|
205
|
-
Duplicate links: \
|
204
|
+
\e[32mbarman\e[0m, 2 secs ago:
|
205
|
+
Duplicate links: \e[36mhttp://is.gd/1qLk3\e[0m and \e[36mhttp://is.gd/1qLk3\e[0m
|
206
206
|
|
207
207
|
END
|
208
208
|
)
|
@@ -219,8 +219,26 @@ Duplicate links: \033[36mhttp://is.gd/1qLk3\033[0m and \033[36mhttp://is.gd/1qLk
|
|
219
219
|
}
|
220
220
|
Util.expects(:humanize_time_diff).returns([2, "secs"])
|
221
221
|
@output.expects(:puts).with(<<-END
|
222
|
-
\
|
223
|
-
I salute you \
|
222
|
+
\e[32mbarman\e[0m, 2 secs ago:
|
223
|
+
I salute you \e[33m@fooman\e[0m, \e[33m@barbaz\e[0m, and \e[33m@spoonman\e[0m!
|
224
|
+
|
225
|
+
END
|
226
|
+
)
|
227
|
+
@io.show_record(record)
|
228
|
+
end
|
229
|
+
|
230
|
+
should "not highlight email addresses as usernames in a status" do
|
231
|
+
record = {
|
232
|
+
:user => "barman",
|
233
|
+
:status => {
|
234
|
+
:created_at => Time.at(1),
|
235
|
+
:text => "Hi, @fooman! You should notify @barbaz, barbaz@foo.net",
|
236
|
+
}
|
237
|
+
}
|
238
|
+
Util.expects(:humanize_time_diff).returns([2, "secs"])
|
239
|
+
@output.expects(:puts).with(<<-END
|
240
|
+
\e[32mbarman\e[0m, 2 secs ago:
|
241
|
+
Hi, \e[33m@fooman\e[0m! You should notify \e[33m@barbaz\e[0m, barbaz@foo.net
|
224
242
|
|
225
243
|
END
|
226
244
|
)
|
@@ -233,15 +251,19 @@ I salute you \033[33m@fooman\033[0m, \033[33m@barbaz\033[0m, and \033[33m@spoonm
|
|
233
251
|
should "match a proper username reference" do
|
234
252
|
assert_full_match IO::USERNAME_REGEX, "@nick"
|
235
253
|
assert_full_match IO::USERNAME_REGEX, "@nick_man"
|
254
|
+
assert_full_match IO::USERNAME_REGEX, "@nick"
|
255
|
+
assert_full_match IO::USERNAME_REGEX, " @nick"
|
236
256
|
end
|
237
257
|
|
238
258
|
should "not match an inproper username reference" do
|
239
259
|
assert_no_full_match IO::USERNAME_REGEX, "@"
|
240
260
|
assert_no_full_match IO::USERNAME_REGEX, "nick"
|
261
|
+
assert_no_full_match IO::USERNAME_REGEX, "-@nick"
|
241
262
|
assert_no_full_match IO::USERNAME_REGEX, "@nick-man"
|
242
|
-
assert_no_full_match IO::USERNAME_REGEX, " @nick"
|
243
263
|
assert_no_full_match IO::USERNAME_REGEX, "@nick "
|
244
264
|
assert_no_full_match IO::USERNAME_REGEX, " @nick "
|
265
|
+
assert_no_full_match IO::USERNAME_REGEX, "man @nick"
|
266
|
+
assert_no_full_match IO::USERNAME_REGEX, "man@nick"
|
245
267
|
end
|
246
268
|
end
|
247
269
|
|
data/test/startup_config_test.rb
CHANGED
@@ -3,7 +3,7 @@ require "test_helper"
|
|
3
3
|
module Tweetwine
|
4
4
|
|
5
5
|
class StartupConfigTest < Test::Unit::TestCase
|
6
|
-
TEST_CONFIG_FILE = File.dirname(__FILE__) << "/test_config.yaml"
|
6
|
+
TEST_CONFIG_FILE = File.dirname(__FILE__) << "/fixtures/test_config.yaml"
|
7
7
|
|
8
8
|
context "A StartupConfig instance" do
|
9
9
|
context "upon initialization" do
|
data/test/util_test.rb
CHANGED
@@ -50,6 +50,37 @@ class UtilTest < Test::Unit::TestCase
|
|
50
50
|
assert_equal 8, Util.parse_int_gt(false, 8, 4, "ethical working hours per day")
|
51
51
|
assert_raise(ArgumentError) { Util.parse_int_gt(3, 8, 4, "ethical working hours per day") }
|
52
52
|
end
|
53
|
+
|
54
|
+
context "for replacing the contents of a string with a regexp that uses group syntax" do
|
55
|
+
should "replace the contents by using the matching groups of the regexp" do
|
56
|
+
assert_equal "hello", Util.str_gsub_by_group("hello", /he(f)/) { |s| s.upcase }
|
57
|
+
assert_equal "", Util.str_gsub_by_group("", /.+([ai])/) { |s| s.upcase }
|
58
|
+
assert_equal "hello", Util.str_gsub_by_group("hello", /.+([ai])/) { |s| s.upcase }
|
59
|
+
assert_equal "hEllo", Util.str_gsub_by_group("hello", /.+(e)/) { |s| s.upcase }
|
60
|
+
assert_equal "hEllO", Util.str_gsub_by_group("hello", /([aeio])/) { |s| s.upcase }
|
61
|
+
assert_equal "hEEllOO", Util.str_gsub_by_group("hello", /([aeio])/) { |s| s.upcase * 2 }
|
62
|
+
assert_equal "hEllO", Util.str_gsub_by_group("hello", /([ae]).+([io])/) { |s| s.upcase }
|
63
|
+
assert_equal "hXEXllXOX", Util.str_gsub_by_group("hello", /([ae]).+([io])/) { |s| "X" + s.upcase + "X" }
|
64
|
+
assert_equal "hll", Util.str_gsub_by_group("hello", /.+([ae]).+([io])/) { |s| "" }
|
65
|
+
assert_equal "hll", Util.str_gsub_by_group("hello", /([ae]).+([io])/) { |s| "" }
|
66
|
+
assert_equal "hll", Util.str_gsub_by_group("hello", /([aeio])/) { |s| "" }
|
67
|
+
assert_equal "hell", Util.str_gsub_by_group("hello", /.+([io])/) { |s| "" }
|
68
|
+
assert_equal "hEllo", Util.str_gsub_by_group("hello", /^(a)|.+(e)/) { |s| s.upcase }
|
69
|
+
end
|
70
|
+
|
71
|
+
should "replace the contents by using the whole match if there are no groups in the regexp" do
|
72
|
+
assert_equal "", Util.str_gsub_by_group("", /el/) { |s| s.upcase }
|
73
|
+
assert_equal "hELlo", Util.str_gsub_by_group("hello", /el/) { |s| s.upcase }
|
74
|
+
end
|
75
|
+
|
76
|
+
should "return a new string as the result" do
|
77
|
+
org_str = "hello"
|
78
|
+
new_str = Util.str_gsub_by_group(org_str, /e/) { |s| s.upcase }
|
79
|
+
assert_not_same new_str, org_str
|
80
|
+
assert_equal "hello", org_str
|
81
|
+
assert_equal "hEllo", new_str
|
82
|
+
end
|
83
|
+
end
|
53
84
|
end
|
54
85
|
|
55
86
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tweetwine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tuomas Kareinen
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-14 00:00:00 +03:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -38,7 +38,10 @@ files:
|
|
38
38
|
- CHANGELOG.rdoc
|
39
39
|
- README.rdoc
|
40
40
|
- bin/tweetwine
|
41
|
-
-
|
41
|
+
- example/example_helper.rb
|
42
|
+
- example/fixtures/statuses.json
|
43
|
+
- example/show_latest_statuses_example.rb
|
44
|
+
- example/show_metadata_example.rb
|
42
45
|
- lib/tweetwine/client.rb
|
43
46
|
- lib/tweetwine/io.rb
|
44
47
|
- lib/tweetwine/meta.rb
|
@@ -49,20 +52,22 @@ files:
|
|
49
52
|
- lib/tweetwine/util.rb
|
50
53
|
- lib/tweetwine.rb
|
51
54
|
- test/client_test.rb
|
55
|
+
- test/fixtures/test_config.yaml
|
52
56
|
- test/io_test.rb
|
53
57
|
- test/options_test.rb
|
54
58
|
- test/rest_client_wrapper_test.rb
|
55
59
|
- test/startup_config_test.rb
|
56
|
-
- test/test_config.yaml
|
57
60
|
- test/test_helper.rb
|
58
61
|
- test/url_shortener_test.rb
|
59
62
|
- test/util_test.rb
|
60
63
|
has_rdoc: true
|
61
64
|
homepage: http://github.com/tuomas/tweetwine
|
65
|
+
licenses: []
|
66
|
+
|
62
67
|
post_install_message:
|
63
68
|
rdoc_options:
|
64
69
|
- --title
|
65
|
-
- tweetwine 0.2.
|
70
|
+
- tweetwine 0.2.5
|
66
71
|
- --main
|
67
72
|
- README.rdoc
|
68
73
|
- --exclude
|
@@ -85,9 +90,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
90
|
requirements: []
|
86
91
|
|
87
92
|
rubyforge_project:
|
88
|
-
rubygems_version: 1.3.
|
93
|
+
rubygems_version: 1.3.5
|
89
94
|
signing_key:
|
90
|
-
specification_version:
|
95
|
+
specification_version: 3
|
91
96
|
summary: A simple Twitter agent for command line use
|
92
97
|
test_files: []
|
93
98
|
|