her 0.1.7 → 0.1.8

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.
@@ -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)