tweetwine 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -4,3 +4,4 @@
4
4
  /coverage/
5
5
  /man/
6
6
  !/man/*.ronn
7
+ /rdoc/
data/CHANGELOG.rdoc CHANGED
@@ -1,3 +1,8 @@
1
+ === 0.4.1 released 2011-03-23
2
+
3
+ * Handle socket errors just like connection errors
4
+ * Minor cleanups
5
+
1
6
  === 0.4.0 released 2011-02-22
2
7
 
3
8
  * Add option <tt>-r</tt> to reverse the order of showing tweets
File without changes
data/Rakefile CHANGED
@@ -1,51 +1,51 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'rake/clean'
3
+ require File.expand_path('project', File.dirname(__FILE__))
4
4
 
5
- $LOAD_PATH.unshift(File.expand_path('lib', File.dirname(__FILE__)))
6
- name = 'tweetwine'
7
- require "#{name}/version"
8
- version = Tweetwine.version
5
+ require 'rake/clean'
9
6
 
10
7
  namespace :gem do
11
- CLOBBER.include "#{name}-*.gem"
8
+ CLOBBER.include "#{Project.name}-*.gem"
12
9
 
13
- file "#{name}-#{version}.gem" do |f|
14
- sh %{gem build #{name}.gemspec}
10
+ current_gem = "#{Project.name}-#{Project.version}.gem"
11
+
12
+ file current_gem do |f|
13
+ sh %{gem build #{Project.name}.gemspec}
15
14
  end
16
15
 
17
16
  desc "Package the software as a gem"
18
- task :build => [:"man:build", :"test:all", "#{name}-#{version}.gem"]
17
+ task :build => [:"man:build", :"test:all", current_gem]
19
18
 
20
19
  desc "Install the software as a gem"
21
20
  task :install => :build do
22
- sh %{gem install #{name}-#{version}.gem}
21
+ sh %{gem install #{current_gem}}
23
22
  end
24
23
 
25
24
  desc "Uninstall the gem"
26
25
  task :uninstall => :clean do
27
- sh %{gem uninstall #{name}}
26
+ sh %{gem uninstall #{Project.name}}
28
27
  end
29
28
  end
30
29
 
31
30
  namespace :man do
32
- CLOBBER.include "man/#{name}.?", "man/#{name}.?.html"
31
+ CLOBBER.include "#{Project.dirs.man}/#{Project.name}.?", "#{Project.dirs.man}/#{Project.name}.?.html"
33
32
 
34
33
  desc "Build the manual"
35
34
  task :build do
36
- sh "ronn -br5 --manual='#{name.capitalize} Manual' --organization='Tuomas Kareinen' man/*.ronn"
35
+ sh %{ronn -br5 --manual='#{Project.name.capitalize} Manual' --organization='#{Project.authors.first}' #{Project.dirs.man}/*.ronn}
37
36
  end
38
37
 
39
38
  desc "Show the manual section 7"
40
39
  task :show => :build do
41
- sh "man man/#{name}.7"
40
+ sh %{man #{Project.dirs.man}/#{Project.name}.7}
42
41
  end
43
42
  end
44
43
 
45
- CLOBBER.include 'rdoc'
44
+ CLOBBER.include Project.dirs.rdoc
45
+
46
46
  desc "Generate RDoc"
47
47
  task :rdoc do
48
- sh %{rdoc --encoding=UTF-8 --line-numbers --title='#{name} #{version}' --output=rdoc *.rdoc LICENSE.txt lib}
48
+ sh %{rdoc --encoding=UTF-8 --line-numbers --title='#{Project.title}' --output=#{Project.dirs.rdoc} *.rdoc LICENSE.txt lib}
49
49
  end
50
50
 
51
51
  namespace :test do
@@ -53,7 +53,7 @@ namespace :test do
53
53
  base_dir = options[:base_dir]
54
54
  file_glob = options[:file_glob]
55
55
  test_desc = options[:desc] || "Run #{type} tests"
56
- includes = ['lib', 'test', base_dir].map { |dir| "-I #{dir}" }.join(' ')
56
+ includes = ['lib', Project.dirs.test, base_dir].map { |dir| "-I #{dir}" }.join(' ')
57
57
  warn_opt = options[:warn] ? '-w' : ''
58
58
 
59
59
  desc test_desc
@@ -68,11 +68,11 @@ namespace :test do
68
68
  end
69
69
 
70
70
  create_test_task :unit,
71
- :base_dir => 'test/unit',
71
+ :base_dir => "#{Project.dirs.test}/unit",
72
72
  :file_glob => '**/*_test.rb',
73
73
  :warn => true
74
74
  create_test_task :example,
75
- :base_dir => 'test/example',
75
+ :base_dir => "#{Project.dirs.test}/example",
76
76
  :file_glob => '**/*_example.rb',
77
77
  :desc => 'Run integration/example tests',
78
78
  :warn => false
@@ -80,12 +80,10 @@ module Tweetwine
80
80
  response = yield connection, uri
81
81
  raise HttpError.new(response.code, response.message) unless response.is_a? Net::HTTPSuccess
82
82
  response.body
83
- rescue Errno::ECONNABORTED, Errno::ECONNRESET => e
83
+ rescue Errno::ECONNABORTED, Errno::ECONNRESET, SocketError => e
84
84
  raise ConnectionError, e
85
85
  rescue Timeout::Error => e
86
86
  raise TimeoutError, e
87
- rescue Net::HTTPError => e
88
- raise HttpError, e
89
87
  end
90
88
 
91
89
  def https_scheme?(uri)
data/lib/tweetwine/ui.rb CHANGED
@@ -10,6 +10,7 @@ module Tweetwine
10
10
  }.freeze
11
11
  HASHTAG_REGEX = /#[\w-]+/
12
12
  USERNAME_REGEX = /^(@\w+)|\s+(@\w+)/
13
+ URI_SCHEMES_TO_COLORIZE = %w{http https}
13
14
 
14
15
  def initialize(options = {})
15
16
  @in = options[:in] || $stdin
@@ -96,7 +97,7 @@ module Tweetwine
96
97
  if @colors
97
98
  status = colorize_matching(:yellow, status, USERNAME_REGEX)
98
99
  status = colorize_matching(:magenta, status, HASHTAG_REGEX)
99
- status = colorize_matching(:cyan, status, Uri.extract(status, %w{http https}).uniq)
100
+ status = colorize_matching(:cyan, status, Uri.extract(status, URI_SCHEMES_TO_COLORIZE).uniq)
100
101
  end
101
102
  status
102
103
  end
@@ -1,7 +1,7 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module Tweetwine
4
- VERSION = '0.4.0'.freeze
4
+ VERSION = '0.4.1'.freeze
5
5
 
6
6
  class << self
7
7
  def version
data/project.rb ADDED
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+
3
+ require 'ostruct'
4
+
5
+ name = 'tweetwine'
6
+ $LOAD_PATH.unshift File.expand_path('lib', File.dirname(__FILE__))
7
+ require "#{name}/version"
8
+
9
+ Project = OpenStruct.new({
10
+ :name => name,
11
+ :version => Tweetwine.version.dup,
12
+ :summary => Tweetwine.summary,
13
+ :description => '',
14
+ :email => 'tkareine@gmail.com',
15
+ :homepage => 'https://github.com/tkareine/tweetwine',
16
+ :authors => ['Tuomas Kareinen'],
17
+ :dirs => OpenStruct.new({
18
+ :man => 'man',
19
+ :rdoc => 'rdoc',
20
+ :test => 'test'
21
+ }).freeze
22
+ })
23
+
24
+ Project.description = <<-END
25
+ A simple but tasty Twitter agent for command line use, designed for quickly
26
+ showing the latest tweets.
27
+ END
28
+ Project.title = "#{Project.name} #{Project.version}"
29
+
30
+ Project.freeze
@@ -1,6 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
- require "test_helper"
3
+ require "unit_helper"
4
4
 
5
5
  require "fileutils"
6
6
  require "tempfile"
@@ -190,10 +190,7 @@ class ConfigTest < UnitTestCase
190
190
  end
191
191
 
192
192
  should "ignore nonexisting config file for initial read" do
193
- assert_contains_exactly(@default_config.keys, @config.keys) do |a, b|
194
- # On Ruby 1.8, Symbol does not have #<=> operator for comparison.
195
- a.to_s <=> b.to_s
196
- end
193
+ assert_contains_exactly @default_config.keys, @config.keys
197
194
  end
198
195
 
199
196
  should "save config to the file, implicitly without config file, env lookouts, and excludes set itself" do
@@ -79,17 +79,18 @@ class HttpTest < UnitTestCase
79
79
  end
80
80
 
81
81
  [
82
- [Errno::ECONNABORTED, 'abort'],
83
- [Errno::ECONNRESET, 'reset']
84
- ].each do |error, desc|
85
- should "retry connection upon connection #{desc} to #{method} request" do
82
+ [Errno::ECONNABORTED, 'connection abort'],
83
+ [Errno::ECONNRESET, 'connection reset'],
84
+ [SocketError, 'socket error']
85
+ ].each do |(error, desc)|
86
+ should "retry connection upon #{desc} to #{method} request" do
86
87
  stub_request(method, LATEST_ARTICLES_URL).to_raise(error).then.to_return(:body => RESPONSE_BODY)
87
88
  @ui.expects(:warn).with("Could not connect -- retrying in 4 seconds")
88
89
  @client.send(method, LATEST_ARTICLES_URL)
89
90
  assert_equal(RESPONSE_BODY, @client.send(method, LATEST_ARTICLES_URL))
90
91
  end
91
92
 
92
- should "retry connection a maximum of certain number of times upon connection #{desc} to #{method} request" do
93
+ should "retry connection a maximum of certain number of times upon #{desc} to #{method} request" do
93
94
  stub_request(method, LATEST_ARTICLES_URL).to_raise(error)
94
95
  io_calls = sequence("IO")
95
96
  Http::Client::MAX_RETRIES.times { @ui.expects(:warn).in_sequence(io_calls) }
@@ -48,6 +48,8 @@ class PromiseTest < UnitTestCase
48
48
  assert_equal(@result.to_s, @promise.to_s)
49
49
  end
50
50
 
51
+ private
52
+
51
53
  def eval_action
52
54
  @promise * 42 # just do something with it
53
55
  end
@@ -16,28 +16,28 @@ class SupportTest < UnitTestCase
16
16
  ["foo", false, "nonempty string"],
17
17
  [[], true, "empty array"],
18
18
  [%w{a b}, false, "nonempty array"]
19
- ].each do |(subject, emptiness, description)|
20
- should "return #{emptiness} for blank? with #{description}" do
19
+ ].each do |(subject, emptiness, desc)|
20
+ should "return #{emptiness} for blank? with #{desc}" do
21
21
  assert_equal emptiness, blank?(subject)
22
22
  end
23
23
 
24
- should "return #{!emptiness} for present? with #{description}" do
24
+ should "return #{!emptiness} for present? with #{desc}" do
25
25
  assert_equal !emptiness, present?(subject)
26
26
  end
27
27
 
28
- should "return non-empty subject for presence, when subject is #{description}" do
28
+ should "return non-empty subject for presence, when subject is #{desc}" do
29
29
  actual = presence(subject)
30
30
  expected = present?(subject) ? subject : nil
31
31
  assert_same expected, actual
32
32
  end
33
33
 
34
- should "return value of block for presence, when subject is #{description}" do
34
+ should "return value of block for presence, when subject is #{desc}" do
35
35
  actual = presence(subject) { |s| s.size }
36
36
  expected = present?(subject) ? subject.size : nil
37
37
  assert_same expected, actual
38
38
  end
39
39
 
40
- should "allow presence to be used with || operator, when subject is #{description}" do
40
+ should "allow presence to be used with || operator, when subject is #{desc}" do
41
41
  alternative = "hey"
42
42
  actual = presence(subject) || alternative
43
43
  expected = present?(subject) ? subject : alternative
@@ -47,31 +47,66 @@ class SupportTest < UnitTestCase
47
47
  end
48
48
 
49
49
  context "for humanizing time differences" do
50
+ should "accept string and time arguments" do
51
+ start = '2009-01-01 01:01:00'
52
+ stop = Time.parse '2009-01-01 01:03:00'
53
+ assert_commutative([2, 'min'], [start, stop]) do |a, b|
54
+ humanize_time_diff(a, b)
55
+ end
56
+ end
57
+
50
58
  should "use second granularity for time differences smaller than a minute" do
51
- assert_equal [1, "sec"], humanize_time_diff(Time.parse("2009-01-01 00:00:59").to_s, Time.parse("2009-01-01 00:01:00"))
52
- assert_equal [0, "sec"], humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:00"))
53
- assert_equal [1, "sec"], humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:01"))
54
- assert_equal [59, "sec"], humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:59"))
59
+ [
60
+ [0, '2009-01-01 01:00:00', '2009-01-01 01:00:00'],
61
+ [1, '2009-01-01 00:00:59', '2009-01-01 00:01:00'],
62
+ [1, '2009-01-01 01:00:00', '2009-01-01 01:00:01'],
63
+ [59, '2009-01-01 01:00:00', '2009-01-01 01:00:59']
64
+ ].each do |(diff, start, stop)|
65
+ assert_commutative([diff, 'sec'], [start, stop]) do |a, b|
66
+ humanize_time_diff(a, b)
67
+ end
68
+ end
55
69
  end
56
70
 
57
71
  should "use minute granularity for time differences greater than a minute but smaller than an hour" do
58
- assert_equal [59, "min"], humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 01:59"))
59
- assert_equal [59, "min"], humanize_time_diff(Time.parse("2009-01-01 01:00:30").to_s, Time.parse("2009-01-01 01:59:00"))
60
- assert_equal [57, "min"], humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:00"))
61
- assert_equal [56, "min"], humanize_time_diff(Time.parse("2009-01-01 01:01:31").to_s, Time.parse("2009-01-01 01:58:00"))
62
- assert_equal [57, "min"], humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:29"))
63
- assert_equal [58, "min"], humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:30"))
72
+ [
73
+ [1, '2009-01-01 01:00:00', '2009-01-01 01:01:00'],
74
+ [2, '2009-01-01 01:01:00', '2009-01-01 01:03:29'],
75
+ [3, '2009-01-01 01:01:00', '2009-01-01 01:03:30'],
76
+ [59, '2009-01-01 01:00:00', '2009-01-01 01:59:00'],
77
+ [59, '2009-01-01 01:00:30', '2009-01-01 01:59:00'],
78
+ [57, '2009-01-01 01:01:00', '2009-01-01 01:58:00']
79
+ ].each do |(diff, start, stop)|
80
+ assert_commutative([diff, 'min'], [start, stop]) do |a, b|
81
+ humanize_time_diff(a, b)
82
+ end
83
+ end
64
84
  end
65
85
 
66
86
  should "use hour granularity for time differences greater than an hour but smaller than a day" do
67
- assert_equal [1, "hour"], humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 02:00"))
68
- assert_equal [1, "hour"], humanize_time_diff(Time.parse("2009-01-01 02:00").to_s, Time.parse("2009-01-01 01:00"))
69
- assert_equal [2, "hours"], humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 03:00"))
87
+ [
88
+ [1, 'hour', '2009-01-01 01:00', '2009-01-01 02:00'],
89
+ [2, 'hours', '2009-01-01 01:00', '2009-01-01 03:00'],
90
+ [2, 'hours', '2009-01-01 01:00', '2009-01-01 03:29'],
91
+ [3, 'hours', '2009-01-01 01:00', '2009-01-01 03:30']
92
+ ].each do |(diff, unit, start, stop)|
93
+ assert_commutative([diff, unit], [start, stop]) do |a, b|
94
+ humanize_time_diff(a, b)
95
+ end
96
+ end
70
97
  end
71
98
 
72
99
  should "use day granularity for time differences greater than a day" do
73
- assert_equal [1, "day"], humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-02 03:00"))
74
- assert_equal [2, "days"], humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-03 03:00"))
100
+ [
101
+ [1, 'day', '2009-01-01 01:00', '2009-01-02 01:00'],
102
+ [2, 'days', '2009-01-01 01:00', '2009-01-03 01:00'],
103
+ [2, 'days', '2009-01-01 01:00', '2009-01-03 12:59'],
104
+ [3, 'days', '2009-01-01 01:00', '2009-01-03 13:00']
105
+ ].each do |(diff, unit, start, stop)|
106
+ assert_commutative([diff, unit], [start, stop]) do |a, b|
107
+ humanize_time_diff(a, b)
108
+ end
109
+ end
75
110
  end
76
111
  end
77
112
 
@@ -194,7 +229,7 @@ class SupportTest < UnitTestCase
194
229
  %w{- dash},
195
230
  %w{_ underscore},
196
231
  %w{+ plus}
197
- ].each do |char, desc|
232
+ ].each do |(char, desc)|
198
233
  should "not affect already unescaped characters, case #{desc}" do
199
234
  assert_equal char, unescape_html(char)
200
235
  end
@@ -206,7 +241,7 @@ class SupportTest < UnitTestCase
206
241
  %w{&amp; &},
207
242
  %w{&quot; "},
208
243
  %W{&nbsp; \ }
209
- ].each do |input, expected|
244
+ ].each do |(input, expected)|
210
245
  should "unescape HTML-escaped characters, case '#{input}'" do
211
246
  assert_equal expected, unescape_html(input)
212
247
  end
@@ -228,12 +263,12 @@ class SupportTest < UnitTestCase
228
263
  end
229
264
 
230
265
  should "support both a non-array and a single element array path for finding the value" do
231
- assert_equal "beautiful", find_hash_path(@outer_hash, :simple)
232
- assert_equal "beautiful", find_hash_path(@outer_hash, [:simple])
266
+ assert_equal @outer_hash[:simple], find_hash_path(@outer_hash, :simple)
267
+ assert_equal @outer_hash[:simple], find_hash_path(@outer_hash, [:simple])
233
268
  end
234
269
 
235
270
  should "find a nested value with an array path" do
236
- assert_equal "slick", find_hash_path(@outer_hash, [:inner, :salmon])
271
+ assert_equal @inner_hash[:salmon], find_hash_path(@outer_hash, [:inner, :salmon])
237
272
  end
238
273
 
239
274
  should "return the default value of the hash if the value cannot be found" do
@@ -243,15 +278,19 @@ class SupportTest < UnitTestCase
243
278
  end
244
279
 
245
280
  should "return the default value of the hash if invalid path value" do
246
- assert_equal @outer_hash.default, find_hash_path(@outer_hash, nil)
247
- assert_equal @outer_hash.default, find_hash_path(@outer_hash, [:no_such, nil])
248
- assert_equal @outer_hash.default, find_hash_path(@outer_hash, [:simple, nil])
249
- assert_equal @outer_hash.default, find_hash_path(@outer_hash, [:inner, nil])
250
- assert_equal @outer_hash.default, find_hash_path(@outer_hash, [:inner, :salmon, nil])
281
+ [
282
+ nil,
283
+ [:no_such, nil],
284
+ [:simple, nil],
285
+ [:inner, nil],
286
+ [:inner, :salmon, nil]
287
+ ].each do |path|
288
+ assert_equal @outer_hash.default, find_hash_path(@outer_hash, path)
289
+ end
251
290
  end
252
291
 
253
292
  should "return nil if nil hash value" do
254
- assert_equal nil, find_hash_path(nil, nil)
293
+ assert_equal nil, find_hash_path(nil, [:salmon])
255
294
  end
256
295
  end
257
296
  end
@@ -1,5 +1,7 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'timecop'
4
+
3
5
  module Tweetwine::Test
4
6
  module TweetHelper
5
7
  FIELD_PATHS = {
@@ -10,11 +12,13 @@ module Tweetwine::Test
10
12
  :status => %w{status text}
11
13
  }.freeze
12
14
 
15
+ DEFAULT_TIMESTAMP = Time.utc(2011, 'feb', 17, 22, 28, 0)
16
+
13
17
  DEFAULT_FIELD_VALUES = {
14
18
  :from_user => 'fred',
15
19
  :to_user => nil,
16
20
  :retweet => nil,
17
- :created_at => Time.utc(2011, 'feb', 17, 22, 28, 0).iso8601,
21
+ :created_at => DEFAULT_TIMESTAMP.iso8601,
18
22
  :status => nil
19
23
  }.freeze
20
24
 
@@ -38,6 +42,14 @@ module Tweetwine::Test
38
42
  Tweetwine::Tweet.new(create_record(fields), FIELD_PATHS)
39
43
  end
40
44
 
45
+ def at_default_time(&block)
46
+ Timecop.freeze(TweetHelper::DEFAULT_TIMESTAMP, &block)
47
+ end
48
+
49
+ def create_timestamp(minus_seconds)
50
+ (TweetHelper::DEFAULT_TIMESTAMP - minus_seconds).iso8601
51
+ end
52
+
41
53
  private
42
54
 
43
55
  def find_hash_of_field_path(hash, path)
@@ -14,7 +14,7 @@ class TweetTest < UnitTestCase
14
14
  end
15
15
  end
16
16
 
17
- context "for equivalence" do
17
+ context "for equality" do
18
18
  should "equal to another tweet with same content" do
19
19
  status = 'foo'
20
20
  first = create_tweet(:status => status)
data/test/unit/ui_test.rb CHANGED
@@ -86,18 +86,19 @@ class UITest < UnitTestCase
86
86
  should "output regular tweet" do
87
87
  from_user = "fooman"
88
88
  status = "Hi, @barman! Lulz woo! #hellos"
89
+ time = 2
89
90
  tweet = create_tweet(
90
91
  :from_user => from_user,
91
- :status => status
92
+ :status => status,
93
+ :created_at => create_timestamp(time)
92
94
  )
93
- Support.expects(:humanize_time_diff).returns([2, "secs"])
94
95
  @out.expects(:puts).with(<<-END
95
- #{from_user}, 2 secs ago:
96
+ #{from_user}, #{time} sec ago:
96
97
  #{status}
97
98
 
98
99
  END
99
100
  )
100
- @ui.show_tweet(tweet)
101
+ show_tweet_at_default_time(tweet)
101
102
  end
102
103
 
103
104
  should "output replying tweet" do
@@ -109,14 +110,13 @@ class UITest < UnitTestCase
109
110
  :status => status,
110
111
  :to_user => to_user
111
112
  )
112
- Support.expects(:humanize_time_diff).returns([2, "secs"])
113
113
  @out.expects(:puts).with(<<-END
114
- #{from_user}, in reply to #{to_user}, 2 secs ago:
114
+ #{from_user}, in reply to #{to_user}, 0 sec ago:
115
115
  #{status}
116
116
 
117
117
  END
118
118
  )
119
- @ui.show_tweet(tweet)
119
+ show_tweet_at_default_time(tweet)
120
120
  end
121
121
 
122
122
  should "output regular retweet" do
@@ -128,14 +128,13 @@ class UITest < UnitTestCase
128
128
  :status => status,
129
129
  :rt_user => rt_user
130
130
  )
131
- Support.expects(:humanize_time_diff).returns([2, "secs"])
132
131
  @out.expects(:puts).with(<<-END
133
- #{rt_user} RT #{from_user}, 2 secs ago:
132
+ #{rt_user} RT #{from_user}, 0 sec ago:
134
133
  #{status}
135
134
 
136
135
  END
137
136
  )
138
- @ui.show_tweet(tweet)
137
+ show_tweet_at_default_time(tweet)
139
138
  end
140
139
 
141
140
  should "output replying retweet" do
@@ -149,14 +148,13 @@ class UITest < UnitTestCase
149
148
  :status => status,
150
149
  :rt_user => rt_user
151
150
  )
152
- Support.expects(:humanize_time_diff).returns([2, "secs"])
153
151
  @out.expects(:puts).with(<<-END
154
- #{rt_user} RT #{from_user}, in reply to #{to_user}, 2 secs ago:
152
+ #{rt_user} RT #{from_user}, in reply to #{to_user}, 0 sec ago:
155
153
  #{status}
156
154
 
157
155
  END
158
156
  )
159
- @ui.show_tweet(tweet)
157
+ show_tweet_at_default_time(tweet)
160
158
  end
161
159
 
162
160
  should "unescape HTML in a status" do
@@ -167,14 +165,13 @@ class UITest < UnitTestCase
167
165
  :from_user => from_user,
168
166
  :status => escaped_status
169
167
  )
170
- Support.expects(:humanize_time_diff).returns([2, "secs"])
171
168
  @out.expects(:puts).with(<<-END
172
- #{from_user}, 2 secs ago:
169
+ #{from_user}, 0 sec ago:
173
170
  #{unescaped_status}
174
171
 
175
172
  END
176
173
  )
177
- @ui.show_tweet(tweet)
174
+ show_tweet_at_default_time(tweet)
178
175
  end
179
176
 
180
177
  should "output a preview of a status" do
@@ -212,14 +209,13 @@ class UITest < UnitTestCase
212
209
  :from_user => from_user,
213
210
  :status => status
214
211
  )
215
- Support.expects(:humanize_time_diff).returns([2, "secs"])
216
212
  @out.expects(:puts).with(<<-END
217
- \e[32m#{from_user}\e[0m, 2 secs ago:
213
+ \e[32m#{from_user}\e[0m, 0 sec ago:
218
214
  #{status}
219
215
 
220
216
  END
221
217
  )
222
- @ui.show_tweet(tweet)
218
+ show_tweet_at_default_time(tweet)
223
219
  end
224
220
 
225
221
  should "output replying tweet" do
@@ -230,14 +226,13 @@ class UITest < UnitTestCase
230
226
  :status => "@#{to_user}! How are you doing?",
231
227
  :to_user => to_user
232
228
  )
233
- Support.expects(:humanize_time_diff).returns([2, "secs"])
234
229
  @out.expects(:puts).with(<<-END
235
- \e[32m#{from_user}\e[0m, in reply to \e[32m#{to_user}\e[0m, 2 secs ago:
230
+ \e[32m#{from_user}\e[0m, in reply to \e[32m#{to_user}\e[0m, 0 sec ago:
236
231
  \e[33m@#{to_user}\e[0m! How are you doing?
237
232
 
238
233
  END
239
234
  )
240
- @ui.show_tweet(tweet)
235
+ show_tweet_at_default_time(tweet)
241
236
  end
242
237
 
243
238
  should "output regular retweet" do
@@ -249,14 +244,13 @@ class UITest < UnitTestCase
249
244
  :status => status,
250
245
  :rt_user => rt_user
251
246
  )
252
- Support.expects(:humanize_time_diff).returns([2, "secs"])
253
247
  @out.expects(:puts).with(<<-END
254
- \e[32m#{rt_user}\e[0m RT \e[32m#{from_user}\e[0m, 2 secs ago:
248
+ \e[32m#{rt_user}\e[0m RT \e[32m#{from_user}\e[0m, 0 sec ago:
255
249
  #{status}
256
250
 
257
251
  END
258
252
  )
259
- @ui.show_tweet(tweet)
253
+ show_tweet_at_default_time(tweet)
260
254
  end
261
255
 
262
256
  should "output replying retweet" do
@@ -269,14 +263,13 @@ class UITest < UnitTestCase
269
263
  :status => "@#{to_user}, reply worth retweeting",
270
264
  :rt_user => rt_user
271
265
  )
272
- Support.expects(:humanize_time_diff).returns([2, "secs"])
273
266
  @out.expects(:puts).with(<<-END
274
- \e[32m#{rt_user}\e[0m RT \e[32m#{from_user}\e[0m, in reply to \e[32m#{to_user}\e[0m, 2 secs ago:
267
+ \e[32m#{rt_user}\e[0m RT \e[32m#{from_user}\e[0m, in reply to \e[32m#{to_user}\e[0m, 0 sec ago:
275
268
  \e[33m@#{to_user}\e[0m, reply worth retweeting
276
269
 
277
270
  END
278
271
  )
279
- @ui.show_tweet(tweet)
272
+ show_tweet_at_default_time(tweet)
280
273
  end
281
274
 
282
275
  should "output a preview of a status" do
@@ -297,14 +290,13 @@ class UITest < UnitTestCase
297
290
  :from_user => from_user,
298
291
  :status => "Lulz, so happy! #{hashtags[0]} #{hashtags[1]}"
299
292
  )
300
- Support.expects(:humanize_time_diff).returns([2, "secs"])
301
293
  @out.expects(:puts).with(<<-END
302
- \e[32m#{from_user}\e[0m, 2 secs ago:
294
+ \e[32m#{from_user}\e[0m, 0 sec ago:
303
295
  Lulz, so happy! \e[35m#{hashtags[0]}\e[0m \e[35m#{hashtags[1]}\e[0m
304
296
 
305
297
  END
306
298
  )
307
- @ui.show_tweet(tweet)
299
+ show_tweet_at_default_time(tweet)
308
300
  end
309
301
 
310
302
  %w{http://is.gd/1qLk3 http://is.gd/1qLk3?id=foo}.each do |url|
@@ -314,14 +306,13 @@ Lulz, so happy! \e[35m#{hashtags[0]}\e[0m \e[35m#{hashtags[1]}\e[0m
314
306
  :from_user => from_user,
315
307
  :status => "New Rails³ - #{url}"
316
308
  )
317
- Support.expects(:humanize_time_diff).returns([2, "secs"])
318
309
  @out.expects(:puts).with(<<-END
319
- \e[32m#{from_user}\e[0m, 2 secs ago:
310
+ \e[32m#{from_user}\e[0m, 0 sec ago:
320
311
  New Rails³ - \e[36m#{url}\e[0m
321
312
 
322
313
  END
323
314
  )
324
- @ui.show_tweet(tweet)
315
+ show_tweet_at_default_time(tweet)
325
316
  end
326
317
  end
327
318
 
@@ -335,14 +326,13 @@ New Rails³ - \e[36m#{url}\e[0m
335
326
  :from_user => from_user,
336
327
  :status => "Links: #{first_url} and #{second_url} np"
337
328
  )
338
- Support.expects(:humanize_time_diff).returns([2, "secs"])
339
329
  @out.expects(:puts).with(<<-END
340
- \e[32m#{from_user}\e[0m, 2 secs ago:
330
+ \e[32m#{from_user}\e[0m, 0 sec ago:
341
331
  Links: \e[36m#{first_url}\e[0m and \e[36m#{second_url}\e[0m np
342
332
 
343
333
  END
344
334
  )
345
- @ui.show_tweet(tweet)
335
+ show_tweet_at_default_time(tweet)
346
336
  end
347
337
  end
348
338
 
@@ -353,14 +343,13 @@ Links: \e[36m#{first_url}\e[0m and \e[36m#{second_url}\e[0m np
353
343
  :from_user => from_user,
354
344
  :status => "I salute you #{users[0]}, #{users[1]}, and #{users[2]}!"
355
345
  )
356
- Support.expects(:humanize_time_diff).returns([2, "secs"])
357
346
  @out.expects(:puts).with(<<-END
358
- \e[32m#{from_user}\e[0m, 2 secs ago:
347
+ \e[32m#{from_user}\e[0m, 0 sec ago:
359
348
  I salute you \e[33m#{users[0]}\e[0m, \e[33m#{users[1]}\e[0m, and \e[33m#{users[2]}\e[0m!
360
349
 
361
350
  END
362
351
  )
363
- @ui.show_tweet(tweet)
352
+ show_tweet_at_default_time(tweet)
364
353
  end
365
354
 
366
355
  should "not highlight email addresses as usernames in a status" do
@@ -371,86 +360,118 @@ I salute you \e[33m#{users[0]}\e[0m, \e[33m#{users[1]}\e[0m, and \e[33m#{users[2
371
360
  :from_user => from_user,
372
361
  :status => "Hi, #{users[0]}! You should notify #{users[1]}, #{email}"
373
362
  )
374
- Support.expects(:humanize_time_diff).returns([2, "secs"])
375
363
  @out.expects(:puts).with(<<-END
376
- \e[32m#{from_user}\e[0m, 2 secs ago:
364
+ \e[32m#{from_user}\e[0m, 0 sec ago:
377
365
  Hi, \e[33m#{users[0]}\e[0m! You should notify \e[33m#{users[1]}\e[0m, #{email}
378
366
 
379
367
  END
380
368
  )
381
- @ui.show_tweet(tweet)
369
+ show_tweet_at_default_time(tweet)
382
370
  end
383
371
  end
384
372
 
385
373
  context "for outputting a collection of tweets" do
386
374
  setup do
387
- @users = %w{first_user second_user}
388
- statuses = @users.map { |from| "Hi, I'm #{from}." }
389
- @users_and_statuses = @users.zip statuses
390
- @outputs = @users_and_statuses.map { |(user, status)| <<-END
391
- #{user}, 2 secs ago:
375
+ users_and_times = [
376
+ ['first', 11],
377
+ ['second', 12],
378
+ ['third', 13]
379
+ ]
380
+ statuses = users_and_times.map { |(user, _)| "Hi, I'm #{user}." }
381
+ users_and_statuses = users_and_times.zip(statuses)
382
+ @outputs = Hash[users_and_statuses.map { |(user, time), status|
383
+ output = <<-END
384
+ #{user}, #{time} sec ago:
392
385
  #{status}
393
386
 
394
- END
395
- }
396
- @tweets = @users_and_statuses.map { |(user, status)| create_tweet(
397
- :from_user => user,
398
- :status => status
387
+ END
388
+ [user.to_sym, output]
389
+ }]
390
+ @tweets = users_and_statuses.map { |(user, time), status| create_tweet(
391
+ :from_user => user,
392
+ :status => status,
393
+ :created_at => create_timestamp(time)
399
394
  )}
400
- Support.expects(:humanize_time_diff).twice.returns([2, "secs"])
401
395
  end
402
396
 
403
- should "output tweets in descending order" do
404
- ui = UI.new({ :out => @out, :show_reverse => false })
405
- @out.expects(:puts).with(@outputs[0])
406
- @out.expects(:puts).with(@outputs[1])
407
- ui.show_tweets(@tweets)
397
+ should "output tweets in normal order" do
398
+ @ui = UI.new({ :out => @out, :show_reverse => false })
399
+ [:first, :second, :third].each do |user|
400
+ @out.expects(:puts).with(@outputs[user])
401
+ end
402
+ show_tweets_at_default_time(@tweets)
408
403
  end
409
404
 
410
- should "output tweets in ascending order" do
411
- ui = UI.new({ :out => @out, :show_reverse => true })
412
- @out.expects(:puts).with(@outputs[1])
413
- @out.expects(:puts).with(@outputs[0])
414
- ui.show_tweets(@tweets)
405
+ should "output tweets in reverse order" do
406
+ @ui = UI.new({ :out => @out, :show_reverse => true })
407
+ [:third, :second, :first].each do |user|
408
+ @out.expects(:puts).with(@outputs[user])
409
+ end
410
+ show_tweets_at_default_time(@tweets)
415
411
  end
416
412
  end
417
413
  end
418
414
 
419
415
  context "username regex" do
420
- should "match a proper username reference" do
421
- assert_full_match UI::USERNAME_REGEX, "@nick"
422
- assert_full_match UI::USERNAME_REGEX, "@nick_man"
423
- assert_full_match UI::USERNAME_REGEX, "@nick"
424
- assert_full_match UI::USERNAME_REGEX, " @nick"
416
+ [
417
+ ['@nick', 'normal'],
418
+ ['@nick_man', 'underscore separated'],
419
+ [' @nick', 'beginning with space']
420
+ ].each do |(nick, desc)|
421
+ should "match proper username reference, case #{desc}" do
422
+ assert_full_match UI::USERNAME_REGEX, nick
423
+ end
425
424
  end
426
425
 
427
- should "not match an inproper username reference" do
428
- assert_no_full_match UI::USERNAME_REGEX, "@"
429
- assert_no_full_match UI::USERNAME_REGEX, "nick"
430
- assert_no_full_match UI::USERNAME_REGEX, "-@nick"
431
- assert_no_full_match UI::USERNAME_REGEX, "@nick-man"
432
- assert_no_full_match UI::USERNAME_REGEX, "@nick "
433
- assert_no_full_match UI::USERNAME_REGEX, " @nick "
434
- assert_no_full_match UI::USERNAME_REGEX, "man @nick"
435
- assert_no_full_match UI::USERNAME_REGEX, "man@nick"
426
+ [
427
+ ['@', 'just prefix'],
428
+ ['nick', 'just body'],
429
+ ['-@nick', 'beginning with dash'],
430
+ ['@nick-man', 'dash separated'],
431
+ ['@nick ', 'ending with space'],
432
+ [' @nick ', 'surrounded with space'],
433
+ ['man @nick', 'space separated'],
434
+ ['man@nick', 'prefix in between']
435
+ ].each do |(no_nick, desc)|
436
+ should "not match an inproper username reference, case #{desc}" do
437
+ assert_no_full_match UI::USERNAME_REGEX, no_nick
438
+ end
436
439
  end
437
440
  end
438
441
 
439
442
  context "hashtag regex" do
440
- should "match a proper hashtag reference" do
441
- assert_full_match UI::HASHTAG_REGEX, "#mayhem"
442
- assert_full_match UI::HASHTAG_REGEX, "#friday_mayhem"
443
- assert_full_match UI::HASHTAG_REGEX, "#friday-mayhem"
443
+ [
444
+ ['#mayhem', 'normal'],
445
+ ['#friday_mayhem', 'underscore separated'],
446
+ ['#friday-mayhem', 'dash separated']
447
+ ].each do |(hashtag, desc)|
448
+ should "match a proper hashtag reference, case #{desc}" do
449
+ assert_full_match UI::HASHTAG_REGEX, hashtag
450
+ end
444
451
  end
445
452
 
446
- should "not match an inproper hashtag reference" do
447
- assert_no_full_match UI::USERNAME_REGEX, "#"
448
- assert_no_full_match UI::USERNAME_REGEX, "mayhem"
449
- assert_no_full_match UI::USERNAME_REGEX, " #mayhem"
450
- assert_no_full_match UI::USERNAME_REGEX, "#mayhem "
451
- assert_no_full_match UI::USERNAME_REGEX, " #mayhem "
453
+ [
454
+ ['#', 'just prefix'],
455
+ ['mayhem', 'just body'],
456
+ [' #mayhem', 'beginning with space'],
457
+ ['#mayhem ', 'ending with space'],
458
+ [' #mayhem ', 'surrounded with space']
459
+ ].each do |(no_hashtag, desc)|
460
+ should "not match an inproper hashtag reference, case #{desc}" do
461
+ assert_no_full_match UI::HASHTAG_REGEX, no_hashtag
462
+ end
452
463
  end
453
464
  end
465
+
466
+ private
467
+
468
+ def show_tweet_at_default_time(tweet)
469
+ at_default_time { @ui.show_tweet(tweet) }
470
+ end
471
+
472
+ def show_tweets_at_default_time(tweets)
473
+ at_default_time { @ui.show_tweets(tweets) }
474
+ end
454
475
  end
455
476
 
456
477
  end
@@ -9,42 +9,64 @@ Mocha::Configuration.prevent(:stubbing_non_existent_method)
9
9
 
10
10
  module Tweetwine::Test
11
11
  module Assertions
12
- # Asserts whether an Enumeration like object contains all the elements.
12
+ # Asserts whether an Enumeration-like object contains all the elements.
13
13
  # Fails unless +actual+ contains the same elements as +expected+, ignoring
14
14
  # the order of the elements.
15
- #
16
- # The method sorts +expected+ and +actual+ in order to compare them. By
17
- # default, this sorting is done by calling #sort for each of them. If the
18
- # method is called with a block, it is passed to the #sort calls.
19
- def assert_contains_exactly(expected, actual, msg = nil, &sorter)
20
- expected = block_given? ? expected.sort(&sorter) : expected.sort
21
- actual = block_given? ? actual.sort(&sorter) : actual.sort
22
- assert_equal(expected, actual, get_message(msg) {
23
- 'after sorting, collection %s is not equal to %s' % [expected.inspect, actual.inspect]
15
+ def assert_contains_exactly(expected, actual, msg_diff_size = nil, msg_diff_elems = nil)
16
+ assert_equal(expected.size, actual.size, message(msg_diff_size) {
17
+ 'Expected %s to be of same size as %s' % [actual.inspect, expected.inspect]
18
+ })
19
+ assert(enumerable_minus_each_element(actual, expected).empty?, message(msg_diff_elems) {
20
+ 'Expected %s to contain all the elements of %s' % [actual.inspect, expected.inspect]
24
21
  })
25
22
  end
26
23
 
27
24
  # Fails unless +str+ is a full match to +regex+.
28
25
  def assert_full_match(regex, str, msg = nil)
29
26
  match_data = regex.match(str)
30
- assert(str == match_data.to_s, get_message(msg) {
31
- '%s is not a full match to %s' % [str, regex.inspect]
27
+ assert(str == match_data.to_s, message(msg) {
28
+ 'Expected %s to be a full match to %s' % [str, regex.inspect]
32
29
  })
33
30
  end
34
31
 
35
32
  # Fails if +str+ is a full match to +regex+.
36
33
  def assert_no_full_match(regex, str, msg = nil)
37
34
  match_data = regex.match(str)
38
- assert(str != match_data.to_s, get_message(msg) {
39
- '%s is a full match to %s' % [str, regex.inspect]
35
+ assert(str != match_data.to_s, message(msg) {
36
+ 'Expected %s not to be a full match to %s' % [str, regex.inspect]
37
+ })
38
+ end
39
+
40
+ # Fails unless +fun.call(*args)+ is equal to +expected+ and
41
+ # +fun.call(*args)+ is equal to +fun.call(*args.reverse)+.
42
+ def assert_commutative(expected, args, msg_not_expected = nil, msg_not_commutative = nil, &fun)
43
+ left_args = args
44
+ left_actual = fun.call(left_args)
45
+ assert_equal(expected, left_actual, message(msg_not_expected) {
46
+ 'Expected %s, not %s' % [expected.inspect, left_actual.inspect]
47
+ })
48
+ right_args = args.reverse
49
+ right_actual = fun.call(*right_args)
50
+ assert_equal(left_actual, right_actual, message(msg_not_commutative) {
51
+ 'Expected fun%s => %s to be commutative with fun%s => %s' %
52
+ [left_args.inspect, left_actual.inspect, right_args.inspect, right_actual.inspect]
40
53
  })
41
54
  end
42
55
 
43
56
  private
44
57
 
45
- def get_message(given, &default)
58
+ def message(given, &default)
46
59
  given.nil? ? default.call : given
47
60
  end
61
+
62
+ def enumerable_minus_each_element(enumerable, elements)
63
+ remaining = enumerable.dup.to_a
64
+ elements.each do |e|
65
+ index = remaining.index(e)
66
+ remaining.delete_at(index) if index
67
+ end
68
+ remaining
69
+ end
48
70
  end
49
71
 
50
72
  module Doubles
@@ -13,7 +13,7 @@ class UriTest < UnitTestCase
13
13
  %w{. period},
14
14
  %w{- dash},
15
15
  %w{_ underscore},
16
- ].each do |char, desc|
16
+ ].each do |(char, desc)|
17
17
  should "not encode safe characters, case #{desc}" do
18
18
  assert_equal char, Uri.percent_encode(char)
19
19
  end
@@ -29,7 +29,7 @@ class UriTest < UnitTestCase
29
29
  %w{/ %2F slash},
30
30
  %w{: %3A colon},
31
31
  %w{, %2C comma}
32
- ].each do |char, expected, desc|
32
+ ].each do |(char, expected, desc)|
33
33
  should "encode unsafe characters that URI.encode leaves by default unencoded, case #{desc}" do
34
34
  assert_equal char, Uri.parser.escape(char)
35
35
  assert_equal expected, Uri.percent_encode(char)
data/tweetwine.gemspec CHANGED
@@ -1,27 +1,18 @@
1
1
  # coding: utf-8
2
2
 
3
- $LOAD_PATH.unshift(File.expand_path('lib', File.dirname(__FILE__)))
4
- name = 'tweetwine'
5
- require "#{name}/version"
6
- version = Tweetwine.version
3
+ require File.expand_path('project', File.dirname(__FILE__))
7
4
 
8
5
  Gem::Specification.new do |s|
9
- s.name = name
10
- s.version = version.dup
11
-
12
- s.summary = Tweetwine.summary
13
- s.description = <<-END
14
- A simple but tasty Twitter agent for command line use, designed for quickly
15
- showing the latest tweets.
16
- END
17
-
18
- s.email = 'tkareine@gmail.com'
19
- s.homepage = 'https://github.com/tkareine/tweetwine'
20
-
21
- s.authors = ['Tuomas Kareinen']
22
-
23
- s.files = `git ls-files`.split("\n") + Dir['man/**/*.[1-9]']
24
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
6
+ s.name = Project.name
7
+ s.version = Project.version
8
+ s.summary = Project.summary
9
+ s.description = Project.description
10
+ s.email = Project.email
11
+ s.homepage = Project.homepage
12
+ s.authors = Project.authors
13
+
14
+ s.files = `git ls-files`.split("\n") + Dir["#{Project.dirs.man}/**/*.[1-9]"]
15
+ s.test_files = `git ls-files -- #{Project.dirs.test}/*`.split("\n")
25
16
  s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
26
17
 
27
18
  s.add_dependency 'oauth', '~> 0.4.4'
@@ -45,6 +36,5 @@ default. For Ruby 1.8, you can install 'json' gem, for example.
45
36
 
46
37
  s.has_rdoc = true
47
38
  s.extra_rdoc_files = Dir['*.rdoc', 'LICENSE.txt']
48
- s.rdoc_options << '--title' << "#{name} #{version}" \
49
- << '--exclude' << 'test'
39
+ s.rdoc_options << '--title' << Project.title << '--exclude' << Project.dirs.test
50
40
  end
metadata CHANGED
@@ -1,8 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tweetwine
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 13
4
5
  prerelease:
5
- version: 0.4.0
6
+ segments:
7
+ - 0
8
+ - 4
9
+ - 1
10
+ version: 0.4.1
6
11
  platform: ruby
7
12
  authors:
8
13
  - Tuomas Kareinen
@@ -10,7 +15,7 @@ autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
17
 
13
- date: 2011-02-22 00:00:00 +02:00
18
+ date: 2011-03-23 00:00:00 +02:00
14
19
  default_executable:
15
20
  dependencies:
16
21
  - !ruby/object:Gem::Dependency
@@ -21,6 +26,11 @@ dependencies:
21
26
  requirements:
22
27
  - - ~>
23
28
  - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 0
32
+ - 4
33
+ - 4
24
34
  version: 0.4.4
25
35
  type: :runtime
26
36
  version_requirements: *id001
@@ -32,6 +42,11 @@ dependencies:
32
42
  requirements:
33
43
  - - ~>
34
44
  - !ruby/object:Gem::Version
45
+ hash: 31
46
+ segments:
47
+ - 0
48
+ - 1
49
+ - 2
35
50
  version: 0.1.2
36
51
  type: :development
37
52
  version_requirements: *id002
@@ -43,6 +58,11 @@ dependencies:
43
58
  requirements:
44
59
  - - ~>
45
60
  - !ruby/object:Gem::Version
61
+ hash: 1
62
+ segments:
63
+ - 0
64
+ - 6
65
+ - 3
46
66
  version: 0.6.3
47
67
  type: :development
48
68
  version_requirements: *id003
@@ -54,6 +74,11 @@ dependencies:
54
74
  requirements:
55
75
  - - ~>
56
76
  - !ruby/object:Gem::Version
77
+ hash: 23
78
+ segments:
79
+ - 0
80
+ - 2
81
+ - 0
57
82
  version: 0.2.0
58
83
  type: :development
59
84
  version_requirements: *id004
@@ -65,6 +90,11 @@ dependencies:
65
90
  requirements:
66
91
  - - ~>
67
92
  - !ruby/object:Gem::Version
93
+ hash: 15
94
+ segments:
95
+ - 0
96
+ - 5
97
+ - 2
68
98
  version: 0.5.2
69
99
  type: :development
70
100
  version_requirements: *id005
@@ -76,6 +106,11 @@ dependencies:
76
106
  requirements:
77
107
  - - ~>
78
108
  - !ruby/object:Gem::Version
109
+ hash: 35
110
+ segments:
111
+ - 0
112
+ - 9
113
+ - 12
79
114
  version: 0.9.12
80
115
  type: :development
81
116
  version_requirements: *id006
@@ -87,6 +122,11 @@ dependencies:
87
122
  requirements:
88
123
  - - ~>
89
124
  - !ruby/object:Gem::Version
125
+ hash: 21
126
+ segments:
127
+ - 1
128
+ - 0
129
+ - 1
90
130
  version: 1.0.1
91
131
  type: :development
92
132
  version_requirements: *id007
@@ -98,6 +138,11 @@ dependencies:
98
138
  requirements:
99
139
  - - ~>
100
140
  - !ruby/object:Gem::Version
141
+ hash: 49
142
+ segments:
143
+ - 0
144
+ - 8
145
+ - 7
101
146
  version: 0.8.7
102
147
  type: :development
103
148
  version_requirements: *id008
@@ -109,6 +154,11 @@ dependencies:
109
154
  requirements:
110
155
  - - ~>
111
156
  - !ruby/object:Gem::Version
157
+ hash: 5
158
+ segments:
159
+ - 0
160
+ - 7
161
+ - 3
112
162
  version: 0.7.3
113
163
  type: :development
114
164
  version_requirements: *id009
@@ -120,6 +170,11 @@ dependencies:
120
170
  requirements:
121
171
  - - ~>
122
172
  - !ruby/object:Gem::Version
173
+ hash: 25
174
+ segments:
175
+ - 0
176
+ - 3
177
+ - 5
123
178
  version: 0.3.5
124
179
  type: :development
125
180
  version_requirements: *id010
@@ -131,6 +186,11 @@ dependencies:
131
186
  requirements:
132
187
  - - ~>
133
188
  - !ruby/object:Gem::Version
189
+ hash: 11
190
+ segments:
191
+ - 1
192
+ - 6
193
+ - 2
134
194
  version: 1.6.2
135
195
  type: :development
136
196
  version_requirements: *id011
@@ -152,6 +212,7 @@ files:
152
212
  - Gemfile
153
213
  - LICENSE.txt
154
214
  - README.md
215
+ - RELEASING.txt
155
216
  - Rakefile
156
217
  - bin/tweetwine
157
218
  - contrib/tweetwine-completion.bash
@@ -174,7 +235,7 @@ files:
174
235
  - lib/tweetwine/url_shortener.rb
175
236
  - lib/tweetwine/version.rb
176
237
  - man/tweetwine.7.ronn
177
- - release-script.txt
238
+ - project.rb
178
239
  - test/example/authorization_example.rb
179
240
  - test/example/example_helper.rb
180
241
  - test/example/global_options_example.rb
@@ -223,12 +284,14 @@ has_rdoc: true
223
284
  homepage: https://github.com/tkareine/tweetwine
224
285
  licenses: []
225
286
 
226
- post_install_message: "\n\
227
- Tweetwine requires a JSON parser library. Ruby 1.9 comes bundled with one by\n\
228
- default. For Ruby 1.8, you can install 'json' gem, for example.\n\n"
287
+ post_install_message: |+
288
+
289
+ Tweetwine requires a JSON parser library. Ruby 1.9 comes bundled with one by
290
+ default. For Ruby 1.8, you can install 'json' gem, for example.
291
+
229
292
  rdoc_options:
230
293
  - --title
231
- - tweetwine 0.4.0
294
+ - tweetwine 0.4.1
232
295
  - --exclude
233
296
  - test
234
297
  require_paths:
@@ -238,17 +301,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
238
301
  requirements:
239
302
  - - ">="
240
303
  - !ruby/object:Gem::Version
304
+ hash: 3
305
+ segments:
306
+ - 0
241
307
  version: "0"
242
308
  required_rubygems_version: !ruby/object:Gem::Requirement
243
309
  none: false
244
310
  requirements:
245
311
  - - ">="
246
312
  - !ruby/object:Gem::Version
313
+ hash: 3
314
+ segments:
315
+ - 0
247
316
  version: "0"
248
317
  requirements: []
249
318
 
250
319
  rubyforge_project:
251
- rubygems_version: 1.5.2
320
+ rubygems_version: 1.6.2
252
321
  signing_key:
253
322
  specification_version: 3
254
323
  summary: Tweetwine shows the latest tweets from the command line quickly.