julienXX-www-delicious 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/CHANGELOG.rdoc +61 -0
  2. data/LICENSE.rdoc +25 -0
  3. data/Manifest +46 -0
  4. data/README.rdoc +201 -0
  5. data/Rakefile +57 -0
  6. data/lib/www/delicious/bundle.rb +73 -0
  7. data/lib/www/delicious/element.rb +73 -0
  8. data/lib/www/delicious/errors.rb +46 -0
  9. data/lib/www/delicious/post.rb +123 -0
  10. data/lib/www/delicious/tag.rb +101 -0
  11. data/lib/www/delicious/version.rb +33 -0
  12. data/lib/www/delicious.rb +941 -0
  13. data/setup.rb +1585 -0
  14. data/test/bundle_test.rb +63 -0
  15. data/test/delicious_test.rb +372 -0
  16. data/test/fixtures/net_response_invalid_account.yml +25 -0
  17. data/test/fixtures/net_response_success.yml +23 -0
  18. data/test/online_test.rb +147 -0
  19. data/test/post_test.rb +68 -0
  20. data/test/tag_test.rb +69 -0
  21. data/test/test_all.rb +19 -0
  22. data/test/test_helper.rb +43 -0
  23. data/test/testcases/element/bundle.xml +1 -0
  24. data/test/testcases/element/invalid_root.xml +2 -0
  25. data/test/testcases/element/post.xml +2 -0
  26. data/test/testcases/element/post_unshared.xml +2 -0
  27. data/test/testcases/element/tag.xml +1 -0
  28. data/test/testcases/response/bundles_all.xml +5 -0
  29. data/test/testcases/response/bundles_all_empty.xml +2 -0
  30. data/test/testcases/response/bundles_delete.xml +2 -0
  31. data/test/testcases/response/bundles_set.xml +2 -0
  32. data/test/testcases/response/bundles_set_error.xml +2 -0
  33. data/test/testcases/response/posts_add.xml +2 -0
  34. data/test/testcases/response/posts_all.xml +12 -0
  35. data/test/testcases/response/posts_dates.xml +14 -0
  36. data/test/testcases/response/posts_dates_with_tag.xml +14 -0
  37. data/test/testcases/response/posts_delete.xml +2 -0
  38. data/test/testcases/response/posts_get.xml +7 -0
  39. data/test/testcases/response/posts_get_with_tag.xml +6 -0
  40. data/test/testcases/response/posts_recent.xml +19 -0
  41. data/test/testcases/response/posts_recent_with_tag.xml +19 -0
  42. data/test/testcases/response/tags_get.xml +5 -0
  43. data/test/testcases/response/tags_get_empty.xml +2 -0
  44. data/test/testcases/response/tags_rename.xml +2 -0
  45. data/test/testcases/response/update.delicious1.xml +2 -0
  46. data/test/testcases/response/update.xml +3 -0
  47. data/www-delicious.gemspec +44 -0
  48. metadata +151 -0
@@ -0,0 +1,63 @@
1
+ #
2
+ # = WWW::Delicious
3
+ #
4
+ # Ruby client for del.icio.us API.
5
+ #
6
+ #
7
+ # Category:: WWW
8
+ # Package:: WWW::Delicious
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # License:: MIT License
11
+ #
12
+ #--
13
+ #
14
+ #++
15
+
16
+
17
+ require 'test_helper'
18
+ require 'www/delicious/bundle'
19
+
20
+
21
+ class BundleTest < Test::Unit::TestCase
22
+
23
+ def test_bundle
24
+ expected = { :name => 'MyTag', :tags => %w(foo bar) }
25
+ assert_attributes(instance(expected), expected)
26
+ end
27
+
28
+ def test_tag_from_rexml
29
+ dom = REXML::Document.new(File.read(TESTCASES_PATH + '/element/bundle.xml'))
30
+ expected = { :name => 'music', :tags => %w(ipod mp3 music) }
31
+
32
+ element = WWW::Delicious::Bundle.from_rexml(dom.root)
33
+ assert_attributes(element, expected)
34
+ end
35
+
36
+
37
+ def test_bundle_name_strips_whitespaces
38
+ [' foo ', 'foo ', ' foo ', ' foo'].each do |v|
39
+ assert_equal('foo', instance(:name => v).name) # => 'foo'
40
+ end
41
+ end
42
+
43
+ def test_to_s_returns_name_as_string
44
+ assert_equal('foobar', instance(:name => 'foobar', :tags => %w(foo bar)).to_s)
45
+ end
46
+
47
+ def test_to_s_returns_empty_string_with_name_nil
48
+ assert_equal('', instance(:name => nil).to_s)
49
+ end
50
+
51
+
52
+ # def test_valid
53
+ # end
54
+
55
+
56
+ protected
57
+
58
+ # returns a stub instance
59
+ def instance(values = {}, &block)
60
+ WWW::Delicious::Bundle.new(values)
61
+ end
62
+
63
+ end
@@ -0,0 +1,372 @@
1
+ #
2
+ # = WWW::Delicious
3
+ #
4
+ # Ruby client for del.icio.us API.
5
+ #
6
+ #
7
+ # Category:: WWW
8
+ # Package:: WWW::Delicious
9
+ # Author:: Simone Carletti <weppos@weppos.net>
10
+ # License:: MIT License
11
+ #
12
+ #--
13
+ #
14
+ #++
15
+
16
+
17
+ require 'test_helper'
18
+
19
+
20
+ class DeliciousTest < Test::Unit::TestCase
21
+
22
+ TEST_USERNAME = 'username'
23
+ TEST_PASSWORD = 'password'
24
+
25
+
26
+ def setup
27
+ @delicious = instance
28
+ end
29
+
30
+
31
+ def test_initialize_should_raise_without_account
32
+ assert_raise(ArgumentError) { WWW::Delicious.new() }
33
+ assert_raise(ArgumentError) { WWW::Delicious.new(TEST_USERNAME) }
34
+ end
35
+
36
+ def test_initialize_should_set_account_credentials
37
+ assert_equal(TEST_USERNAME, @delicious.username)
38
+ assert_equal(TEST_PASSWORD, @delicious.password)
39
+ end
40
+
41
+ def test_initialize_should_allow_option_user_agent
42
+ useragent = 'MyClass/1.0 (Foo/Bar +http://foo.com/)'
43
+ delicious = instance(:user_agent => useragent)
44
+ assert_equal(useragent, delicious.user_agent)
45
+ end
46
+
47
+ def test_initialize_should_default_option_user_agent_unless_option
48
+ useragent = instance.user_agent
49
+ assert_match("Ruby/#{RUBY_VERSION}", useragent)
50
+ assert_match("#{WWW::Delicious::NAME}/#{WWW::Delicious::VERSION}", useragent)
51
+ end
52
+
53
+ def test_initialize_should_allow_option_base_uri
54
+ base_uri = 'https://ma.gnolia.com/api/mirrord'
55
+ delicious = instance(:base_uri => base_uri)
56
+ assert_equal(URI.parse(base_uri), delicious.base_uri)
57
+ end
58
+
59
+ def test_initialize_should_default_option_base_uri_unless_option
60
+ base_uri = instance.base_uri
61
+ assert_equal(URI.parse('https://api.del.icio.us'), base_uri)
62
+ end
63
+
64
+
65
+ # =========================================================================
66
+ # HTTP Request common checks
67
+ # =========================================================================
68
+
69
+ def test_request_raises_without_http_client
70
+ @delicious.http_client = nil
71
+ assert_raise(WWW::Delicious::Error) { @delicious.update }
72
+ end
73
+
74
+ def test_request_waits_necessary_time_between_requests
75
+ @delicious.expects(:make_request).times(4).returns(load_fixture('/net_response_success.yml'))
76
+ @delicious.valid_account? # 1st request
77
+ 3.times do |time|
78
+ lr = @delicious.instance_variable_get(:@last_request)
79
+ @delicious.valid_account? # N request
80
+ nr = @delicious.instance_variable_get(:@last_request)
81
+ time_diff = (nr - lr)
82
+ assert !(time_diff < WWW::Delicious::SECONDS_BEFORE_NEW_REQUEST),
83
+ "Request ##{time} run after `#{time_diff}' seconds " +
84
+ "but it should wait at least `#{WWW::Delicious::SECONDS_BEFORE_NEW_REQUEST}' seconds"
85
+ end
86
+ end
87
+
88
+
89
+ def test_valid_account
90
+ @delicious.expects(:make_request).once.returns(load_fixture('/net_response_success.yml'))
91
+ assert(@delicious.valid_account?)
92
+ end
93
+
94
+ def test_invalid_account
95
+ @delicious.expects(:make_request).once.returns(load_fixture('/net_response_invalid_account.yml'))
96
+ assert(!@delicious.valid_account?)
97
+ end
98
+
99
+
100
+ # =========================================================================
101
+ # Update
102
+ # =========================================================================
103
+
104
+ def test_update
105
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
106
+ assert_equal(@delicious.update, Time.parse("2008-08-02T11:55:35Z"))
107
+ end
108
+
109
+ def test_update_raises_without_update_root_node
110
+ @delicious.expects(:request).once.returns(mock_response('/response/bundles_all.xml'))
111
+ error = assert_raise(WWW::Delicious::ResponseError) do
112
+ @delicious.update
113
+ end
114
+ assert_match(/`update`/, error.message)
115
+ end
116
+
117
+ def test_update_delicious1
118
+ @delicious.expects(:request).once.returns(mock_response('/response/update.delicious1.xml'))
119
+ assert_equal(@delicious.update, Time.parse("2008-03-12T08:41:20Z"))
120
+ end
121
+
122
+
123
+ # =========================================================================
124
+ # Bundles
125
+ # =========================================================================
126
+
127
+ def test_bundles_all
128
+ @delicious.expects(:request).once.returns(mock_response('/response/bundles_all.xml'))
129
+ expected = [ ['music', %w(ipod mp3 music)], ['pc', %w(computer software hardware)] ]
130
+
131
+ results = @delicious.bundles_all
132
+ assert_instance_of(Array, results)
133
+ assert_equal(2, results.length)
134
+
135
+ results.each_with_index do |bundle, index|
136
+ assert_instance_of(WWW::Delicious::Bundle, bundle)
137
+ name, tags = expected[index]
138
+ assert_equal(name, bundle.name)
139
+ assert_equal(tags, bundle.tags)
140
+ end
141
+ end
142
+
143
+ def test_bundles_all_empty
144
+ @delicious.expects(:request).once.returns(mock_response('/response/bundles_all_empty.xml'))
145
+ results = @delicious.bundles_all
146
+ assert_instance_of(Array, results)
147
+ assert_equal(0, results.length)
148
+ end
149
+
150
+ def test_bundles_all_raises_without_bundles_root_node
151
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
152
+ error = assert_raise(WWW::Delicious::ResponseError) do
153
+ @delicious.bundles_all
154
+ end
155
+ assert_match(/`bundles`/, error.message)
156
+ end
157
+
158
+
159
+ def test_bundles_set
160
+ @delicious.expects(:request).once.returns(mock_response('/response/bundles_set.xml'))
161
+ assert(@delicious.bundles_set('name', %w(foo bar)))
162
+ end
163
+
164
+ def test_bundles_set_raises_with_response_error
165
+ @delicious.expects(:request).once.returns(mock_response('/response/bundles_set_error.xml'))
166
+ error = assert_raise(WWW::Delicious::Error) do
167
+ @delicious.bundles_set('name', %w(foo bar))
168
+ end
169
+ assert_match(/you must supply a bundle name/, error.message)
170
+ end
171
+
172
+ def test_bundles_set_raises_without_result_root_node
173
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
174
+ error = assert_raise(WWW::Delicious::ResponseError) do
175
+ @delicious.bundles_set('name', %w(foo bar))
176
+ end
177
+ assert_match(/`result`/, error.message)
178
+ end
179
+
180
+
181
+ def test_bundles_delete
182
+ @delicious.expects(:request).once.returns(mock_response('/response/bundles_delete.xml'))
183
+ assert(@delicious.bundles_delete('name'))
184
+ end
185
+
186
+ def test_bundles_delete_raises_without_result_root_node
187
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
188
+ error = assert_raise(WWW::Delicious::ResponseError) do
189
+ @delicious.bundles_delete('name')
190
+ end
191
+ assert_match(/`result`/, error.message)
192
+ end
193
+
194
+
195
+ # =========================================================================
196
+ # Tags
197
+ # =========================================================================
198
+
199
+ def test_tags_get
200
+ @delicious.expects(:request).once.returns(mock_response('/response/tags_get.xml'))
201
+ expected = [ ['activedesktop', 1], ['business', 14] ]
202
+
203
+ results = @delicious.tags_get
204
+ assert_instance_of(Array, results)
205
+ assert_equal(2, results.length)
206
+
207
+ results.each_with_index do |tag, index|
208
+ assert_instance_of(WWW::Delicious::Tag, tag)
209
+ name, count = expected[index]
210
+ assert_equal(name, tag.name)
211
+ assert_equal(count, tag.count)
212
+ end
213
+ end
214
+
215
+ def test_tags_get_empty
216
+ @delicious.expects(:request).once.returns(mock_response('/response/tags_get_empty.xml'))
217
+ results = @delicious.tags_get
218
+ assert_instance_of(Array, results)
219
+ assert_equal(0, results.length)
220
+ end
221
+
222
+ def test_tags_get_raises_without_bundles_root_node
223
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
224
+ error = assert_raise(WWW::Delicious::ResponseError) do
225
+ @delicious.tags_get
226
+ end
227
+ assert_match(/`tags`/, error.message)
228
+ end
229
+
230
+
231
+ def test_tags_rename
232
+ @delicious.expects(:request).once.returns(mock_response('/response/tags_rename.xml'))
233
+ assert(@delicious.tags_rename('old', 'new'))
234
+ end
235
+
236
+ def test_tags_rename_raises_without_result_root_node
237
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
238
+ error = assert_raise(WWW::Delicious::ResponseError) do
239
+ @delicious.tags_rename('foo', 'bar')
240
+ end
241
+ assert_match(/`result`/, error.message)
242
+ end
243
+
244
+
245
+ # =========================================================================
246
+ # Posts
247
+ # =========================================================================
248
+
249
+ def test_posts_get
250
+ @delicious.expects(:request).once.returns(mock_response('/response/posts_get.xml'))
251
+ results = @delicious.posts_get
252
+ assert_instance_of(Array, results)
253
+ assert_equal(3, results.length)
254
+ assert_equal('New to Git? - GitHub', results.first.title)
255
+ assert_equal('.c( whytheluckystiff )o. -- The Fully Upturned Bin', results.last.title)
256
+ end
257
+
258
+ def test_posts_get_raises_without_posts_root_node
259
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
260
+ error = assert_raise(WWW::Delicious::ResponseError) do
261
+ @delicious.posts_get
262
+ end
263
+ assert_match(/`posts`/, error.message)
264
+ end
265
+
266
+
267
+ def test_posts_recent
268
+ @delicious.expects(:request).once.returns(mock_response('/response/posts_recent.xml'))
269
+ results = @delicious.posts_recent
270
+ assert_instance_of(Array, results)
271
+ assert_equal(15, results.length)
272
+ assert_equal('New to Git? - GitHub', results.first.title)
273
+ assert_equal('RichText | Lightview for modal dialogs on Rails', results.last.title)
274
+ end
275
+
276
+ def test_posts_recent_raises_without_posts_root_node
277
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
278
+ error = assert_raise(WWW::Delicious::ResponseError) do
279
+ @delicious.posts_recent
280
+ end
281
+ assert_match(/`posts`/, error.message)
282
+ end
283
+
284
+
285
+ def test_posts_all
286
+ @delicious.expects(:request).once.returns(mock_response('/response/posts_all.xml'))
287
+ results = @delicious.posts_all
288
+ assert_instance_of(Array, results)
289
+ assert_equal(8, results.length)
290
+ assert_equal('New to Git? - GitHub', results.first.title)
291
+ assert_equal('ASP 101 - Object Oriented ASP: Using Classes in Classic ASP', results.last.title)
292
+ end
293
+
294
+ def test_posts_all_raises_without_posts_root_node
295
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
296
+ error = assert_raise(WWW::Delicious::ResponseError) do
297
+ @delicious.posts_all
298
+ end
299
+ assert_match(/`posts`/, error.message)
300
+ end
301
+
302
+
303
+ def test_posts_dates
304
+ @delicious.expects(:request).once.returns(mock_response('/response/posts_dates.xml'))
305
+ results = @delicious.posts_dates
306
+ assert_instance_of(Hash, results)
307
+ assert_equal(10, results.length)
308
+ end
309
+
310
+ def test_posts_dates_raises_without_dates_root_node
311
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
312
+ error = assert_raise(WWW::Delicious::ResponseError) do
313
+ @delicious.posts_dates
314
+ end
315
+ assert_match(/`dates`/, error.message)
316
+ end
317
+
318
+
319
+ def test_posts_add
320
+ params = {:url => 'http://localhost', :title => 'Just a test'}
321
+ @delicious.expects(:request).times(2).returns(mock_response('/response/posts_add.xml'))
322
+ assert(@delicious.posts_add(WWW::Delicious::Post.new(params)))
323
+ assert(@delicious.posts_add(params))
324
+ end
325
+
326
+
327
+ def test_posts_delete
328
+ @delicious.expects(:request).once.returns(mock_response('/response/posts_delete.xml'))
329
+ assert(@delicious.posts_delete('test'))
330
+ end
331
+
332
+ def test_posts_delete_raises_without_result_root_node
333
+ @delicious.expects(:request).once.returns(mock_response('/response/update.xml'))
334
+ error = assert_raise(WWW::Delicious::ResponseError) do
335
+ @delicious.posts_delete('test')
336
+ end
337
+ assert_match(/`result`/, error.message)
338
+ end
339
+
340
+
341
+
342
+ protected
343
+
344
+ # returns a stub instance
345
+ def instance(options = {}, &block)
346
+ WWW::Delicious.new(TEST_USERNAME, TEST_PASSWORD, options, &block)
347
+ end
348
+
349
+ def load_testcase(file)
350
+ File.read(TESTCASES_PATH + file)
351
+ end
352
+
353
+ def load_fixture(file)
354
+ YAML.load(File.read(FIXTURES_PATH + file))
355
+ end
356
+
357
+ def mock_response(file_or_content)
358
+ content = case
359
+ when file_or_content =~ /\.xml$/
360
+ load_testcase(file_or_content)
361
+ when file_or_content =~ /\.yml$/
362
+ load_fixture(file_or_content)
363
+ else
364
+ file_or_content.to_s
365
+ end
366
+
367
+ response = mock()
368
+ response.expects(:body).at_least(1).returns(content)
369
+ response
370
+ end
371
+
372
+ end
@@ -0,0 +1,25 @@
1
+ --- !ruby/object:Net::HTTPUnauthorized
2
+ body: |
3
+ <?xml version="1.0" standalone="yes"?>
4
+ <result code="access denied" />
5
+ <!-- fe02.api.del.ac4.yahoo.net uncompressed/chunked Tue Jul 29 13:53:52 PDT 2008 -->
6
+
7
+ body_exist: true
8
+ code: "401"
9
+ header:
10
+ connection:
11
+ - close
12
+ p3p:
13
+ - policyref="http://p3p.yahoo.com/w3c/p3p.xml", CP="CAO DSP COR CUR ADM DEV TAI PSA PSD IVAi IVDi CONi TELo OTPi OUR DELi SAMi OTRi UNRi PUBi IND PHY ONL UNI PUR FIN COM NAV INT DEM CNT STA POL HEA PRE GOV"
14
+ content-type:
15
+ - text/xml; charset=utf-8
16
+ date:
17
+ - Tue, 29 Jul 2008 20:53:52 GMT
18
+ www-authenticate:
19
+ - Basic realm="del.icio.us API"
20
+ transfer-encoding:
21
+ - chunked
22
+ http_version: "1.1"
23
+ message: Unauthorized
24
+ read: true
25
+ socket: