her 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -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) GET /users/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 # GET /users
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" }) # POST /users/1
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" }) # PUT /users/1
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) # GET /users/1
103
+ # @user = User.find(1)
104
+ # # Fetched via GET "/users/1"
93
105
  # @user.fullname = "Tobias Fünke"
94
- # @user.save # PUT /users/1
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 # POST /users
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.perform_hook(self, :before, :update)
103
- self.class.perform_hook(self, :before, :save)
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.perform_hook(self, :after, :save)
108
- self.class.perform_hook(self, :after, :update)
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.perform_hook(self, :before, :create)
112
- self.class.perform_hook(self, :before, :save)
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.perform_hook(self, :after, :save)
117
- self.class.perform_hook(self, :after, :create)
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) # GET /users/1
126
- # @user.destroy # DELETE /users/1
148
+ # @user = User.find(1)
149
+ # @user.destroy
150
+ # # Called via DELETE "/users/1"
127
151
  def destroy # {{{
128
152
  params = @data.dup
129
- self.class.perform_hook(self, :before, :destroy)
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(self, :after, :destroy)
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) # DELETE /users/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 for the resource
31
+ # Define an *has_many* relationship.
32
32
  #
33
- # * `User.has_many :comments` is used to check if the "user" JSON
34
- # resource we receive has a `comments` key and map it to an array
35
- # of Comment objects
36
- # * `User.has_many :comments` creates a User.comments method to would
37
- # make an extra HTTP request (to `/users/:id/comments`) if there was no "comments" key
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 for the resource
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
- # * `User.has_one :category` is used to check if the "category" JSON
52
- # resource we receive has a `category` key and map it to a Category object
53
- # * `User.has_one :category` creates a User.category method to would
54
- # make an extra HTTP request (to `/users/category`) if there was no "category" key
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 for the resource
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
- # * `User.belongs_to :organization` is used to check if the "organization" JSON
69
- # resource we receive has a `organization` key and map it to an Organization object
70
- # * `User.belongs_to :organization` creates a User.organization method to would
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)