tuomas-tweetwine 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,13 @@
1
+ === 0.2.2 released 2009-09-03
2
+
3
+ * Highlight hashtags in statuses.
4
+ * URL shortening step shortens only unique URLs.
5
+ * URL shortening step is skipped if
6
+ - there is a connection error to the URL shortening service, or
7
+ - required libraries are not installed (nokogiri).
8
+ * Fixed a colorization bug for duplicate URLs.
9
+ * Removed dependencies to Rubygems.
10
+
1
11
  === 0.2.1 released 2009-08-17
2
12
 
3
13
  * Command line option "-v" show version information.
data/MIT-LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 Tuomas Kareinen.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.rdoc CHANGED
@@ -84,24 +84,4 @@ com >.
84
84
 
85
85
  == Legal notes
86
86
 
87
- This software is licensed under the terms of the "MIT license":
88
-
89
- Copyright (c) 2009 Tuomas Kareinen.
90
-
91
- Permission is hereby granted, free of charge, to any person obtaining a copy
92
- of this software and associated documentation files (the "Software"), to
93
- deal in the Software without restriction, including without limitation the
94
- rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
95
- sell copies of the Software, and to permit persons to whom the Software is
96
- furnished to do so, subject to the following conditions:
97
-
98
- The above copyright notice and this permission notice shall be included in
99
- all copies or substantial portions of the Software.
100
-
101
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
102
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
103
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
104
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
105
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
106
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
107
- IN THE SOFTWARE.
87
+ Copyright (c) 2009 Tuomas Kareinen. See MIT-LICENSE.txt in this directory.
data/Rakefile CHANGED
@@ -1,15 +1,16 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib"))
2
+
1
3
  require "rubygems"
2
4
 
3
- package_name = "tweetwine"
4
- require "lib/#{package_name}"
5
- full_name = Tweetwine::Meta::NAME
6
- version = Tweetwine::Meta::VERSION
5
+ name = "tweetwine"
6
+ require "#{name}"
7
+ version = Tweetwine::VERSION
7
8
 
8
9
  require "rake/clean"
9
10
 
10
11
  require "rake/gempackagetask"
11
12
  spec = Gem::Specification.new do |s|
12
- s.name = package_name
13
+ s.name = name
13
14
  s.version = version
14
15
  s.homepage = "http://github.com/tuomas/tweetwine"
15
16
  s.summary = "A simple Twitter agent for command line use"
@@ -19,14 +20,14 @@ spec = Gem::Specification.new do |s|
19
20
  s.email = "tkareine@gmail.com"
20
21
 
21
22
  s.platform = Gem::Platform::RUBY
22
- s.files = FileList["Rakefile", "*.rdoc", "bin/**/*", "lib/**/*", "test/**/*"].to_a
23
+ s.files = FileList["Rakefile", "MIT-LICENSE.txt", "*.rdoc", "bin/**/*", "lib/**/*", "test/**/*"].to_a
23
24
  s.executables = ["tweetwine"]
24
25
 
25
26
  s.add_dependency("rest-client", ">= 1.0.0")
26
27
 
27
28
  s.has_rdoc = true
28
- s.extra_rdoc_files = FileList["*.rdoc"].to_a
29
- s.rdoc_options << "--title" << "#{full_name} #{version}" \
29
+ s.extra_rdoc_files = FileList["MIT-LICENSE.txt", "*.rdoc"].to_a
30
+ s.rdoc_options << "--title" << "#{name} #{version}" \
30
31
  << "--main" << "README.rdoc" \
31
32
  << "--exclude" << "test" \
32
33
  << "--line-numbers"
@@ -45,29 +46,30 @@ task :gemspec do
45
46
  end
46
47
 
47
48
  task :install => [:package] do
48
- sh %{sudo gem install pkg/#{package_name}-#{version}.gem}
49
+ sh %{sudo gem install pkg/#{name}-#{version}.gem}
49
50
  end
50
51
 
51
52
  task :uninstall => [:clean] do
52
- sh %{sudo gem uninstall #{package_name}}
53
+ sh %{sudo gem uninstall #{name}}
53
54
  end
54
55
 
55
56
  require "rake/rdoctask"
56
57
  desc "Create documentation"
57
58
  Rake::RDocTask.new(:rdoc) do |rd|
58
59
  rd.rdoc_dir = "rdoc"
59
- rd.title = "#{full_name} #{version}"
60
+ rd.title = "#{name} #{version}"
60
61
  rd.main = "README.rdoc"
61
- rd.rdoc_files.include("*.rdoc", "lib/**/*.rb")
62
+ rd.rdoc_files.include("MIT-LICENSE.txt", "*.rdoc", "lib/**/*.rb")
62
63
  rd.options << "--line-numbers"
63
64
  end
64
65
 
65
66
  require "rake/testtask"
66
67
  desc "Run tests"
67
- Rake::TestTask.new do |t|
68
- t.test_files = FileList["test/*_test.rb"]
68
+ Rake::TestTask.new(:test) do |t|
69
+ t.test_files = FileList["test/**/*_test.rb"]
69
70
  t.verbose = true
70
71
  t.warning = true
72
+ t.libs << "test"
71
73
  end
72
74
 
73
75
  desc "Find code smells"
@@ -77,7 +79,7 @@ end
77
79
 
78
80
  desc "Search unfinished parts of source code"
79
81
  task :todo do
80
- FileList["**/*.rb"].egrep /#.*(TODO|FIXME)/
82
+ FileList["**/*.rb", "**/*.rdoc", "**/*.txt"].egrep /(TODO|FIXME)/
81
83
  end
82
84
 
83
85
  task :default => :test
data/bin/tweetwine CHANGED
@@ -10,10 +10,8 @@ trap("INT") do
10
10
  exit(EXIT_SIGINT)
11
11
  end
12
12
 
13
- require "rubygems"
14
13
  require "optparse"
15
-
16
- require File.dirname(__FILE__) << "/../lib/tweetwine"
14
+ require "tweetwine"
17
15
 
18
16
  include Tweetwine
19
17
 
@@ -47,7 +45,7 @@ Usage: tweetwine [options...] [command]
47
45
  options[:page_num] = arg
48
46
  end
49
47
  opt.on("-v", "--version", "Show version information and exit") do
50
- puts Meta
48
+ puts "#{File.basename($0)} #{VERSION}"
51
49
  exit(EXIT_VERSION)
52
50
  end
53
51
  opt.on_tail("-h", "--help", "Show this help message and exit") do
@@ -159,12 +159,14 @@ module Tweetwine
159
159
  end
160
160
 
161
161
  def shorten_urls!(status)
162
- url_pairs = URI.extract(status, ["http", "https"]).map do |url_to_be_shortened|
162
+ url_pairs = URI.extract(status, ["http", "https"]).uniq.map do |url_to_be_shortened|
163
163
  [url_to_be_shortened, @url_shortener.shorten(url_to_be_shortened)]
164
164
  end
165
165
  url_pairs.reject { |pair| pair.last.nil? || pair.last.empty? }.each do |url_pair|
166
- status.sub!(url_pair.first, url_pair.last)
166
+ status.gsub!(url_pair.first, url_pair.last)
167
167
  end
168
+ rescue ClientError, LoadError => e
169
+ @io.warn "#{e}. Skipping URL shortening..."
168
170
  end
169
171
  end
170
172
  end
data/lib/tweetwine/io.rb CHANGED
@@ -9,7 +9,8 @@ module Tweetwine
9
9
  :yellow => 33
10
10
  }
11
11
 
12
- NICK_REGEX = /@\w+/
12
+ HASHTAG_REGEX = /#[\w-]+/
13
+ USERNAME_REGEX = /@\w+/
13
14
 
14
15
  def initialize(options)
15
16
  @input = options[:input] || $stdin
@@ -78,9 +79,10 @@ module Tweetwine
78
79
  def format_status(status)
79
80
  status = status.dup
80
81
  if @colorize
81
- colorize_all!(:yellow, status, NICK_REGEX)
82
- URI.extract(status, ["http", "https"]).each do |url|
83
- colorize_first!(:cyan, status, url)
82
+ colorize_all!(:yellow, status, USERNAME_REGEX)
83
+ colorize_all!(:magenta, status, HASHTAG_REGEX)
84
+ URI.extract(status, ["http", "https"]).uniq.each do |url|
85
+ colorize_all!(:cyan, status, url)
84
86
  end
85
87
  end
86
88
  status
@@ -104,10 +106,6 @@ module Tweetwine
104
106
  str.gsub!(pattern) { |s| colorize_str(COLOR_CODES[color.to_sym], s) }
105
107
  end
106
108
 
107
- def colorize_first!(color, str, pattern)
108
- str.sub!(pattern) { |s| colorize_str(COLOR_CODES[color.to_sym], s) }
109
- end
110
-
111
109
  def colorize!(color, str)
112
110
  str.replace colorize_str(COLOR_CODES[color.to_sym], str)
113
111
  end
@@ -1,10 +1,3 @@
1
1
  module Tweetwine
2
- module Meta #:nodoc:
3
- NAME = "Tweetwine"
4
- VERSION = "0.2.1"
5
-
6
- def self.to_s
7
- "#{NAME} #{VERSION}"
8
- end
9
- end
2
+ VERSION = "0.2.2"
10
3
  end
@@ -1,7 +1,8 @@
1
1
  module Tweetwine
2
2
  class Options
3
- def initialize(options)
3
+ def initialize(options, source = nil)
4
4
  @hash = options.to_hash
5
+ @source = source
5
6
  end
6
7
 
7
8
  def [](key)
@@ -10,7 +11,11 @@ module Tweetwine
10
11
 
11
12
  def require(key)
12
13
  value = @hash[key]
13
- raise RuntimeError, "Option #{key} is required" if value.nil?
14
+ if value.nil?
15
+ msg = "Option #{key} is required"
16
+ msg << " for #{@source}" if @source
17
+ raise ArgumentError, msg
18
+ end
14
19
  value
15
20
  end
16
21
  end
@@ -10,7 +10,7 @@ module Tweetwine
10
10
 
11
11
  def self.method_missing(name, *args, &block)
12
12
  RestClient.send(name, *args, &block)
13
- rescue RestClient::Exception, SystemCallError => e
13
+ rescue RestClient::Exception, SocketError, SystemCallError => e
14
14
  raise ClientError, e.message
15
15
  end
16
16
  end
@@ -1,9 +1,8 @@
1
1
  module Tweetwine
2
2
  class UrlShortener
3
3
  def initialize(options)
4
- require "nokogiri"
5
- options = Options.new(options)
6
- @method = options[:method].to_sym || :get
4
+ options = Options.new(options, "URL shortening")
5
+ @method = (options[:method] || :get).to_sym
7
6
  @service_url = options.require :service_url
8
7
  @url_param_name = options.require :url_param_name
9
8
  @extra_params = options[:extra_params] || {}
@@ -16,6 +15,7 @@ module Tweetwine
16
15
  end
17
16
 
18
17
  def shorten(url)
18
+ require "nokogiri"
19
19
  rest = case @method
20
20
  when :get
21
21
  tmp = @extra_params.dup
data/lib/tweetwine.rb CHANGED
@@ -8,5 +8,5 @@
8
8
  url_shortener
9
9
  client
10
10
  }.each do |f|
11
- require File.dirname(__FILE__) << "/tweetwine/#{f}"
11
+ require "tweetwine/#{f}"
12
12
  end
data/test/client_test.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) << "/test_helper"
1
+ require "test_helper"
2
2
  require "json"
3
3
 
4
4
  Mocha::Configuration.allow(:stubbing_non_existent_method)
@@ -12,9 +12,9 @@ class ClientTest < Test::Unit::TestCase
12
12
  end
13
13
 
14
14
  should "raise exception when no authentication data is given" do
15
- assert_raises(ArgumentError) { Client.new(@io, {}) }
16
- assert_raises(ArgumentError) { Client.new(@io, { :password => "bar" }) }
17
- assert_raises(ArgumentError) { Client.new(@io, { :username => "", :password => "bar" }) }
15
+ assert_raise(ArgumentError) { Client.new(@io, {}) }
16
+ assert_raise(ArgumentError) { Client.new(@io, { :password => "bar" }) }
17
+ assert_raise(ArgumentError) { Client.new(@io, { :username => "", :password => "bar" }) }
18
18
  assert_nothing_raised { Client.new(@io, { :username => "foo", :password => "bar" }) }
19
19
  end
20
20
 
@@ -29,7 +29,7 @@ class ClientTest < Test::Unit::TestCase
29
29
  end
30
30
 
31
31
  should "raise an exception for configured number of statuses if not in allowed range" do
32
- assert_raises(ArgumentError) { Client.new(@io, { :username => "foo", :password => "bar", :num_statuses => 0 }) }
32
+ assert_raise(ArgumentError) { Client.new(@io, { :username => "foo", :password => "bar", :num_statuses => 0 }) }
33
33
  end
34
34
 
35
35
  should "use default page number if not configured otherwise" do
@@ -43,7 +43,7 @@ class ClientTest < Test::Unit::TestCase
43
43
  end
44
44
 
45
45
  should "raise an exception for configured page number if not in allowed range" do
46
- assert_raises(ArgumentError) { Client.new(@io, { :username => "foo", :password => "bar", :page_num => 0 }) }
46
+ assert_raise(ArgumentError) { Client.new(@io, { :username => "foo", :password => "bar", :page_num => 0 }) }
47
47
  end
48
48
  end
49
49
 
@@ -343,6 +343,73 @@ class ClientTest < Test::Unit::TestCase
343
343
  @io.expects(:show_record).with(gen_records[0])
344
344
  @client.update(status)
345
345
  end
346
+
347
+ should "reuse a shortened URL for duplicate long URLs" do
348
+ long_urls = ["http://www.w3.org/TR/1999/REC-xpath-19991116"] * 2
349
+ long_status = long_urls.join(" and ")
350
+ short_url = "http://shorten.it/2k7mk"
351
+ short_status = ([short_url] * 2).join(" and ")
352
+ status_records, gen_records = create_test_statuses(
353
+ { :user => @username,
354
+ :status => {
355
+ :created_at => Time.at(1).to_s,
356
+ :text => short_status,
357
+ :in_reply_to => nil
358
+ }
359
+ }
360
+ )
361
+ RestClientWrapper.expects(:post) \
362
+ .with("#{@base_url}/statuses/update.json", {:status => short_status}) \
363
+ .returns(status_records[0].to_json)
364
+ @url_shortener.expects(:shorten).with(long_urls.first).returns(short_url)
365
+ @io.expects(:show_status_preview).with(short_status)
366
+ @io.expects(:confirm).with("Really send?").returns(true)
367
+ @io.expects(:info).with("Sent status update.\n\n")
368
+ @io.expects(:show_record).with(gen_records[0])
369
+ @client.update(long_status)
370
+ end
371
+
372
+ context "in erroneous situations" do
373
+ setup do
374
+ @url = "http://www.w3.org/TR/1999/REC-xpath-19991116"
375
+ @status = "skimming through #{@url}"
376
+ @status_records, @gen_records = create_test_statuses(
377
+ { :user => @username,
378
+ :status => {
379
+ :created_at => Time.at(1).to_s,
380
+ :text => @status,
381
+ :in_reply_to => nil
382
+ }
383
+ }
384
+ )
385
+ end
386
+
387
+ should "skip shortening URLs if required libraries are not found" do
388
+ RestClientWrapper.expects(:post) \
389
+ .with("#{@base_url}/statuses/update.json", {:status => @status}) \
390
+ .returns(@status_records[0].to_json)
391
+ @url_shortener.expects(:shorten).with(@url).raises(LoadError, "gem not found")
392
+ @io.expects(:warn)
393
+ @io.expects(:show_status_preview).with(@status)
394
+ @io.expects(:confirm).with("Really send?").returns(true)
395
+ @io.expects(:info).with("Sent status update.\n\n")
396
+ @io.expects(:show_record).with(@gen_records[0])
397
+ @client.update(@status)
398
+ end
399
+
400
+ should "skip shortening URLs upon connection error to the URL shortening service" do
401
+ RestClientWrapper.expects(:post) \
402
+ .with("#{@base_url}/statuses/update.json", {:status => @status}) \
403
+ .returns(@status_records[0].to_json)
404
+ @url_shortener.expects(:shorten).with(@url).raises(ClientError, "connection error")
405
+ @io.expects(:warn)
406
+ @io.expects(:show_status_preview).with(@status)
407
+ @io.expects(:confirm).with("Really send?").returns(true)
408
+ @io.expects(:info).with("Sent status update.\n\n")
409
+ @io.expects(:show_record).with(@gen_records[0])
410
+ @client.update(@status)
411
+ end
412
+ end
346
413
  end
347
414
  end
348
415
 
data/test/io_test.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) << "/test_helper"
1
+ require "test_helper"
2
2
 
3
3
  module Tweetwine
4
4
 
@@ -9,7 +9,6 @@ class IOTest < Test::Unit::TestCase
9
9
  @output = mock()
10
10
  @io = IO.new({ :input => @input, :output => @output })
11
11
  end
12
-
13
12
  should "output prompt and return input as trimmed" do
14
13
  @output.expects(:print).with("The answer: ")
15
14
  @input.expects(:gets).returns(" 42 ")
@@ -63,7 +62,7 @@ fooman
63
62
  end
64
63
 
65
64
  should "output a record as status info when status is given, without in-reply info" do
66
- status = "Hi, @barman! Lulz woo!"
65
+ status = "Hi, @barman! Lulz woo! #hellos"
67
66
  record = {
68
67
  :user => "fooman",
69
68
  :status => {
@@ -153,14 +152,14 @@ Wondering the meaning of life.
153
152
  :user => "barman",
154
153
  :status => {
155
154
  :created_at => Time.at(1),
156
- :text => "Hi, @fooman! How are you doing?",
155
+ :text => "Hi, @fooman! How are you doing? #hellos",
157
156
  :in_reply_to => "fooman"
158
157
  }
159
158
  }
160
159
  Util.expects(:humanize_time_diff).returns([2, "secs"])
161
160
  @output.expects(:puts).with(<<-END
162
161
  \033[32mbarman\033[0m, in reply to \033[32mfooman\033[0m, 2 secs ago:
163
- Hi, \033[33m@fooman\033[0m! How are you doing?
162
+ Hi, \033[33m@fooman\033[0m! How are you doing? \033[35m#hellos\033[0m
164
163
 
165
164
  END
166
165
  )
@@ -178,7 +177,7 @@ Hi, \033[33m@fooman\033[0m! How are you doing?
178
177
  @io.show_status_preview(status)
179
178
  end
180
179
 
181
- should "highlight HTTP and HTTPS URIs in a status" do
180
+ should "highlight HTTP and HTTPS URLs in a status" do
182
181
  record = {
183
182
  :user => "barman",
184
183
  :status => {
@@ -196,7 +195,25 @@ Three links: \033[36mhttp://bit.ly/18rU_Vx\033[0m \033[36mhttp://is.gd/1qLk3\033
196
195
  @io.show_record(record)
197
196
  end
198
197
 
199
- should "highlight nicks in a status" do
198
+ should "highlight HTTP and HTTPS URLs in a status, even if duplicates" do
199
+ record = {
200
+ :user => "barman",
201
+ :status => {
202
+ :created_at => Time.at(1),
203
+ :text => "Duplicate links: http://is.gd/1qLk3 and http://is.gd/1qLk3",
204
+ }
205
+ }
206
+ Util.expects(:humanize_time_diff).returns([2, "secs"])
207
+ @output.expects(:puts).with(<<-END
208
+ \033[32mbarman\033[0m, 2 secs ago:
209
+ Duplicate links: \033[36mhttp://is.gd/1qLk3\033[0m and \033[36mhttp://is.gd/1qLk3\033[0m
210
+
211
+ END
212
+ )
213
+ @io.show_record(record)
214
+ end
215
+
216
+ should "highlight usernames in a status" do
200
217
  record = {
201
218
  :user => "barman",
202
219
  :status => {
@@ -215,16 +232,35 @@ I salute you \033[33m@fooman\033[0m, \033[33m@barbaz\033[0m, and \033[33m@spoonm
215
232
  end
216
233
  end
217
234
 
218
- context "Nick regex" do
219
- should "match a proper nick reference" do
220
- assert_full_match IO::NICK_REGEX, "@nick"
221
- assert_full_match IO::NICK_REGEX, "@nick_man"
235
+ context "Username regex" do
236
+ should "match a proper username reference" do
237
+ assert_full_match IO::USERNAME_REGEX, "@nick"
238
+ assert_full_match IO::USERNAME_REGEX, "@nick_man"
239
+ end
240
+
241
+ should "not match an inproper username reference" do
242
+ assert_no_full_match IO::USERNAME_REGEX, "@"
243
+ assert_no_full_match IO::USERNAME_REGEX, "nick"
244
+ assert_no_full_match IO::USERNAME_REGEX, "@nick-man"
245
+ assert_no_full_match IO::USERNAME_REGEX, " @nick"
246
+ assert_no_full_match IO::USERNAME_REGEX, "@nick "
247
+ assert_no_full_match IO::USERNAME_REGEX, " @nick "
248
+ end
249
+ end
250
+
251
+ context "Hashtag regex" do
252
+ should "match a proper hashtag reference" do
253
+ assert_full_match IO::HASHTAG_REGEX, "#mayhem"
254
+ assert_full_match IO::HASHTAG_REGEX, "#friday_mayhem"
255
+ assert_full_match IO::HASHTAG_REGEX, "#friday-mayhem"
222
256
  end
223
257
 
224
- should "not match an inproper nick reference" do
225
- assert_no_full_match IO::NICK_REGEX, "@"
226
- assert_no_full_match IO::NICK_REGEX, "nick"
227
- assert_no_full_match IO::NICK_REGEX, "@nick-man"
258
+ should "not match an inproper hashtag reference" do
259
+ assert_no_full_match IO::USERNAME_REGEX, "#"
260
+ assert_no_full_match IO::USERNAME_REGEX, "mayhem"
261
+ assert_no_full_match IO::USERNAME_REGEX, " #mayhem"
262
+ assert_no_full_match IO::USERNAME_REGEX, "#mayhem "
263
+ assert_no_full_match IO::USERNAME_REGEX, " #mayhem "
228
264
  end
229
265
  end
230
266
  end
data/test/options_test.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) << "/test_helper"
1
+ require "test_helper"
2
2
 
3
3
  module Tweetwine
4
4
 
@@ -9,9 +9,33 @@ class OptionsTest < Test::Unit::TestCase
9
9
  assert_equal nil, Options.new({})[:a]
10
10
  end
11
11
 
12
- should "require missing value (a value that is nil)" do
13
- assert_equal "alpha", Options.new({:a => "alpha"}).require(:a)
14
- assert_raises(RuntimeError) { Options.new({}).require(:a) }
12
+ context "for requiring options" do
13
+ should "raise ArgumentError if there's no value for the required option (a value that is nil)" do
14
+ assert_equal "alpha", Options.new({:a => "alpha"}).require(:a)
15
+ assert_raise(ArgumentError) { Options.new({}).require(:a) }
16
+ end
17
+
18
+ should "indicate the required option upon failure" do
19
+ error = nil
20
+ begin
21
+ Options.new({}).require(:a)
22
+ flunk "should have raised ArgumentError"
23
+ rescue ArgumentError => e
24
+ error = e
25
+ end
26
+ assert_equal("Option a is required", e.to_s)
27
+ end
28
+
29
+ should "indicate the required option upon failure, with optional error source" do
30
+ error = nil
31
+ begin
32
+ Options.new({}, "test options").require(:a)
33
+ flunk "should have raised ArgumentError"
34
+ rescue ArgumentError => e
35
+ error = e
36
+ end
37
+ assert_equal("Option a is required for test options", e.to_s)
38
+ end
15
39
  end
16
40
  end
17
41
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) << "/test_helper"
1
+ require "test_helper"
2
2
  require "rest_client"
3
3
 
4
4
  module Tweetwine
@@ -9,14 +9,21 @@ class RestClientWrapperTest < Test::Unit::TestCase
9
9
  RestClient.expects(:get) \
10
10
  .with("https://secret:agent@hushhush.net") \
11
11
  .raises(RestClient::Unauthorized)
12
- assert_raises(ClientError) { RestClientWrapper.get("https://secret:agent@hushhush.net") }
12
+ assert_raise(ClientError) { RestClientWrapper.get("https://secret:agent@hushhush.net") }
13
13
  end
14
14
 
15
15
  should "raise ClientError when connection cannot be established" do
16
16
  RestClient.expects(:get) \
17
17
  .with("http://www.invalid.net") \
18
18
  .raises(Errno::ECONNRESET)
19
- assert_raises(ClientError) { RestClientWrapper.get("http://www.invalid.net") }
19
+ assert_raise(ClientError) { RestClientWrapper.get("http://www.invalid.net") }
20
+ end
21
+
22
+ should "raise ClientError when host cannot be resolved" do
23
+ RestClient.expects(:get) \
24
+ .with("http://unknown.net") \
25
+ .raises(SocketError)
26
+ assert_raise(ClientError) { RestClientWrapper.get("http://unknown.net") }
20
27
  end
21
28
  end
22
29
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) << "/test_helper"
1
+ require "test_helper"
2
2
 
3
3
  module Tweetwine
4
4
 
data/test/test_helper.rb CHANGED
@@ -1,5 +1,4 @@
1
- require "rubygems"
2
- require File.dirname(__FILE__) << "/../lib/tweetwine"
1
+ require "tweetwine"
3
2
  require "test/unit"
4
3
  require "shoulda"
5
4
  require "mocha"
@@ -1,66 +1,126 @@
1
- require File.dirname(__FILE__) << "/test_helper"
1
+ require "test_helper"
2
2
 
3
3
  module Tweetwine
4
4
 
5
5
  class UrlShortenerTest < Test::Unit::TestCase
6
- context "An URL shortener configured for HTTP GET" do
7
- should "use parameters as URL query parameters, with just the URL parameter" do
8
- url_shortener = UrlShortener.new({
9
- :method => "get",
10
- :service_url => "http://shorten.it/create",
11
- :url_param_name => "url",
12
- :xpath_selector => "//input[@id='short_url']/@value"
13
- })
14
- RestClientWrapper.expects(:get) \
15
- .with("http://shorten.it/create?url=http://www.ruby-doc.org/core/")
16
- url_shortener.shorten("http://www.ruby-doc.org/core/")
6
+ context "Upon initialization, an URL shortener" do
7
+ should "raise exception if service URL is not given" do
8
+ assert_raise(ArgumentError) do
9
+ UrlShortener.new({
10
+ :service_url => nil,
11
+ :url_param_name => "url",
12
+ :xpath_selector => "//input[@id='short_url']/@value"
13
+ })
14
+ end
15
+ end
16
+
17
+ should "raise exception if URL parameter name is not given" do
18
+ assert_raise(ArgumentError) do
19
+ UrlShortener.new({
20
+ :service_url => "http://shorten.it/create",
21
+ :url_param_name => nil,
22
+ :xpath_selector => "//input[@id='short_url']/@value"
23
+ })
24
+ end
25
+ end
26
+
27
+ should "raise exception if XPath selector is not given" do
28
+ assert_raise(ArgumentError) do
29
+ UrlShortener.new({
30
+ :service_url => "http://shorten.it/create",
31
+ :url_param_name => "url",
32
+ :xpath_selector => nil
33
+ })
34
+ end
17
35
  end
18
36
 
19
- should "use parameters as URL query parameters, with additional extra parameters" do
37
+ should "fallback to use GET method if not given explicitly" do
20
38
  url_shortener = UrlShortener.new({
21
- :method => "get",
22
39
  :service_url => "http://shorten.it/create",
23
40
  :url_param_name => "url",
24
- :extra_params => {
25
- :token => "xyz"
26
- },
27
41
  :xpath_selector => "//input[@id='short_url']/@value"
28
42
  })
29
- RestClientWrapper.expects(:get) \
30
- .with("http://shorten.it/create?token=xyz&url=http://www.ruby-doc.org/core/")
31
- url_shortener.shorten("http://www.ruby-doc.org/core/")
43
+ assert_equal(:get, url_shortener.instance_variable_get(:@method))
32
44
  end
33
45
  end
34
46
 
35
- context "An URL shortener configured for HTTP POST" do
36
- should "use parameters as payload, with just the URL parameter" do
37
- url_shortener = UrlShortener.new({
38
- :method => "post",
39
- :service_url => "http://shorten.it/create",
40
- :url_param_name => "url",
41
- :xpath_selector => "//input[@id='short_url']/@value"
42
- })
43
- RestClientWrapper.expects(:post) \
44
- .with("http://shorten.it/create", {:url => "http://www.ruby-doc.org/core/"})
45
- url_shortener.shorten("http://www.ruby-doc.org/core/")
47
+ context "At runtime, an URL shortener" do
48
+ context "An URL shortener configured for HTTP GET" do
49
+ should "use parameters as URL query parameters, with just the URL parameter" do
50
+ url_shortener = UrlShortener.new({
51
+ :method => "get",
52
+ :service_url => "http://shorten.it/create",
53
+ :url_param_name => "url",
54
+ :xpath_selector => "//input[@id='short_url']/@value"
55
+ })
56
+ RestClientWrapper.expects(:get) \
57
+ .with("http://shorten.it/create?url=http://www.ruby-doc.org/core/")
58
+ url_shortener.shorten("http://www.ruby-doc.org/core/")
59
+ end
60
+
61
+ should "use parameters as URL query parameters, with additional extra parameters" do
62
+ url_shortener = UrlShortener.new({
63
+ :method => "get",
64
+ :service_url => "http://shorten.it/create",
65
+ :url_param_name => "url",
66
+ :extra_params => {
67
+ :token => "xyz"
68
+ },
69
+ :xpath_selector => "//input[@id='short_url']/@value"
70
+ })
71
+ RestClientWrapper.expects(:get) \
72
+ .with("http://shorten.it/create?token=xyz&url=http://www.ruby-doc.org/core/")
73
+ url_shortener.shorten("http://www.ruby-doc.org/core/")
74
+ end
46
75
  end
47
76
 
48
- should "use parameters as payload, with just the URL parameter" do
49
- url_shortener = UrlShortener.new({
50
- :method => "post",
51
- :service_url => "http://shorten.it/create",
52
- :url_param_name => "url",
53
- :extra_params => {
54
- :token => "xyz"
55
- },
56
- :xpath_selector => "//input[@id='short_url']/@value"
57
- })
58
- RestClientWrapper.expects(:post) \
59
- .with("http://shorten.it/create", {
60
- :token => "xyz",
61
- :url => "http://www.ruby-doc.org/core/"
62
- })
63
- url_shortener.shorten("http://www.ruby-doc.org/core/")
77
+ context "An URL shortener configured for HTTP POST" do
78
+ should "use parameters as payload, with just the URL parameter" do
79
+ url_shortener = UrlShortener.new({
80
+ :method => "post",
81
+ :service_url => "http://shorten.it/create",
82
+ :url_param_name => "url",
83
+ :xpath_selector => "//input[@id='short_url']/@value"
84
+ })
85
+ RestClientWrapper.expects(:post) \
86
+ .with("http://shorten.it/create", {:url => "http://www.ruby-doc.org/core/"})
87
+ url_shortener.shorten("http://www.ruby-doc.org/core/")
88
+ end
89
+
90
+ should "use parameters as payload, with additional extra parameters" do
91
+ url_shortener = UrlShortener.new({
92
+ :method => "post",
93
+ :service_url => "http://shorten.it/create",
94
+ :url_param_name => "url",
95
+ :extra_params => {
96
+ :token => "xyz"
97
+ },
98
+ :xpath_selector => "//input[@id='short_url']/@value"
99
+ })
100
+ RestClientWrapper.expects(:post) \
101
+ .with("http://shorten.it/create", {
102
+ :token => "xyz",
103
+ :url => "http://www.ruby-doc.org/core/"
104
+ })
105
+ url_shortener.shorten("http://www.ruby-doc.org/core/")
106
+ end
107
+ end
108
+
109
+ context "An URL shortener in erroenous situations" do
110
+ should "raise ClientError upon connection error" do
111
+ url_shortener = UrlShortener.new({
112
+ :method => "post",
113
+ :service_url => "http://shorten.it/create",
114
+ :url_param_name => "url",
115
+ :xpath_selector => "//input[@id='short_url']/@value"
116
+ })
117
+ RestClientWrapper.expects(:post) \
118
+ .with("http://shorten.it/create", {
119
+ :url => "http://www.ruby-doc.org/core/"
120
+ }) \
121
+ .raises(ClientError, "connection error")
122
+ assert_raise(ClientError) { url_shortener.shorten("http://www.ruby-doc.org/core/") }
123
+ end
64
124
  end
65
125
  end
66
126
  end
data/test/util_test.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) << "/test_helper"
1
+ require "test_helper"
2
2
  require "time"
3
3
 
4
4
  module Tweetwine
@@ -50,7 +50,7 @@ class UtilTest < Test::Unit::TestCase
50
50
  assert_equal 6, Util.parse_int_gt("6", 8, 4, "ethical working hours per day")
51
51
  assert_equal 8, Util.parse_int_gt(nil, 8, 4, "ethical working hours per day")
52
52
  assert_equal 8, Util.parse_int_gt(false, 8, 4, "ethical working hours per day")
53
- assert_raises(ArgumentError) { Util.parse_int_gt(3, 8, 4, "ethical working hours per day") }
53
+ assert_raise(ArgumentError) { Util.parse_int_gt(3, 8, 4, "ethical working hours per day") }
54
54
  end
55
55
  end
56
56
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tuomas-tweetwine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
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-08-17 00:00:00 -07:00
12
+ date: 2009-09-03 00:00:00 -07:00
13
13
  default_executable: tweetwine
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -29,10 +29,12 @@ executables:
29
29
  extensions: []
30
30
 
31
31
  extra_rdoc_files:
32
+ - MIT-LICENSE.txt
32
33
  - CHANGELOG.rdoc
33
34
  - README.rdoc
34
35
  files:
35
36
  - Rakefile
37
+ - MIT-LICENSE.txt
36
38
  - CHANGELOG.rdoc
37
39
  - README.rdoc
38
40
  - bin/tweetwine
@@ -57,11 +59,10 @@ files:
57
59
  - test/util_test.rb
58
60
  has_rdoc: false
59
61
  homepage: http://github.com/tuomas/tweetwine
60
- licenses:
61
62
  post_install_message:
62
63
  rdoc_options:
63
64
  - --title
64
- - Tweetwine 0.2.1
65
+ - tweetwine 0.2.2
65
66
  - --main
66
67
  - README.rdoc
67
68
  - --exclude
@@ -84,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
85
  requirements: []
85
86
 
86
87
  rubyforge_project:
87
- rubygems_version: 1.3.5
88
+ rubygems_version: 1.2.0
88
89
  signing_key:
89
90
  specification_version: 3
90
91
  summary: A simple Twitter agent for command line use