tweetwine 0.2.5 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG.rdoc +30 -17
  2. data/README.rdoc +16 -17
  3. data/Rakefile +2 -0
  4. data/bin/tweetwine +3 -68
  5. data/example/example_helper.rb +31 -41
  6. data/example/fixtures/{statuses.json → home.json} +0 -0
  7. data/example/fixtures/mentions.json +1 -0
  8. data/example/fixtures/search.json +1 -0
  9. data/example/fixtures/update.json +1 -0
  10. data/example/fixtures/user.json +1 -0
  11. data/example/fixtures/users.json +1 -0
  12. data/example/search_statuses_example.rb +36 -0
  13. data/example/show_followers_example.rb +23 -0
  14. data/example/show_friends_example.rb +23 -0
  15. data/example/show_home_example.rb +51 -0
  16. data/example/show_mentions_example.rb +23 -0
  17. data/example/show_metadata_example.rb +54 -7
  18. data/example/show_user_example.rb +37 -0
  19. data/example/update_status_example.rb +65 -0
  20. data/lib/tweetwine/cli.rb +241 -0
  21. data/lib/tweetwine/client.rb +94 -57
  22. data/lib/tweetwine/io.rb +39 -28
  23. data/lib/tweetwine/meta.rb +1 -1
  24. data/lib/tweetwine/retrying_http.rb +93 -0
  25. data/lib/tweetwine/startup_config.rb +14 -15
  26. data/lib/tweetwine/url_shortener.rb +13 -8
  27. data/lib/tweetwine/util.rb +14 -0
  28. data/lib/tweetwine.rb +2 -1
  29. data/test/cli_test.rb +16 -0
  30. data/test/client_test.rb +275 -205
  31. data/test/fixtures/test_config.yaml +2 -1
  32. data/test/io_test.rb +89 -62
  33. data/test/retrying_http_test.rb +127 -0
  34. data/test/startup_config_test.rb +52 -27
  35. data/test/test_helper.rb +32 -17
  36. data/test/url_shortener_test.rb +18 -18
  37. data/test/util_test.rb +145 -47
  38. metadata +20 -7
  39. data/example/show_latest_statuses_example.rb +0 -45
  40. data/lib/tweetwine/rest_client_wrapper.rb +0 -37
  41. data/test/rest_client_wrapper_test.rb +0 -68
@@ -5,14 +5,14 @@ module Tweetwine
5
5
  class UrlShortenerTest < Test::Unit::TestCase
6
6
  context "An UrlShortener instance" do
7
7
  setup do
8
- @rest_client = mock()
8
+ @http_client = mock()
9
9
  end
10
10
 
11
11
  context "upon initialization" do
12
12
  should "raise exception if service URL is not given" do
13
13
  assert_raise(ArgumentError) do
14
14
  UrlShortener.new(
15
- @rest_client,
15
+ @http_client,
16
16
  {
17
17
  :service_url => nil,
18
18
  :url_param_name => "url",
@@ -25,7 +25,7 @@ class UrlShortenerTest < Test::Unit::TestCase
25
25
  should "raise exception if URL parameter name is not given" do
26
26
  assert_raise(ArgumentError) do
27
27
  UrlShortener.new(
28
- @rest_client,
28
+ @http_client,
29
29
  {
30
30
  :service_url => "http://shorten.it/create",
31
31
  :url_param_name => nil,
@@ -38,7 +38,7 @@ class UrlShortenerTest < Test::Unit::TestCase
38
38
  should "raise exception if XPath selector is not given" do
39
39
  assert_raise(ArgumentError) do
40
40
  UrlShortener.new(
41
- @rest_client,
41
+ @http_client,
42
42
  {
43
43
  :service_url => "http://shorten.it/create",
44
44
  :url_param_name => "url",
@@ -50,7 +50,7 @@ class UrlShortenerTest < Test::Unit::TestCase
50
50
 
51
51
  should "fallback to use GET method if not given explicitly" do
52
52
  url_shortener = UrlShortener.new(
53
- @rest_client,
53
+ @http_client,
54
54
  {
55
55
  :service_url => "http://shorten.it/create",
56
56
  :url_param_name => "url",
@@ -65,7 +65,7 @@ class UrlShortenerTest < Test::Unit::TestCase
65
65
  context "configured for HTTP GET" do
66
66
  should "use parameters as URL query parameters, with just the URL parameter" do
67
67
  url_shortener = UrlShortener.new(
68
- @rest_client,
68
+ @http_client,
69
69
  {
70
70
  :method => "get",
71
71
  :service_url => "http://shorten.it/create",
@@ -73,14 +73,14 @@ class UrlShortenerTest < Test::Unit::TestCase
73
73
  :xpath_selector => "//input[@id='short_url']/@value"
74
74
  }
75
75
  )
76
- @rest_client.expects(:get) \
76
+ @http_client.expects(:get) \
77
77
  .with("http://shorten.it/create?url=http://www.ruby-doc.org/core/")
78
78
  url_shortener.shorten("http://www.ruby-doc.org/core/")
79
79
  end
80
80
 
81
81
  should "use parameters as URL query parameters, with additional extra parameters" do
82
82
  url_shortener = UrlShortener.new(
83
- @rest_client,
83
+ @http_client,
84
84
  {
85
85
  :method => "get",
86
86
  :service_url => "http://shorten.it/create",
@@ -91,7 +91,7 @@ class UrlShortenerTest < Test::Unit::TestCase
91
91
  :xpath_selector => "//input[@id='short_url']/@value"
92
92
  }
93
93
  )
94
- @rest_client.expects(:get) \
94
+ @http_client.expects(:get) \
95
95
  .with("http://shorten.it/create?token=xyz&url=http://www.ruby-doc.org/core/")
96
96
  url_shortener.shorten("http://www.ruby-doc.org/core/")
97
97
  end
@@ -100,7 +100,7 @@ class UrlShortenerTest < Test::Unit::TestCase
100
100
  context "configured for HTTP POST" do
101
101
  should "use parameters as payload, with just the URL parameter" do
102
102
  url_shortener = UrlShortener.new(
103
- @rest_client,
103
+ @http_client,
104
104
  {
105
105
  :method => "post",
106
106
  :service_url => "http://shorten.it/create",
@@ -108,14 +108,14 @@ class UrlShortenerTest < Test::Unit::TestCase
108
108
  :xpath_selector => "//input[@id='short_url']/@value"
109
109
  }
110
110
  )
111
- @rest_client.expects(:post) \
111
+ @http_client.expects(:post) \
112
112
  .with("http://shorten.it/create", {:url => "http://www.ruby-doc.org/core/"})
113
113
  url_shortener.shorten("http://www.ruby-doc.org/core/")
114
114
  end
115
115
 
116
116
  should "use parameters as payload, with additional extra parameters" do
117
117
  url_shortener = UrlShortener.new(
118
- @rest_client,
118
+ @http_client,
119
119
  {
120
120
  :method => "post",
121
121
  :service_url => "http://shorten.it/create",
@@ -126,7 +126,7 @@ class UrlShortenerTest < Test::Unit::TestCase
126
126
  :xpath_selector => "//input[@id='short_url']/@value"
127
127
  }
128
128
  )
129
- @rest_client.expects(:post) \
129
+ @http_client.expects(:post) \
130
130
  .with("http://shorten.it/create", {
131
131
  :token => "xyz",
132
132
  :url => "http://www.ruby-doc.org/core/"
@@ -136,9 +136,9 @@ class UrlShortenerTest < Test::Unit::TestCase
136
136
  end
137
137
 
138
138
  context "in erroenous situations" do
139
- should "raise ClientError upon connection error" do
139
+ should "raise HttpError upon connection error" do
140
140
  url_shortener = UrlShortener.new(
141
- @rest_client,
141
+ @http_client,
142
142
  {
143
143
  :method => "post",
144
144
  :service_url => "http://shorten.it/create",
@@ -146,12 +146,12 @@ class UrlShortenerTest < Test::Unit::TestCase
146
146
  :xpath_selector => "//input[@id='short_url']/@value"
147
147
  }
148
148
  )
149
- @rest_client.expects(:post) \
149
+ @http_client.expects(:post) \
150
150
  .with("http://shorten.it/create", {
151
151
  :url => "http://www.ruby-doc.org/core/"
152
152
  }) \
153
- .raises(ClientError, "connection error")
154
- assert_raise(ClientError) { url_shortener.shorten("http://www.ruby-doc.org/core/") }
153
+ .raises(HttpError, "connection error")
154
+ assert_raise(HttpError) { url_shortener.shorten("http://www.ruby-doc.org/core/") }
155
155
  end
156
156
  end
157
157
  end
data/test/util_test.rb CHANGED
@@ -4,76 +4,104 @@ require "time"
4
4
  module Tweetwine
5
5
 
6
6
  class UtilTest < Test::Unit::TestCase
7
- should "humanize time difference" do
8
- assert_equal [1, "sec"], Util.humanize_time_diff(Time.parse("2009-01-01 00:00:59").to_s, Time.parse("2009-01-01 00:01:00"))
9
- assert_equal [0, "sec"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:00"))
10
- assert_equal [1, "sec"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:01"))
11
- assert_equal [59, "sec"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:59"))
12
- assert_equal [59, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 01:59"))
13
- assert_equal [59, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00:30").to_s, Time.parse("2009-01-01 01:59:00"))
14
- assert_equal [57, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:00"))
15
- assert_equal [56, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:01:31").to_s, Time.parse("2009-01-01 01:58:00"))
16
- assert_equal [57, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:29"))
17
- assert_equal [58, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:30"))
18
- assert_equal [1, "hour"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 02:00"))
19
- assert_equal [1, "hour"], Util.humanize_time_diff(Time.parse("2009-01-01 02:00").to_s, Time.parse("2009-01-01 01:00"))
20
- assert_equal [2, "hours"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 03:00"))
21
- assert_equal [1, "day"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-02 03:00"))
22
- assert_equal [2, "days"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-03 03:00"))
7
+ context "for humanizing time differences" do
8
+ should "use second granularity for time differences smaller than a minute" do
9
+ assert_equal [1, "sec"], Util.humanize_time_diff(Time.parse("2009-01-01 00:00:59").to_s, Time.parse("2009-01-01 00:01:00"))
10
+ assert_equal [0, "sec"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:00"))
11
+ assert_equal [1, "sec"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:01"))
12
+ assert_equal [59, "sec"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00:00").to_s, Time.parse("2009-01-01 01:00:59"))
13
+ end
14
+
15
+ should "use minute granularity for time differences greater than a minute but smaller than an hour" do
16
+ assert_equal [59, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 01:59"))
17
+ assert_equal [59, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00:30").to_s, Time.parse("2009-01-01 01:59:00"))
18
+ assert_equal [57, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:00"))
19
+ assert_equal [56, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:01:31").to_s, Time.parse("2009-01-01 01:58:00"))
20
+ assert_equal [57, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:29"))
21
+ assert_equal [58, "min"], Util.humanize_time_diff(Time.parse("2009-01-01 01:01:00").to_s, Time.parse("2009-01-01 01:58:30"))
22
+ end
23
+
24
+ should "use hour granularity for time differences greater than an hour but smaller than a day" do
25
+ assert_equal [1, "hour"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 02:00"))
26
+ assert_equal [1, "hour"], Util.humanize_time_diff(Time.parse("2009-01-01 02:00").to_s, Time.parse("2009-01-01 01:00"))
27
+ assert_equal [2, "hours"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-01 03:00"))
28
+ end
29
+
30
+ should "use day granularity for time differences greater than a day" do
31
+ assert_equal [1, "day"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-02 03:00"))
32
+ assert_equal [2, "days"], Util.humanize_time_diff(Time.parse("2009-01-01 01:00").to_s, Time.parse("2009-01-03 03:00"))
33
+ end
23
34
  end
24
35
 
25
- should "symbolize hash keys" do
26
- given = {
27
- "alpha" => "A",
28
- :beta => "B",
29
- "charlie" => "C",
30
- "delta" => {
31
- "echelon" => "E",
32
- "fox" => "F"
36
+ context "for recursively symbolizing keys in a hash" do
37
+ should "symbolize hash keys correctly" do
38
+ given = {
39
+ "alpha" => "A",
40
+ :beta => "B",
41
+ "charlie" => "C",
42
+ "delta" => {
43
+ "echelon" => "E",
44
+ "fox" => "F"
45
+ }
33
46
  }
34
- }
35
- expected = {
36
- :alpha => "A",
37
- :beta => "B",
38
- :charlie => "C",
39
- :delta => {
40
- :echelon => "E",
41
- :fox => "F"
47
+ expected = {
48
+ :alpha => "A",
49
+ :beta => "B",
50
+ :charlie => "C",
51
+ :delta => {
52
+ :echelon => "E",
53
+ :fox => "F"
54
+ }
42
55
  }
43
- }
44
- assert_equal expected, Util.symbolize_hash_keys(given)
56
+ assert_equal expected, Util.symbolize_hash_keys(given)
57
+ end
45
58
  end
46
59
 
47
- should "parse integers from strings, with minimum and default values, and naming parameter" do
48
- assert_equal 6, Util.parse_int_gt("6", 8, 4, "ethical working hours per day")
49
- assert_equal 8, Util.parse_int_gt(nil, 8, 4, "ethical working hours per day")
50
- assert_equal 8, Util.parse_int_gt(false, 8, 4, "ethical working hours per day")
51
- assert_raise(ArgumentError) { Util.parse_int_gt(3, 8, 4, "ethical working hours per day") }
60
+ context "for parsing integers from strings, with minimum and default values, and naming parameter" do
61
+ should "return an integer from its string presentation" do
62
+ assert_equal 6, Util.parse_int_gt("6", 8, 4, "ethical working hours per day")
63
+ end
64
+
65
+ should "return default value if the string parameter is falsy" do
66
+ assert_equal 8, Util.parse_int_gt(nil, 8, 4, "ethical working hours per day")
67
+ assert_equal 8, Util.parse_int_gt(false, 8, 4, "ethical working hours per day")
68
+ end
69
+
70
+ should "raise an error if the parsed value is less than the minimum parameter" do
71
+ assert_raise(ArgumentError) { Util.parse_int_gt(3, 8, 4, "ethical working hours per day") }
72
+ assert_raise(ArgumentError) { Util.parse_int_gt("3", 8, 4, "ethical working hours per day") }
73
+ end
52
74
  end
53
75
 
54
76
  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 }
77
+ should "replace the contents of the string by using a single matching group of the regexp" do
59
78
  assert_equal "hEllo", Util.str_gsub_by_group("hello", /.+(e)/) { |s| s.upcase }
60
79
  assert_equal "hEllO", Util.str_gsub_by_group("hello", /([aeio])/) { |s| s.upcase }
61
80
  assert_equal "hEEllOO", Util.str_gsub_by_group("hello", /([aeio])/) { |s| s.upcase * 2 }
81
+ assert_equal "hll", Util.str_gsub_by_group("hello", /([aeio])/) { |s| "" }
82
+ assert_equal "hell", Util.str_gsub_by_group("hello", /.+([io])/) { |s| "" }
83
+ end
84
+
85
+ should "replace the contents of the string by using multiple matching groups of the regexp" do
62
86
  assert_equal "hEllO", Util.str_gsub_by_group("hello", /([ae]).+([io])/) { |s| s.upcase }
63
87
  assert_equal "hXEXllXOX", Util.str_gsub_by_group("hello", /([ae]).+([io])/) { |s| "X" + s.upcase + "X" }
64
88
  assert_equal "hll", Util.str_gsub_by_group("hello", /.+([ae]).+([io])/) { |s| "" }
65
89
  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
90
  assert_equal "hEllo", Util.str_gsub_by_group("hello", /^(a)|.+(e)/) { |s| s.upcase }
69
91
  end
70
92
 
71
- should "replace the contents by using the whole match if there are no groups in the regexp" do
93
+ should "replace the contents of the string by using the whole regexp if there are no groups in the regexp an the regexp matches" do
72
94
  assert_equal "", Util.str_gsub_by_group("", /el/) { |s| s.upcase }
73
95
  assert_equal "hELlo", Util.str_gsub_by_group("hello", /el/) { |s| s.upcase }
74
96
  end
75
97
 
76
- should "return a new string as the result" do
98
+ should "not change the contents of the string if the regexp does not match" do
99
+ assert_equal "", Util.str_gsub_by_group("", /.+([ai])/) { |s| s.upcase }
100
+ assert_equal "hello", Util.str_gsub_by_group("hello", /.+([ai])/) { |s| s.upcase }
101
+ assert_equal "hello", Util.str_gsub_by_group("hello", /he(f)/) { |s| s.upcase }
102
+ end
103
+
104
+ should "return a new string as the result, leaving the original string unmodified" do
77
105
  org_str = "hello"
78
106
  new_str = Util.str_gsub_by_group(org_str, /e/) { |s| s.upcase }
79
107
  assert_not_same new_str, org_str
@@ -81,6 +109,76 @@ class UtilTest < Test::Unit::TestCase
81
109
  assert_equal "hEllo", new_str
82
110
  end
83
111
  end
112
+
113
+ context "for percent-encoding strings" do
114
+ should "not encode safe characters" do
115
+ assert_equal "a", Util.percent_encode("a")
116
+ assert_equal "B", Util.percent_encode("B")
117
+ assert_equal "3", Util.percent_encode("3")
118
+ assert_equal ".", Util.percent_encode(".")
119
+ assert_equal "-", Util.percent_encode("-")
120
+ assert_equal "_", Util.percent_encode("_")
121
+ end
122
+
123
+ should "encode space character with precent-encoding, not with '+' character" do
124
+ assert_equal "%20", Util.percent_encode(" ")
125
+ end
126
+
127
+ should "encode unsafe characters that URI.encode leaves by default unencoded" do
128
+ assert_equal "&", URI.encode("&")
129
+ assert_equal "%26", Util.percent_encode("&")
130
+ assert_equal "?", URI.encode("?")
131
+ assert_equal "%3F", Util.percent_encode("?")
132
+ assert_equal "/", URI.encode("/")
133
+ assert_equal "%2F", Util.percent_encode("/")
134
+ assert_equal ":", URI.encode(":")
135
+ assert_equal "%3A", Util.percent_encode(":")
136
+ assert_equal ",", URI.encode(",")
137
+ assert_equal "%2C", Util.percent_encode(",")
138
+ end
139
+ end
140
+
141
+ context "for traversing a hash with a path expression for finding a value" do
142
+ setup do
143
+ @inner_hash = {
144
+ :salmon => "slick"
145
+ }
146
+ @inner_hash.default = "no such element in inner hash"
147
+ @outer_hash = {
148
+ :simple => "beautiful",
149
+ :inner => @inner_hash,
150
+ :fishy => nil
151
+ }
152
+ @outer_hash.default = "no such element in outer hash"
153
+ end
154
+
155
+ should "support both a non-array and a single element array path for finding the value" do
156
+ assert_equal "beautiful", Util.find_hash_path(@outer_hash, :simple)
157
+ assert_equal "beautiful", Util.find_hash_path(@outer_hash, [:simple])
158
+ end
159
+
160
+ should "find a nested value with an array path" do
161
+ assert_equal "slick", Util.find_hash_path(@outer_hash, [:inner, :salmon])
162
+ end
163
+
164
+ should "return the default value of the hash if the value cannot be found" do
165
+ assert_equal @outer_hash.default, Util.find_hash_path(@outer_hash, :difficult)
166
+ assert_equal @inner_hash.default, Util.find_hash_path(@outer_hash, [:inner, :cucumber])
167
+ assert_equal @outer_hash.default, Util.find_hash_path(@outer_hash, [:fishy, :no_such])
168
+ end
169
+
170
+ should "return the default value of the hash if invalid path value" do
171
+ assert_equal @outer_hash.default, Util.find_hash_path(@outer_hash, nil)
172
+ assert_equal @outer_hash.default, Util.find_hash_path(@outer_hash, [:no_such, nil])
173
+ assert_equal @outer_hash.default, Util.find_hash_path(@outer_hash, [:simple, nil])
174
+ assert_equal @outer_hash.default, Util.find_hash_path(@outer_hash, [:inner, nil])
175
+ assert_equal @outer_hash.default, Util.find_hash_path(@outer_hash, [:inner, :salmon, nil])
176
+ end
177
+
178
+ should "return nil if nil hash value" do
179
+ assert_equal nil, Util.find_hash_path(nil, nil)
180
+ end
181
+ end
84
182
  end
85
183
 
86
184
  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.5
4
+ version: 0.2.7
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-14 00:00:00 +03:00
12
+ date: 2009-12-22 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -39,23 +39,36 @@ files:
39
39
  - README.rdoc
40
40
  - bin/tweetwine
41
41
  - example/example_helper.rb
42
- - example/fixtures/statuses.json
43
- - example/show_latest_statuses_example.rb
42
+ - example/fixtures/home.json
43
+ - example/fixtures/mentions.json
44
+ - example/fixtures/search.json
45
+ - example/fixtures/update.json
46
+ - example/fixtures/user.json
47
+ - example/fixtures/users.json
48
+ - example/search_statuses_example.rb
49
+ - example/show_followers_example.rb
50
+ - example/show_friends_example.rb
51
+ - example/show_home_example.rb
52
+ - example/show_mentions_example.rb
44
53
  - example/show_metadata_example.rb
54
+ - example/show_user_example.rb
55
+ - example/update_status_example.rb
56
+ - lib/tweetwine/cli.rb
45
57
  - lib/tweetwine/client.rb
46
58
  - lib/tweetwine/io.rb
47
59
  - lib/tweetwine/meta.rb
48
60
  - lib/tweetwine/options.rb
49
- - lib/tweetwine/rest_client_wrapper.rb
61
+ - lib/tweetwine/retrying_http.rb
50
62
  - lib/tweetwine/startup_config.rb
51
63
  - lib/tweetwine/url_shortener.rb
52
64
  - lib/tweetwine/util.rb
53
65
  - lib/tweetwine.rb
66
+ - test/cli_test.rb
54
67
  - test/client_test.rb
55
68
  - test/fixtures/test_config.yaml
56
69
  - test/io_test.rb
57
70
  - test/options_test.rb
58
- - test/rest_client_wrapper_test.rb
71
+ - test/retrying_http_test.rb
59
72
  - test/startup_config_test.rb
60
73
  - test/test_helper.rb
61
74
  - test/url_shortener_test.rb
@@ -67,7 +80,7 @@ licenses: []
67
80
  post_install_message:
68
81
  rdoc_options:
69
82
  - --title
70
- - tweetwine 0.2.5
83
+ - tweetwine 0.2.7
71
84
  - --main
72
85
  - README.rdoc
73
86
  - --exclude
@@ -1,45 +0,0 @@
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
@@ -1,37 +0,0 @@
1
- require "rest_client"
2
-
3
- module Tweetwine
4
- class ClientError < RuntimeError; end
5
-
6
- class RestClientWrapper
7
- instance_methods.each { |m| undef_method m unless m =~ /(^__|^send$|^object_id$)/ }
8
-
9
- MAX_RETRIES = 3
10
- RETRY_BASE_WAIT_TIMEOUT = 4
11
-
12
- def initialize(io)
13
- @io = io
14
- end
15
-
16
- protected
17
-
18
- def method_missing(name, *args, &block)
19
- tries = 0
20
- begin
21
- tries += 1
22
- RestClient.send(name, *args, &block)
23
- rescue Errno::ECONNRESET => e
24
- if tries < MAX_RETRIES
25
- timeout = RETRY_BASE_WAIT_TIMEOUT**tries
26
- @io.warn("Could not connect -- retrying in #{timeout} seconds")
27
- sleep timeout
28
- retry
29
- else
30
- raise ClientError, e
31
- end
32
- rescue RestClient::Exception, SocketError, SystemCallError => e
33
- raise ClientError, e
34
- end
35
- end
36
- end
37
- end
@@ -1,68 +0,0 @@
1
- require "test_helper"
2
- require "rest_client"
3
-
4
- class Object
5
- def sleep(timeout); end # speed up tests
6
- end
7
-
8
- module Tweetwine
9
-
10
- class RestClientWrapperTest < Test::Unit::TestCase
11
- context "A RestClientWrapper instance" do
12
- setup do
13
- @io = mock()
14
- @rest_client = RestClientWrapper.new(@io)
15
- end
16
-
17
- should "raise ClientError for an invalid request" do
18
- RestClient.expects(:get) \
19
- .with("https://secret:agent@hushhush.net") \
20
- .raises(RestClient::Unauthorized)
21
- assert_raise(ClientError) { @rest_client.get("https://secret:agent@hushhush.net") }
22
- end
23
-
24
- should "raise ClientError when connection cannot be established" do
25
- RestClient.expects(:get) \
26
- .with("http://www.invalid.net") \
27
- .raises(Errno::ECONNABORTED)
28
- assert_raise(ClientError) { @rest_client.get("http://www.invalid.net") }
29
- end
30
-
31
- should "raise ClientError when host cannot be resolved" do
32
- RestClient.expects(:get) \
33
- .with("http://unknown.net") \
34
- .raises(SocketError)
35
- assert_raise(ClientError) { @rest_client.get("http://unknown.net") }
36
- end
37
-
38
- should "retry connection upon connection reset" do
39
- rest_client_calls = sequence("RestClient")
40
- RestClient.expects(:get) \
41
- .with("http://www.heavilyloaded.net") \
42
- .in_sequence(rest_client_calls) \
43
- .raises(Errno::ECONNRESET)
44
- RestClient.expects(:get) \
45
- .with("http://www.heavilyloaded.net") \
46
- .in_sequence(rest_client_calls)
47
- @io.expects(:warn).with("Could not connect -- retrying in 4 seconds")
48
- @rest_client.get("http://www.heavilyloaded.net")
49
- end
50
-
51
- should "retry connection a maximum of certain number of times" do
52
- rest_client_calls = sequence("RestClient")
53
- io_calls = sequence("IO")
54
- RestClientWrapper::MAX_RETRIES.times do
55
- RestClient.expects(:get) \
56
- .with("http://www.heavilyloaded.net") \
57
- .in_sequence(rest_client_calls) \
58
- .raises(Errno::ECONNRESET)
59
- end
60
- (RestClientWrapper::MAX_RETRIES - 1).times do
61
- @io.expects(:warn).in_sequence(io_calls)
62
- end
63
- assert_raise(ClientError) { @rest_client.get("http://www.heavilyloaded.net") }
64
- end
65
- end
66
- end
67
-
68
- end