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 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: tweetwine [options...] [command]
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 "#{File.basename($0)} #{Tweetwine::VERSION}"
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
@@ -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[:io]
16
- @rest_client = dependencies[:rest_client]
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[:url_shortener].call(options[:shorten_urls])
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 = /@\w+/
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
- colorize_all!(:yellow, status, USERNAME_REGEX)
83
- colorize_all!(:magenta, status, HASHTAG_REGEX)
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
- "\033[#{color_code}m#{str}\033[0m"
118
+ "\e[#{color_code}m#{str}\e[0m"
115
119
  end
116
120
  end
117
121
  end
@@ -1,3 +1,3 @@
1
1
  module Tweetwine
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  end
@@ -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
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
- \033[32mfooman\033[0m
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
- \033[32mfooman\033[0m, 2 secs ago:
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
- \033[32mbarman\033[0m, in reply to \033[32mfooman\033[0m, 2 secs ago:
158
- Hi, \033[33m@fooman\033[0m! How are you doing? \033[35m#hellos\033[0m
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
- \033[33m@nick\033[0m, check \033[36mhttp://bit.ly/18rU_Vx\033[0m
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
- \033[32mbarman\033[0m, 2 secs ago:
187
- Three links: \033[36mhttp://bit.ly/18rU_Vx\033[0m \033[36mhttp://is.gd/1qLk3\033[0m and \033[36mhttps://is.gd/2rLk4\033[0m
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
- \033[32mbarman\033[0m, 2 secs ago:
205
- Duplicate links: \033[36mhttp://is.gd/1qLk3\033[0m and \033[36mhttp://is.gd/1qLk3\033[0m
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
- \033[32mbarman\033[0m, 2 secs ago:
223
- I salute you \033[33m@fooman\033[0m, \033[33m@barbaz\033[0m, and \033[33m@spoonman\033[0m!
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
 
@@ -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
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 00:00:00 +03:00
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
- - lib/tweetwine
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.4
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.1
93
+ rubygems_version: 1.3.5
89
94
  signing_key:
90
- specification_version: 2
95
+ specification_version: 3
91
96
  summary: A simple Twitter agent for command line use
92
97
  test_files: []
93
98