www-delicious 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.rdoc +41 -0
- data/{MIT-LICENSE → MIT-LICENSE.rdoc} +0 -0
- data/Manifest +49 -0
- data/{README → README.rdoc} +13 -14
- data/Rakefile +36 -118
- data/TODO +4 -0
- data/lib/www/delicious.rb +527 -446
- data/lib/www/delicious/bundle.rb +41 -22
- data/lib/www/delicious/element.rb +72 -0
- data/lib/www/delicious/errors.rb +2 -2
- data/lib/www/delicious/post.rb +71 -61
- data/lib/www/delicious/tag.rb +43 -62
- data/lib/www/delicious/version.rb +1 -1
- data/test/fixtures/net_response_invalid_account.yml +25 -0
- data/test/fixtures/net_response_success.yml +23 -0
- data/test/helper.rb +19 -79
- data/test/test_all.rb +17 -0
- data/test/test_offline.rb +17 -0
- data/test/test_online.rb +19 -0
- data/test/testcases/element/bundle.xml +1 -0
- data/test/testcases/element/invalid_root.xml +2 -0
- data/test/testcases/element/post.xml +2 -0
- data/test/testcases/element/post_unshared.xml +2 -0
- data/test/testcases/element/tag.xml +1 -0
- data/test/testcases/response/bundles_all.xml +5 -0
- data/test/testcases/response/bundles_all_empty.xml +2 -0
- data/test/testcases/response/bundles_delete.xml +2 -0
- data/test/testcases/response/bundles_set.xml +2 -0
- data/test/testcases/response/bundles_set_error.xml +2 -0
- data/test/testcases/response/posts_add.xml +2 -0
- data/test/testcases/response/posts_all.xml +12 -0
- data/test/testcases/response/posts_dates.xml +14 -0
- data/test/testcases/response/posts_dates_with_tag.xml +14 -0
- data/test/testcases/response/posts_delete.xml +2 -0
- data/test/testcases/response/posts_get.xml +7 -0
- data/test/testcases/response/posts_get_with_tag.xml +6 -0
- data/test/testcases/response/posts_recent.xml +19 -0
- data/test/testcases/response/posts_recent_with_tag.xml +19 -0
- data/test/testcases/response/tags_get.xml +5 -0
- data/test/testcases/response/tags_get_empty.xml +2 -0
- data/test/testcases/response/tags_rename.xml +2 -0
- data/test/testcases/response/update.delicious1.xml +2 -0
- data/test/testcases/response/update.xml +3 -0
- data/test/unit/bundle_test.rb +62 -0
- data/test/unit/delicious_test.rb +186 -238
- data/test/unit/online/online_test.rb +147 -0
- data/test/unit/post_test.rb +67 -0
- data/test/unit/tag_test.rb +68 -0
- data/www-delicious.gemspec +146 -0
- metadata +85 -31
- data/CHANGELOG +0 -5
- data/test/unit/delicious_bundle_test.rb +0 -90
- data/test/unit/delicious_online_test.rb +0 -143
- data/test/unit/delicious_post_test.rb +0 -102
- data/test/unit/delicious_tag_test.rb +0 -140
data/lib/www/delicious/bundle.rb
CHANGED
@@ -14,41 +14,60 @@
|
|
14
14
|
#++
|
15
15
|
|
16
16
|
|
17
|
-
|
17
|
+
require 'www/delicious/element'
|
18
|
+
|
19
|
+
|
20
|
+
module WWW
|
18
21
|
class Delicious
|
19
22
|
|
20
|
-
|
23
|
+
#
|
24
|
+
# = Delicious Bundle
|
25
|
+
#
|
26
|
+
# Represents a single Bundle element.
|
27
|
+
#
|
28
|
+
class Bundle < Element
|
21
29
|
|
22
|
-
# The name of the bundle
|
30
|
+
# The name of the bundle.
|
23
31
|
attr_accessor :name
|
24
32
|
|
25
|
-
# The collection of <tt>WWW::Delicious::Tags</tt
|
33
|
+
# The collection of <tt>WWW::Delicious::Tags</tt>.
|
26
34
|
attr_accessor :tags
|
27
35
|
|
28
|
-
|
29
|
-
#
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
def initialize(name, tags = [], &block) # :yields: bundle
|
34
|
-
raise ArgumentError, '`tags` expected to be an Array' unless tags.kind_of?(Array)
|
35
|
-
|
36
|
-
self.name = name.to_s()
|
37
|
-
self.tags = tags
|
38
|
-
yield(self) if block_given?
|
39
|
-
self
|
36
|
+
|
37
|
+
# Returns value for <tt>name</tt> attribute.
|
38
|
+
# Value is always normalized as lower string.
|
39
|
+
def name
|
40
|
+
@name.to_s.strip unless @name.nil?
|
40
41
|
end
|
41
42
|
|
42
|
-
public
|
43
43
|
#
|
44
|
-
#
|
44
|
+
# Returns a string representation of this Bundle.
|
45
|
+
# In case name is nil this method will return an empty string.
|
45
46
|
#
|
46
|
-
def
|
47
|
-
|
48
|
-
element.attribute_value(:tags) { |v| v.to_s().split(' ') })
|
47
|
+
def to_s
|
48
|
+
name.to_s
|
49
49
|
end
|
50
50
|
|
51
|
+
|
52
|
+
class << self
|
53
|
+
|
54
|
+
#
|
55
|
+
# Creates and returns new instance from a REXML +element+.
|
56
|
+
#
|
57
|
+
# Implements Element#from_rexml.
|
58
|
+
#
|
59
|
+
def from_rexml(element)
|
60
|
+
raise ArgumentError, "`element` expected to be a `REXML::Element`" unless element.kind_of? REXML::Element
|
61
|
+
self.new do |instance|
|
62
|
+
instance.name = element.if_attribute_value(:name)
|
63
|
+
# FIXME: value must be converted to array of Tag
|
64
|
+
instance.tags = element.if_attribute_value(:tags) { |value| value.split(' ') }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
51
70
|
end
|
52
|
-
|
71
|
+
|
53
72
|
end
|
54
73
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#
|
2
|
+
# = WWW::Delicious
|
3
|
+
#
|
4
|
+
# Ruby client for del.icio.us API.
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# Category:: WWW
|
8
|
+
# Package:: WWW::Delicious
|
9
|
+
# Subpackage:: WWW::Delicious::Post
|
10
|
+
# Author:: Simone Carletti <weppos@weppos.net>
|
11
|
+
#
|
12
|
+
#--
|
13
|
+
# SVN: $Id$
|
14
|
+
#++
|
15
|
+
|
16
|
+
|
17
|
+
module WWW
|
18
|
+
class Delicious
|
19
|
+
|
20
|
+
#
|
21
|
+
# = Abstract structure
|
22
|
+
#
|
23
|
+
# Represent the most basic structure all Struc(s) must inherith from.
|
24
|
+
#
|
25
|
+
class Element
|
26
|
+
|
27
|
+
#
|
28
|
+
# Initializes a new instance and populate attributes from +attrs+.
|
29
|
+
#
|
30
|
+
# class User < Element
|
31
|
+
# attr_accessor :first_name
|
32
|
+
# attr_accessor :last_name
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# User.new
|
36
|
+
# User.new(:first_name => 'foo')
|
37
|
+
# User.new(:first_name => 'John', :last_name => 'Doe')
|
38
|
+
#
|
39
|
+
# You can even use a block.
|
40
|
+
# The following statements are equals:
|
41
|
+
#
|
42
|
+
# User.new(:first_name => 'John', :last_name => 'Doe')
|
43
|
+
#
|
44
|
+
# User.new do |user|
|
45
|
+
# user.first_name => 'John'
|
46
|
+
# user.last_name => 'Doe'
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Warning. In order to set an attribute a valid attribute writer must be available,
|
50
|
+
# otherwise this method will raise an exception.
|
51
|
+
#
|
52
|
+
def initialize(attrs = {}, &block)
|
53
|
+
attrs.each { |key, value| self.send("#{key}=".to_sym, value) }
|
54
|
+
yield self if block_given?
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
class << self
|
59
|
+
|
60
|
+
#
|
61
|
+
# Creates and returns new instance from a REXML +element+.
|
62
|
+
#
|
63
|
+
def from_rexml(element, options)
|
64
|
+
raise NotImplementedError
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
data/lib/www/delicious/errors.rb
CHANGED
@@ -13,7 +13,7 @@
|
|
13
13
|
#++
|
14
14
|
|
15
15
|
|
16
|
-
module WWW
|
16
|
+
module WWW
|
17
17
|
class Delicious
|
18
18
|
|
19
19
|
|
@@ -39,7 +39,7 @@ module WWW #:nodoc:
|
|
39
39
|
# Usually raised in case of a malformed, invalid or empty XML response.
|
40
40
|
#
|
41
41
|
class ResponseError < Error; end
|
42
|
-
|
42
|
+
|
43
43
|
|
44
44
|
end
|
45
45
|
end
|
data/lib/www/delicious/post.rb
CHANGED
@@ -14,82 +14,68 @@
|
|
14
14
|
#++
|
15
15
|
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
require 'www/delicious/element'
|
18
|
+
|
19
19
|
|
20
|
-
|
20
|
+
module WWW
|
21
|
+
class Delicious
|
22
|
+
|
23
|
+
class Post < Element
|
21
24
|
|
22
|
-
#
|
23
|
-
attr_accessor :url
|
24
|
-
attr_accessor :replace, :shared
|
25
|
+
# The Post URL
|
26
|
+
attr_accessor :url
|
25
27
|
|
26
|
-
|
27
|
-
|
28
|
-
# Creates a new <tt>WWW::Delicious::Post</tt> with given values.
|
29
|
-
# If +values_or_rexml+ is a REXML element, the element is parsed
|
30
|
-
# and all values assigned to this instance attributes.
|
31
|
-
#
|
32
|
-
def initialize(values_or_rexml, &block) # :yields: post
|
33
|
-
case values_or_rexml
|
34
|
-
when Hash
|
35
|
-
initialize_from_hash(values_or_rexml)
|
36
|
-
when REXML::Element
|
37
|
-
initialize_from_rexml(values_or_rexml)
|
38
|
-
else
|
39
|
-
raise ArgumentError, 'Expected `values_or_rexml` to be `Hash` or `REXML::Element`'
|
40
|
-
end
|
41
|
-
|
42
|
-
yield(self) if block_given?
|
43
|
-
self
|
44
|
-
end
|
28
|
+
# The title of the Post
|
29
|
+
attr_accessor :title
|
45
30
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
31
|
+
# The extended description for the Post
|
32
|
+
attr_accessor :notes
|
33
|
+
|
34
|
+
# The number of other users who saved this Post
|
35
|
+
attr_accessor :others
|
36
|
+
|
37
|
+
# The unique Id for this Post
|
38
|
+
attr_accessor :uid
|
39
|
+
|
40
|
+
# Tags for this Post
|
41
|
+
attr_accessor :tags
|
42
|
+
|
43
|
+
# Timestamp this Post was last saved at
|
44
|
+
attr_accessor :time
|
45
|
+
|
46
|
+
# Whether this Post must replace previous version of the same Post.
|
47
|
+
attr_accessor :replace
|
48
|
+
|
49
|
+
# Whether this Post is private
|
50
|
+
attr_accessor :shared
|
51
|
+
|
52
|
+
|
53
|
+
# Returns the value for <tt>shared</tt> attribute.
|
54
|
+
def shared
|
55
|
+
!(@shared == false)
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
#
|
62
|
-
def initialize_from_rexml(element)
|
63
|
-
self.url = element.attribute_value(:href) { |v| URI.parse(v) }
|
64
|
-
self.title = element.attribute_value(:description)
|
65
|
-
self.notes = element.attribute_value(:extended)
|
66
|
-
self.others = element.attribute_value(:others).to_i() # cast nil to 0
|
67
|
-
self.uid = element.attribute_value(:hash)
|
68
|
-
self.tags = element.attribute_value(:tag) { |v| v.split(' ') }.to_a()
|
69
|
-
self.time = element.attribute_value(:time) { |v| Time.parse(v) }
|
70
|
-
self.shared = element.attribute_value(:shared) { |v| v == 'no' ? false : true }
|
58
|
+
# Returns the value for <tt>replace</tt> attribute.
|
59
|
+
def replace
|
60
|
+
!(@replace == false)
|
71
61
|
end
|
72
62
|
|
73
|
-
public
|
74
|
-
#
|
75
63
|
# Returns a params-style representation suitable for API calls.
|
76
|
-
#
|
77
64
|
def to_params()
|
78
65
|
params = {}
|
79
|
-
params[:url]
|
80
|
-
params[:description]
|
81
|
-
params[:extended]
|
82
|
-
params[:shared]
|
83
|
-
params[:tags]
|
84
|
-
params[:replace]
|
85
|
-
params[:dt]
|
86
|
-
|
66
|
+
params[:url] = url
|
67
|
+
params[:description] = title
|
68
|
+
params[:extended] = notes if notes
|
69
|
+
params[:shared] = shared
|
70
|
+
params[:tags] = tags.join(' ') if tags.respond_to? :join
|
71
|
+
params[:replace] = replace
|
72
|
+
params[:dt] = WWW::Delicious::TIME_CONVERTER.call(time) if time
|
73
|
+
params
|
87
74
|
end
|
88
75
|
|
89
76
|
|
90
|
-
public
|
91
77
|
#
|
92
|
-
# Returns
|
78
|
+
# Returns whether this object is valid for an API request.
|
93
79
|
#
|
94
80
|
# To be valid +url+ and +title+ must not be empty.
|
95
81
|
#
|
@@ -107,6 +93,30 @@ module WWW #:nodoc:
|
|
107
93
|
return !(url.nil? or url.empty? or title.nil? or title.empty?)
|
108
94
|
end
|
109
95
|
|
96
|
+
|
97
|
+
class << self
|
98
|
+
|
99
|
+
#
|
100
|
+
# Creates and returns new instance from a REXML +element+.
|
101
|
+
#
|
102
|
+
# Implements Element#from_rexml.
|
103
|
+
#
|
104
|
+
def from_rexml(element)
|
105
|
+
raise ArgumentError, "`element` expected to be a `REXML::Element`" unless element.kind_of? REXML::Element
|
106
|
+
self.new do |instance|
|
107
|
+
instance.url = element.if_attribute_value(:href) { |v| URI.parse(v) }
|
108
|
+
instance.title = element.if_attribute_value(:description)
|
109
|
+
instance.notes = element.if_attribute_value(:extended)
|
110
|
+
instance.others = element.if_attribute_value(:others).to_i # cast nil to 0
|
111
|
+
instance.uid = element.if_attribute_value(:hash)
|
112
|
+
instance.tags = element.if_attribute_value(:tag) { |v| v.split(' ') }.to_a
|
113
|
+
instance.time = element.if_attribute_value(:time) { |v| Time.parse(v) }
|
114
|
+
instance.shared = element.if_attribute_value(:shared) { |v| v == 'no' ? false : true }
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
110
120
|
end
|
111
121
|
|
112
122
|
end
|
data/lib/www/delicious/tag.rb
CHANGED
@@ -14,82 +14,45 @@
|
|
14
14
|
#++
|
15
15
|
|
16
16
|
|
17
|
-
|
17
|
+
require 'www/delicious/element'
|
18
|
+
|
19
|
+
|
20
|
+
module WWW
|
18
21
|
class Delicious
|
19
22
|
|
20
|
-
|
23
|
+
#
|
24
|
+
# = Delicious Tag
|
25
|
+
#
|
26
|
+
# Represents a single Tag element.
|
27
|
+
#
|
28
|
+
class Tag < Element
|
21
29
|
|
22
|
-
# The name of the tag
|
23
|
-
|
30
|
+
# The name of the tag.
|
31
|
+
attr_accessor :name
|
24
32
|
|
25
33
|
# The number of links tagged with this tag.
|
26
34
|
# It should be set only from an API response.
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
public
|
31
|
-
#
|
32
|
-
# Creates a new <tt>WWW::Delicious::Tag</tt>.
|
33
|
-
#
|
34
|
-
def initialize(values_or_rexml, &block) # :yields: tag
|
35
|
-
case values_or_rexml
|
36
|
-
when Hash
|
37
|
-
initialize_from_hash(values_or_rexml)
|
38
|
-
when REXML::Element
|
39
|
-
initialize_from_rexml(values_or_rexml)
|
40
|
-
else
|
41
|
-
raise ArgumentError, 'Expected `values_or_rexml` to be `Hash` or `REXML::Element`'
|
42
|
-
end
|
43
|
-
|
44
|
-
yield(self) if block_given?
|
45
|
-
self
|
46
|
-
end
|
47
|
-
|
48
|
-
public
|
49
|
-
#
|
50
|
-
# Initializes <tt>WWW::Delicious::Tag</tt> from a REXML fragment.
|
51
|
-
#
|
52
|
-
def initialize_from_rexml(element)
|
53
|
-
self.name = element.attribute_value(:tag)
|
54
|
-
self.count = element.attribute_value(:count)
|
55
|
-
end
|
56
|
-
|
57
|
-
public
|
58
|
-
#
|
59
|
-
# Initializes <tt>WWW::Delicious::Tag</tt> from an Hash.
|
60
|
-
#
|
61
|
-
def initialize_from_hash(values)
|
62
|
-
self.name = values[:name]
|
63
|
-
self.count = values[:count]
|
64
|
-
end
|
35
|
+
attr_accessor :count
|
65
36
|
|
66
37
|
|
67
|
-
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
#
|
72
|
-
# Leading and trailing whitespaces are stripped.
|
73
|
-
#
|
74
|
-
def name=(value)
|
75
|
-
@name = value.to_s().strip()
|
38
|
+
# Returns value for <tt>name</tt> attribute.
|
39
|
+
# Value is always normalized as lower string.
|
40
|
+
def name
|
41
|
+
@name.to_s.strip unless @name.nil?
|
76
42
|
end
|
77
43
|
|
78
|
-
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
#
|
83
|
-
def count=(value)
|
84
|
-
@count = value.to_i()
|
44
|
+
# Returns value for <tt>count</tt> attribute.
|
45
|
+
# Value is always normalized to Fixnum.
|
46
|
+
def count
|
47
|
+
@count.to_i
|
85
48
|
end
|
86
49
|
|
87
|
-
public
|
88
50
|
#
|
89
51
|
# Returns a string representation of this Tag.
|
52
|
+
# In case name is nil this method will return an empty string.
|
90
53
|
#
|
91
|
-
def to_s
|
92
|
-
|
54
|
+
def to_s
|
55
|
+
name.to_s
|
93
56
|
end
|
94
57
|
|
95
58
|
|
@@ -111,7 +74,25 @@ module WWW #:nodoc:
|
|
111
74
|
# # => false
|
112
75
|
#
|
113
76
|
def api_valid?
|
114
|
-
|
77
|
+
return !name.empty?
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
class << self
|
82
|
+
|
83
|
+
#
|
84
|
+
# Creates and returns new instance from a REXML +element+.
|
85
|
+
#
|
86
|
+
# Implements Element#from_rexml.
|
87
|
+
#
|
88
|
+
def from_rexml(element)
|
89
|
+
raise ArgumentError, "`element` expected to be a `REXML::Element`" unless element.kind_of? REXML::Element
|
90
|
+
self.new do |instance|
|
91
|
+
instance.name = element.if_attribute_value(:tag)
|
92
|
+
instance.count = element.if_attribute_value(:count) { |value| value.to_i }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
115
96
|
end
|
116
97
|
|
117
98
|
end
|