her 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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