ideaoforder-www-delicious 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/CHANGELOG.rdoc +46 -0
  2. data/Manifest +49 -0
  3. data/README.rdoc +209 -0
  4. data/Rakefile +55 -0
  5. data/lib/www/delicious/bundle.rb +73 -0
  6. data/lib/www/delicious/element.rb +73 -0
  7. data/lib/www/delicious/errors.rb +46 -0
  8. data/lib/www/delicious/post.rb +123 -0
  9. data/lib/www/delicious/tag.rb +101 -0
  10. data/lib/www/delicious/version.rb +29 -0
  11. data/lib/www/delicious.rb +949 -0
  12. data/setup.rb +1585 -0
  13. data/test/fixtures/net_response_invalid_account.yml +25 -0
  14. data/test/fixtures/net_response_success.yml +23 -0
  15. data/test/helper.rb +49 -0
  16. data/test/test_all.rb +18 -0
  17. data/test/test_offline.rb +18 -0
  18. data/test/test_online.rb +20 -0
  19. data/test/testcases/element/bundle.xml +1 -0
  20. data/test/testcases/element/invalid_root.xml +2 -0
  21. data/test/testcases/element/post.xml +2 -0
  22. data/test/testcases/element/post_unshared.xml +2 -0
  23. data/test/testcases/element/tag.xml +1 -0
  24. data/test/testcases/response/bundles_all.xml +5 -0
  25. data/test/testcases/response/bundles_all_empty.xml +2 -0
  26. data/test/testcases/response/bundles_delete.xml +2 -0
  27. data/test/testcases/response/bundles_set.xml +2 -0
  28. data/test/testcases/response/bundles_set_error.xml +2 -0
  29. data/test/testcases/response/posts_add.xml +2 -0
  30. data/test/testcases/response/posts_all.xml +12 -0
  31. data/test/testcases/response/posts_dates.xml +14 -0
  32. data/test/testcases/response/posts_dates_with_tag.xml +14 -0
  33. data/test/testcases/response/posts_delete.xml +2 -0
  34. data/test/testcases/response/posts_get.xml +7 -0
  35. data/test/testcases/response/posts_get_with_tag.xml +6 -0
  36. data/test/testcases/response/posts_recent.xml +19 -0
  37. data/test/testcases/response/posts_recent_with_tag.xml +19 -0
  38. data/test/testcases/response/tags_get.xml +5 -0
  39. data/test/testcases/response/tags_get_empty.xml +2 -0
  40. data/test/testcases/response/tags_rename.xml +2 -0
  41. data/test/testcases/response/update.delicious1.xml +2 -0
  42. data/test/testcases/response/update.xml +3 -0
  43. data/test/unit/bundle_test.rb +63 -0
  44. data/test/unit/delicious_test.rb +369 -0
  45. data/test/unit/online/online_test.rb +148 -0
  46. data/test/unit/post_test.rb +68 -0
  47. data/test/unit/tag_test.rb +69 -0
  48. data/www-delicious.gemspec +146 -0
  49. metadata +143 -0
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,46 @@
1
+ = Changelog
2
+
3
+
4
+ == development
5
+
6
+ * CHANGED: Don't use File.dirname(__FILE__) in require statement to prevent recursive inclusions.
7
+
8
+
9
+ == Release 0.2.0
10
+
11
+ * ADDED: :base_uri initialization option allows to create a new instance specifying a custom base_uri for all API calls. This is useful, for example, if you want to use ma.gno.lia Mirror'd APIs (http://wiki.ma.gnolia.com/Mirror%27d_API) instead the del.icio.us one (thanks to Jörg Battermann).
12
+
13
+ * ADDED: two new REXML::Element core extension elements to enhance interaction with node elements.
14
+
15
+ * FIXED: a wrong indentation in README file causes all list items to be rendered as source code.
16
+
17
+ * FIXED: Missing WWW::Delicious::Bundle#to_s method causes a class ID representation to be returned.
18
+
19
+ * FIXED: Missing unit tests for post_ calls (closes #18).
20
+
21
+ * FIXED: Added test for `shared` Post attribute and fixed an issue with duplicate `replace` method definition (closes #11).
22
+
23
+ * CHANGED: improved documentation and added more examples (closes #21).
24
+
25
+ * CHANGED: REXML::Element#attribute_value core extension has been renamed to REXML::Element#if_attribute_value.
26
+
27
+ * CHANGED: Renamed TESTCASE_PATH to TESTCASES_PATH.
28
+
29
+ * CHANGED: WWW::Delicious::Tag, WWW::Delicious::Bundle, WWW::Delicious::Post now extend WWW::Delicious::Element. Simplified classes.
30
+
31
+ * CHANGED: WWW::Delicious::Tag#to_s always returns a string even if name is nil.
32
+
33
+ * CHANGED: WWW::Delicious::Tag :count attribute is now stored and returned as Fixnum instead of String.
34
+
35
+ * CHANGED: Unit test reorganization (closes #22).
36
+
37
+ * CHANGED: Simplified and tidyfied test system with Mocha (closes #19).
38
+
39
+ * CHANGED: Various internal API methods have been renamed for coherence with their new scope.
40
+
41
+ * CHANGED: Integrated Echoe, cleaned Rakefile (closes #23).
42
+
43
+
44
+ == Release 0.1.0 (2008-05-11)
45
+
46
+ * Initial public release.
data/Manifest ADDED
@@ -0,0 +1,49 @@
1
+ CHANGELOG.rdoc
2
+ lib/www/delicious/bundle.rb
3
+ lib/www/delicious/element.rb
4
+ lib/www/delicious/errors.rb
5
+ lib/www/delicious/post.rb
6
+ lib/www/delicious/tag.rb
7
+ lib/www/delicious/version.rb
8
+ lib/www/delicious.rb
9
+ LICENSE.rdoc
10
+ Rakefile
11
+ README.rdoc
12
+ setup.rb
13
+ test/fixtures/net_response_invalid_account.yml
14
+ test/fixtures/net_response_success.yml
15
+ test/helper.rb
16
+ test/test_all.rb
17
+ test/test_offline.rb
18
+ test/test_online.rb
19
+ test/testcases/element/bundle.xml
20
+ test/testcases/element/invalid_root.xml
21
+ test/testcases/element/post.xml
22
+ test/testcases/element/post_unshared.xml
23
+ test/testcases/element/tag.xml
24
+ test/testcases/response/bundles_all.xml
25
+ test/testcases/response/bundles_all_empty.xml
26
+ test/testcases/response/bundles_delete.xml
27
+ test/testcases/response/bundles_set.xml
28
+ test/testcases/response/bundles_set_error.xml
29
+ test/testcases/response/posts_add.xml
30
+ test/testcases/response/posts_all.xml
31
+ test/testcases/response/posts_dates.xml
32
+ test/testcases/response/posts_dates_with_tag.xml
33
+ test/testcases/response/posts_delete.xml
34
+ test/testcases/response/posts_get.xml
35
+ test/testcases/response/posts_get_with_tag.xml
36
+ test/testcases/response/posts_recent.xml
37
+ test/testcases/response/posts_recent_with_tag.xml
38
+ test/testcases/response/tags_get.xml
39
+ test/testcases/response/tags_get_empty.xml
40
+ test/testcases/response/tags_rename.xml
41
+ test/testcases/response/update.delicious1.xml
42
+ test/testcases/response/update.xml
43
+ test/unit/bundle_test.rb
44
+ test/unit/delicious_test.rb
45
+ test/unit/online/online_test.rb
46
+ test/unit/post_test.rb
47
+ test/unit/tag_test.rb
48
+ TODO
49
+ Manifest
data/README.rdoc ADDED
@@ -0,0 +1,209 @@
1
+ = WWW::Delicious
2
+
3
+ http://www-delicious.rubyforge.org/
4
+ http://code.simonecarletti.com/www-delicious
5
+
6
+
7
+ == Description
8
+
9
+ WWW::Delicious is a Ruby client for http://del.icio.us XML API.
10
+
11
+ It provides both read and write functionality. You can read user Posts, Tags
12
+ and Bundles but you can create new Posts, Tags and Bundles as well.
13
+
14
+
15
+ == Authors
16
+
17
+ * {Simone Carletti}[http://www.simonecarletti.com/] <weppos@weppos.net>
18
+ If you like this software, consider to {recommend me}[http://www.workingwithrails.com/person/11967-simone-carletti] at Working with Rails.
19
+
20
+
21
+ == Website
22
+
23
+ * {Homepage}[http://code.simonecarletti.com/www-delicious]
24
+ * {API}[http://www-delicious.rubyforge.org/]
25
+
26
+
27
+ == Source
28
+
29
+ * {at GitHub}[http://github.com/weppos/www-delicious/]
30
+ * {at RubyForge}[http://rubyforge.org/projects/www-delicious/]
31
+
32
+
33
+ == Dependencies
34
+
35
+ * Ruby >= 1.8.6 (not tested with previous versions)
36
+
37
+
38
+ == Download and Installation
39
+
40
+ RubyGems[http://rubyforge.org/projects/rubygems/] is the preferred install method.
41
+ To get the latest version, simply type the following instruction into your command prompt:
42
+
43
+ $ sudo gem install www-delicious
44
+
45
+ Depending on your system, you might need su privileges.
46
+
47
+ To install the library manually, downlad the latest version from
48
+ navigate to the root library directory and enter:
49
+
50
+ $ sudo ruby setup.rb
51
+
52
+ If you need the latest development version you can download the source code
53
+ from one of the GIT repositories listed above.
54
+ Beware that the code might not be as stable as the official release.
55
+
56
+
57
+ == Overview
58
+
59
+ WWW::Delicious maps all the original del.icio.us API calls and provides some
60
+ additional convenient methods to perform common tasks.
61
+ Please read the official documentation (http://del.icio.us/help/api/)
62
+ to learn more about del.icio.us API.
63
+
64
+ WWW::Delicious is 100% compatible with all del.icio.us API constraints,
65
+ including the requirement to set a valid user agent or wait at least
66
+ one second between queries.
67
+ Basically, the main benefit from using this library is that you don't need
68
+ to take care of all these low level details, if you don't want:
69
+ WWW::Delicious will try to give you the most with less efforts.
70
+
71
+
72
+ == Usage
73
+
74
+ In order to use this library you need a valid del.icio.us account.
75
+ Go to http://del.icio.us/ and register for a new account if you don't
76
+ already have one.
77
+
78
+ Then create a valid instance of WWW::Delicious with the account credentials.
79
+
80
+ require 'www/delicious'
81
+
82
+ # create a new instance with given username and password
83
+ d = WWW::Delicious.new('username', 'password')
84
+
85
+ Now you can use your delicious instance to call on of the API methods available.
86
+
87
+
88
+ === Last account update
89
+
90
+ The following example show you how to get the last account update Time.
91
+
92
+ require 'www/delicious'
93
+ d = WWW::Delicious.new('username', 'password')
94
+
95
+ time = d.update # => Fri May 02 18:02:48 UTC 2008
96
+
97
+
98
+ === Reading Posts
99
+
100
+ You can fetch your posts in 3 different ways:
101
+
102
+ require 'www/delicious'
103
+ d = WWW::Delicious.new('username', 'password')
104
+
105
+ # 1. get all posts
106
+ posts = d.posts_all
107
+
108
+ # 2. get recent posts
109
+ posts = d.posts_recent
110
+
111
+ # 3. get a single post (the latest one if no criteria is given)
112
+ posts = d.posts_get(:tag => 'ruby')
113
+
114
+ Each post call accepts some options to refine your search.
115
+ For example, you can always search for posts matching a specific tag.
116
+
117
+ posts = d.posts_all(:tag => 'ruby')
118
+ posts = d.posts_recent(:tag => 'ruby')
119
+ posts = d.posts_get(:tag => 'ruby')
120
+
121
+
122
+ === Creating a new Post
123
+
124
+ require 'www/delicious'
125
+ d = WWW::Delicious.new('username', 'password')
126
+
127
+ # add a post from options
128
+ d.posts_add(:url => 'http://www.simonecarletti.com/', :title => 'Cool site!')
129
+
130
+ # add a post from WWW::Delicious::Post
131
+ d.posts_add(WWW::Delicious::Post.new(:url => 'http://www.simonecarletti.com/', :title => 'Cool site!'))
132
+
133
+
134
+ === Deleting a Posts
135
+
136
+ require 'www/delicious'
137
+ d = WWW::Delicious.new('username', 'password')
138
+
139
+ # delete given post (the URL can be either a string or an URI)
140
+ d.posts_delete('http://www.foobar.com/')
141
+
142
+ Note. Actually you cannot delete a post from a WWW::Delicious::Post instance.
143
+ It means, the following example doesn't work as some ActiveRecord user might expect.
144
+
145
+ post = WWW::Delicious::Post.new(:url => 'http://www.foobar.com/')
146
+ post.delete
147
+
148
+ This feature is already in the TODO list. For now, use the following workaround
149
+ to delete a given Post.
150
+
151
+ # delete a post from an existing post = WWW::Delicious::Post
152
+ d.posts_delete(post.url)
153
+
154
+
155
+ === Tags
156
+
157
+ Working with tags it's really easy. You can get all your tags or rename an existing tag.
158
+
159
+ require 'www/delicious'
160
+ d = WWW::Delicious.new('username', 'password')
161
+
162
+ # get all tags
163
+ tags = d.tags_get
164
+
165
+ # print all tag names
166
+ tags.each { |t| puts t.name }
167
+
168
+ # rename the tag gems to gem
169
+ d.tags_rename('gems', 'gem')
170
+
171
+
172
+ === Bundles
173
+
174
+ WWW::Delicious enables you to get all bundles from given account.
175
+
176
+ require 'www/delicious'
177
+ d = WWW::Delicious.new('username', 'password')
178
+
179
+ # get all bundles
180
+ bundles = d.bundles_all
181
+
182
+ # print all bundle names
183
+ bundles.each { |b| puts b.name }
184
+
185
+ You can also create new bundles or delete existing ones.
186
+
187
+ require 'www/delicious'
188
+ d = WWW::Delicious.new('username', 'password')
189
+
190
+ # set a new bundle for tags ruby, rails and gem
191
+ d.bundles_set('MyBundle', %w(ruby rails gem))
192
+
193
+ # delete the old bundle
194
+ d.bundles_delete('OldBundle')
195
+
196
+
197
+ == FeedBack and Bug reports
198
+
199
+ Feel free to email {Simone Carletti}[mailto:weppos@weppos.net]
200
+ with any questions or feedback.
201
+
202
+ Please submit your bug reports to the Redmine installation for WWW::Delicious
203
+ available at http://code.simonecarletti.com/www-delicious.
204
+
205
+
206
+ == Changelog
207
+
208
+ See CHANGELOG for details.
209
+
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rubygems'
2
+ require 'echoe'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/lib")
5
+ require 'www/delicious'
6
+
7
+
8
+ # Common package properties
9
+ PKG_NAME = ENV['PKG_NAME'] || WWW::Delicious::GEM
10
+ PKG_VERSION = ENV['PKG_VERSION'] || WWW::Delicious::VERSION
11
+ PKG_SUMMARY = "Ruby client for del.icio.us API."
12
+ PKG_FILES = FileList.new("{lib,test}/**/*.rb") do |fl|
13
+ fl.exclude 'TODO'
14
+ fl.include %w(README.rdoc CHANGELOG.rdoc LICENSE.rdoc)
15
+ fl.include %w(Rakefile setup.rb)
16
+ end
17
+ RUBYFORGE_PROJECT = 'www-delicious'
18
+
19
+ if ENV['SNAPSHOT'].to_i == 1
20
+ PKG_VERSION << "." << Time.now.utc.strftime("%Y%m%d%H%M%S")
21
+ end
22
+
23
+
24
+ Echoe.new(PKG_NAME, PKG_VERSION) do |p|
25
+ p.author = "Simone Carletti"
26
+ p.email = "weppos@weppos.net"
27
+ p.summary = PKG_SUMMARY
28
+ p.description = <<-EOF
29
+ WWW::Delicious is a del.icio.us API client implemented in Ruby. \
30
+ It provides access to all available del.icio.us API queries \
31
+ and returns the original XML response as a friendly Ruby object.
32
+ EOF
33
+ p.url = "http://code.simonecarletti.com/www-delicious"
34
+ p.project = RUBYFORGE_PROJECT
35
+
36
+ p.need_zip = true
37
+ p.rcov_options = ["-x Rakefile -x mocha -x rcov"]
38
+ p.rdoc_pattern = /^(lib|CHANGELOG.rdoc|README.rdoc)/
39
+
40
+ p.development_dependencies = ["rake >=0.8",
41
+ "echoe >=3",
42
+ "mocha >=0.9"]
43
+ end
44
+
45
+
46
+ begin
47
+ require 'code_statistics'
48
+ desc "Show library's code statistics"
49
+ task :stats do
50
+ CodeStatistics.new(["WWW::Delicious", "lib"],
51
+ ["Tests", "test"]).to_s
52
+ end
53
+ rescue LoadError
54
+ puts "CodeStatistics (Rails) is not available"
55
+ end
@@ -0,0 +1,73 @@
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
+ # SVN: $Id$
14
+ #++
15
+
16
+
17
+ require 'www/delicious/element'
18
+
19
+
20
+ module WWW
21
+ class Delicious
22
+
23
+ #
24
+ # = Delicious Bundle
25
+ #
26
+ # Represents a single Bundle element.
27
+ #
28
+ class Bundle < Element
29
+
30
+ # The name of the bundle.
31
+ attr_accessor :name
32
+
33
+ # The collection of <tt>WWW::Delicious::Tags</tt>.
34
+ attr_accessor :tags
35
+
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?
41
+ end
42
+
43
+ #
44
+ # Returns a string representation of this Bundle.
45
+ # In case name is nil this method will return an empty string.
46
+ #
47
+ def to_s
48
+ name.to_s
49
+ end
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
+
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,73 @@
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
+ # 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
+
59
+ class << self
60
+
61
+ #
62
+ # Creates and returns new instance from a REXML +element+.
63
+ #
64
+ def from_rexml(element, options)
65
+ raise NotImplementedError
66
+ end
67
+
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,46 @@
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
+ # SVN: $Id$
14
+ #++
15
+
16
+
17
+ module WWW
18
+ class Delicious
19
+
20
+
21
+ #
22
+ # = WWW::Delicious::Error
23
+ #
24
+ # Base exception for all WWW::Delicious errors.
25
+ #
26
+ class Error < StandardError; end
27
+
28
+ #
29
+ # = WWW::Delicious::HTTPError
30
+ #
31
+ # HTTP connection related error.
32
+ # Raised when an HTTP request fails or in case of unexpected behavior.
33
+ #
34
+ class HTTPError < Error; end
35
+
36
+ #
37
+ # = WWW::Delicious::ResponseError
38
+ #
39
+ # Response related error.
40
+ # Usually raised in case of a malformed, invalid or empty XML response.
41
+ #
42
+ class ResponseError < Error; end
43
+
44
+
45
+ end
46
+ end
@@ -0,0 +1,123 @@
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
+ require 'www/delicious/element'
18
+
19
+
20
+ module WWW
21
+ class Delicious
22
+
23
+ class Post < Element
24
+
25
+ # The Post URL
26
+ attr_accessor :url
27
+
28
+ # The title of the Post
29
+ attr_accessor :title
30
+
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
+ end
57
+
58
+ # Returns the value for <tt>replace</tt> attribute.
59
+ def replace
60
+ !(@replace == false)
61
+ end
62
+
63
+ # Returns a params-style representation suitable for API calls.
64
+ def to_params()
65
+ params = {}
66
+ params[:url] = url # this could/should convert back from URI object (MD)
67
+ params[:description] = title
68
+ params[:extended] = notes if notes
69
+ params[:shared] = 'no' if !shared # (MD)
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
74
+ end
75
+
76
+
77
+ #
78
+ # Returns whether this object is valid for an API request.
79
+ #
80
+ # To be valid +url+ and +title+ must not be empty.
81
+ #
82
+ # === Examples
83
+ #
84
+ # post = WWW::Delicious::Post.new(:url => 'http://localhost', :title => 'foo')
85
+ # post.api_valid?
86
+ # # => true
87
+ #
88
+ # post = WWW::Delicious::Post.new(:url => 'http://localhost')
89
+ # post.api_valid?
90
+ # # => false
91
+ #
92
+ def api_valid?
93
+ return !(url.nil? or url.empty? or title.nil? or title.empty?)
94
+ end
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) } - this was breaking a lot of the API calls (MD)
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
+
120
+ end
121
+
122
+ end
123
+ end