her 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +7 -3
- data/README.md +82 -40
- data/Rakefile +1 -1
- data/her.gemspec +2 -2
- data/lib/her.rb +1 -1
- data/lib/her/api.rb +48 -32
- data/lib/her/middleware/default_parse_json.rb +18 -8
- data/lib/her/model.rb +3 -1
- data/lib/her/model/hooks.rb +52 -12
- data/lib/her/model/http.rb +142 -0
- data/lib/her/model/introspection.rb +32 -0
- data/lib/her/model/orm.rb +46 -20
- data/lib/her/model/relationships.rb +51 -16
- data/lib/her/version.rb +1 -1
- data/spec/api_spec.rb +25 -4
- data/spec/middleware/default_parse_json_spec.rb +24 -0
- data/spec/model/hooks_spec.rb +80 -80
- data/spec/model/http_spec.rb +58 -0
- data/spec/model/introspection_spec.rb +27 -0
- data/spec/model/orm_spec.rb +8 -0
- metadata +15 -10
data/lib/her/model/http.rb
CHANGED
@@ -37,13 +37,35 @@ module Her
|
|
37
37
|
yield @her_api.request(attrs)
|
38
38
|
end # }}}
|
39
39
|
|
40
|
+
# Make a GET request and return either a collection or a resource
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# class User
|
44
|
+
# include Her::Model
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# @popular_users = User.get(:popular)
|
48
|
+
# # Fetched via GET "/users/popular"
|
49
|
+
def get(path, attrs={}) # {{{
|
50
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
51
|
+
get_raw(path, attrs) do |parsed_data|
|
52
|
+
if parsed_data[:data].is_a?(Array)
|
53
|
+
new_collection(parsed_data)
|
54
|
+
else
|
55
|
+
new(parsed_data[:data])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end # }}}
|
59
|
+
|
40
60
|
# Make a GET request and return the parsed JSON response (not mapped to objects)
|
41
61
|
def get_raw(path, attrs={}, &block) # {{{
|
62
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
42
63
|
request(attrs.merge(:_method => :get, :_path => path), &block)
|
43
64
|
end # }}}
|
44
65
|
|
45
66
|
# Make a GET request and return a collection of resources
|
46
67
|
def get_collection(path, attrs={}) # {{{
|
68
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
47
69
|
get_raw(path, attrs) do |parsed_data|
|
48
70
|
new_collection(parsed_data)
|
49
71
|
end
|
@@ -51,18 +73,33 @@ module Her
|
|
51
73
|
|
52
74
|
# Make a GET request and return a collection of resources
|
53
75
|
def get_resource(path, attrs={}) # {{{
|
76
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
54
77
|
get_raw(path, attrs) do |parsed_data|
|
55
78
|
new(parsed_data[:data])
|
56
79
|
end
|
57
80
|
end # }}}
|
58
81
|
|
82
|
+
# Make a POST request and return either a collection or a resource
|
83
|
+
def post(path, attrs={}) # {{{
|
84
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
85
|
+
post_raw(path, attrs) do |parsed_data|
|
86
|
+
if parsed_data[:data].is_a?(Array)
|
87
|
+
new_collection(parsed_data)
|
88
|
+
else
|
89
|
+
new(parsed_data[:data])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end # }}}
|
93
|
+
|
59
94
|
# Make a POST request and return the parsed JSON response (not mapped to objects)
|
60
95
|
def post_raw(path, attrs={}, &block) # {{{
|
96
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
61
97
|
request(attrs.merge(:_method => :post, :_path => path), &block)
|
62
98
|
end # }}}
|
63
99
|
|
64
100
|
# Make a POST request and return a collection of resources
|
65
101
|
def post_collection(path, attrs={}) # {{{
|
102
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
66
103
|
post_raw(path, attrs) do |parsed_data|
|
67
104
|
new_collection(parsed_data)
|
68
105
|
end
|
@@ -70,18 +107,33 @@ module Her
|
|
70
107
|
|
71
108
|
# Make a POST request and return a collection of resources
|
72
109
|
def post_resource(path, attrs={}) # {{{
|
110
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
73
111
|
post_raw(path, attrs) do |parsed_data|
|
74
112
|
new(parsed_data[:data])
|
75
113
|
end
|
76
114
|
end # }}}
|
77
115
|
|
116
|
+
# Make a PUT request and return either a collection or a resource
|
117
|
+
def put(path, attrs={}) # {{{
|
118
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
119
|
+
put_raw(path, attrs) do |parsed_data|
|
120
|
+
if parsed_data[:data].is_a?(Array)
|
121
|
+
new_collection(parsed_data)
|
122
|
+
else
|
123
|
+
new(parsed_data[:data])
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end # }}}
|
127
|
+
|
78
128
|
# Make a PUT request and return the parsed JSON response (not mapped to objects)
|
79
129
|
def put_raw(path, attrs={}, &block) # {{{
|
130
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
80
131
|
request(attrs.merge(:_method => :put, :_path => path), &block)
|
81
132
|
end # }}}
|
82
133
|
|
83
134
|
# Make a PUT request and return a collection of resources
|
84
135
|
def put_collection(path, attrs={}) # {{{
|
136
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
85
137
|
put_raw(path, attrs) do |parsed_data|
|
86
138
|
new_collection(parsed_data)
|
87
139
|
end
|
@@ -89,18 +141,33 @@ module Her
|
|
89
141
|
|
90
142
|
# Make a PUT request and return a collection of resources
|
91
143
|
def put_resource(path, attrs={}) # {{{
|
144
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
92
145
|
put_raw(path, attrs) do |parsed_data|
|
93
146
|
new(parsed_data[:data])
|
94
147
|
end
|
95
148
|
end # }}}
|
96
149
|
|
150
|
+
# Make a PATCH request and return either a collection or a resource
|
151
|
+
def patch(path, attrs={}) # {{{
|
152
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
153
|
+
patch_raw(path, attrs) do |parsed_data|
|
154
|
+
if parsed_data[:data].is_a?(Array)
|
155
|
+
new_collection(parsed_data)
|
156
|
+
else
|
157
|
+
new(parsed_data[:data])
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end # }}}
|
161
|
+
|
97
162
|
# Make a PATCH request and return the parsed JSON response (not mapped to objects)
|
98
163
|
def patch_raw(path, attrs={}, &block) # {{{
|
164
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
99
165
|
request(attrs.merge(:_method => :patch, :_path => path), &block)
|
100
166
|
end # }}}
|
101
167
|
|
102
168
|
# Make a PATCH request and return a collection of resources
|
103
169
|
def patch_collection(path, attrs={}) # {{{
|
170
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
104
171
|
patch_raw(path, attrs) do |parsed_data|
|
105
172
|
new_collection(parsed_data)
|
106
173
|
end
|
@@ -108,18 +175,33 @@ module Her
|
|
108
175
|
|
109
176
|
# Make a PATCH request and return a collection of resources
|
110
177
|
def patch_resource(path, attrs={}) # {{{
|
178
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
111
179
|
patch_raw(path, attrs) do |parsed_data|
|
112
180
|
new(parsed_data[:data])
|
113
181
|
end
|
114
182
|
end # }}}
|
115
183
|
|
184
|
+
# Make a DELETE request and return either a collection or a resource
|
185
|
+
def delete(path, attrs={}) # {{{
|
186
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
187
|
+
delete_raw(path, attrs) do |parsed_data|
|
188
|
+
if parsed_data[:data].is_a?(Array)
|
189
|
+
new_collection(parsed_data)
|
190
|
+
else
|
191
|
+
new(parsed_data[:data])
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end # }}}
|
195
|
+
|
116
196
|
# Make a DELETE request and return the parsed JSON response (not mapped to objects)
|
117
197
|
def delete_raw(path, attrs={}, &block) # {{{
|
198
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
118
199
|
request(attrs.merge(:_method => :delete, :_path => path), &block)
|
119
200
|
end # }}}
|
120
201
|
|
121
202
|
# Make a DELETE request and return a collection of resources
|
122
203
|
def delete_collection(path, attrs={}) # {{{
|
204
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
123
205
|
delete_raw(path, attrs) do |parsed_data|
|
124
206
|
new_collection(parsed_data)
|
125
207
|
end
|
@@ -127,10 +209,70 @@ module Her
|
|
127
209
|
|
128
210
|
# Make a DELETE request and return a collection of resources
|
129
211
|
def delete_resource(path, attrs={}) # {{{
|
212
|
+
path = "#{@her_collection_path}/#{path}" if path.is_a?(Symbol)
|
130
213
|
delete_raw(path, attrs) do |parsed_data|
|
131
214
|
new(parsed_data[:data])
|
132
215
|
end
|
133
216
|
end # }}}
|
217
|
+
|
218
|
+
# Define custom GET requests
|
219
|
+
#
|
220
|
+
# @example
|
221
|
+
# class User
|
222
|
+
# include Her::Model
|
223
|
+
# custom_get :popular
|
224
|
+
# end
|
225
|
+
#
|
226
|
+
# User.popular
|
227
|
+
# # Fetched from GET "/users/popular"
|
228
|
+
def custom_get(*paths) # {{{
|
229
|
+
metaclass = (class << self; self; end)
|
230
|
+
paths.each do |path|
|
231
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
232
|
+
get(path, attrs.first || Hash.new)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end # }}}
|
236
|
+
|
237
|
+
# Define custom POST requests
|
238
|
+
def custom_post(*paths) # {{{
|
239
|
+
metaclass = (class << self; self; end)
|
240
|
+
paths.each do |path|
|
241
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
242
|
+
post(path, attrs.first || Hash.new)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end # }}}
|
246
|
+
|
247
|
+
# Define custom PUT requests
|
248
|
+
def custom_put(*paths) # {{{
|
249
|
+
metaclass = (class << self; self; end)
|
250
|
+
paths.each do |path|
|
251
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
252
|
+
put(path, attrs.first || Hash.new)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end # }}}
|
256
|
+
|
257
|
+
# Define custom PATCH requests
|
258
|
+
def custom_patch(*paths) # {{{
|
259
|
+
metaclass = (class << self; self; end)
|
260
|
+
paths.each do |path|
|
261
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
262
|
+
patch(path, attrs.first || Hash.new)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end # }}}
|
266
|
+
|
267
|
+
# Define custom DELETE requests
|
268
|
+
def custom_delete(*paths) # {{{
|
269
|
+
metaclass = (class << self; self; end)
|
270
|
+
paths.each do |path|
|
271
|
+
metaclass.send(:define_method, path.to_sym) do |*attrs|
|
272
|
+
delete(path, attrs.first || Hash.new)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end # }}}
|
134
276
|
end
|
135
277
|
end
|
136
278
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Her
|
2
|
+
module Model
|
3
|
+
module Introspection
|
4
|
+
# Inspect an element, returns it for introspection.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# class User
|
8
|
+
# include Her::Model
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# @user = User.find(1)
|
12
|
+
# p @user # => #<User(/users/1) id=1 name="Tobias Fünke">
|
13
|
+
def inspect # {{{
|
14
|
+
resource_path = self.class.collection_path
|
15
|
+
resource_path << "/#{id}" if @data.include?(:id)
|
16
|
+
"#<#{self.class}(#{resource_path}) #{@data.inject([]) { |memo, item| key, value = item; memo << "#{key}=#{attribute_for_inspect(value)}"}.join(" ")}>"
|
17
|
+
end # }}}
|
18
|
+
|
19
|
+
private
|
20
|
+
# @private
|
21
|
+
def attribute_for_inspect(value) # {{{
|
22
|
+
if value.is_a?(String) && value.length > 50
|
23
|
+
"#{value[0..50]}...".inspect
|
24
|
+
elsif value.is_a?(Date) || value.is_a?(Time)
|
25
|
+
%("#{value}")
|
26
|
+
else
|
27
|
+
value.inspect
|
28
|
+
end
|
29
|
+
end # }}}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/her/model/orm.rb
CHANGED
@@ -32,15 +32,23 @@ module Her
|
|
32
32
|
end # }}}
|
33
33
|
|
34
34
|
# Initialize a collection of resources with raw data from an HTTP request
|
35
|
+
#
|
36
|
+
# @param [Hash] parsed_data The raw `parsed_data` parsed from the HTTP response
|
35
37
|
def new_collection(parsed_data) # {{{
|
36
38
|
collection_data = parsed_data[:data]
|
37
39
|
Her::Model::ORM.initialize_collection(self.to_s.downcase.to_sym, collection_data)
|
38
40
|
end # }}}
|
39
41
|
|
42
|
+
# Return `true` if a resource was not saved yet
|
43
|
+
def new? # {{{
|
44
|
+
!@data.include?(:id)
|
45
|
+
end # }}}
|
46
|
+
|
40
47
|
# Fetch a specific resource based on an ID
|
41
48
|
#
|
42
49
|
# @example
|
43
|
-
# @user = User.find(1)
|
50
|
+
# @user = User.find(1)
|
51
|
+
# # Fetched via GET "/users/1"
|
44
52
|
def find(id, params={}) # {{{
|
45
53
|
request(params.merge(:_method => :get, :_path => "#{@her_collection_path}/#{id}")) do |parsed_data|
|
46
54
|
new(parsed_data[:data])
|
@@ -50,7 +58,8 @@ module Her
|
|
50
58
|
# Fetch a collection of resources
|
51
59
|
#
|
52
60
|
# @example
|
53
|
-
# @users = User.all
|
61
|
+
# @users = User.all
|
62
|
+
# # Fetched via GET "/users"
|
54
63
|
def all(params={}) # {{{
|
55
64
|
request(params.merge(:_method => :get, :_path => "#{@her_collection_path}")) do |parsed_data|
|
56
65
|
new_collection(parsed_data)
|
@@ -60,7 +69,8 @@ module Her
|
|
60
69
|
# Create a resource and return it
|
61
70
|
#
|
62
71
|
# @example
|
63
|
-
# @user = User.create({ :fullname => "Tobias Fünke" })
|
72
|
+
# @user = User.create({ :fullname => "Tobias Fünke" })
|
73
|
+
# # Called via POST "/users/1"
|
64
74
|
def create(params={}) # {{{
|
65
75
|
resource = new(params)
|
66
76
|
perform_hook(resource, :before, :create)
|
@@ -80,7 +90,8 @@ module Her
|
|
80
90
|
# Save an existing resource and return it
|
81
91
|
#
|
82
92
|
# @example
|
83
|
-
# @user = User.save_existing(1, { :fullname => "Tobias Fünke" })
|
93
|
+
# @user = User.save_existing(1, { :fullname => "Tobias Fünke" })
|
94
|
+
# # Called via PUT "/users/1"
|
84
95
|
def save_existing(id, params) # {{{
|
85
96
|
resource = new(params.merge(:id => id))
|
86
97
|
resource.save
|
@@ -89,32 +100,44 @@ module Her
|
|
89
100
|
# Save a resource
|
90
101
|
#
|
91
102
|
# @example Save a resource after fetching it
|
92
|
-
# @user = User.find(1)
|
103
|
+
# @user = User.find(1)
|
104
|
+
# # Fetched via GET "/users/1"
|
93
105
|
# @user.fullname = "Tobias Fünke"
|
94
|
-
# @user.save
|
106
|
+
# @user.save
|
107
|
+
# # Called via PUT "/users/1"
|
95
108
|
#
|
96
109
|
# @example Save a new resource by creating it
|
97
110
|
# @user = User.new({ :fullname => "Tobias Fünke" })
|
98
|
-
# @user.save
|
111
|
+
# @user.save
|
112
|
+
# # Called via POST "/users"
|
99
113
|
def save # {{{
|
100
114
|
params = @data.dup
|
115
|
+
resource = self
|
101
116
|
if @data[:id]
|
102
|
-
self.class.
|
103
|
-
|
117
|
+
self.class.class_eval do
|
118
|
+
perform_hook(resource, :before, :update)
|
119
|
+
perform_hook(resource, :before, :save)
|
120
|
+
end
|
104
121
|
self.class.request(params.merge(:_method => :put, :_path => "#{self.class.collection_path}/#{id}")) do |parsed_data|
|
105
122
|
@data = parsed_data[:data]
|
106
123
|
end
|
107
|
-
self.class.
|
108
|
-
|
124
|
+
self.class.class_eval do
|
125
|
+
perform_hook(resource, :after, :save)
|
126
|
+
perform_hook(resource, :after, :update)
|
127
|
+
end
|
109
128
|
self
|
110
129
|
else
|
111
|
-
self.class.
|
112
|
-
|
130
|
+
self.class.class_eval do
|
131
|
+
perform_hook(resource, :before, :create)
|
132
|
+
perform_hook(resource, :before, :save)
|
133
|
+
end
|
113
134
|
self.class.request(params.merge(:_method => :post, :_path => "#{self.class.collection_path}")) do |parsed_data|
|
114
135
|
@data = parsed_data[:data]
|
115
136
|
end
|
116
|
-
self.class.
|
117
|
-
|
137
|
+
self.class.class_eval do
|
138
|
+
perform_hook(resource, :after, :save)
|
139
|
+
perform_hook(resource, :after, :create)
|
140
|
+
end
|
118
141
|
end
|
119
142
|
self
|
120
143
|
end # }}}
|
@@ -122,22 +145,25 @@ module Her
|
|
122
145
|
# Destroy a resource
|
123
146
|
#
|
124
147
|
# @example
|
125
|
-
# @user = User.find(1)
|
126
|
-
# @user.destroy
|
148
|
+
# @user = User.find(1)
|
149
|
+
# @user.destroy
|
150
|
+
# # Called via DELETE "/users/1"
|
127
151
|
def destroy # {{{
|
128
152
|
params = @data.dup
|
129
|
-
|
153
|
+
resource = self
|
154
|
+
self.class.class_eval { perform_hook(resource, :before, :destroy) }
|
130
155
|
self.class.request(params.merge(:_method => :delete, :_path => "#{self.class.collection_path}/#{id}")) do |parsed_data|
|
131
156
|
@data = parsed_data[:data]
|
132
157
|
end
|
133
|
-
self.class.perform_hook(
|
158
|
+
self.class.class_eval { perform_hook(resource, :after, :destroy) }
|
134
159
|
self
|
135
160
|
end # }}}
|
136
161
|
|
137
162
|
# Destroy an existing resource
|
138
163
|
#
|
139
164
|
# @example
|
140
|
-
# User.destroy_existing(1)
|
165
|
+
# User.destroy_existing(1)
|
166
|
+
# # Called via DELETE "/users/1"
|
141
167
|
def destroy_existing(id) # {{{
|
142
168
|
params = {}
|
143
169
|
request(params.merge(:_method => :delete, :_path => "#{collection_path}/#{id}")) do |parsed_data|
|
@@ -28,13 +28,24 @@ module Her
|
|
28
28
|
data
|
29
29
|
end # }}}
|
30
30
|
|
31
|
-
# Define an *has_many* relationship
|
31
|
+
# Define an *has_many* relationship.
|
32
32
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
33
|
+
# @param [Symbol] name The name of the model
|
34
|
+
# @param [Hash] attrs Options (currently not used)
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# class User
|
38
|
+
# include Her::API
|
39
|
+
# has_many :articles
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# class Article
|
43
|
+
# include Her::API
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# @user = User.find(1)
|
47
|
+
# @user.articles # => [#<Article(articles/2) id=2 title="Hello world.">]
|
48
|
+
# # Fetched via GET "/users/1/articles"
|
38
49
|
def has_many(name, attrs={}) # {{{
|
39
50
|
@her_relationships ||= {}
|
40
51
|
(@her_relationships[:has_many] ||= []) << attrs.merge(:name => name)
|
@@ -46,12 +57,24 @@ module Her
|
|
46
57
|
end
|
47
58
|
end # }}}
|
48
59
|
|
49
|
-
# Define an *has_one* relationship
|
60
|
+
# Define an *has_one* relationship.
|
61
|
+
#
|
62
|
+
# @param [Symbol] name The name of the model
|
63
|
+
# @param [Hash] attrs Options (currently not used)
|
64
|
+
#
|
65
|
+
# @example
|
66
|
+
# class User
|
67
|
+
# include Her::API
|
68
|
+
# has_one :organization
|
69
|
+
# end
|
50
70
|
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
71
|
+
# class Organization
|
72
|
+
# include Her::API
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# @user = User.find(1)
|
76
|
+
# @user.organization # => #<Organization(organizations/2) id=2 name="Foobar Inc.">
|
77
|
+
# # Fetched via GET "/users/1/organization"
|
55
78
|
def has_one(name, attrs={}) # {{{
|
56
79
|
@her_relationships ||= {}
|
57
80
|
(@her_relationships[:has_one] ||= []) << attrs.merge(:name => name)
|
@@ -63,12 +86,24 @@ module Her
|
|
63
86
|
end
|
64
87
|
end # }}}
|
65
88
|
|
66
|
-
# Define a *belongs_to* relationship
|
89
|
+
# Define a *belongs_to* relationship.
|
90
|
+
#
|
91
|
+
# @param [Symbol] name The name of the model
|
92
|
+
# @param [Hash] attrs Options (currently not used)
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# class User
|
96
|
+
# include Her::API
|
97
|
+
# belongs_to :team
|
98
|
+
# end
|
99
|
+
#
|
100
|
+
# class Team
|
101
|
+
# include Her::API
|
102
|
+
# end
|
67
103
|
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
# make an extra HTTP request (to `/organizations/:organization_id`) if there was no "organization" key
|
104
|
+
# @user = User.find(1)
|
105
|
+
# @user.team # => #<Team(teams/2) id=2 name="Developers">
|
106
|
+
# # Fetched via GET "/teams/2"
|
72
107
|
def belongs_to(name, attrs={}) # {{{
|
73
108
|
@her_relationships ||= {}
|
74
109
|
(@her_relationships[:belongs_to] ||= []) << attrs.merge(:name => name)
|