tweetwine 0.2.5 → 0.2.7

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.
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