kippt 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.travis.yml +1 -0
  2. data/CHANGELOG.md +8 -0
  3. data/Gemfile +2 -0
  4. data/README.md +20 -3
  5. data/TODO.md +43 -0
  6. data/kippt.gemspec +6 -6
  7. data/lib/kippt/client.rb +46 -8
  8. data/lib/kippt/clip.rb +83 -4
  9. data/lib/kippt/clip_collection.rb +4 -0
  10. data/lib/kippt/clips.rb +8 -4
  11. data/lib/kippt/collection.rb +22 -9
  12. data/lib/kippt/collection_resource.rb +25 -8
  13. data/lib/kippt/comment.rb +25 -0
  14. data/lib/kippt/comment_collection.rb +10 -0
  15. data/lib/kippt/comments.rb +43 -0
  16. data/lib/kippt/connection.rb +14 -8
  17. data/lib/kippt/follow_relationship.rb +50 -0
  18. data/lib/kippt/followers.rb +26 -0
  19. data/lib/kippt/following.rb +26 -0
  20. data/lib/kippt/like.rb +48 -0
  21. data/lib/kippt/likes.rb +48 -0
  22. data/lib/kippt/list.rb +29 -4
  23. data/lib/kippt/list_collection.rb +4 -0
  24. data/lib/kippt/resource.rb +106 -9
  25. data/lib/kippt/saves.rb +25 -0
  26. data/lib/kippt/user.rb +59 -0
  27. data/lib/kippt/user_clips.rb +39 -0
  28. data/lib/kippt/user_collection.rb +14 -0
  29. data/lib/kippt/user_lists.rb +32 -0
  30. data/lib/kippt/users.rb +51 -0
  31. data/lib/kippt/version.rb +1 -1
  32. data/spec/fixtures/clip.json +1 -1
  33. data/spec/fixtures/comment.json +1 -0
  34. data/spec/fixtures/comments.json +1 -0
  35. data/spec/fixtures/feed.json +1 -0
  36. data/spec/fixtures/list.json +1 -1
  37. data/spec/fixtures/user.json +1 -0
  38. data/spec/fixtures/users.json +2 -0
  39. data/spec/fixtures/users_with_multiple_pages.json +1 -0
  40. data/spec/kippt/client_spec.rb +63 -8
  41. data/spec/kippt/clip_collection_spec.rb +3 -3
  42. data/spec/kippt/clip_spec.rb +109 -4
  43. data/spec/kippt/clips_spec.rb +18 -7
  44. data/spec/kippt/comment_spec.rb +25 -0
  45. data/spec/kippt/comments_spec.rb +103 -0
  46. data/spec/kippt/follow_relationship_spec.rb +34 -0
  47. data/spec/kippt/followers_spec.rb +17 -0
  48. data/spec/kippt/following_spec.rb +17 -0
  49. data/spec/kippt/list_collection_spec.rb +3 -3
  50. data/spec/kippt/list_spec.rb +92 -6
  51. data/spec/kippt/lists_spec.rb +2 -1
  52. data/spec/kippt/saves_spec.rb +20 -0
  53. data/spec/kippt/user_clips_spec.rb +29 -0
  54. data/spec/kippt/user_collection_spec.rb +14 -0
  55. data/spec/kippt/user_lists_spec.rb +13 -0
  56. data/spec/kippt/user_spec.rb +71 -0
  57. data/spec/kippt/users_spec.rb +59 -0
  58. data/spec/spec_helper.rb +60 -4
  59. metadata +106 -24
  60. data/lib/kippt/account.rb +0 -10
  61. data/spec/kippt/account_spec.rb +0 -28
@@ -2,6 +2,7 @@ language: ruby
2
2
  rvm:
3
3
  - 1.8.7
4
4
  - 1.9.3
5
+ - 2.0.0
5
6
  - jruby-18mode
6
7
  - jruby-19mode
7
8
  - rbx-18mode
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0 / July 7, 2013
4
+
5
+ After being long time in development this update adds support for all the
6
+ [new Kippt APIs](http://blog.kippt.com/2013/04/10/say-hi-to-api-and-apps/).
7
+
8
+ README has been updated to reflect the additions to the API. There has also
9
+ been plenty of refactoring done under the covers.
10
+
3
11
  ## 1.1 / July 20, 2012
4
12
 
5
13
  Changes in response to feedback from [Matias Korhonen](https://github.com/k33l0r):
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ gem "rake"
4
+
3
5
  platform :jruby do
4
6
  gem "jruby-openssl"
5
7
  end
data/README.md CHANGED
@@ -49,19 +49,26 @@ client = Kippt::Client.new(username: "vesan", token: "2544d6bfddf5893ec8617")
49
49
  # Methods called on `client` will use the passed credentials
50
50
  ```
51
51
 
52
+ Or you can use the API unauthenticated:
53
+
54
+ ```ruby
55
+ client = Kippt::Client.new(unauthenticated: true)
56
+ ```
57
+
52
58
 
53
59
  ### Account
54
60
 
55
- You can get the account details (username and token):
61
+ You can get the current authenticated user:
56
62
 
57
63
  ```ruby
58
64
  client = Kippt::Client.new(username: "vesan", token: "2544d6bfddf5893ec8617")
59
65
  account = client.account
60
66
  account.username #=> "vesan"
61
- account.token #=> "2544d6bfddf5893ec8617"
67
+ account = client.account(true) # includes the API token
68
+ account.api_token #=> "2544d6bfddf5893ec8617"
62
69
  ```
63
70
 
64
- Always use token instead of the password if possible because it's more secure.
71
+ Always use the API token instead of the password if possible because it's more secure.
65
72
 
66
73
 
67
74
  ### Resources
@@ -168,6 +175,16 @@ clip = client.clips[clip_id]
168
175
  clip.destroy #=> true
169
176
  ```
170
177
 
178
+ ### Debugging
179
+
180
+ To get more information on what is going on under the covers, set `DEBUG=true`
181
+ as environment variable or pass `debug: true` in the Kippt::Client options hash
182
+ like:
183
+
184
+ ```ruby
185
+ client = Kippt::Client.new(unauthenticated: true, debug: true)
186
+ ```
187
+
171
188
 
172
189
  ## Contributing
173
190
 
data/TODO.md ADDED
@@ -0,0 +1,43 @@
1
+ * [DONE] Adding support for unauthenticated requests
2
+ * [DONE] Timestamps as time
3
+ * Better exceptions
4
+
5
+ # Clip
6
+
7
+ * [DONE] Getting the feed of authenticated user
8
+ * [DONE] Getting the user of the clip
9
+ * [DONE] Support for including list & via data
10
+ * [DONE] Getting the list of the clip
11
+ * [DONE] Getting the original clip the clip was created via
12
+ * [DONE] Getting the comments of a clip
13
+ * [DONE] Getting the likes of a clip
14
+ * [DONE] Getting the saves of a clip
15
+ * [DONE] Getting and setting is favorited (How does is starred work with it?)
16
+ * [DONE] Getting the media of the clip (experimental)
17
+ * [DONE] Getting the type of the clip
18
+ * [DONE] Getting the favicon url of the clip
19
+ * [DONE] Getting the app url fo the clip
20
+
21
+ # User
22
+
23
+ * [DONE] Support for all the user API's (still missing following/unfollowing users)
24
+ * [DONE] Getting the user for the authenticated user
25
+ * [DONE] Getting the embedded user for likes
26
+ * [DONE] Getting the counts
27
+
28
+ # List
29
+
30
+ * [DONE] Support for is private
31
+ * [DONE] Getting the user
32
+ * [DONE] Getting & setting the description
33
+ * [DONE] Getting the collaborators of the list
34
+ * [DONE] Getting the app url fo the clip
35
+ * [DONE] Getting the rss url fo the clip
36
+ * [DONE] Add support for following and unfollowing a list
37
+ * [DONE] Handle "List not found" error
38
+
39
+ # Comment
40
+
41
+ * [DONE] Add support for comments
42
+
43
+
@@ -15,11 +15,11 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Kippt::VERSION
17
17
 
18
- gem.add_dependency "faraday", "~> 0.7.6"
19
- gem.add_dependency "faraday_middleware", "~> 0.8.7"
20
- gem.add_dependency "multi_json", "~> 1.3.4"
18
+ gem.add_dependency "faraday", "~> 0.8"
19
+ gem.add_dependency "faraday_middleware", "~> 0.8"
20
+ gem.add_dependency "multi_json", "~> 1.3"
21
21
 
22
- gem.add_development_dependency "rspec", "~> 2.9.0"
23
- gem.add_development_dependency "webmock", "~> 1.8.6"
24
- gem.add_development_dependency "simplecov", "~> 0.6.4"
22
+ gem.add_development_dependency "rspec", "~> 2.9"
23
+ gem.add_development_dependency "webmock", "~> 1.11"
24
+ gem.add_development_dependency "simplecov", "~> 0.7"
25
25
  end
@@ -1,7 +1,7 @@
1
1
  require "kippt/connection"
2
- require "kippt/account"
3
2
  require "kippt/clips"
4
3
  require "kippt/lists"
4
+ require "kippt/users"
5
5
 
6
6
  class Kippt::Client
7
7
  include Kippt::Connection
@@ -9,18 +9,42 @@ class Kippt::Client
9
9
  attr_reader :username, :token, :password
10
10
 
11
11
  def initialize(options = {})
12
- @username = options.fetch(:username) { raise ArgumentError.new("username is required") }
12
+ self.debug = options.fetch(:debug, nil)
13
13
 
14
- @password = options.fetch(:password) { nil }
15
- @token = options.fetch(:token) { nil }
14
+ if options[:unauthenticated]
15
+ # Unauthenticated
16
+ else
17
+ @username = options.fetch(:username) { raise ArgumentError.new("username is required") }
16
18
 
17
- if @password.nil? && @token.nil?
18
- raise ArgumentError.new("password or token is required")
19
+ @password = options.fetch(:password) { nil }
20
+ @token = options.fetch(:token) { nil }
21
+
22
+ if @password.nil? && @token.nil?
23
+ raise ArgumentError.new("password or token is required")
24
+ end
19
25
  end
20
26
  end
21
27
 
22
- def account
23
- Kippt::Account.new(get("account").body)
28
+ def debug=(value)
29
+ @debug = value
30
+ end
31
+
32
+ def debug
33
+ if @debug.nil?
34
+ !!ENV["DEBUG"]
35
+ else
36
+ @debug
37
+ end
38
+ end
39
+ alias_method :debug?, :debug
40
+
41
+ def account(include_api_token = false)
42
+ if include_api_token
43
+ url = "account?include_data=api_token"
44
+ else
45
+ url = "account"
46
+ end
47
+ Kippt::User.new(get(url).body, self)
24
48
  end
25
49
 
26
50
  def lists
@@ -30,4 +54,18 @@ class Kippt::Client
30
54
  def clips
31
55
  Kippt::Clips.new(self)
32
56
  end
57
+
58
+ def users
59
+ Kippt::Users.new(self)
60
+ end
61
+
62
+ def collection_resource_for(resource_class, *options)
63
+ resource_class.new(*([self] + options))
64
+ end
65
+
66
+ def resource_from_url(resource_class, url)
67
+ raise ArgumentError.new("The parameter URL can't be blank") if url.nil? || url == ""
68
+
69
+ resource_class.new(self.get(url).body, self)
70
+ end
33
71
  end
@@ -1,11 +1,90 @@
1
- require "ostruct"
2
1
  require "kippt/resource"
2
+ require "kippt/list"
3
+ require "kippt/comments"
4
+ require "kippt/likes"
5
+ require "kippt/saves"
6
+ require "kippt/user"
3
7
 
4
8
  class Kippt::Clip
5
9
  include Kippt::Resource
6
10
 
7
- attributes :url_domain, :updated, :is_starred, :title,
8
- :url, :notes, :created, :list, :id, :resource_uri
11
+ attributes :url_domain, :is_starred, :title,
12
+ :url, :notes, :id, :resource_uri,
13
+ :type, :favicon_url, :app_url, :media,
14
+ :updated => Time, :created => Time,
15
+ :user => Kippt::User
9
16
 
10
- writable_attributes :is_starred, :title, :url, :notes, :list
17
+ writable_attributes :is_favorite, :title, :url, :notes, :list
18
+
19
+ boolean_attributes :is_favorite
20
+
21
+ alias :is_starred :is_favorite
22
+ alias :is_starred= :is_favorite=
23
+ alias :starred? :favorite?
24
+
25
+ embedded_attributes :list => "Kippt::List", :via => "Kippt::Clip"
26
+
27
+ def collection_resource_class
28
+ Kippt::Clips
29
+ end
30
+
31
+ def list_uri
32
+ if attributes.list.is_a? String
33
+ attributes.list
34
+ else
35
+ list.resource_uri
36
+ end
37
+ end
38
+
39
+ def comments
40
+ Kippt::Comments.new(client, self)
41
+ end
42
+
43
+ def all_comments_embedded?
44
+ comments_count == comments_data.size
45
+ end
46
+
47
+ def comments_count
48
+ attributes.comments["count"]
49
+ end
50
+
51
+ def comments_data
52
+ attributes.comments["data"]
53
+ end
54
+
55
+ def likes
56
+ Kippt::Likes.new(client, self)
57
+ end
58
+
59
+ def all_likes_embedded?
60
+ likes_count == likes_data.size
61
+ end
62
+
63
+ def likes_count
64
+ attributes.likes["count"]
65
+ end
66
+
67
+ def likes_data
68
+ attributes.likes["data"]
69
+ end
70
+
71
+ def saves
72
+ Kippt::Saves.new(client, self)
73
+ end
74
+
75
+ def saves_count
76
+ attributes.saves["count"]
77
+ end
78
+
79
+ def saves_data
80
+ attributes.saves["data"]
81
+ end
82
+
83
+ def like
84
+ Kippt::Like.new(client, self).save
85
+ end
86
+
87
+ def unlike
88
+ Kippt::Like.new(client, self).destroy
89
+ end
11
90
  end
@@ -7,4 +7,8 @@ class Kippt::ClipCollection
7
7
  def object_class
8
8
  Kippt::Clip
9
9
  end
10
+
11
+ def collection_resource_class
12
+ Kippt::Clips
13
+ end
10
14
  end
@@ -27,17 +27,21 @@ class Kippt::Clips
27
27
  "clips"
28
28
  end
29
29
 
30
+ def feed
31
+ Kippt::ClipCollection.new(client.get("clips/feed").body, client)
32
+ end
33
+
30
34
  def search(parameters)
31
35
  if parameters.is_a?(String)
32
36
  Kippt::ClipCollection.new(
33
- @client.get("search/clips", {:q => parameters}).body,
34
- self)
37
+ client.get("search/clips", {:q => parameters}).body,
38
+ client)
35
39
  else
36
40
  validate_search_parameters(parameters)
37
41
 
38
42
  Kippt::ClipCollection.new(
39
- @client.get("search/clips", parameters).body,
40
- self)
43
+ client.get("search/clips", parameters).body,
44
+ client)
41
45
  end
42
46
  end
43
47
 
@@ -3,21 +3,24 @@ module Kippt::Collection
3
3
 
4
4
  attr_reader :total_count, :limit, :offset
5
5
 
6
- def initialize(data, collection_resource = nil)
7
- meta = data.fetch("meta")
8
- @limit = meta.fetch("limit")
9
- @offset = meta.fetch("offset")
6
+ def initialize(data, client = nil)
7
+ meta = data.fetch("meta") { {} }
8
+ @limit = meta.fetch("limit") { nil }
9
+ @offset = meta.fetch("offset") { nil }
10
10
  @next = meta.fetch("next") { nil }
11
11
  @previous = meta.fetch("previous") { nil }
12
- @total_count = meta.fetch("total_count")
12
+ @total_count = meta.fetch("total_count") { nil }
13
13
 
14
- @collection_resource = collection_resource
14
+ @client = client
15
15
 
16
16
  @object_data = data.fetch("objects")
17
17
  end
18
18
 
19
+ extend Forwardable
20
+ def_delegators :objects, :size, :length
21
+
19
22
  def objects
20
- @objects ||= @object_data.map {|data| object_class.new(data, @collection_resource) }
23
+ @objects ||= @object_data.map {|data| object_class.new(data, client) }
21
24
  end
22
25
 
23
26
  def [](index)
@@ -35,7 +38,7 @@ module Kippt::Collection
35
38
  def next_page
36
39
  raise Kippt::APIError.new("There is no next page") if @next.nil? || @next == ""
37
40
 
38
- @collection_resource.collection_from_url(@next)
41
+ collection_resource.collection_from_url(@next)
39
42
  end
40
43
 
41
44
  def previous_page?
@@ -46,7 +49,17 @@ module Kippt::Collection
46
49
  def previous_page
47
50
  raise Kippt::APIError.new("There is no previous page") if @previous.nil? || @previous == ""
48
51
 
49
- @collection_resource.collection_from_url(@previous)
52
+ collection_resource.collection_from_url(@previous)
50
53
  end
51
54
  alias_method :prev_page, :previous_page
55
+
56
+ private
57
+
58
+ def collection_resource
59
+ @collection_resource ||= client.collection_resource_for(collection_resource_class)
60
+ end
61
+
62
+ def client
63
+ @client
64
+ end
52
65
  end
@@ -1,16 +1,29 @@
1
1
  module Kippt::CollectionResource
2
+ # For certain objects you can get extra data by giving option `include_data`.
3
+ # For example with clips you can add `include_data: "list,via"`.
2
4
  def all(options = {})
3
5
  validate_collection_options(options)
4
6
 
5
- collection_class.new(@client.get(base_uri, options).body, self)
7
+ collection_class.new(client.get(base_uri, options).body, client)
6
8
  end
7
9
 
8
10
  def build(attributes = {})
9
- object_class.new(attributes, self)
11
+ object_class.new(attributes, client)
10
12
  end
11
13
 
12
- def [](resource_id)
13
- object_class.new(@client.get("#{base_uri}/#{resource_id}").body)
14
+ def create(attributes = {})
15
+ build(attributes).save
16
+ end
17
+
18
+ # For certain objects you can get extra data by giving option `include_data`.
19
+ # For example with clips you can add `include_data: "list,via"`.
20
+ def [](resource_id, options = {})
21
+ response = client.get("#{base_uri}/#{resource_id}", options)
22
+ if response.success?
23
+ object_class.new(response.body, client)
24
+ else
25
+ raise Kippt::APIError.new("Resource could not be loaded: #{response.body["message"]}")
26
+ end
14
27
  end
15
28
 
16
29
  alias find []
@@ -18,14 +31,14 @@ module Kippt::CollectionResource
18
31
  def collection_from_url(url)
19
32
  raise ArgumentError.new("The parameter URL can't be blank") if url.nil? || url == ""
20
33
 
21
- collection_class.new(@client.get(url).body, self)
34
+ collection_class.new(client.get(url).body, client)
22
35
  end
23
36
 
24
37
  def save_resource(object)
25
38
  if object.id
26
- response = @client.put("#{base_uri}/#{object.id}", :data => writable_parameters_from(object))
39
+ response = client.put("#{base_uri}/#{object.id}", :data => writable_parameters_from(object))
27
40
  else
28
- response = @client.post("#{base_uri}", :data => writable_parameters_from(object))
41
+ response = client.post("#{base_uri}", :data => writable_parameters_from(object))
29
42
  end
30
43
 
31
44
  save_response = {:success => response.success?}
@@ -39,7 +52,7 @@ module Kippt::CollectionResource
39
52
 
40
53
  def destroy_resource(resource)
41
54
  if resource.id
42
- @client.delete("#{base_uri}/#{resource.id}").success?
55
+ client.delete("#{base_uri}/#{resource.id}").success?
43
56
  end
44
57
  end
45
58
 
@@ -56,4 +69,8 @@ module Kippt::CollectionResource
56
69
  def writable_parameters_from(resource)
57
70
  resource.writable_attributes_hash
58
71
  end
72
+
73
+ def client
74
+ @client
75
+ end
59
76
  end