www-delicious 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/CHANGELOG.rdoc +41 -0
  2. data/{MIT-LICENSE → MIT-LICENSE.rdoc} +0 -0
  3. data/Manifest +49 -0
  4. data/{README → README.rdoc} +13 -14
  5. data/Rakefile +36 -118
  6. data/TODO +4 -0
  7. data/lib/www/delicious.rb +527 -446
  8. data/lib/www/delicious/bundle.rb +41 -22
  9. data/lib/www/delicious/element.rb +72 -0
  10. data/lib/www/delicious/errors.rb +2 -2
  11. data/lib/www/delicious/post.rb +71 -61
  12. data/lib/www/delicious/tag.rb +43 -62
  13. data/lib/www/delicious/version.rb +1 -1
  14. data/test/fixtures/net_response_invalid_account.yml +25 -0
  15. data/test/fixtures/net_response_success.yml +23 -0
  16. data/test/helper.rb +19 -79
  17. data/test/test_all.rb +17 -0
  18. data/test/test_offline.rb +17 -0
  19. data/test/test_online.rb +19 -0
  20. data/test/testcases/element/bundle.xml +1 -0
  21. data/test/testcases/element/invalid_root.xml +2 -0
  22. data/test/testcases/element/post.xml +2 -0
  23. data/test/testcases/element/post_unshared.xml +2 -0
  24. data/test/testcases/element/tag.xml +1 -0
  25. data/test/testcases/response/bundles_all.xml +5 -0
  26. data/test/testcases/response/bundles_all_empty.xml +2 -0
  27. data/test/testcases/response/bundles_delete.xml +2 -0
  28. data/test/testcases/response/bundles_set.xml +2 -0
  29. data/test/testcases/response/bundles_set_error.xml +2 -0
  30. data/test/testcases/response/posts_add.xml +2 -0
  31. data/test/testcases/response/posts_all.xml +12 -0
  32. data/test/testcases/response/posts_dates.xml +14 -0
  33. data/test/testcases/response/posts_dates_with_tag.xml +14 -0
  34. data/test/testcases/response/posts_delete.xml +2 -0
  35. data/test/testcases/response/posts_get.xml +7 -0
  36. data/test/testcases/response/posts_get_with_tag.xml +6 -0
  37. data/test/testcases/response/posts_recent.xml +19 -0
  38. data/test/testcases/response/posts_recent_with_tag.xml +19 -0
  39. data/test/testcases/response/tags_get.xml +5 -0
  40. data/test/testcases/response/tags_get_empty.xml +2 -0
  41. data/test/testcases/response/tags_rename.xml +2 -0
  42. data/test/testcases/response/update.delicious1.xml +2 -0
  43. data/test/testcases/response/update.xml +3 -0
  44. data/test/unit/bundle_test.rb +62 -0
  45. data/test/unit/delicious_test.rb +186 -238
  46. data/test/unit/online/online_test.rb +147 -0
  47. data/test/unit/post_test.rb +67 -0
  48. data/test/unit/tag_test.rb +68 -0
  49. data/www-delicious.gemspec +146 -0
  50. metadata +85 -31
  51. data/CHANGELOG +0 -5
  52. data/test/unit/delicious_bundle_test.rb +0 -90
  53. data/test/unit/delicious_online_test.rb +0 -143
  54. data/test/unit/delicious_post_test.rb +0 -102
  55. data/test/unit/delicious_tag_test.rb +0 -140
@@ -14,41 +14,60 @@
14
14
  #++
15
15
 
16
16
 
17
- module WWW #:nodoc:
17
+ require 'www/delicious/element'
18
+
19
+
20
+ module WWW
18
21
  class Delicious
19
22
 
20
- class Bundle
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
- public
29
- #
30
- # Creates a new <tt>WWW::Delicious::Bundle</tt> with given +name+
31
- # and adds given array of +tags+ to current tags collection.
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
- # Creates a new <tt>WWW::Delicious::Bundle</tt> from a REXML fragment.
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 self.from_rexml(element)
47
- return new(element.attribute_value(:name) { |v| v.to_s() },
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
@@ -13,7 +13,7 @@
13
13
  #++
14
14
 
15
15
 
16
- module WWW #:nodoc:
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
@@ -14,82 +14,68 @@
14
14
  #++
15
15
 
16
16
 
17
- module WWW #:nodoc:
18
- class Delicious
17
+ require 'www/delicious/element'
18
+
19
19
 
20
- class Post
20
+ module WWW
21
+ class Delicious
22
+
23
+ class Post < Element
21
24
 
22
- # TODO: filter and validate
23
- attr_accessor :url, :title, :notes, :others, :uid, :tags, :time
24
- attr_accessor :replace, :shared
25
+ # The Post URL
26
+ attr_accessor :url
25
27
 
26
- public
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
- public
47
- #
48
- # Initializes <tt>WWW::Delicious::Post</tt> from an +Hash+.
49
- #
50
- def initialize_from_hash(values)
51
- %w(url title notes others udi tags time shared replace).each do |v|
52
- self.instance_variable_set("@#{v}".to_sym(), values[v.to_sym()])
53
- end
54
- self.shared = true if self.shared.nil?
55
- self.replace = true if self.replace.nil?
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
- public
59
- #
60
- # Initializes <tt>WWW::Delicious::Post</tt> from a REXML fragment.
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] = self.url
80
- params[:description] = self.title
81
- params[:extended] = self.notes if self.notes
82
- params[:shared] = self.shared
83
- params[:tags] = self.tags.join(' ') if self.tags
84
- params[:replace] = self.replace
85
- params[:dt] = WWW::Delicious::TIME_CONVERTER.call(self.time) if self.time
86
- return params
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 wheter this object is valid for an API request.
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
@@ -14,82 +14,45 @@
14
14
  #++
15
15
 
16
16
 
17
- module WWW #:nodoc:
17
+ require 'www/delicious/element'
18
+
19
+
20
+ module WWW
18
21
  class Delicious
19
22
 
20
- class Tag
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
- attr_reader :name
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
- attr_reader :count
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
- public
68
- #
69
- # Sets +name+ for this instance to given +value+.
70
- # +value+ is always cast to a +String+.
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
- public
79
- #
80
- # Sets +count+ for this instance to given +value+.
81
- # +value+ is always cast to +Integer+.
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
- return self.name
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
- return !name.empty?
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