dimelo_ccp_api 0.4.1

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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +15 -0
  5. data/CHANGELOG.md +29 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +59 -0
  9. data/Rakefile +23 -0
  10. data/VERSION +1 -0
  11. data/dimelo_ccp_api.gemspec +26 -0
  12. data/examples/dimelo_api_test +34 -0
  13. data/gemfiles/Gemfile.activesupport-3.2.x +5 -0
  14. data/gemfiles/Gemfile.activesupport-4.0.x +5 -0
  15. data/gemfiles/Gemfile.activesupport-4.1.x +5 -0
  16. data/gemfiles/Gemfile.activesupport-head +5 -0
  17. data/lib/dimelo/ccp/api/basic_object.rb +17 -0
  18. data/lib/dimelo/ccp/api/client.rb +46 -0
  19. data/lib/dimelo/ccp/api/common/openable.rb +23 -0
  20. data/lib/dimelo/ccp/api/common/publishable.rb +23 -0
  21. data/lib/dimelo/ccp/api/common/starrable.rb +23 -0
  22. data/lib/dimelo/ccp/api/connection.rb +86 -0
  23. data/lib/dimelo/ccp/api/error.rb +71 -0
  24. data/lib/dimelo/ccp/api/lazzy_collection.rb +114 -0
  25. data/lib/dimelo/ccp/api/model/answer.rb +39 -0
  26. data/lib/dimelo/ccp/api/model/attachment.rb +44 -0
  27. data/lib/dimelo/ccp/api/model/category.rb +12 -0
  28. data/lib/dimelo/ccp/api/model/category_group.rb +12 -0
  29. data/lib/dimelo/ccp/api/model/feedback.rb +20 -0
  30. data/lib/dimelo/ccp/api/model/feedback_comment.rb +31 -0
  31. data/lib/dimelo/ccp/api/model/membership.rb +12 -0
  32. data/lib/dimelo/ccp/api/model/private_message.rb +8 -0
  33. data/lib/dimelo/ccp/api/model/question.rb +20 -0
  34. data/lib/dimelo/ccp/api/model/role.rb +8 -0
  35. data/lib/dimelo/ccp/api/model/user.rb +37 -0
  36. data/lib/dimelo/ccp/api/model/webhook.rb +9 -0
  37. data/lib/dimelo/ccp/api/model.rb +209 -0
  38. data/lib/dimelo/ccp/api/version.rb +7 -0
  39. data/lib/dimelo/ccp/api.rb +62 -0
  40. data/lib/dimelo_ccp_api.rb +1 -0
  41. data/spec/examples/openable_examples.rb +37 -0
  42. data/spec/examples/starrable_example.rb +57 -0
  43. data/spec/fixtures/files/logo.jpg +0 -0
  44. data/spec/lib/dimelo/ccp/api/client_spec.rb +111 -0
  45. data/spec/lib/dimelo/ccp/api/connection_spec.rb +129 -0
  46. data/spec/lib/dimelo/ccp/api/model/attachment_spec.rb +26 -0
  47. data/spec/lib/dimelo/ccp/api/model/feedback_spec.rb +10 -0
  48. data/spec/lib/dimelo/ccp/api/model/question_spec.rb +10 -0
  49. data/spec/lib/dimelo/ccp/api/model_spec.rb +162 -0
  50. data/spec/spec_helper.rb +7 -0
  51. metadata +174 -0
@@ -0,0 +1,39 @@
1
+ module Dimelo::CCP
2
+ class Answer < Dimelo::CCP::API::Model
3
+ include ::Dimelo::CCP::API::Common::Publishable
4
+
5
+ path 'questions/%{question_id}/answers/%{id}'
6
+
7
+ attributes :id, :body, :body_format, :flow_state, :user_id, :permalink,
8
+ :attachments_count, :comments_count,
9
+ :created_at, :updated_at, :question_id, :ipaddr, :question_flow_state
10
+
11
+ submit_attributes :body, :body_format, :user_id, :question_id
12
+
13
+ belongs_to :user
14
+ belongs_to :question
15
+
16
+ has_many :answer_attachments
17
+
18
+ def admin_stamp
19
+ path = "#{compute_path(attributes)}/admin_stamp"
20
+ response = client.transport(:post, path)
21
+ self.attributes = Dimelo::CCP::API.decode_json(response)
22
+ errors.empty?
23
+ end
24
+
25
+ def author_stamp
26
+ path = "#{compute_path(attributes)}/author_stamp"
27
+ response = client.transport(:post, path)
28
+ self.attributes = Dimelo::CCP::API.decode_json(response)
29
+ errors.empty?
30
+ end
31
+
32
+ def unstamp
33
+ path = "#{compute_path(attributes)}/stamp"
34
+ response = client.transport(:delete, path)
35
+ self.attributes = Dimelo::CCP::API.decode_json(response)
36
+ errors.empty?
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,44 @@
1
+ module Dimelo::CCP
2
+ class Attachment < Dimelo::CCP::API::Model
3
+ attributes :id, :file, :original, :question_id
4
+ end
5
+
6
+ class AnswerAttachment < Attachment
7
+ path 'questions/%{question_id}/answers/%{answer_id}/attachments/%{id}'
8
+
9
+ attributes :id, :file, :original, :answer_id, :question_id
10
+
11
+ belongs_to :answer
12
+
13
+ submit_attributes :file, :question_id, :answer_id
14
+ end
15
+
16
+ class FeedbackCommentAttachment < Attachment
17
+ path 'feedbacks/%{feedback_id}/comments/%{comment_id}/attachments/%{id}'
18
+
19
+ attributes :id, :file, :original, :feedback_id, :comment_id
20
+ belongs_to :feedback_comment
21
+
22
+ submit_attributes :file, :question_id, :answer_id
23
+ end
24
+
25
+ class QuestionAttachment < Attachment
26
+ path 'questions/%{question_id}/attachments/%{id}'
27
+
28
+ attributes :id, :file, :original, :question_id
29
+
30
+ belongs_to :question
31
+
32
+ submit_attributes :file, :question_id
33
+ end
34
+
35
+ class FeedbackAttachment < Attachment
36
+ path 'feedbacks/%{feedback_id}/attachments/%{id}'
37
+
38
+ attributes :id, :file, :original, :feedback_id
39
+
40
+ belongs_to :question
41
+
42
+ submit_attributes :file, :feedback_id
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ module Dimelo::CCP
2
+ class Category < Dimelo::CCP::API::Model
3
+ path 'category_groups/%{category_group_id}/categories/%{id}'
4
+
5
+ attributes :id, :category_group_id, :name, :description, :questions_count, :permalink, :picture
6
+ alias :to_s :name
7
+
8
+ belongs_to :category_group
9
+ has_many :questions
10
+
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Dimelo::CCP
2
+ class CategoryGroup < Dimelo::CCP::API::Model
3
+
4
+ attributes :id, :name, :item_name, :multiple, :optional
5
+
6
+ alias_method :multiple?, :multiple
7
+ alias_method :optional?, :optional
8
+
9
+ has_many :categories
10
+
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ module Dimelo::CCP
2
+ class Feedback < Dimelo::CCP::API::Model
3
+ include ::Dimelo::CCP::API::Common::Openable
4
+ include ::Dimelo::CCP::API::Common::Publishable
5
+ include ::Dimelo::CCP::API::Common::Starrable
6
+
7
+ attributes :id, :title, :body, :body_format, :flow_state, :score, :user_id,
8
+ :category_id, :category_ids, :category_names, :status_id, :star, :starred_at,
9
+ :closed, :attachments_count, :comments_count, :positive_votes_count, :negative_votes_count,
10
+ :permalink, :ipaddr, :created_at, :updated_at
11
+
12
+ submit_attributes :title, :body, :body_format, :category_ids, :user_id
13
+
14
+ belongs_to :user
15
+ belongs_to :category
16
+ has_many :feedback_comments
17
+ alias :comments :feedback_comments
18
+
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module Dimelo::CCP
2
+ class FeedbackComment < Dimelo::CCP::API::Model
3
+ include ::Dimelo::CCP::API::Common::Publishable
4
+
5
+ STATUS_COMMENT_PATH = 'feedbacks/%{feedback_id}/status_comments/%{id}'
6
+ COMMENT_PATH = 'feedbacks/%{feedback_id}/comments/%{id}'
7
+
8
+ path COMMENT_PATH
9
+
10
+ attributes :id, :feedback_id, :body, :body_format, :flow_state, :user_id, :type, :status_id, :attachments_count, :created_at, :updated_at, :permalink, :ipaddr
11
+ submit_attributes :body, :body_format, :user_id, :feedback_id, :status_id
12
+
13
+ belongs_to :user
14
+ belongs_to :feedback
15
+
16
+ def create
17
+ self.class.path(STATUS_COMMENT_PATH) if status_id
18
+ super
19
+ ensure
20
+ self.class.path(COMMENT_PATH) if status_id
21
+ end
22
+
23
+ def update
24
+ self.class.path(STATUS_COMMENT_PATH) if status_id
25
+ super
26
+ ensure
27
+ self.class.path(COMMENT_PATH) if status_id
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,12 @@
1
+ module Dimelo::CCP
2
+ class Membership < Dimelo::CCP::API::Model
3
+
4
+ path 'users/%{user_id}/memberships/%{id}'
5
+
6
+ attributes :id, :user_id, :role, :domain, :domain_application_id
7
+ submit_attributes :user_id, :role, :domain
8
+
9
+ belongs_to :user
10
+
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ module Dimelo::CCP
2
+ class PrivateMessage < Dimelo::CCP::API::Model
3
+
4
+ attributes :id, :title, :body, :html_body, :raw_body, :from_user_id, :to_user_id, :parent_id, :root_id, :created_at, :updated_at
5
+ submit_attributes :title, :body, :from_user_id, :to_user_id, :parent_id
6
+
7
+ end
8
+ end
@@ -0,0 +1,20 @@
1
+ module Dimelo::CCP
2
+ class Question < Dimelo::CCP::API::Model
3
+ include ::Dimelo::CCP::API::Common::Openable
4
+ include ::Dimelo::CCP::API::Common::Publishable
5
+ include ::Dimelo::CCP::API::Common::Starrable
6
+
7
+ attributes :id, :title, :body, :body_format, :flow_state, :score, :user_id,
8
+ :ipaddr, :category_id, :category_ids, :category_names, :starred_at,
9
+ :answers_count, :attachments_count, :usefulnesses_yes_count, :usefulnesses_no_count,
10
+ :star, :closed, :permalink, :created_at, :updated_at
11
+
12
+ submit_attributes :title, :body, :body_format, :category_ids, :user_id
13
+
14
+ belongs_to :user
15
+ belongs_to :category
16
+ has_many :answers
17
+ has_many :question_attachments
18
+
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ module Dimelo::CCP
2
+ class Role < Dimelo::CCP::API::Model
3
+
4
+ attributes :id, :label, :team
5
+ attributes :view_site, :edit_customization, :view_admin, :edit_grids, :send_private_message, :view_analytics, :view_identities, :view_advanced_admin, :configure_extensions, :configure_mobile
6
+
7
+ end
8
+ end
@@ -0,0 +1,37 @@
1
+ module Dimelo::CCP
2
+ class User < Dimelo::CCP::API::Model
3
+ CUSTOM_FIELD_COUNT = 10
4
+ CUSTOM_FIELD_ATTRIBUTES = (1..CUSTOM_FIELD_COUNT).map { |i| "custom_field_#{i}".to_sym }.freeze
5
+
6
+ attributes :id, :firstname, :lastname, :signature, :email, :private_message, :type, :username, :flow_state, :about, :avatar, :created_at, :updated_at, :blocked, :team
7
+ attributes *CUSTOM_FIELD_ATTRIBUTES
8
+
9
+ submit_attributes :type, :firstname, :lastname, :email, :username, :avatar_url, :about
10
+
11
+ has_many :memberships
12
+ has_many :questions
13
+ has_many :answers
14
+ has_many :feedbacks
15
+
16
+ def avatar_url(size='normal')
17
+ avatar.try(:[], size).try(:[], 'url')
18
+ end
19
+
20
+ # Blocks the specified user
21
+ def block
22
+ path = "#{compute_path(attributes)}/block"
23
+ response = client.transport(:post, path)
24
+ self.attributes = Dimelo::CCP::API.decode_json(response)
25
+ errors.empty?
26
+ end
27
+
28
+ # Unblocks the specified user
29
+ def unblock
30
+ path = "#{compute_path(attributes)}/unblock"
31
+ response = client.transport(:post, path)
32
+ self.attributes = Dimelo::CCP::API.decode_json(response)
33
+ errors.empty?
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+ module Dimelo::CCP
2
+ class Webhook < Dimelo::CCP::API::Model
3
+
4
+ attributes :id, :endpoint_enabled, :endpoint_url, :preprod_settings, :verify_token
5
+ attributes :answer__destroyed, :question__destroyed, :identity__destroyed, :comment__destroyed, :feedback__destroyed, :status_comment__destroyed
6
+
7
+ submit_attributes :id, :endpoint_enabled, :endpoint_url, :preprod_settings, :verify_token, :answer__destroyed, :question__destroyed, :identity__destroyed, :comment__destroyed, :feedback__destroyed, :status_comment__destroyed
8
+ end
9
+ end
@@ -0,0 +1,209 @@
1
+ require 'active_model'
2
+
3
+ module Dimelo::CCP
4
+ module API
5
+ class Model
6
+ extend ActiveModel::Translation
7
+ extend ActiveModel::Naming
8
+ include ActiveModel::Validations
9
+
10
+ class << self
11
+
12
+ def path(*args)
13
+ @path = args.first if args.any?
14
+ @path ||= "#{name.demodulize.pluralize.underscore}/%{id}"
15
+ end
16
+
17
+ def attribute(arg)
18
+ @attributes ||= []
19
+ @attributes << arg
20
+ attr_reader(arg)
21
+ class_eval "
22
+ def #{arg}=(val)
23
+ @tracked_attributes << :#{arg}
24
+ @#{arg} = val
25
+ end"
26
+ end
27
+
28
+ def attributes(*args)
29
+ args.each do |arg|
30
+ attribute arg
31
+ end
32
+ @attributes
33
+ end
34
+
35
+ def submit_attributes(*args)
36
+ @submit_attributes = args if args.any?
37
+ @submit_attributes ||= []
38
+ end
39
+
40
+ def has_many(association, options={})
41
+ foreign_class = options[:class_name] || "#{name.gsub(/(\w+)$/, '')}#{association.to_s.singularize.camelize}"
42
+ foreign_reference = self.name.demodulize.underscore
43
+ foreign_key = "#{foreign_reference}_id"
44
+
45
+ class_eval <<-EOS, __FILE__, __LINE__ + 1
46
+
47
+ def #{association}(client=nil)
48
+ # FIXME: clear cache if client change, or something like that
49
+ client ||= @client
50
+ @#{association} ||= #{foreign_class}.find({:#{foreign_key} => self.id}, client).each do |instance|
51
+ instance.#{foreign_reference} = self
52
+ end
53
+ end
54
+
55
+ def #{association}=(items)
56
+ @#{association} = items.each{ |i| i.#{foreign_reference} = self }
57
+ end
58
+
59
+ EOS
60
+
61
+ end
62
+
63
+ def belongs_to(association, options={})
64
+ attr_writer association
65
+ foreign_class = options[:class_name] || "#{name.gsub(/(\w+)$/, '')}#{association.to_s.camelize}"
66
+ foreign_reference = self.name.demodulize.underscore
67
+ foreign_key = "#{association}_id"
68
+
69
+ class_eval <<-EOS, __FILE__, __LINE__ + 1
70
+
71
+ def #{association}(client=nil)
72
+ client ||= @client
73
+ @#{association} ||= #{foreign_class}.find(self.#{foreign_key}, client)
74
+ end
75
+
76
+ EOS
77
+ end
78
+
79
+ def find(*args)
80
+ client = args.pop
81
+ criterias = args.pop
82
+ criterias = {:id => criterias} unless criterias.is_a?(Hash)
83
+ Dimelo::CCP::API::LazzyCollection.new(criterias) do |criterias|
84
+ parse(client.transport(:get, compute_path(criterias), criterias), client)
85
+ end
86
+ end
87
+
88
+ def parse(document, client=nil)
89
+ object = Dimelo::CCP::API.decode_json(document)
90
+ object.is_a?(Array) ? object.map{ |i| new(i, client) } : new(object, client)
91
+ end
92
+
93
+ # Inspired by https://github.com/svenfuchs/i18n/blob/master/lib/i18n/core_ext/string/interpolate.rb
94
+ INTERPOLATION_PATTERN = /%\{(\w+)\}/ # matches placeholders like "%{foo}"
95
+ def compute_path(criterias={})
96
+ path.gsub(INTERPOLATION_PATTERN) do |match|
97
+ criterias.delete($1.to_sym) || ''
98
+ end.chomp '/'
99
+ end
100
+
101
+ end
102
+
103
+ attr_accessor :client
104
+ attr_reader :errors, :tracked_attributes
105
+
106
+ delegate :compute_path, :to => 'self.class'
107
+
108
+ def initialize(hash={}, client=nil)
109
+ @errors = ActiveModel::Errors.new(self)
110
+ @tracked_attributes = []
111
+ self.client = client
112
+ hash.each do |k,v|
113
+ self.send("#{k}=", v) if self.respond_to?("#{k}=")
114
+ end
115
+ end
116
+
117
+ def errors=(errs)
118
+ @errors = ActiveModel::Errors.new(self).tap do |errors|
119
+ errs.each do |error|
120
+ errors.add(error['attribute'], error['type'])
121
+ end
122
+ end
123
+ end
124
+
125
+ def attributes
126
+ Hash[self.class.attributes.map{ |key| [key, self.send(key)] }]
127
+ end
128
+
129
+ def attributes=(hash)
130
+ hash.each do |k, value|
131
+ if self.respond_to? "#{k}="
132
+ self.send("#{k}=", value)
133
+ else
134
+ warn("Unknown field or method #{k} for object #{self.inspect}")
135
+ end
136
+ end
137
+ end
138
+
139
+ def tracked_submit_attributes
140
+ @tracked_attributes & self.class.submit_attributes
141
+ end
142
+
143
+ def submit_attributes
144
+ Hash[tracked_submit_attributes.map{ |key| [key, self.send(key)] }]
145
+ end
146
+
147
+ def new_record?
148
+ id.blank?
149
+ end
150
+
151
+ def save
152
+ if new_record?
153
+ create
154
+ else
155
+ update
156
+ end
157
+ end
158
+
159
+ def create
160
+ attrs = submit_attributes
161
+ path = compute_path(attrs)
162
+ response = client.transport(:post, path, attrs)
163
+ self.attributes = Dimelo::CCP::API.decode_json(response)
164
+ id.present?
165
+ end
166
+
167
+ def update
168
+ attrs = submit_attributes
169
+ path = compute_path(attributes)
170
+ response = client.transport(:put, path, attrs)
171
+ self.attributes = Dimelo::CCP::API.decode_json(response)
172
+ errors.empty?
173
+ end
174
+
175
+ def valid?
176
+ true
177
+ end
178
+
179
+ def destroy
180
+ client.transport(:delete, compute_path(self.attributes))
181
+ freeze
182
+ end
183
+
184
+ def reload
185
+ raise ArgumentError.new("You cannot fetch models without a populated id attribute") if id.nil?
186
+ other = self.class.find(id, client)
187
+ self.attributes.merge!(other.attributes) if other
188
+ self
189
+ end
190
+
191
+ def ==(other)
192
+ other.is_a?(self.class) and self.id == other.id and self.id.present?
193
+ end
194
+
195
+ def merge!(other)
196
+ self.attributes = other.attributes
197
+ end
198
+
199
+ def to_json
200
+ Dimelo::CCP::API.encode_json(self.attributes)
201
+ end
202
+
203
+ def warn(message)
204
+ defined?(Rails) ? Rails.logger.warn(message) : STDERR.puts(message)
205
+ end
206
+
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,7 @@
1
+ module Dimelo
2
+ module CCP
3
+ module API
4
+ VERSION = File.read(File.join(File.dirname(__FILE__),'..', '..', '..', '..','VERSION') ).strip
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,62 @@
1
+ require 'active_support'
2
+ require 'active_support/json'
3
+ require 'active_support/core_ext'
4
+ require 'faraday'
5
+ require 'uri'
6
+
7
+ module Dimelo
8
+ module CCP
9
+
10
+ autoload :Answer, 'dimelo/ccp/api/model/answer'
11
+ autoload :Attachment, 'dimelo/ccp/api/model/attachment'
12
+ autoload :Category, 'dimelo/ccp/api/model/category'
13
+ autoload :CategoryGroup, 'dimelo/ccp/api/model/category_group'
14
+ autoload :Feedback, 'dimelo/ccp/api/model/feedback'
15
+ autoload :FeedbackComment,'dimelo/ccp/api/model/feedback_comment'
16
+ autoload :Membership, 'dimelo/ccp/api/model/membership'
17
+ autoload :PrivateMessage, 'dimelo/ccp/api/model/private_message'
18
+ autoload :Question, 'dimelo/ccp/api/model/question'
19
+ autoload :Role, 'dimelo/ccp/api/model/role'
20
+ autoload :User, 'dimelo/ccp/api/model/user'
21
+ autoload :Webhook, 'dimelo/ccp/api/model/webhook'
22
+
23
+ # Attachments
24
+ autoload :AnswerAttachment, 'dimelo/ccp/api/model/attachment'
25
+ autoload :CommentAttachment, 'dimelo/ccp/api/model/attachment'
26
+ autoload :FeedbackAttachment, 'dimelo/ccp/api/model/attachment'
27
+ autoload :FeedbackCommentAttachment, 'dimelo/ccp/api/model/attachment'
28
+ autoload :QuestionAttachment, 'dimelo/ccp/api/model/attachment'
29
+
30
+ module API
31
+
32
+ autoload :VERSION, 'dimelo/ccp/api/version'
33
+ autoload :Client, 'dimelo/ccp/api/client'
34
+ autoload :Connection, 'dimelo/ccp/api/connection'
35
+ autoload :Model, 'dimelo/ccp/api/model'
36
+ autoload :BasicObject, 'dimelo/ccp/api/basic_object'
37
+ autoload :LazzyCollection, 'dimelo/ccp/api/lazzy_collection'
38
+
39
+ require 'dimelo/ccp/api/error'
40
+
41
+ class << self
42
+
43
+ def decode_json(document)
44
+ ActiveSupport::JSON.decode(document)
45
+ end
46
+
47
+ def encode_json(object)
48
+ ActiveSupport::JSON.encode(object)
49
+ end
50
+
51
+ end
52
+
53
+ module Common
54
+
55
+ autoload :Openable, 'dimelo/ccp/api/common/openable'
56
+ autoload :Publishable, 'dimelo/ccp/api/common/publishable'
57
+ autoload :Starrable, 'dimelo/ccp/api/common/starrable'
58
+
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1 @@
1
+ require 'dimelo/ccp/api'
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples_for 'common model actions' do
4
+
5
+ before :each do
6
+ @response = {'title' => 'new title'}.to_json
7
+ @client = double
8
+ allow(@client).to receive(:transport) { @response }
9
+ @content = described_class.new({'id' => 123, 'title' => 'old title'}, @client)
10
+ allow(@content).to receive(:errors) { [] }
11
+ end
12
+
13
+ %w(open close publish unpublish).each do |action|
14
+ describe action do
15
+
16
+ it 'sends a put to the appropriate uri' do
17
+ path = @content.compute_path(@content.attributes) + "/#{action}"
18
+ expect(@client).to receive(:transport).with(:put, path).and_return(@response)
19
+ @content.send(action)
20
+ end
21
+
22
+ it 'updates the object with the new attributes' do
23
+ expect {
24
+ @content.send(action)
25
+ }.to change { @content.title }.from('old title').to('new title')
26
+ end
27
+
28
+ it 'returns a boolean indicating any errors' do
29
+ expect {
30
+ allow(@content).to receive(:errors) { ['uh-oh'] }
31
+ }.to change { @content.send(action) }.from(true).to(false)
32
+ end
33
+
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples_for 'starrable object' do
4
+
5
+ before :each do
6
+ @response = {'title' => 'new title'}.to_json
7
+ @client = double
8
+ allow(@client).to receive(:transport) { @response }
9
+ @content = described_class.new({'id' => 123, 'title' => 'old title'}, @client)
10
+ allow(@content).to receive(:errors) { [] }
11
+ end
12
+
13
+ describe '#star!' do
14
+
15
+ it 'sends a put to the appropriate uri' do
16
+ path = @content.compute_path(@content.attributes) + "/star"
17
+ expect(@client).to receive(:transport).with(:put, path).and_return(@response)
18
+ @content.star!
19
+ end
20
+
21
+ it 'updates the object with the new attributes' do
22
+ expect {
23
+ @content.star!
24
+ }.to change { @content.title }.from('old title').to('new title')
25
+ end
26
+
27
+ it 'returns a boolean indicating any errors' do
28
+ expect {
29
+ allow(@content).to receive(:errors) { ['uh-oh'] }
30
+ }.to change { @content.star! }.from(true).to(false)
31
+ end
32
+
33
+ end
34
+
35
+ describe '#unstar!' do
36
+
37
+ it 'sends a put to the appropriate uri' do
38
+ path = @content.compute_path(@content.attributes) + "/unstar"
39
+ expect(@client).to receive(:transport).with(:put, path).and_return(@response)
40
+ @content.unstar!
41
+ end
42
+
43
+ it 'updates the object with the new attributes' do
44
+ expect {
45
+ @content.unstar!
46
+ }.to change { @content.title }.from('old title').to('new title')
47
+ end
48
+
49
+ it 'returns a boolean indicating any errors' do
50
+ expect {
51
+ allow(@content).to receive(:errors) { ['uh-oh'] }
52
+ }.to change { @content.unstar! }.from(true).to(false)
53
+ end
54
+
55
+ end
56
+
57
+ end
Binary file