kippt 1.1.0 → 2.0.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.
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
@@ -0,0 +1,25 @@
1
+ require "kippt/resource"
2
+ require "kippt/user"
3
+ require "kippt/clip"
4
+
5
+ class Kippt::Comment
6
+ include Kippt::Resource
7
+
8
+ attributes :body, :id, :resource_uri,
9
+ :created => Time, :user => Kippt::User
10
+
11
+ writable_attributes :body
12
+
13
+ attr_reader :clip
14
+
15
+ def initialize(attributes = {}, client = nil, clip = nil)
16
+ super(attributes, client)
17
+ @clip = clip
18
+ end
19
+
20
+ private
21
+
22
+ def collection_resource
23
+ @collection_resource ||= client.collection_resource_for(Kippt::Comments, clip)
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ require "kippt/collection"
2
+ require "kippt/comment"
3
+
4
+ class Kippt::CommentCollection
5
+ include Kippt::Collection
6
+
7
+ def object_class
8
+ Kippt::Comment
9
+ end
10
+ end
@@ -0,0 +1,43 @@
1
+ require "kippt/comment_collection"
2
+ require "kippt/comment"
3
+
4
+ class Kippt::Comments
5
+ include Kippt::CollectionResource
6
+
7
+ attr_reader :clip
8
+
9
+ def initialize(client, clip)
10
+ @client = client
11
+ @clip = clip
12
+ end
13
+
14
+ def self.valid_filter_parameters
15
+ [:limit, :offset]
16
+ end
17
+
18
+ def object_class
19
+ Kippt::Comment
20
+ end
21
+
22
+ def collection_class
23
+ Kippt::CommentCollection
24
+ end
25
+
26
+ def base_uri
27
+ "clips/#{clip.id}/comments"
28
+ end
29
+
30
+ def all(options = {})
31
+ validate_collection_options(options)
32
+
33
+ if options.empty? && @clip.all_comments_embedded?
34
+ collection_class.new({"objects" => @clip.comments_data}, client)
35
+ else
36
+ collection_class.new(client.get(base_uri, options).body, client)
37
+ end
38
+ end
39
+
40
+ def build(attributes = {})
41
+ object_class.new(attributes, client, clip)
42
+ end
43
+ end
@@ -2,6 +2,8 @@ require "multi_json"
2
2
  require "faraday_middleware/response_middleware"
3
3
 
4
4
  module Kippt::Connection
5
+ HOST = "kippt.com"
6
+
5
7
  class ParseMultiJson < FaradayMiddleware::ResponseMiddleware
6
8
  define_parser do |body|
7
9
  begin
@@ -31,22 +33,26 @@ module Kippt::Connection
31
33
  private
32
34
 
33
35
  def connection
34
- @connection ||= Faraday.new("https://kippt.com/api") do |builder|
36
+ @connection ||= Faraday.new("https://#{HOST}/api") do |builder|
35
37
  builder.use Kippt::Connection::ParseMultiJson
36
- # builder.use Faraday::Response::Logger
38
+ builder.use Faraday::Response::Logger if debug?
37
39
  builder.adapter Faraday.default_adapter
38
40
  end
39
41
  end
40
42
 
41
43
  def request(method, url, options)
44
+ if @password
45
+ connection.basic_auth(@username, @password)
46
+ end
47
+
42
48
  response = connection.send(method) do |req|
43
49
  set_default_headers(req)
44
50
 
45
- if @password
46
- connection.basic_auth(@username, @password)
47
- else
48
- req.headers["X-Kippt-Username"] = @username
49
- req.headers["X-Kippt-API-Token"] = @token
51
+ unless @password
52
+ if @username && @token
53
+ req.headers["X-Kippt-Username"] = @username
54
+ req.headers["X-Kippt-API-Token"] = @token
55
+ end
50
56
  end
51
57
 
52
58
  if method == :get
@@ -56,7 +62,7 @@ module Kippt::Connection
56
62
  req.body = MultiJson.dump(options[:data])
57
63
  end
58
64
  end
59
-
65
+
60
66
  if response.status == 401
61
67
  raise Kippt::APIError.new(response.body["message"])
62
68
  end
@@ -0,0 +1,50 @@
1
+ class Kippt::FollowRelationship
2
+ attr_reader :user
3
+
4
+ def initialize(client, user)
5
+ @client = client
6
+ @user = user
7
+ end
8
+
9
+ def following?
10
+ response = client.get("users/#{user.id}/relationship/")
11
+
12
+ if response.success?
13
+ response.body["following"]
14
+ else
15
+ raise Kippt::APIError.new("Resource could not be loaded: #{response.body["message"]}")
16
+ end
17
+ end
18
+
19
+ def follow
20
+ response = update_following(true)
21
+
22
+ if response.success?
23
+ true
24
+ else
25
+ raise Kippt::APIError.new("Problem with following: #{response.body["message"]}")
26
+ end
27
+ end
28
+
29
+ def unfollow
30
+ response = update_following(false)
31
+
32
+ if response.success?
33
+ true
34
+ else
35
+ raise Kippt::APIError.new("Problem with unfollowing: #{response.body["message"]}")
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def update_following(value)
42
+ follow_value = value ? "follow" : "unfollow"
43
+
44
+ client.post("users/#{user.id}/relationship/", :data => {:action => follow_value})
45
+ end
46
+
47
+ def client
48
+ @client
49
+ end
50
+ end
@@ -0,0 +1,26 @@
1
+ require "kippt/collection_resource"
2
+ require "kippt/user_collection"
3
+ require "kippt/user"
4
+
5
+ class Kippt::Followers
6
+ include Kippt::CollectionResource
7
+
8
+ attr_reader :user
9
+
10
+ def initialize(client, user)
11
+ @client = client
12
+ @user = user
13
+ end
14
+
15
+ def object_class
16
+ Kippt::User
17
+ end
18
+
19
+ def collection_class
20
+ Kippt::UserCollection
21
+ end
22
+
23
+ def base_uri
24
+ "users/#{user.id}/followers"
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ require "kippt/collection_resource"
2
+ require "kippt/user_collection"
3
+ require "kippt/user"
4
+
5
+ class Kippt::Following
6
+ include Kippt::CollectionResource
7
+
8
+ attr_reader :user
9
+
10
+ def initialize(client, user)
11
+ @client = client
12
+ @user = user
13
+ end
14
+
15
+ def object_class
16
+ Kippt::User
17
+ end
18
+
19
+ def collection_class
20
+ Kippt::UserCollection
21
+ end
22
+
23
+ def base_uri
24
+ "users/#{user.id}/following"
25
+ end
26
+ end
@@ -0,0 +1,48 @@
1
+ require "kippt/users"
2
+
3
+ class Kippt::Like
4
+ def initialize(client, clip)
5
+ @client = client
6
+ @errors = []
7
+ @clip = clip
8
+ end
9
+
10
+ def id
11
+ nil
12
+ end
13
+
14
+ def collection_resource_class
15
+ Kippt::Likes
16
+ end
17
+
18
+ def writable_attributes_hash
19
+ nil
20
+ end
21
+
22
+ def save
23
+ @errors = []
24
+ response = collection_resource.save_resource(self)
25
+ if response[:error_message]
26
+ errors << response[:error_message]
27
+ end
28
+ response[:success]
29
+ end
30
+
31
+ def destroy
32
+ collection_resource.destroy_resource(self)
33
+ end
34
+
35
+ private
36
+
37
+ def collection_resource
38
+ @collection_resource ||= client.collection_resource_for(collection_resource_class, clip)
39
+ end
40
+
41
+ def client
42
+ @client
43
+ end
44
+
45
+ def clip
46
+ @clip
47
+ end
48
+ end
@@ -0,0 +1,48 @@
1
+ require "kippt/user_collection"
2
+ require "kippt/user"
3
+ require "kippt/like"
4
+
5
+ class Kippt::Likes
6
+ include Kippt::CollectionResource
7
+
8
+ attr_reader :clip
9
+
10
+ def initialize(client, clip)
11
+ @client = client
12
+ @clip = clip
13
+ end
14
+
15
+ def self.valid_filter_parameters
16
+ []
17
+ end
18
+
19
+ def object_class
20
+ Kippt::User
21
+ end
22
+
23
+ def collection_class
24
+ Kippt::UserCollection
25
+ end
26
+
27
+ def base_uri
28
+ "clips/#{clip.id}/likes"
29
+ end
30
+
31
+ def all(options = {})
32
+ validate_collection_options(options)
33
+
34
+ if options.empty? && @clip.all_likes_embedded?
35
+ collection_class.new({"objects" => @clip.likes_data}, client)
36
+ else
37
+ collection_class.new(client.get(base_uri, options).body, client)
38
+ end
39
+ end
40
+
41
+ def build
42
+ Kippt::Like.new(client, clip)
43
+ end
44
+
45
+ def destroy_resource(resource)
46
+ client.delete(base_uri).success?
47
+ end
48
+ end
@@ -1,10 +1,35 @@
1
- require "ostruct"
1
+ require "kippt/user"
2
2
 
3
3
  class Kippt::List
4
4
  include Kippt::Resource
5
5
 
6
- attributes :id, :rss_url, :updated, :title,
7
- :created, :slug, :resource_uri
6
+ attributes :app_url, :id, :rss_url, :title,
7
+ :slug, :resource_uri, :description,
8
+ :updated => Time, :created => Time,
9
+ :user => Kippt::User
10
+ boolean_attributes :is_private
8
11
 
9
- writable_attributes :title
12
+ writable_attributes :title, :description
13
+
14
+ def collection_resource_class
15
+ Kippt::Lists
16
+ end
17
+
18
+ def collaborators
19
+ attributes.collaborators["data"].map {|collborator_data|
20
+ Kippt::User.new(collborator_data, client)
21
+ }
22
+ end
23
+
24
+ def follow
25
+ response = client.post("#{resource_uri}relationship", :data => {:action => "follow"})
26
+ raise Kippt::APIError.new("There was an error with the request: #{response.body["message"]}") unless response.success?
27
+ response.success?
28
+ end
29
+
30
+ def unfollow
31
+ response = client.post("#{resource_uri}relationship", :data => {:action => "unfollow"})
32
+ raise Kippt::APIError.new("There was an error with the request: #{response.body["message"]}") unless response.success?
33
+ response.success?
34
+ end
10
35
  end
@@ -7,4 +7,8 @@ class Kippt::ListCollection
7
7
  def object_class
8
8
  Kippt::List
9
9
  end
10
+
11
+ def collection_resource_class
12
+ Kippt::Lists
13
+ end
10
14
  end
@@ -1,10 +1,12 @@
1
+ require "ostruct"
2
+
1
3
  module Kippt::Resource
2
4
  def self.included(base)
3
5
  base.instance_eval do
4
6
  extend Forwardable
5
7
  attr_reader :attributes, :errors
6
8
 
7
- def_delegators "self.class", :writable_attribute_names, :attribute_names
9
+ def_delegators "self.class", :writable_attribute_names, :attribute_names, :embedded_attribute_names
8
10
  end
9
11
 
10
12
  base.extend(ClassMethods)
@@ -13,31 +15,116 @@ module Kippt::Resource
13
15
  module ClassMethods
14
16
  attr_reader :writable_attribute_names, :attribute_names
15
17
 
18
+ def embedded_attribute_names
19
+ @embedded_attribute_names || []
20
+ end
21
+
16
22
  def attributes(*attribs)
17
- @attribute_names = attribs.map {|attrib| attrib.to_sym }
18
- def_delegators :attributes, *@attribute_names
23
+ @attribute_names ||= []
24
+ hashes, other = attribs.partition {|attrib| attrib.is_a? Hash }
25
+
26
+ attribute_names = convert_to_symbols(other)
27
+ def_delegators :attributes, *attribute_names
28
+ @attribute_names += attribute_names
29
+
30
+ mappings = hashes.reduce({}, :update)
31
+ mappings.each do |attrib, object_class|
32
+ if object_class.to_s == "Time"
33
+ define_method(attrib) do
34
+ Time.at(attributes.send(attrib))
35
+ end
36
+ else
37
+ reified_class = _get_class(object_class)
38
+ define_method(attrib) do
39
+ value = attributes.send(attrib)
40
+ reified_class.new(value) unless value.nil?
41
+ end
42
+ end
43
+ end
44
+ @attribute_names += convert_to_symbols(mappings.keys)
45
+ end
46
+
47
+ def boolean_attributes(*attribs)
48
+ @attribute_names ||= []
49
+ attribute_names = convert_to_symbols(attribs)
50
+ def_delegators :attributes, *attribute_names
51
+ @attribute_names += attribute_names
52
+
53
+ attribs.each do |attribute_name|
54
+ if result = attribute_name.to_s.match(/\Ais\_(.*)/)
55
+ define_method "#{result[1]}?" do
56
+ send(attribute_name) if respond_to?(attribute_name)
57
+ end
58
+ end
59
+ end
19
60
  end
20
61
 
21
62
  def writable_attributes(*attribs)
22
- @writable_attribute_names = attribs.map {|attrib| attrib.to_sym }
63
+ @writable_attribute_names = convert_to_symbols(attribs)
23
64
  @writable_attribute_names.freeze
24
- def_delegators :attributes, *(@writable_attribute_names.map {|attrib| attrib.to_s + "=" })
65
+ def_delegators :attributes, *(@writable_attribute_names.map {|attrib| attrib.to_s + "=" }).dup
66
+ end
67
+
68
+ def embedded_attributes(*attribs)
69
+ mappings = attribs.reduce({}, :update)
70
+ @embedded_attribute_names = convert_to_symbols(mappings.keys)
71
+ @embedded_attribute_names.freeze
72
+
73
+ mappings.each do |attrib, attribute_class|
74
+ reified_class = _get_class(attribute_class)
75
+ define_method(attrib) do
76
+ value = attributes.send(attrib)
77
+ if value.is_a? String
78
+ client.resource_from_url(reified_class, value)
79
+ elsif value.is_a? reified_class
80
+ value
81
+ else
82
+ reified_class.new(value, client)
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def convert_to_symbols(list)
91
+ list.map {|item| item.to_sym }
92
+ end
93
+
94
+ protected
95
+
96
+ def _get_class(camel_cased_word)
97
+ if camel_cased_word.is_a? Class
98
+ camel_cased_word
99
+ else
100
+ names = camel_cased_word.split('::')
101
+ names.shift if names.empty? || names.first.empty?
102
+
103
+ constant = Object
104
+ names.each do |name|
105
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
106
+ end
107
+ constant
108
+ end
25
109
  end
26
110
  end
27
111
 
28
- def initialize(attributes = {}, collection_resource = nil)
112
+ def initialize(attributes = {}, client = nil)
29
113
  @attributes = OpenStruct.new(attributes)
30
114
  @errors = []
31
- @collection_resource = collection_resource
115
+ @client = client
32
116
  end
33
117
 
34
118
  def destroy
35
- @collection_resource.destroy_resource(self)
119
+ collection_resource.destroy_resource(self)
36
120
  end
37
121
 
38
122
  def writable_attributes_hash
39
123
  writable_attribute_names.inject({}) do |parameters, attribute_name|
40
124
  value = self.send(attribute_name)
125
+ if embedded_attribute_names.include?(attribute_name) && !value.is_a?(String)
126
+ value = value.resource_uri
127
+ end
41
128
  unless value.nil?
42
129
  parameters[attribute_name] = value
43
130
  end
@@ -47,7 +134,7 @@ module Kippt::Resource
47
134
 
48
135
  def save
49
136
  @errors = []
50
- response = @collection_resource.save_resource(self)
137
+ response = collection_resource.save_resource(self)
51
138
  if response[:error_message]
52
139
  errors << response[:error_message]
53
140
  else
@@ -60,4 +147,14 @@ module Kippt::Resource
60
147
  end
61
148
  response[:success]
62
149
  end
150
+
151
+ private
152
+
153
+ def collection_resource
154
+ @collection_resource ||= client.collection_resource_for(collection_resource_class)
155
+ end
156
+
157
+ def client
158
+ @client
159
+ end
63
160
  end