her 0.1.5 → 0.1.6

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.
data/README.md CHANGED
@@ -166,6 +166,23 @@ For `belongs_to` relationship, an extra HTTP request (to `GET /organizations/2`)
166
166
 
167
167
  However, subsequent calls to `#comments` or `#role` will not trigger the extra HTTP request.
168
168
 
169
+ ## Hooks
170
+
171
+ You can add *before* and *after* hooks to your models that are triggered on specific actions (`save`, `update`, `create`, `destroy`):
172
+
173
+ ```ruby
174
+ class User
175
+ include Her::Model
176
+ before_save :set_internal_id
177
+
178
+ def set_internal_id
179
+ self.internal_id = 42 # Will be passed in the HTTP request
180
+ end
181
+ end
182
+ ```
183
+
184
+ In the future, adding hooks to all models will be possible, as well as defining and triggering your own hooks (eg. for your custom requests).
185
+
169
186
  ## Custom requests
170
187
 
171
188
  You can easily add custom methods for your models. You can either use `get_collection` (which maps the returned data to a collection of resources), `get_resource` (which maps the returned data to a single resource) or `get_raw` (which yields the parsed data return from the HTTP request). Other HTTP methods are supported (`post_raw`, `put_resource`, etc.)
@@ -224,7 +241,6 @@ Category.all
224
241
 
225
242
  ## Things to be done
226
243
 
227
- * Deleting resources
228
244
  * Support for Faraday middleware to handle caching, alternative formats, etc.
229
245
  * Hooks before save, update, create, destroy, etc.
230
246
  * Better error handling
@@ -14,6 +14,7 @@ module Her
14
14
  autoload :HTTP, "her/model/http"
15
15
  autoload :ORM, "her/model/orm"
16
16
  autoload :Relationships, "her/model/relationships"
17
+ autoload :Hooks, "her/model/hooks"
17
18
 
18
19
  extend ActiveSupport::Concern
19
20
 
@@ -26,6 +27,7 @@ module Her
26
27
  extend Her::Model::HTTP
27
28
  extend Her::Model::ORM
28
29
  extend Her::Model::Relationships
30
+ extend Her::Model::Hooks
29
31
 
30
32
  # Define default settings
31
33
  collection_path "#{self.to_s.downcase.pluralize}"
@@ -0,0 +1,40 @@
1
+ module Her
2
+ module Model
3
+ module Hooks
4
+ # Return hooks
5
+ # @private
6
+ def hooks # {{{
7
+ @her_hooks
8
+ end # }}}
9
+
10
+ # @private
11
+ def set_hook(time, name, action) # {{{
12
+ @her_hooks ||= {}
13
+ (@her_hooks["#{time}_#{name}".to_sym] ||= []) << action
14
+ end # }}}
15
+
16
+ # @private
17
+ def perform_hook(record, time, name) # {{{
18
+ @her_hooks ||= {}
19
+ hooks = @her_hooks["#{time}_#{name}".to_sym] || []
20
+ hooks.each do |hook|
21
+ if hook.is_a? Symbol
22
+ record.send(hook)
23
+ else
24
+ hook.call(record)
25
+ end
26
+ end
27
+ end # }}}
28
+
29
+ def before_save(method=nil, &block); set_hook(:before, :save, method || block); end
30
+ def before_create(method=nil, &block); set_hook(:before, :create, method || block); end
31
+ def before_update(method=nil, &block); set_hook(:before, :update, method || block); end
32
+ def before_destroy(method=nil, &block); set_hook(:before, :destroy, method || block); end
33
+
34
+ def after_save(method=nil, &block); set_hook(:after, :save, method || block); end
35
+ def after_create(method=nil, &block); set_hook(:after, :create, method || block); end
36
+ def after_update(method=nil, &block); set_hook(:after, :update, method || block); end
37
+ def after_destroy(method=nil, &block); set_hook(:after, :destroy, method || block); end
38
+ end # }}}
39
+ end
40
+ end
@@ -20,14 +20,14 @@ module Her
20
20
  def method_missing(method, attrs=nil) # {{{
21
21
  assignment_method = method.to_s =~ /\=$/
22
22
  method = method.to_s.gsub(/(\?|\!|\=)$/, "").to_sym
23
- if @data.include?(method)
24
- if attrs and assignment_method
25
- @data[method.to_s.gsub(/\=$/, "").to_sym] = attrs
26
- else
23
+ if attrs and assignment_method
24
+ @data[method.to_s.gsub(/\=$/, "").to_sym] = attrs
25
+ else
26
+ if @data.include?(method)
27
27
  @data[method]
28
+ else
29
+ super
28
30
  end
29
- else
30
- super
31
31
  end
32
32
  end # }}}
33
33
 
@@ -38,6 +38,9 @@ module Her
38
38
  end # }}}
39
39
 
40
40
  # Fetch a specific resource based on an ID
41
+ #
42
+ # @example
43
+ # @user = User.find(1) GET /users/1
41
44
  def find(id, params={}) # {{{
42
45
  request(params.merge(:_method => :get, :_path => "#{@her_collection_path}/#{id}")) do |parsed_data|
43
46
  new(parsed_data[:data])
@@ -45,28 +48,100 @@ module Her
45
48
  end # }}}
46
49
 
47
50
  # Fetch a collection of resources
51
+ #
52
+ # @example
53
+ # @users = User.all # GET /users
48
54
  def all(params={}) # {{{
49
55
  request(params.merge(:_method => :get, :_path => "#{@her_collection_path}")) do |parsed_data|
50
56
  new_collection(parsed_data)
51
57
  end
52
58
  end # }}}
53
59
 
54
- # Create a resource
60
+ # Create a resource and return it
61
+ #
62
+ # @example
63
+ # @user = User.create({ :fullname => "Tobias Fünke" }) # POST /users/1
55
64
  def create(params={}) # {{{
65
+ resource = new(params)
66
+ perform_hook(resource, :before, :create)
67
+ perform_hook(resource, :before, :save)
68
+ params = resource.instance_eval { @data }
56
69
  request(params.merge(:_method => :post, :_path => "#{@her_collection_path}")) do |parsed_data|
57
- new(parsed_data[:data])
70
+ resource.instance_eval do
71
+ @data = parsed_data[:data]
72
+ end
58
73
  end
74
+ perform_hook(resource, :after, :save)
75
+ perform_hook(resource, :after, :create)
76
+
77
+ resource
78
+ end # }}}
79
+
80
+ # Save an existing resource and return it
81
+ #
82
+ # @example
83
+ # @user = User.save_existing(1, { :fullname => "Tobias Fünke" }) # PUT /users/1
84
+ def save_existing(id, params) # {{{
85
+ resource = new(params.merge(:id => id))
86
+ resource.save
59
87
  end # }}}
60
88
 
61
89
  # Save a resource
90
+ #
91
+ # @example Save a resource after fetching it
92
+ # @user = User.find(1) # GET /users/1
93
+ # @user.fullname = "Tobias Fünke"
94
+ # @user.save # PUT /users/1
95
+ #
96
+ # @example Save a new resource by creating it
97
+ # @user = User.new({ :fullname => "Tobias Fünke" })
98
+ # @user.save # POST /users
62
99
  def save # {{{
63
100
  params = @data.dup
64
101
  if @data[:id]
102
+ self.class.perform_hook(self, :before, :update)
103
+ self.class.perform_hook(self, :before, :save)
65
104
  self.class.request(params.merge(:_method => :put, :_path => "#{self.class.collection_path}/#{id}")) do |parsed_data|
66
105
  @data = parsed_data[:data]
67
106
  end
107
+ self.class.perform_hook(self, :after, :save)
108
+ self.class.perform_hook(self, :after, :update)
109
+ self
68
110
  else
69
- self.class.create(params)
111
+ self.class.perform_hook(self, :before, :create)
112
+ self.class.perform_hook(self, :before, :save)
113
+ self.class.request(params.merge(:_method => :post, :_path => "#{self.class.collection_path}")) do |parsed_data|
114
+ @data = parsed_data[:data]
115
+ end
116
+ self.class.perform_hook(self, :after, :save)
117
+ self.class.perform_hook(self, :after, :create)
118
+ end
119
+ self
120
+ end # }}}
121
+
122
+ # Destroy a resource
123
+ #
124
+ # @example
125
+ # @user = User.find(1) # GET /users/1
126
+ # @user.destroy # DELETE /users/1
127
+ def destroy # {{{
128
+ params = @data.dup
129
+ self.class.perform_hook(self, :before, :destroy)
130
+ self.class.request(params.merge(:_method => :delete, :_path => "#{self.class.collection_path}/#{id}")) do |parsed_data|
131
+ @data = parsed_data[:data]
132
+ end
133
+ self.class.perform_hook(self, :after, :destroy)
134
+ self
135
+ end # }}}
136
+
137
+ # Destroy an existing resource
138
+ #
139
+ # @example
140
+ # User.destroy_existing(1) # DELETE /users/1
141
+ def destroy_existing(id) # {{{
142
+ params = {}
143
+ request(params.merge(:_method => :delete, :_path => "#{collection_path}/#{id}")) do |parsed_data|
144
+ new(parsed_data[:data])
70
145
  end
71
146
  end # }}}
72
147
  end
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.1.5"
2
+ VERSION = "0.1.6"
3
3
  end
@@ -0,0 +1,264 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
3
+
4
+ describe Her::Model::Hooks do
5
+ context "adding hooks to a model" do
6
+ before do # {{{
7
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
8
+ class User
9
+ include Her::Model
10
+ end
11
+ end # }}}
12
+
13
+ describe "method hooks" do
14
+ it "handles “before save” method hooks" do # {{{
15
+ User.before_save :set_internal_id
16
+ User.hooks[:before_save].length.should == 1
17
+ User.hooks[:before_save].first.class.should == Symbol
18
+ end # }}}
19
+
20
+ it "handles “before create” method hooks" do # {{{
21
+ User.before_create :set_internal_id
22
+ User.hooks[:before_create].length.should == 1
23
+ User.hooks[:before_create].first.class.should == Symbol
24
+ end # }}}
25
+
26
+ it "handles “before update” method hooks" do # {{{
27
+ User.before_update :set_internal_id
28
+ User.hooks[:before_update].length.should == 1
29
+ User.hooks[:before_update].first.class.should == Symbol
30
+ end # }}}
31
+
32
+ it "handles “before destroy” method hooks" do # {{{
33
+ User.before_destroy :set_internal_id
34
+ User.hooks[:before_destroy].length.should == 1
35
+ User.hooks[:before_destroy].first.class.should == Symbol
36
+ end # }}}
37
+
38
+ it "handles “after save” method hooks" do # {{{
39
+ User.after_save :set_internal_id
40
+ User.hooks[:after_save].length.should == 1
41
+ User.hooks[:after_save].first.class.should == Symbol
42
+ end # }}}
43
+
44
+ it "handles “after create” method hooks" do # {{{
45
+ User.after_create :set_internal_id
46
+ User.hooks[:after_create].length.should == 1
47
+ User.hooks[:after_create].first.class.should == Symbol
48
+ end # }}}
49
+
50
+ it "handles “after update” method hooks" do # {{{
51
+ User.after_update :set_internal_id
52
+ User.hooks[:after_update].length.should == 1
53
+ User.hooks[:after_update].first.class.should == Symbol
54
+ end # }}}
55
+
56
+ it "handles “after destroy” method hooks" do # {{{
57
+ User.after_destroy :set_internal_id
58
+ User.hooks[:after_destroy].length.should == 1
59
+ User.hooks[:after_destroy].first.class.should == Symbol
60
+ end # }}}
61
+ end
62
+
63
+ describe "block hooks" do
64
+ it "handles “before save” block hooks" do # {{{
65
+ User.before_save { |record| record.internal_id = 42 }
66
+ User.hooks[:before_save].length.should == 1
67
+ User.hooks[:before_save].first.class.should == Proc
68
+ end # }}}
69
+
70
+ it "handles “before create” block hooks" do # {{{
71
+ User.before_create { |record| record.internal_id = 42 }
72
+ User.hooks[:before_create].length.should == 1
73
+ User.hooks[:before_create].first.class.should == Proc
74
+ end # }}}
75
+
76
+ it "handles “before update” block hooks" do # {{{
77
+ User.before_update { |record| record.internal_id = 42 }
78
+ User.hooks[:before_update].length.should == 1
79
+ User.hooks[:before_update].first.class.should == Proc
80
+ end # }}}
81
+
82
+ it "handles “before destroy” block hooks" do # {{{
83
+ User.before_destroy { |record| record.internal_id = 42 }
84
+ User.hooks[:before_destroy].length.should == 1
85
+ User.hooks[:before_destroy].first.class.should == Proc
86
+ end # }}}
87
+
88
+ it "handles “after save” block hooks" do # {{{
89
+ User.after_save { |record| record.internal_id = 42 }
90
+ User.hooks[:after_save].length.should == 1
91
+ User.hooks[:after_save].first.class.should == Proc
92
+ end # }}}
93
+
94
+ it "handles “after create” block hooks" do # {{{
95
+ User.after_create { |record| record.internal_id = 42 }
96
+ User.hooks[:after_create].length.should == 1
97
+ User.hooks[:after_create].first.class.should == Proc
98
+ end # }}}
99
+
100
+ it "handles “after update” block hooks" do # {{{
101
+ User.after_update { |record| record.internal_id = 42 }
102
+ User.hooks[:after_update].length.should == 1
103
+ User.hooks[:after_update].first.class.should == Proc
104
+ end # }}}
105
+
106
+ it "handles “after destroy” block hooks" do # {{{
107
+ User.after_destroy { |record| record.internal_id = 42 }
108
+ User.hooks[:after_destroy].length.should == 1
109
+ User.hooks[:after_destroy].first.class.should == Proc
110
+ end # }}}
111
+ end
112
+ end
113
+
114
+ context "perform hooks on a model" do
115
+ before do # {{{
116
+ Her::API.setup :base_uri => "https://api.example.com"
117
+ FakeWeb.register_uri(:post, "https://api.example.com/users", :body => { :data => { :id => 1, :name => "Tobias Fünke" } }.to_json)
118
+ FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke" } }.to_json)
119
+ FakeWeb.register_uri(:put, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke" } }.to_json)
120
+ FakeWeb.register_uri(:delete, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke" } }.to_json)
121
+
122
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
123
+ class User
124
+ include Her::Model
125
+ attr_accessor :internal_save_id, :internal_create_id, :internal_update_id, :internal_destroy_id
126
+ attr_accessor :internal_after_save_id, :internal_after_create_id, :internal_after_update_id, :internal_after_destroy_id
127
+
128
+ def change_internal_save_id; @internal_save_id = 100; end
129
+ def change_internal_create_id; @internal_create_id = 101; end
130
+ def change_internal_update_id; @internal_update_id = 102; end
131
+ def change_internal_destroy_id; @internal_destroy_id = 103; end
132
+
133
+ def change_internal_after_save_id; @internal_after_save_id = 100; end
134
+ def change_internal_after_create_id; @internal_after_create_id = 101; end
135
+ def change_internal_after_update_id; @internal_after_update_id = 102; end
136
+ def change_internal_after_destroy_id; @internal_after_destroy_id = 103; end
137
+ end
138
+ end # }}}
139
+
140
+ describe "method hooks" do
141
+ before do # {{{
142
+ User.before_save :change_internal_save_id
143
+ User.before_update :change_internal_update_id
144
+ User.before_create :change_internal_create_id
145
+ User.before_destroy :change_internal_destroy_id
146
+
147
+ User.after_save :change_internal_after_save_id
148
+ User.after_update :change_internal_after_update_id
149
+ User.after_create :change_internal_after_create_id
150
+ User.after_destroy :change_internal_after_destroy_id
151
+ end # }}}
152
+
153
+ it "perform “before save” “before create” method hook on Model#save without an ID" do # {{{
154
+ @user = User.new(:fullname => "Tobias Fünke")
155
+ @user.save
156
+ @user.internal_save_id.should == 100
157
+ @user.internal_create_id.should == 101
158
+ @user.internal_update_id.should == nil
159
+ end # }}}
160
+
161
+ it "perform “before save” and “before update” method hook on Model#save with an ID" do # {{{
162
+ @user = User.find(1)
163
+ @user.save
164
+ @user.internal_save_id.should == 100
165
+ @user.internal_create_id.should == nil
166
+ @user.internal_update_id.should == 102
167
+ end # }}}
168
+
169
+ it "perform “before destroy” method hook on Model#destroy" do # {{{
170
+ @user = User.find(1)
171
+ @user.destroy
172
+ @user.internal_save_id.should == nil
173
+ @user.internal_create_id.should == nil
174
+ @user.internal_update_id.should == nil
175
+ @user.internal_destroy_id.should == 103
176
+ end # }}}
177
+
178
+ it "perform “after save” “after create” method hook on Model#save without an ID" do # {{{
179
+ @user = User.new(:fullname => "Tobias Fünke")
180
+ @user.save
181
+ @user.internal_after_save_id.should == 100
182
+ @user.internal_after_create_id.should == 101
183
+ @user.internal_after_update_id.should == nil
184
+ end # }}}
185
+
186
+ it "perform “after save” “after update” method hook on Model#save with an ID" do # {{{
187
+ @user = User.find(1)
188
+ @user.save
189
+ @user.internal_after_save_id.should == 100
190
+ @user.internal_after_create_id.should == nil
191
+ @user.internal_after_update_id.should == 102
192
+ end # }}}
193
+
194
+ it "perform “after save” “after update” method hook on Model.save_existing" do # {{{
195
+ @user = User.save_existing(1, { :fullname => "Tobias Fünke" })
196
+ @user.internal_after_save_id.should == 100
197
+ @user.internal_after_create_id.should == nil
198
+ @user.internal_after_update_id.should == 102
199
+ end # }}}
200
+
201
+ it "perform “after save” “after create” method hook on Model.create" do # {{{
202
+ @user = User.create({ :fullname => "Tobias Fünke" })
203
+ @user.internal_after_save_id.should == 100
204
+ @user.internal_after_create_id.should == 101
205
+ @user.internal_after_update_id.should == nil
206
+ end # }}}
207
+ end
208
+
209
+ describe "block hooks" do
210
+ before do # {{{
211
+ User.before_save { |record| record.internal_save_id = 200 }
212
+ User.before_create { |record| record.internal_create_id = 201 }
213
+ User.before_update { |record| record.internal_update_id = 202 }
214
+ User.before_destroy { |record| record.internal_destroy_id = 203 }
215
+
216
+ User.after_save { |record| record.internal_after_save_id = 200 }
217
+ User.after_create { |record| record.internal_after_create_id = 201 }
218
+ User.after_update { |record| record.internal_after_update_id = 202 }
219
+ User.after_destroy { |record| record.internal_after_destroy_id = 203 }
220
+ end # }}}
221
+
222
+ it "perform “before save” and “before create” block hook on Model#save without an ID" do # {{{
223
+ @user = User.new(:fullname => "Tobias Fünke")
224
+ @user.save
225
+ @user.internal_save_id.should == 200
226
+ @user.internal_create_id.should == 201
227
+ @user.internal_update_id.should == nil
228
+ end # }}}
229
+
230
+ it "perform “before save” and “before update” block hook on Model#save with an ID" do # {{{
231
+ @user = User.find(1)
232
+ @user.save
233
+ @user.internal_save_id.should == 200
234
+ @user.internal_create_id.should == nil
235
+ @user.internal_update_id.should == 202
236
+ end # }}}
237
+
238
+ it "perform “before destroy” block hook on Model#destroy" do # {{{
239
+ @user = User.find(1)
240
+ @user.destroy
241
+ @user.internal_save_id.should == nil
242
+ @user.internal_create_id.should == nil
243
+ @user.internal_update_id.should == nil
244
+ @user.internal_destroy_id.should == 203
245
+ end # }}}
246
+
247
+ it "perform “after save” “after create” block hook on Model#save without an ID" do # {{{
248
+ @user = User.new(:fullname => "Tobias Fünke")
249
+ @user.save
250
+ @user.internal_after_save_id.should == 200
251
+ @user.internal_after_create_id.should == 201
252
+ @user.internal_after_update_id.should == nil
253
+ end # }}}
254
+
255
+ it "perform “after save” “after update” block hook on Model#save with an ID" do # {{{
256
+ @user = User.find(1)
257
+ @user.save
258
+ @user.internal_after_save_id.should == 200
259
+ @user.internal_after_create_id.should == nil
260
+ @user.internal_after_update_id.should == 202
261
+ end # }}}
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,149 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
3
+
4
+ describe Her::Model::HTTP do
5
+ context "binding a model with an API" do
6
+ it "binds a model to an instance of Her::API" do # {{{
7
+ @api = Her::API.new
8
+ @api.setup :base_uri => "https://api.example.com"
9
+
10
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
11
+ class User
12
+ include Her::Model
13
+ end
14
+ User.uses_api @api
15
+
16
+ User.class_eval do
17
+ @her_api.should_not == nil
18
+ @her_api.base_uri.should == "https://api.example.com"
19
+ end
20
+ end # }}}
21
+
22
+ it "binds a model directly to Her::API" do # {{{
23
+ Her::API.setup :base_uri => "https://api.example.com"
24
+
25
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
26
+ class User
27
+ include Her::Model
28
+ end
29
+
30
+ User.class_eval do
31
+ @her_api.should_not == nil
32
+ @her_api.base_uri.should == "https://api.example.com"
33
+ end
34
+ end # }}}
35
+
36
+ it "binds two models to two different instances of Her::API" do # {{{
37
+ @api1 = Her::API.new
38
+ @api1.setup :base_uri => "https://api1.example.com"
39
+
40
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
41
+ class User; include Her::Model; end
42
+ User.uses_api @api1
43
+
44
+ User.class_eval do
45
+ @her_api.base_uri.should == "https://api1.example.com"
46
+ end
47
+
48
+ @api2 = Her::API.new
49
+ @api2.setup :base_uri => "https://api2.example.com"
50
+
51
+ Object.instance_eval { remove_const :Comment } if Object.const_defined?(:Comment)
52
+ class Comment; include Her::Model; end
53
+ Comment.uses_api @api2
54
+
55
+ Comment.class_eval do
56
+ @her_api.base_uri.should == "https://api2.example.com"
57
+ end
58
+ end # }}}
59
+
60
+ it "binds one model to Her::API and another one to an instance of Her::API" do # {{{
61
+ Her::API.setup :base_uri => "https://api1.example.com"
62
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
63
+ class User; include Her::Model; end
64
+
65
+ User.class_eval do
66
+ @her_api.base_uri.should == "https://api1.example.com"
67
+ end
68
+
69
+ @api = Her::API.new
70
+ @api.setup :base_uri => "https://api2.example.com"
71
+
72
+ Object.instance_eval { remove_const :Comment } if Object.const_defined?(:Comment)
73
+ class Comment; include Her::Model; end
74
+ Comment.uses_api @api
75
+
76
+ Comment.class_eval do
77
+ @her_api.base_uri.should == "https://api2.example.com"
78
+ end
79
+ end # }}}
80
+ end
81
+
82
+ context "making HTTP requests" do
83
+ before do # {{{
84
+ @api = Her::API.new
85
+ @api.setup :base_uri => "https://api.example.com"
86
+ FakeWeb.register_uri(:get, "https://api.example.com/users", :body => { :data => [{ :id => 1 }] }.to_json)
87
+ FakeWeb.register_uri(:get, "https://api.example.com/users?page=2", :body => { :data => [{ :id => 2 }] }.to_json)
88
+ FakeWeb.register_uri(:get, "https://api.example.com/users/popular", :body => { :data => [{ :id => 1 }, { :id => 2 }] }.to_json)
89
+ FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1 } }.to_json)
90
+ FakeWeb.register_uri(:post, "https://api.example.com/users", :body => { :data => [{ :id => 3 }] }.to_json)
91
+ FakeWeb.register_uri(:put, "https://api.example.com/users/4", :body => { :data => [{ :id => 4 }] }.to_json)
92
+ FakeWeb.register_uri(:patch, "https://api.example.com/users/6", :body => { :data => [{ :id => 6 }] }.to_json)
93
+ FakeWeb.register_uri(:delete, "https://api.example.com/users/5", :body => { :data => [{ :id => 5 }] }.to_json)
94
+
95
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
96
+ class User
97
+ include Her::Model
98
+ end
99
+ User.uses_api @api
100
+ end # }}}
101
+
102
+ it "handle raw GET" do # {{{
103
+ User.get_raw("/users") do |parsed_data|
104
+ parsed_data[:data].should == [{ :id => 1 }]
105
+ end
106
+ end # }}}
107
+
108
+ it "handle raw POST" do # {{{
109
+ User.post_raw("/users") do |parsed_data|
110
+ parsed_data[:data].should == [{ :id => 3 }]
111
+ end
112
+ end # }}}
113
+
114
+ it "handle raw PUT" do # {{{
115
+ User.put_raw("/users/4") do |parsed_data|
116
+ parsed_data[:data].should == [{ :id => 4 }]
117
+ end
118
+ end # }}}
119
+
120
+ it "handle raw PATCH" do # {{{
121
+ User.patch_raw("/users/6") do |parsed_data|
122
+ parsed_data[:data].should == [{ :id => 6 }]
123
+ end
124
+ end # }}}
125
+
126
+ it "handle raw DELETE" do # {{{
127
+ User.delete_raw("/users/5") do |parsed_data|
128
+ parsed_data[:data].should == [{ :id => 5 }]
129
+ end
130
+ end # }}}
131
+
132
+ it "handle querystring parameters" do # {{{
133
+ User.get_raw("/users", :page => 2) do |parsed_data|
134
+ parsed_data[:data].should == [{ :id => 2 }]
135
+ end
136
+ end # }}}
137
+
138
+ it "handle GET collection" do # {{{
139
+ @users = User.get_collection("/users/popular")
140
+ @users.length.should == 2
141
+ @users.first.id.should == 1
142
+ end # }}}
143
+
144
+ it "handle GET resource" do # {{{
145
+ @user = User.get_resource("/users/1")
146
+ @user.id.should == 1
147
+ end # }}}
148
+ end
149
+ end
@@ -0,0 +1,113 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
3
+
4
+ describe Her::Model::ORM do
5
+ context "mapping data to Ruby objects" do
6
+ before do # {{{
7
+ @api = Her::API.new
8
+ @api.setup :base_uri => "https://api.example.com"
9
+ FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke" } }.to_json)
10
+ FakeWeb.register_uri(:get, "https://api.example.com/users", :body => { :data => [{ :id => 1, :name => "Tobias Fünke" }, { :id => 2, :name => "Lindsay Fünke" }] }.to_json)
11
+
12
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
13
+ class User
14
+ include Her::Model
15
+ end
16
+ User.uses_api @api
17
+ end # }}}
18
+
19
+ it "maps a single resource to a Ruby object" do # {{{
20
+ @user = User.find(1)
21
+ @user.id.should == 1
22
+ @user.name.should == "Tobias Fünke"
23
+ end # }}}
24
+
25
+ it "maps a collection of resources to an array of Ruby objects" do # {{{
26
+ @users = User.all
27
+ @users.length.should == 2
28
+ @users.first.name.should == "Tobias Fünke"
29
+ end # }}}
30
+ end
31
+
32
+ context "creating resources" do
33
+ before do # {{{
34
+ Her::API.setup :base_uri => "https://api.example.com"
35
+ FakeWeb.register_uri(:post, "https://api.example.com/users", :body => { :data => { :id => 1, :fullname => "Tobias Fünke" } }.to_json)
36
+
37
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
38
+ class User
39
+ include Her::Model
40
+ end
41
+ end # }}}
42
+
43
+ it "handle one-line resource creation" do # {{{
44
+ @user = User.create(:fullname => "Tobias Fünke")
45
+ @user.id.should == 1
46
+ @user.fullname.should == "Tobias Fünke"
47
+ end # }}}
48
+
49
+ it "handle resource creation through Model.new + #save" do # {{{
50
+ @user = User.new(:fullname => "Tobias Fünke")
51
+ @user.save
52
+ @user.fullname.should == "Tobias Fünke"
53
+ end # }}}
54
+ end
55
+
56
+ context "updating resources" do
57
+ before do # {{{
58
+ @api = Her::API.new
59
+ @api.setup :base_uri => "https://api.example.com"
60
+ FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :fullname => "Tobias Fünke" } }.to_json)
61
+ FakeWeb.register_uri(:put, "https://api.example.com/users/1", :body => { :data => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json)
62
+
63
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
64
+ class User
65
+ include Her::Model
66
+ end
67
+ end # }}}
68
+
69
+ it "handle resource data update without saving it" do # {{{
70
+ @user = User.find(1)
71
+ @user.fullname.should == "Tobias Fünke"
72
+ @user.fullname = "Kittie Sanchez"
73
+ @user.fullname.should == "Kittie Sanchez"
74
+ end # }}}
75
+
76
+ it "handle resource update through the .update class method" do # {{{
77
+ @user = User.save_existing(1, { :fullname => "Lindsay Fünke" })
78
+ @user.fullname.should == "Lindsay Fünke"
79
+ end # }}}
80
+
81
+ it "handle resource update through #save on an existing resource" do # {{{
82
+ @user = User.find(1)
83
+ @user.fullname = "Lindsay Fünke"
84
+ @user.save
85
+ @user.fullname.should == "Lindsay Fünke"
86
+ end # }}}
87
+ end
88
+
89
+ context "deleting resources" do
90
+ before do # {{{
91
+ @api = Her::API.new
92
+ @api.setup :base_uri => "https://api.example.com"
93
+ FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :fullname => "Tobias Fünke", :active => true } }.to_json)
94
+ FakeWeb.register_uri(:delete, "https://api.example.com/users/1", :body => { :data => { :id => 1, :fullname => "Lindsay Fünke", :active => false } }.to_json)
95
+
96
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
97
+ class User
98
+ include Her::Model
99
+ end
100
+ end # }}}
101
+
102
+ it "handle resource deletion through the .destroy class method" do # {{{
103
+ @user = User.destroy_existing(1)
104
+ @user.active.should be_false
105
+ end # }}}
106
+
107
+ it "handle resource deletion through #destroy on an existing resource" do # {{{
108
+ @user = User.find(1)
109
+ @user.destroy
110
+ @user.active.should be_false
111
+ end # }}}
112
+ end
113
+ end
@@ -0,0 +1,115 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
3
+
4
+ describe Her::Model::Relationships do
5
+ context "setting relationships" do
6
+ before do # {{{
7
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
8
+ class User
9
+ include Her::Model
10
+ end
11
+ end # }}}
12
+
13
+ it "handles a single 'has_many' relationship" do # {{{
14
+ User.has_many :comments
15
+ User.relationships[:has_many].should == [{ :name => :comments }]
16
+ end # }}}
17
+
18
+ it "handles multiples 'has_many' relationship" do # {{{
19
+ User.has_many :comments
20
+ User.has_many :posts
21
+ User.relationships[:has_many].should == [{ :name => :comments }, { :name => :posts }]
22
+ end # }}}
23
+
24
+ it "handles a single 'has_one' relationship" do # {{{
25
+ User.has_one :category
26
+ User.relationships[:has_one].should == [{ :name => :category }]
27
+ end # }}}
28
+
29
+ it "handles multiples 'has_one' relationship" do # {{{
30
+ User.has_one :category
31
+ User.has_one :role
32
+ User.relationships[:has_one].should == [{ :name => :category }, { :name => :role }]
33
+ end # }}}
34
+
35
+ it "handles a single belongs_to relationship" do # {{{
36
+ User.belongs_to :organization
37
+ User.relationships[:belongs_to].should == [{ :name => :organization }]
38
+ end # }}}
39
+
40
+ it "handles multiples 'belongs_to' relationship" do # {{{
41
+ User.belongs_to :organization
42
+ User.belongs_to :family
43
+ User.relationships[:belongs_to].should == [{ :name => :organization }, { :name => :family }]
44
+ end # }}}
45
+ end
46
+
47
+ context "handling relationships" do
48
+ before do # {{{
49
+ Her::API.setup :base_uri => "https://api.example.com"
50
+ FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke", :comments => [{ :id => 2, :body => "Tobias, you blow hard!" }, { :id => 3, :body => "I wouldn't mind kissing that man between the cheeks, so to speak" }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 1, :name => "Bluth Company" }, :organization_id => 1 } }.to_json)
51
+ FakeWeb.register_uri(:get, "https://api.example.com/users/2", :body => { :data => { :id => 2, :name => "Lindsay Fünke", :organization_id => 1 } }.to_json)
52
+ FakeWeb.register_uri(:get, "https://api.example.com/users/2/comments", :body => { :data => [{ :id => 4, :body => "They're having a FIRESALE?" }, { :id => 5, :body => "Is this the tiny town from Footloose?" }] }.to_json)
53
+ FakeWeb.register_uri(:get, "https://api.example.com/users/2/role", :body => { :data => { :id => 2, :body => "User" } }.to_json)
54
+ FakeWeb.register_uri(:get, "https://api.example.com/organizations/1", :body => { :data => { :id => 1, :name => "Bluth Company" } }.to_json)
55
+
56
+ Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
57
+ class User
58
+ include Her::Model
59
+ has_many :comments
60
+ has_one :role
61
+ belongs_to :organization
62
+ end
63
+
64
+ Object.instance_eval { remove_const :Organization } if Object.const_defined?(:Organization)
65
+ class Organization
66
+ include Her::Model
67
+ end
68
+
69
+ Object.instance_eval { remove_const :Comment } if Object.const_defined?(:Comment)
70
+ class Comment
71
+ include Her::Model
72
+ end
73
+
74
+ Object.instance_eval { remove_const :Role } if Object.const_defined?(:Role)
75
+ class Role
76
+ include Her::Model
77
+ end
78
+
79
+ @user_with_included_data = User.find(1)
80
+ @user_without_included_data = User.find(2)
81
+ end # }}}
82
+
83
+ it "maps an array of included data through has_many" do # {{{
84
+ @user_with_included_data.comments.length.should == 2
85
+ @user_with_included_data.comments.first.id.should == 2
86
+ @user_with_included_data.comments.first.body.should == "Tobias, you blow hard!"
87
+ end # }}}
88
+
89
+ it "fetches data that was not included through has_many" do # {{{
90
+ @user_without_included_data.comments.length.should == 2
91
+ @user_without_included_data.comments.first.id.should == 4
92
+ @user_without_included_data.comments.first.body.should == "They're having a FIRESALE?"
93
+ end # }}}
94
+
95
+ it "maps an array of included data through has_one" do # {{{
96
+ @user_with_included_data.role.id.should == 1
97
+ @user_with_included_data.role.body.should == "Admin"
98
+ end # }}}
99
+
100
+ it "fetches data that was not included through has_one" do # {{{
101
+ @user_without_included_data.role.id.should == 2
102
+ @user_without_included_data.role.body.should == "User"
103
+ end # }}}
104
+
105
+ it "maps an array of included data through belongs_to" do # {{{
106
+ @user_with_included_data.organization.id.should == 1
107
+ @user_with_included_data.organization.name.should == "Bluth Company"
108
+ end # }}}
109
+
110
+ it "fetches data that was not included through belongs_to" do # {{{
111
+ @user_without_included_data.organization.id.should == 1
112
+ @user_without_included_data.organization.name.should == "Bluth Company"
113
+ end # }}}
114
+ end
115
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: her
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-04-11 00:00:00.000000000Z
12
+ date: 2012-04-15 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -173,12 +173,16 @@ files:
173
173
  - lib/her/api.rb
174
174
  - lib/her/model.rb
175
175
  - lib/her/model/base.rb
176
+ - lib/her/model/hooks.rb
176
177
  - lib/her/model/http.rb
177
178
  - lib/her/model/orm.rb
178
179
  - lib/her/model/relationships.rb
179
180
  - lib/her/version.rb
180
181
  - spec/api_spec.rb
181
- - spec/model_spec.rb
182
+ - spec/model/hooks_spec.rb
183
+ - spec/model/http_spec.rb
184
+ - spec/model/orm_spec.rb
185
+ - spec/model/relationships_spec.rb
182
186
  - spec/spec_helper.rb
183
187
  homepage: https://github.com/remiprev/her
184
188
  licenses: []
@@ -194,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
194
198
  version: '0'
195
199
  segments:
196
200
  - 0
197
- hash: -4167601811325738400
201
+ hash: 1685847524195482169
198
202
  required_rubygems_version: !ruby/object:Gem::Requirement
199
203
  none: false
200
204
  requirements:
@@ -203,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
203
207
  version: '0'
204
208
  segments:
205
209
  - 0
206
- hash: -4167601811325738400
210
+ hash: 1685847524195482169
207
211
  requirements: []
208
212
  rubyforge_project:
209
213
  rubygems_version: 1.8.18
@@ -213,6 +217,9 @@ summary: A simple Representational State Transfer-based Hypertext Transfer Proto
213
217
  Object Relational Mapper. Her?
214
218
  test_files:
215
219
  - spec/api_spec.rb
216
- - spec/model_spec.rb
220
+ - spec/model/hooks_spec.rb
221
+ - spec/model/http_spec.rb
222
+ - spec/model/orm_spec.rb
223
+ - spec/model/relationships_spec.rb
217
224
  - spec/spec_helper.rb
218
225
  has_rdoc:
@@ -1,336 +0,0 @@
1
- # encoding: utf-8
2
- require File.join(File.dirname(__FILE__), "spec_helper.rb")
3
-
4
- describe Her::Model do
5
- describe Her::Model::HTTP do
6
- context "binding a model with an API" do
7
- it "binds a model to an instance of Her::API" do # {{{
8
- @api = Her::API.new
9
- @api.setup :base_uri => "https://api.example.com"
10
-
11
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
12
- class User
13
- include Her::Model
14
- end
15
- User.uses_api @api
16
-
17
- User.class_eval do
18
- @her_api.should_not == nil
19
- @her_api.base_uri.should == "https://api.example.com"
20
- end
21
- end # }}}
22
-
23
- it "binds a model directly to Her::API" do # {{{
24
- Her::API.setup :base_uri => "https://api.example.com"
25
-
26
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
27
- class User
28
- include Her::Model
29
- end
30
-
31
- User.class_eval do
32
- @her_api.should_not == nil
33
- @her_api.base_uri.should == "https://api.example.com"
34
- end
35
- end # }}}
36
-
37
- it "binds two models to two different instances of Her::API" do # {{{
38
- @api1 = Her::API.new
39
- @api1.setup :base_uri => "https://api1.example.com"
40
-
41
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
42
- class User; include Her::Model; end
43
- User.uses_api @api1
44
-
45
- User.class_eval do
46
- @her_api.base_uri.should == "https://api1.example.com"
47
- end
48
-
49
- @api2 = Her::API.new
50
- @api2.setup :base_uri => "https://api2.example.com"
51
-
52
- Object.instance_eval { remove_const :Comment } if Object.const_defined?(:Comment)
53
- class Comment; include Her::Model; end
54
- Comment.uses_api @api2
55
-
56
- Comment.class_eval do
57
- @her_api.base_uri.should == "https://api2.example.com"
58
- end
59
- end # }}}
60
-
61
- it "binds one model to Her::API and another one to an instance of Her::API" do # {{{
62
- Her::API.setup :base_uri => "https://api1.example.com"
63
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
64
- class User; include Her::Model; end
65
-
66
- User.class_eval do
67
- @her_api.base_uri.should == "https://api1.example.com"
68
- end
69
-
70
- @api = Her::API.new
71
- @api.setup :base_uri => "https://api2.example.com"
72
-
73
- Object.instance_eval { remove_const :Comment } if Object.const_defined?(:Comment)
74
- class Comment; include Her::Model; end
75
- Comment.uses_api @api
76
-
77
- Comment.class_eval do
78
- @her_api.base_uri.should == "https://api2.example.com"
79
- end
80
- end # }}}
81
- end
82
-
83
- context "making HTTP requests" do
84
- before do # {{{
85
- @api = Her::API.new
86
- @api.setup :base_uri => "https://api.example.com"
87
- FakeWeb.register_uri(:get, "https://api.example.com/users", :body => { :data => [{ :id => 1 }] }.to_json)
88
- FakeWeb.register_uri(:get, "https://api.example.com/users?page=2", :body => { :data => [{ :id => 2 }] }.to_json)
89
- FakeWeb.register_uri(:get, "https://api.example.com/users/popular", :body => { :data => [{ :id => 1 }, { :id => 2 }] }.to_json)
90
- FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1 } }.to_json)
91
- FakeWeb.register_uri(:post, "https://api.example.com/users", :body => { :data => [{ :id => 3 }] }.to_json)
92
- FakeWeb.register_uri(:put, "https://api.example.com/users/4", :body => { :data => [{ :id => 4 }] }.to_json)
93
- FakeWeb.register_uri(:patch, "https://api.example.com/users/6", :body => { :data => [{ :id => 6 }] }.to_json)
94
- FakeWeb.register_uri(:delete, "https://api.example.com/users/5", :body => { :data => [{ :id => 5 }] }.to_json)
95
-
96
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
97
- class User
98
- include Her::Model
99
- end
100
- User.uses_api @api
101
- end # }}}
102
-
103
- it "handle raw GET" do # {{{
104
- User.get_raw("/users") do |parsed_data|
105
- parsed_data[:data].should == [{ :id => 1 }]
106
- end
107
- end # }}}
108
-
109
- it "handle raw POST" do # {{{
110
- User.post_raw("/users") do |parsed_data|
111
- parsed_data[:data].should == [{ :id => 3 }]
112
- end
113
- end # }}}
114
-
115
- it "handle raw PUT" do # {{{
116
- User.put_raw("/users/4") do |parsed_data|
117
- parsed_data[:data].should == [{ :id => 4 }]
118
- end
119
- end # }}}
120
-
121
- it "handle raw PATCH" do # {{{
122
- User.patch_raw("/users/6") do |parsed_data|
123
- parsed_data[:data].should == [{ :id => 6 }]
124
- end
125
- end # }}}
126
-
127
- it "handle raw DELETE" do # {{{
128
- User.delete_raw("/users/5") do |parsed_data|
129
- parsed_data[:data].should == [{ :id => 5 }]
130
- end
131
- end # }}}
132
-
133
- it "handle querystring parameters" do # {{{
134
- User.get_raw("/users", :page => 2) do |parsed_data|
135
- parsed_data[:data].should == [{ :id => 2 }]
136
- end
137
- end # }}}
138
-
139
- it "handle GET collection" do # {{{
140
- @users = User.get_collection("/users/popular")
141
- @users.length.should == 2
142
- @users.first.id.should == 1
143
- end # }}}
144
-
145
- it "handle GET resource" do # {{{
146
- @user = User.get_resource("/users/1")
147
- @user.id.should == 1
148
- end # }}}
149
- end
150
- end
151
-
152
- describe Her::Model::ORM do
153
- context "mapping data to Ruby objects" do
154
- before do # {{{
155
- @api = Her::API.new
156
- @api.setup :base_uri => "https://api.example.com"
157
- FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke" } }.to_json)
158
- FakeWeb.register_uri(:get, "https://api.example.com/users", :body => { :data => [{ :id => 1, :name => "Tobias Fünke" }, { :id => 2, :name => "Lindsay Fünke" }] }.to_json)
159
-
160
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
161
- class User
162
- include Her::Model
163
- end
164
- User.uses_api @api
165
- end # }}}
166
-
167
- it "maps a single resource to a Ruby object" do # {{{
168
- @user = User.find(1)
169
- @user.id.should == 1
170
- @user.name.should == "Tobias Fünke"
171
- end # }}}
172
-
173
- it "maps a collection of resources to an array of Ruby objects" do # {{{
174
- @users = User.all
175
- @users.length.should == 2
176
- @users.first.name.should == "Tobias Fünke"
177
- end # }}}
178
- end
179
-
180
- context "creating resources" do
181
- before do # {{{
182
- Her::API.setup :base_uri => "https://api.example.com"
183
- FakeWeb.register_uri(:post, "https://api.example.com/users", :body => { :data => { :id => 1, :fullname => "Tobias Fünke" } }.to_json)
184
-
185
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
186
- class User
187
- include Her::Model
188
- end
189
- end # }}}
190
-
191
- it "handle one-line resource creation" do # {{{
192
- @user = User.create(:fullname => "Tobias Fünke")
193
- @user.id.should == 1
194
- @user.fullname.should == "Tobias Fünke"
195
- end # }}}
196
-
197
- it "handle resource creation through Model.new + #save" do # {{{
198
- @user = User.new(:fullname => "Tobias Fünke")
199
- @user.save
200
- @user.fullname.should == "Tobias Fünke"
201
- end # }}}
202
- end
203
-
204
- context "updating resources" do
205
- before do # {{{
206
- @api = Her::API.new
207
- @api.setup :base_uri => "https://api.example.com"
208
- FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :fullname => "Tobias Fünke" } }.to_json)
209
- FakeWeb.register_uri(:put, "https://api.example.com/users/1", :body => { :data => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json)
210
-
211
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
212
- class User
213
- include Her::Model
214
- end
215
- end # }}}
216
-
217
- it "handle resource data update without saving it" do # {{{
218
- @user = User.find(1)
219
- @user.fullname.should == "Tobias Fünke"
220
- @user.fullname = "Kittie Sanchez"
221
- @user.fullname.should == "Kittie Sanchez"
222
- end # }}}
223
-
224
- it "handle resource update through #save on an existing resource" do # {{{
225
- @user = User.find(1)
226
- @user.fullname = "Lindsay Fünke"
227
- @user.save
228
- @user.fullname.should == "Lindsay Fünke"
229
- end # }}}
230
- end
231
- end
232
-
233
- describe Her::Model::Relationships do
234
- context "setting relationships" do
235
- before do # {{{
236
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
237
- class User
238
- include Her::Model
239
- end
240
- end # }}}
241
-
242
- it "handles a single 'has_many' relationship" do # {{{
243
- User.has_many :comments
244
- User.relationships[:has_many].should == [{ :name => :comments }]
245
- end # }}}
246
-
247
- it "handles multiples 'has_many' relationship" do # {{{
248
- User.has_many :comments
249
- User.has_many :posts
250
- User.relationships[:has_many].should == [{ :name => :comments }, { :name => :posts }]
251
- end # }}}
252
-
253
- it "handles a single 'has_one' relationship" do # {{{
254
- User.has_one :category
255
- User.relationships[:has_one].should == [{ :name => :category }]
256
- end # }}}
257
-
258
- it "handles multiples 'has_one' relationship" do # {{{
259
- User.has_one :category
260
- User.has_one :role
261
- User.relationships[:has_one].should == [{ :name => :category }, { :name => :role }]
262
- end # }}}
263
-
264
- it "handles a single belongs_to relationship" do # {{{
265
- User.belongs_to :organization
266
- User.relationships[:belongs_to].should == [{ :name => :organization }]
267
- end # }}}
268
-
269
- it "handles multiples 'belongs_to' relationship" do # {{{
270
- User.belongs_to :organization
271
- User.belongs_to :family
272
- User.relationships[:belongs_to].should == [{ :name => :organization }, { :name => :family }]
273
- end # }}}
274
- end
275
-
276
- context "handling relationships" do
277
- before do # {{{
278
- Her::API.setup :base_uri => "https://api.example.com"
279
- FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke", :comments => [{ :id => 2, :body => "Tobias, you blow hard!" }, { :id => 3, :body => "I wouldn't mind kissing that man between the cheeks, so to speak" }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 1, :name => "Bluth Company" }, :organization_id => 1 } }.to_json)
280
- FakeWeb.register_uri(:get, "https://api.example.com/users/2", :body => { :data => { :id => 2, :name => "Lindsay Fünke", :organization_id => 1 } }.to_json)
281
- FakeWeb.register_uri(:get, "https://api.example.com/users/2/comments", :body => { :data => [{ :id => 4, :body => "They're having a FIRESALE?" }, { :id => 5, :body => "Is this the tiny town from Footloose?" }] }.to_json)
282
- FakeWeb.register_uri(:get, "https://api.example.com/users/2/role", :body => { :data => { :id => 2, :body => "User" } }.to_json)
283
- FakeWeb.register_uri(:get, "https://api.example.com/organizations/1", :body => { :data => { :id => 1, :name => "Bluth Company" } }.to_json)
284
-
285
- Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
286
- class User
287
- include Her::Model
288
- has_many :comments
289
- has_one :role
290
- belongs_to :organization
291
- end
292
-
293
- Object.instance_eval { remove_const :Organization } if Object.const_defined?(:Organization)
294
- class Organization
295
- include Her::Model
296
- end
297
-
298
- Object.instance_eval { remove_const :Comment } if Object.const_defined?(:Comment)
299
- class Comment
300
- include Her::Model
301
- end
302
-
303
- Object.instance_eval { remove_const :Role } if Object.const_defined?(:Role)
304
- class Role
305
- include Her::Model
306
- end
307
- end # }}}
308
-
309
- it "maps an array of included data" do # {{{
310
- @user = User.find(1)
311
- @user.comments.length.should == 2
312
- @user.comments.first.id.should == 2
313
- @user.comments.first.body.should == "Tobias, you blow hard!"
314
-
315
- @user.role.id.should == 1
316
- @user.role.body.should == "Admin"
317
-
318
- @user.organization.id.should == 1
319
- @user.organization.name.should == "Bluth Company"
320
- end # }}}
321
-
322
- it "fetches data that was not included" do # {{{
323
- @user = User.find(2)
324
- @user.comments.length.should == 2
325
- @user.comments.first.id.should == 4
326
- @user.comments.first.body.should == "They're having a FIRESALE?"
327
-
328
- @user.role.id.should == 2
329
- @user.role.body.should == "User"
330
-
331
- @user.organization.id.should == 1
332
- @user.organization.name.should == "Bluth Company"
333
- end # }}}
334
- end
335
- end
336
- end