her 0.2.6 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/README.md +78 -39
- data/lib/her/model/introspection.rb +27 -0
- data/lib/her/model/orm.rb +3 -5
- data/lib/her/model/paths.rb +6 -2
- data/lib/her/model/relationships.rb +44 -32
- data/lib/her/version.rb +1 -1
- data/spec/model/hooks_spec.rb +105 -105
- data/spec/model/http_spec.rb +44 -33
- data/spec/model/introspection_spec.rb +27 -6
- data/spec/model/orm_spec.rb +19 -20
- data/spec/model/paths_spec.rb +43 -43
- data/spec/model/relationships_spec.rb +48 -51
- data/spec/spec_helper.rb +28 -13
- metadata +4 -4
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -64,14 +64,16 @@ You can look into the `examples` directory for sample applications using Her.
|
|
64
64
|
|
65
65
|
## Middleware
|
66
66
|
|
67
|
-
Since Her relies on [Faraday](https://github.com/technoweenie/faraday) to send HTTP requests, you can
|
67
|
+
Since Her relies on [Faraday](https://github.com/technoweenie/faraday) to send HTTP requests, you can choose the middleware used to handle requests and responses. Using the block in the `setup` call, you have access to Faraday’s `connection` object and are able to customize the middleware stack used on each request and response.
|
68
68
|
|
69
69
|
### Authentication
|
70
70
|
|
71
|
-
Her doesn’t support
|
71
|
+
Her doesn’t support authentication by default. However, it’s easy to implement one with request middleware. Using the `connection` block, we can add it to the middleware stack.
|
72
|
+
|
73
|
+
For example, to add a API token header to your requests, you would do something like this:
|
72
74
|
|
73
75
|
```ruby
|
74
|
-
class
|
76
|
+
class TokenAuthentication < Faraday::Middleware
|
75
77
|
def initialize(app, options={})
|
76
78
|
@options = options
|
77
79
|
end
|
@@ -84,7 +86,7 @@ end
|
|
84
86
|
|
85
87
|
Her::API.setup :url => "https://api.example.com" do |connection|
|
86
88
|
# This token could be stored in the client session
|
87
|
-
connection.use
|
89
|
+
connection.use TokenAuthentication, :token => "bb2b2dd75413d32c1ac421d39e95b978d1819ff611f68fc2fdd5c8b9c7331192"
|
88
90
|
|
89
91
|
connection.use Faraday::Request::UrlEncoded
|
90
92
|
connection.use Her::Middleware::DefaultParseJSON
|
@@ -106,9 +108,19 @@ By default, Her handles JSON data. It expects the resource/collection data to be
|
|
106
108
|
[{ "id" : 1, "name" : "Tobias Fünke" }]
|
107
109
|
```
|
108
110
|
|
109
|
-
However, you can define your own parsing method
|
111
|
+
However, you can define your own parsing method using a response middleware. The middleware should set `env[:body]` to a hash with three keys: `data`, `errors` and `metadata`. The following code uses a custom middleware to parse the JSON data:
|
110
112
|
|
111
113
|
```ruby
|
114
|
+
# Expects responses like:
|
115
|
+
#
|
116
|
+
# {
|
117
|
+
# "result": {
|
118
|
+
# "id": 1,
|
119
|
+
# "name": "Tobias Fünke"
|
120
|
+
# },
|
121
|
+
# "errors" => []
|
122
|
+
# }
|
123
|
+
#
|
112
124
|
class MyCustomParser < Faraday::Response::Middleware
|
113
125
|
def on_complete(env)
|
114
126
|
json = MultiJson.load(env[:body], :symbolize_keys => true)
|
@@ -125,7 +137,6 @@ Her::API.setup :url => "https://api.example.com" do |connection|
|
|
125
137
|
connection.use MyCustomParser
|
126
138
|
connection.use Faraday::Adapter::NetHttp
|
127
139
|
end
|
128
|
-
# User.find(1) will now expect "https://api.example.com/users/1" to return something like '{ "result" => { "id": 1, "name": "Tobias Fünke" }, "errors" => [] }'
|
129
140
|
```
|
130
141
|
|
131
142
|
### OAuth
|
@@ -219,11 +230,12 @@ end
|
|
219
230
|
|
220
231
|
## Relationships
|
221
232
|
|
222
|
-
You can define `has_many`, `has_one` and `belongs_to` relationships in your models. The relationship data is handled in two different ways.
|
233
|
+
You can define `has_many`, `has_one` and `belongs_to` relationships in your models. The relationship data is handled in two different ways.
|
223
234
|
|
224
|
-
If
|
235
|
+
1. If Her finds relationship data when parsing a resource, that data will be used to create the associated model objects on the resource.
|
236
|
+
2. If no relationship data was included when parsing a resource, calling a method with the same name as the relationship will fetch the data (providing there’s an HTTP request available for it in the API).
|
225
237
|
|
226
|
-
For example
|
238
|
+
For example:
|
227
239
|
|
228
240
|
```ruby
|
229
241
|
class User
|
@@ -249,34 +261,51 @@ end
|
|
249
261
|
If there’s relationship data in the resource, no extra HTTP request is made when calling the `#comments` method and an array of resources is returned:
|
250
262
|
|
251
263
|
```ruby
|
252
|
-
@user = User.find(1)
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
264
|
+
@user = User.find(1)
|
265
|
+
# {
|
266
|
+
# :data => {
|
267
|
+
# :id => 1,
|
268
|
+
# :name => "George Michael Bluth",
|
269
|
+
# :comments => [
|
270
|
+
# { :id => 1, :text => "Foo" },
|
271
|
+
# { :id => 2, :text => "Bar" }
|
272
|
+
# ],
|
273
|
+
# :role => { :id => 1, :name => "Admin" },
|
274
|
+
# :organization => { :id => 2, :name => "Bluth Company" }
|
275
|
+
# }
|
276
|
+
# }
|
277
|
+
@user.comments
|
278
|
+
# [#<Comment id=1 text="Foo">, #<Comment id=2 text="Bar">]
|
279
|
+
@user.role
|
280
|
+
# #<Role id=1 name="Admin">
|
281
|
+
@user.organization
|
282
|
+
# #<Organization id=2 name="Bluth Company">
|
263
283
|
```
|
264
284
|
|
265
|
-
|
285
|
+
If there’s no relationship data in the resource, Her makes a HTTP request to retrieve the data.
|
266
286
|
|
267
287
|
```ruby
|
268
|
-
@user = User.find(1)
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
288
|
+
@user = User.find(1)
|
289
|
+
# { :data => { :id => 1, :name => "George Michael Bluth", :organization_id => 2 }}
|
290
|
+
|
291
|
+
# has_many relationship:
|
292
|
+
@user.comments
|
293
|
+
# GET /users/1/comments
|
294
|
+
# [#<Comment id=1>, #<Comment id=2>]
|
295
|
+
|
296
|
+
# has_one relationship:
|
297
|
+
@user.role
|
298
|
+
# GET /users/1/role
|
299
|
+
# #<Role id=1>
|
300
|
+
|
301
|
+
# belongs_to relationship:
|
302
|
+
@user.organization
|
303
|
+
# (the organization id comes from :organization_id, by default)
|
304
|
+
# GET /organizations/2
|
305
|
+
# #<Organization id=2>
|
277
306
|
```
|
278
307
|
|
279
|
-
|
308
|
+
Subsequent calls to `#comments`, `#role` and `#organization` will not trigger extra HTTP requests and will return the cached objects.
|
280
309
|
|
281
310
|
## Hooks
|
282
311
|
|
@@ -307,14 +336,17 @@ class User
|
|
307
336
|
custom_post :from_default
|
308
337
|
end
|
309
338
|
|
310
|
-
User.popular
|
339
|
+
User.popular
|
311
340
|
# GET /users/popular
|
341
|
+
# [#<User id=1>, #<User id=2>]
|
312
342
|
|
313
|
-
User.unpopular
|
343
|
+
User.unpopular
|
314
344
|
# GET /users/unpopular
|
345
|
+
# [#<User id=3>, #<User id=4>]
|
315
346
|
|
316
|
-
User.from_default(:name => "Maeby Fünke")
|
347
|
+
User.from_default(:name => "Maeby Fünke")
|
317
348
|
# POST /users/from_default?name=Maeby+Fünke
|
349
|
+
# #<User id=5 name="Maeby Fünke">
|
318
350
|
```
|
319
351
|
|
320
352
|
You can also use `get`, `post`, `put` or `delete` (which maps the returned data to either a collection or a resource).
|
@@ -324,11 +356,13 @@ class User
|
|
324
356
|
include Her::Model
|
325
357
|
end
|
326
358
|
|
327
|
-
User.get(:popular)
|
359
|
+
User.get(:popular)
|
328
360
|
# GET /users/popular
|
361
|
+
# [#<User id=1>, #<User id=2>]
|
329
362
|
|
330
|
-
User.get(:single_best)
|
363
|
+
User.get(:single_best)
|
331
364
|
# GET /users/single_best
|
365
|
+
# #<User id=1>
|
332
366
|
```
|
333
367
|
|
334
368
|
Also, `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) can also be used. Other HTTP methods are supported (`post_raw`, `put_resource`, etc.).
|
@@ -348,8 +382,12 @@ class User
|
|
348
382
|
end
|
349
383
|
end
|
350
384
|
|
351
|
-
User.popular
|
352
|
-
|
385
|
+
User.popular
|
386
|
+
# GET /users/popular
|
387
|
+
# [#<User id=1>, #<User id=2>]
|
388
|
+
User.total
|
389
|
+
# GET /users/stats
|
390
|
+
# => 42
|
353
391
|
```
|
354
392
|
|
355
393
|
You can also use full request paths (with strings instead of symbols).
|
@@ -359,8 +397,9 @@ class User
|
|
359
397
|
include Her::Model
|
360
398
|
end
|
361
399
|
|
362
|
-
User.get("/users/popular")
|
400
|
+
User.get("/users/popular")
|
363
401
|
# GET /users/popular
|
402
|
+
# [#<User id=1>, #<User id=2>]
|
364
403
|
```
|
365
404
|
|
366
405
|
## Custom paths
|
@@ -1,6 +1,33 @@
|
|
1
1
|
module Her
|
2
2
|
module Model
|
3
3
|
module Introspection
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
# Finds a class at the same level as this one or at the global level.
|
8
|
+
def nearby_class(name)
|
9
|
+
sibling_class(name) || name.constantize rescue nil
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
# Looks for a class at the same level as this one with the given name.
|
14
|
+
# @private
|
15
|
+
def sibling_class(name)
|
16
|
+
if mod = self.containing_module
|
17
|
+
"#{mod.name}::#{name}".constantize rescue nil
|
18
|
+
else
|
19
|
+
name.constantize rescue nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# If available, returns the containing Module for this class.
|
24
|
+
# @private
|
25
|
+
def containing_module # {{{
|
26
|
+
return unless self.name =~ /::/
|
27
|
+
self.name.split("::")[0..-2].join("::").constantize
|
28
|
+
end # }}}
|
29
|
+
end
|
30
|
+
|
4
31
|
# Inspect an element, returns it for introspection.
|
5
32
|
#
|
6
33
|
# @example
|
data/lib/her/model/orm.rb
CHANGED
@@ -20,10 +20,8 @@ module Her
|
|
20
20
|
|
21
21
|
# Initialize a collection of resources
|
22
22
|
# @private
|
23
|
-
def self.initialize_collection(
|
24
|
-
collection_data = parsed_data[:data].map
|
25
|
-
Object.const_get(name.to_s.classify).new(item_data)
|
26
|
-
end
|
23
|
+
def self.initialize_collection(klass, parsed_data={}) # {{{
|
24
|
+
collection_data = parsed_data[:data].map { |item_data| klass.new(item_data) }
|
27
25
|
Her::Collection.new(collection_data, parsed_data[:metadata], parsed_data[:errors])
|
28
26
|
end # }}}
|
29
27
|
|
@@ -54,7 +52,7 @@ module Her
|
|
54
52
|
#
|
55
53
|
# @param [Array] parsed_data
|
56
54
|
def new_collection(parsed_data) # {{{
|
57
|
-
Her::Model::ORM.initialize_collection(self
|
55
|
+
Her::Model::ORM.initialize_collection(self, parsed_data)
|
58
56
|
end # }}}
|
59
57
|
|
60
58
|
# Return `true` if a resource was not saved yet
|
data/lib/her/model/paths.rb
CHANGED
@@ -35,8 +35,12 @@ module Her
|
|
35
35
|
# end
|
36
36
|
#
|
37
37
|
# User.all # Fetched via GET /utilisateurs
|
38
|
-
def build_request_path(parameters={}) # {{{
|
39
|
-
|
38
|
+
def build_request_path(path=nil, parameters={}) # {{{
|
39
|
+
unless path.is_a?(String)
|
40
|
+
parameters = path || {}
|
41
|
+
path = parameters.include?(:id) ? @her_resource_path : @her_collection_path
|
42
|
+
end
|
43
|
+
path.gsub(/:([\w_]+)/) do
|
40
44
|
# Look for :key or :_key, otherwise raise an exception
|
41
45
|
parameters[$1.to_sym] || parameters["_#{$1}".to_sym] || raise(Her::Errors::PathError.new("Missing :_#{$1} parameter to build the request path (#{path})."))
|
42
46
|
end
|
@@ -15,13 +15,13 @@ module Her
|
|
15
15
|
@her_relationships.each_pair do |type, relationships|
|
16
16
|
relationships.each do |relationship|
|
17
17
|
name = relationship[:name]
|
18
|
-
|
18
|
+
klass = self.nearby_class(relationship[:class_name])
|
19
19
|
next if !data.include?(name) or data[name].nil?
|
20
20
|
data[name] = case type
|
21
21
|
when :has_many
|
22
|
-
Her::Model::ORM.initialize_collection(
|
22
|
+
Her::Model::ORM.initialize_collection(klass, :data => data[name])
|
23
23
|
when :has_one, :belongs_to
|
24
|
-
|
24
|
+
klass.new(data[name])
|
25
25
|
else
|
26
26
|
nil
|
27
27
|
end
|
@@ -49,8 +49,18 @@ module Her
|
|
49
49
|
# @user.articles # => [#<Article(articles/2) id=2 title="Hello world.">]
|
50
50
|
# # Fetched via GET "/users/1/articles"
|
51
51
|
def has_many(name, attrs={}) # {{{
|
52
|
-
|
53
|
-
|
52
|
+
@her_relationships ||= {}
|
53
|
+
attrs = {
|
54
|
+
:class_name => name.to_s.classify,
|
55
|
+
:name => name,
|
56
|
+
:path => "/#{name}"
|
57
|
+
}.merge(attrs)
|
58
|
+
(@her_relationships[:has_many] ||= []) << attrs
|
59
|
+
|
60
|
+
define_method(name) do
|
61
|
+
klass = self.class.nearby_class(attrs[:class_name])
|
62
|
+
@data[name] ||= klass.get_collection("#{self.class.build_request_path(:id => id)}#{attrs[:path]}")
|
63
|
+
end
|
54
64
|
end # }}}
|
55
65
|
|
56
66
|
# Define an *has_one* relationship.
|
@@ -72,8 +82,18 @@ module Her
|
|
72
82
|
# @user.organization # => #<Organization(organizations/2) id=2 name="Foobar Inc.">
|
73
83
|
# # Fetched via GET "/users/1/organization"
|
74
84
|
def has_one(name, attrs={}) # {{{
|
75
|
-
|
76
|
-
|
85
|
+
@her_relationships ||= {}
|
86
|
+
attrs = {
|
87
|
+
:class_name => name.to_s.classify,
|
88
|
+
:name => name,
|
89
|
+
:path => "/#{name}"
|
90
|
+
}.merge(attrs)
|
91
|
+
(@her_relationships[:has_one] ||= []) << attrs
|
92
|
+
|
93
|
+
define_method(name) do
|
94
|
+
klass = self.class.nearby_class(attrs[:class_name])
|
95
|
+
@data[name] ||= klass.get_resource("#{self.class.build_request_path(:id => id)}#{attrs[:path]}")
|
96
|
+
end
|
77
97
|
end # }}}
|
78
98
|
|
79
99
|
# Define a *belongs_to* relationship.
|
@@ -84,10 +104,10 @@ module Her
|
|
84
104
|
# @example
|
85
105
|
# class User
|
86
106
|
# include Her::API
|
87
|
-
# belongs_to :team
|
107
|
+
# belongs_to :team, :class_name => "Group"
|
88
108
|
# end
|
89
109
|
#
|
90
|
-
# class
|
110
|
+
# class Group
|
91
111
|
# include Her::API
|
92
112
|
# end
|
93
113
|
#
|
@@ -95,36 +115,28 @@ module Her
|
|
95
115
|
# @user.team # => #<Team(teams/2) id=2 name="Developers">
|
96
116
|
# # Fetched via GET "/teams/2"
|
97
117
|
def belongs_to(name, attrs={}) # {{{
|
98
|
-
attrs = { :class_name => name.to_s.classify, :name => name, :foreign_key => "#{name}_id" }.merge(attrs)
|
99
|
-
define_relationship(:belongs_to, attrs)
|
100
|
-
end # }}}
|
101
|
-
|
102
|
-
private
|
103
|
-
# @private
|
104
|
-
def define_relationship(type, attrs) # {{{
|
105
118
|
@her_relationships ||= {}
|
106
|
-
|
107
|
-
|
108
|
-
|
119
|
+
attrs = {
|
120
|
+
:class_name => name.to_s.classify,
|
121
|
+
:name => name,
|
122
|
+
:foreign_key => "#{name}_id",
|
123
|
+
:path => "/#{name.to_s.pluralize}/:id"
|
124
|
+
}.merge(attrs)
|
125
|
+
(@her_relationships[:belongs_to] ||= []) << attrs
|
126
|
+
|
127
|
+
define_method(name) do
|
128
|
+
klass = self.class.nearby_class(attrs[:class_name])
|
129
|
+
@data[name] ||= klass.get_resource("#{klass.build_request_path(:id => @data[attrs[:foreign_key].to_sym])}")
|
130
|
+
end
|
131
|
+
end
|
109
132
|
|
110
133
|
# @private
|
111
134
|
def relationship_accessor(type, attrs) # {{{
|
112
135
|
name = attrs[:name]
|
113
136
|
class_name = attrs[:class_name]
|
114
137
|
define_method(name) do
|
115
|
-
|
116
|
-
|
117
|
-
klass = Object.const_get(class_name)
|
118
|
-
path = self.class.build_request_path(:id => id)
|
119
|
-
@data[name] = case type
|
120
|
-
when :belongs_to
|
121
|
-
foreign_key = attrs[:foreign_key].to_sym
|
122
|
-
klass.get_resource("#{klass.build_request_path(:id => @data[foreign_key])}")
|
123
|
-
when :has_many
|
124
|
-
klass.get_collection("#{path}/#{name.to_s.pluralize}")
|
125
|
-
when :has_one
|
126
|
-
klass.get_resource("#{path}/#{name.to_s.singularize}")
|
127
|
-
end
|
138
|
+
klass = self.class.nearby_class(attrs[:class_name])
|
139
|
+
@data[name] ||= klass.get_resource("#{klass.build_request_path(attrs[:path], :id => @data[attrs[:foreign_key].to_sym])}")
|
128
140
|
end
|
129
141
|
end # }}}
|
130
142
|
end
|
data/lib/her/version.rb
CHANGED
data/spec/model/hooks_spec.rb
CHANGED
@@ -4,154 +4,154 @@ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
|
4
4
|
describe Her::Model::Hooks do
|
5
5
|
context "adding hooks to a model" do
|
6
6
|
before do # {{{
|
7
|
-
spawn_model
|
7
|
+
spawn_model "Foo::User"
|
8
8
|
end # }}}
|
9
9
|
|
10
10
|
describe "method hooks" do
|
11
11
|
it "handles “before save” method hooks" do # {{{
|
12
|
-
User.before_save :set_internal_id
|
13
|
-
User.send(:hooks)[:before_save].length.should == 1
|
14
|
-
User.send(:hooks)[:before_save].first.class.should == Symbol
|
12
|
+
Foo::User.before_save :set_internal_id
|
13
|
+
Foo::User.send(:hooks)[:before_save].length.should == 1
|
14
|
+
Foo::User.send(:hooks)[:before_save].first.class.should == Symbol
|
15
15
|
end # }}}
|
16
16
|
|
17
17
|
it "handles “before create” method hooks" do # {{{
|
18
|
-
User.before_create :set_internal_id
|
19
|
-
User.send(:hooks)[:before_create].length.should == 1
|
20
|
-
User.send(:hooks)[:before_create].first.class.should == Symbol
|
18
|
+
Foo::User.before_create :set_internal_id
|
19
|
+
Foo::User.send(:hooks)[:before_create].length.should == 1
|
20
|
+
Foo::User.send(:hooks)[:before_create].first.class.should == Symbol
|
21
21
|
end # }}}
|
22
22
|
|
23
23
|
it "handles “before update” method hooks" do # {{{
|
24
|
-
User.before_update :set_internal_id
|
25
|
-
User.send(:hooks)[:before_update].length.should == 1
|
26
|
-
User.send(:hooks)[:before_update].first.class.should == Symbol
|
24
|
+
Foo::User.before_update :set_internal_id
|
25
|
+
Foo::User.send(:hooks)[:before_update].length.should == 1
|
26
|
+
Foo::User.send(:hooks)[:before_update].first.class.should == Symbol
|
27
27
|
end # }}}
|
28
28
|
|
29
29
|
it "handles “before destroy” method hooks" do # {{{
|
30
|
-
User.before_destroy :set_internal_id
|
31
|
-
User.send(:hooks)[:before_destroy].length.should == 1
|
32
|
-
User.send(:hooks)[:before_destroy].first.class.should == Symbol
|
30
|
+
Foo::User.before_destroy :set_internal_id
|
31
|
+
Foo::User.send(:hooks)[:before_destroy].length.should == 1
|
32
|
+
Foo::User.send(:hooks)[:before_destroy].first.class.should == Symbol
|
33
33
|
end # }}}
|
34
34
|
|
35
35
|
it "handles “after save” method hooks" do # {{{
|
36
|
-
User.after_save :set_internal_id
|
37
|
-
User.send(:hooks)[:after_save].length.should == 1
|
38
|
-
User.send(:hooks)[:after_save].first.class.should == Symbol
|
36
|
+
Foo::User.after_save :set_internal_id
|
37
|
+
Foo::User.send(:hooks)[:after_save].length.should == 1
|
38
|
+
Foo::User.send(:hooks)[:after_save].first.class.should == Symbol
|
39
39
|
end # }}}
|
40
40
|
|
41
41
|
it "handles “after create” method hooks" do # {{{
|
42
|
-
User.after_create :set_internal_id
|
43
|
-
User.send(:hooks)[:after_create].length.should == 1
|
44
|
-
User.send(:hooks)[:after_create].first.class.should == Symbol
|
42
|
+
Foo::User.after_create :set_internal_id
|
43
|
+
Foo::User.send(:hooks)[:after_create].length.should == 1
|
44
|
+
Foo::User.send(:hooks)[:after_create].first.class.should == Symbol
|
45
45
|
end # }}}
|
46
46
|
|
47
47
|
it "handles “after update” method hooks" do # {{{
|
48
|
-
User.after_update :set_internal_id
|
49
|
-
User.send(:hooks)[:after_update].length.should == 1
|
50
|
-
User.send(:hooks)[:after_update].first.class.should == Symbol
|
48
|
+
Foo::User.after_update :set_internal_id
|
49
|
+
Foo::User.send(:hooks)[:after_update].length.should == 1
|
50
|
+
Foo::User.send(:hooks)[:after_update].first.class.should == Symbol
|
51
51
|
end # }}}
|
52
52
|
|
53
53
|
it "handles “after destroy” method hooks" do # {{{
|
54
|
-
User.after_destroy :set_internal_id
|
55
|
-
User.send(:hooks)[:after_destroy].length.should == 1
|
56
|
-
User.send(:hooks)[:after_destroy].first.class.should == Symbol
|
54
|
+
Foo::User.after_destroy :set_internal_id
|
55
|
+
Foo::User.send(:hooks)[:after_destroy].length.should == 1
|
56
|
+
Foo::User.send(:hooks)[:after_destroy].first.class.should == Symbol
|
57
57
|
end # }}}
|
58
58
|
end
|
59
59
|
|
60
60
|
describe "block hooks" do
|
61
61
|
it "handles “before save” block hooks" do # {{{
|
62
|
-
User.before_save { |record| record.internal_id = 42 }
|
63
|
-
User.send(:hooks)[:before_save].length.should == 1
|
64
|
-
User.send(:hooks)[:before_save].first.class.should == Proc
|
62
|
+
Foo::User.before_save { |record| record.internal_id = 42 }
|
63
|
+
Foo::User.send(:hooks)[:before_save].length.should == 1
|
64
|
+
Foo::User.send(:hooks)[:before_save].first.class.should == Proc
|
65
65
|
end # }}}
|
66
66
|
|
67
67
|
it "handles “before create” block hooks" do # {{{
|
68
|
-
User.before_create { |record| record.internal_id = 42 }
|
69
|
-
User.send(:hooks)[:before_create].length.should == 1
|
70
|
-
User.send(:hooks)[:before_create].first.class.should == Proc
|
68
|
+
Foo::User.before_create { |record| record.internal_id = 42 }
|
69
|
+
Foo::User.send(:hooks)[:before_create].length.should == 1
|
70
|
+
Foo::User.send(:hooks)[:before_create].first.class.should == Proc
|
71
71
|
end # }}}
|
72
72
|
|
73
73
|
it "handles “before update” block hooks" do # {{{
|
74
|
-
User.before_update { |record| record.internal_id = 42 }
|
75
|
-
User.send(:hooks)[:before_update].length.should == 1
|
76
|
-
User.send(:hooks)[:before_update].first.class.should == Proc
|
74
|
+
Foo::User.before_update { |record| record.internal_id = 42 }
|
75
|
+
Foo::User.send(:hooks)[:before_update].length.should == 1
|
76
|
+
Foo::User.send(:hooks)[:before_update].first.class.should == Proc
|
77
77
|
end # }}}
|
78
78
|
|
79
79
|
it "handles “before destroy” block hooks" do # {{{
|
80
|
-
User.before_destroy { |record| record.internal_id = 42 }
|
81
|
-
User.send(:hooks)[:before_destroy].length.should == 1
|
82
|
-
User.send(:hooks)[:before_destroy].first.class.should == Proc
|
80
|
+
Foo::User.before_destroy { |record| record.internal_id = 42 }
|
81
|
+
Foo::User.send(:hooks)[:before_destroy].length.should == 1
|
82
|
+
Foo::User.send(:hooks)[:before_destroy].first.class.should == Proc
|
83
83
|
end # }}}
|
84
84
|
|
85
85
|
it "handles “after save” block hooks" do # {{{
|
86
|
-
User.after_save { |record| record.internal_id = 42 }
|
87
|
-
User.send(:hooks)[:after_save].length.should == 1
|
88
|
-
User.send(:hooks)[:after_save].first.class.should == Proc
|
86
|
+
Foo::User.after_save { |record| record.internal_id = 42 }
|
87
|
+
Foo::User.send(:hooks)[:after_save].length.should == 1
|
88
|
+
Foo::User.send(:hooks)[:after_save].first.class.should == Proc
|
89
89
|
end # }}}
|
90
90
|
|
91
91
|
it "handles “after create” block hooks" do # {{{
|
92
|
-
User.after_create { |record| record.internal_id = 42 }
|
93
|
-
User.send(:hooks)[:after_create].length.should == 1
|
94
|
-
User.send(:hooks)[:after_create].first.class.should == Proc
|
92
|
+
Foo::User.after_create { |record| record.internal_id = 42 }
|
93
|
+
Foo::User.send(:hooks)[:after_create].length.should == 1
|
94
|
+
Foo::User.send(:hooks)[:after_create].first.class.should == Proc
|
95
95
|
end # }}}
|
96
96
|
|
97
97
|
it "handles “after update” block hooks" do # {{{
|
98
|
-
User.after_update { |record| record.internal_id = 42 }
|
99
|
-
User.send(:hooks)[:after_update].length.should == 1
|
100
|
-
User.send(:hooks)[:after_update].first.class.should == Proc
|
98
|
+
Foo::User.after_update { |record| record.internal_id = 42 }
|
99
|
+
Foo::User.send(:hooks)[:after_update].length.should == 1
|
100
|
+
Foo::User.send(:hooks)[:after_update].first.class.should == Proc
|
101
101
|
end # }}}
|
102
102
|
|
103
103
|
it "handles “after destroy” block hooks" do # {{{
|
104
|
-
User.after_destroy { |record| record.internal_id = 42 }
|
105
|
-
User.send(:hooks)[:after_destroy].length.should == 1
|
106
|
-
User.send(:hooks)[:after_destroy].first.class.should == Proc
|
104
|
+
Foo::User.after_destroy { |record| record.internal_id = 42 }
|
105
|
+
Foo::User.send(:hooks)[:after_destroy].length.should == 1
|
106
|
+
Foo::User.send(:hooks)[:after_destroy].first.class.should == Proc
|
107
107
|
end # }}}
|
108
108
|
end
|
109
109
|
end
|
110
110
|
|
111
111
|
context "perform hooks on a model" do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
spawn_model :User do
|
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
|
112
|
+
before do # {{{
|
113
|
+
Her::API.setup :url => "https://api.example.com" do |builder|
|
114
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
115
|
+
builder.use Faraday::Request::UrlEncoded
|
116
|
+
builder.adapter :test do |stub|
|
117
|
+
stub.post("/users") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke" }.to_json] }
|
118
|
+
stub.get("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke" }.to_json] }
|
119
|
+
stub.put("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke" }.to_json] }
|
120
|
+
stub.delete("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke" }.to_json] }
|
137
121
|
end
|
138
|
-
end
|
122
|
+
end
|
123
|
+
|
124
|
+
spawn_model "Foo::User" do
|
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
139
|
|
140
140
|
describe "method hooks" do
|
141
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
|
142
|
+
Foo::User.before_save :change_internal_save_id
|
143
|
+
Foo::User.before_update :change_internal_update_id
|
144
|
+
Foo::User.before_create :change_internal_create_id
|
145
|
+
Foo::User.before_destroy :change_internal_destroy_id
|
146
|
+
|
147
|
+
Foo::User.after_save :change_internal_after_save_id
|
148
|
+
Foo::User.after_update :change_internal_after_update_id
|
149
|
+
Foo::User.after_create :change_internal_after_create_id
|
150
|
+
Foo::User.after_destroy :change_internal_after_destroy_id
|
151
151
|
end # }}}
|
152
152
|
|
153
153
|
it "perform “before save” “before create” method hook on Model#save without an ID" do # {{{
|
154
|
-
@user = User.new(:fullname => "Tobias Fünke")
|
154
|
+
@user = Foo::User.new(:fullname => "Tobias Fünke")
|
155
155
|
@user.save
|
156
156
|
@user.internal_save_id.should == 100
|
157
157
|
@user.internal_create_id.should == 101
|
@@ -159,7 +159,7 @@ describe Her::Model::Hooks do
|
|
159
159
|
end # }}}
|
160
160
|
|
161
161
|
it "perform “before save” and “before update” method hook on Model#save with an ID" do # {{{
|
162
|
-
@user = User.find(1)
|
162
|
+
@user = Foo::User.find(1)
|
163
163
|
@user.save
|
164
164
|
@user.internal_save_id.should == 100
|
165
165
|
@user.internal_create_id.should == nil
|
@@ -167,7 +167,7 @@ describe Her::Model::Hooks do
|
|
167
167
|
end # }}}
|
168
168
|
|
169
169
|
it "perform “before destroy” method hook on Model#destroy" do # {{{
|
170
|
-
@user = User.find(1)
|
170
|
+
@user = Foo::User.find(1)
|
171
171
|
@user.destroy
|
172
172
|
@user.internal_save_id.should == nil
|
173
173
|
@user.internal_create_id.should == nil
|
@@ -176,7 +176,7 @@ describe Her::Model::Hooks do
|
|
176
176
|
end # }}}
|
177
177
|
|
178
178
|
it "perform “after save” “after create” method hook on Model#save without an ID" do # {{{
|
179
|
-
@user = User.new(:fullname => "Tobias Fünke")
|
179
|
+
@user = Foo::User.new(:fullname => "Tobias Fünke")
|
180
180
|
@user.save
|
181
181
|
@user.internal_after_save_id.should == 100
|
182
182
|
@user.internal_after_create_id.should == 101
|
@@ -184,7 +184,7 @@ describe Her::Model::Hooks do
|
|
184
184
|
end # }}}
|
185
185
|
|
186
186
|
it "perform “after save” “after update” method hook on Model#save with an ID" do # {{{
|
187
|
-
@user = User.find(1)
|
187
|
+
@user = Foo::User.find(1)
|
188
188
|
@user.save
|
189
189
|
@user.internal_after_save_id.should == 100
|
190
190
|
@user.internal_after_create_id.should == nil
|
@@ -192,14 +192,14 @@ describe Her::Model::Hooks do
|
|
192
192
|
end # }}}
|
193
193
|
|
194
194
|
it "perform “after save” “after update” method hook on Model.save_existing" do # {{{
|
195
|
-
@user = User.save_existing(1, { :fullname => "Tobias Fünke" })
|
195
|
+
@user = Foo::User.save_existing(1, { :fullname => "Tobias Fünke" })
|
196
196
|
@user.internal_after_save_id.should == 100
|
197
197
|
@user.internal_after_create_id.should == nil
|
198
198
|
@user.internal_after_update_id.should == 102
|
199
199
|
end # }}}
|
200
200
|
|
201
201
|
it "perform “after save” “after create” method hook on Model.create" do # {{{
|
202
|
-
@user = User.create({ :fullname => "Tobias Fünke" })
|
202
|
+
@user = Foo::User.create({ :fullname => "Tobias Fünke" })
|
203
203
|
@user.internal_after_save_id.should == 100
|
204
204
|
@user.internal_after_create_id.should == 101
|
205
205
|
@user.internal_after_update_id.should == nil
|
@@ -208,19 +208,19 @@ describe Her::Model::Hooks do
|
|
208
208
|
|
209
209
|
describe "block hooks" do
|
210
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 }
|
211
|
+
Foo::User.before_save { |record| record.internal_save_id = 200 }
|
212
|
+
Foo::User.before_create { |record| record.internal_create_id = 201 }
|
213
|
+
Foo::User.before_update { |record| record.internal_update_id = 202 }
|
214
|
+
Foo::User.before_destroy { |record| record.internal_destroy_id = 203 }
|
215
|
+
|
216
|
+
Foo::User.after_save { |record| record.internal_after_save_id = 200 }
|
217
|
+
Foo::User.after_create { |record| record.internal_after_create_id = 201 }
|
218
|
+
Foo::User.after_update { |record| record.internal_after_update_id = 202 }
|
219
|
+
Foo::User.after_destroy { |record| record.internal_after_destroy_id = 203 }
|
220
220
|
end # }}}
|
221
221
|
|
222
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")
|
223
|
+
@user = Foo::User.new(:fullname => "Tobias Fünke")
|
224
224
|
@user.save
|
225
225
|
@user.internal_save_id.should == 200
|
226
226
|
@user.internal_create_id.should == 201
|
@@ -228,7 +228,7 @@ describe Her::Model::Hooks do
|
|
228
228
|
end # }}}
|
229
229
|
|
230
230
|
it "perform “before save” and “before update” block hook on Model#save with an ID" do # {{{
|
231
|
-
@user = User.find(1)
|
231
|
+
@user = Foo::User.find(1)
|
232
232
|
@user.save
|
233
233
|
@user.internal_save_id.should == 200
|
234
234
|
@user.internal_create_id.should == nil
|
@@ -236,7 +236,7 @@ describe Her::Model::Hooks do
|
|
236
236
|
end # }}}
|
237
237
|
|
238
238
|
it "perform “before destroy” block hook on Model#destroy" do # {{{
|
239
|
-
@user = User.find(1)
|
239
|
+
@user = Foo::User.find(1)
|
240
240
|
@user.destroy
|
241
241
|
@user.internal_save_id.should == nil
|
242
242
|
@user.internal_create_id.should == nil
|
@@ -245,7 +245,7 @@ describe Her::Model::Hooks do
|
|
245
245
|
end # }}}
|
246
246
|
|
247
247
|
it "perform “after save” “after create” block hook on Model#save without an ID" do # {{{
|
248
|
-
@user = User.new(:fullname => "Tobias Fünke")
|
248
|
+
@user = Foo::User.new(:fullname => "Tobias Fünke")
|
249
249
|
@user.save
|
250
250
|
@user.internal_after_save_id.should == 200
|
251
251
|
@user.internal_after_create_id.should == 201
|
@@ -253,7 +253,7 @@ describe Her::Model::Hooks do
|
|
253
253
|
end # }}}
|
254
254
|
|
255
255
|
it "perform “after save” “after update” block hook on Model#save with an ID" do # {{{
|
256
|
-
@user = User.find(1)
|
256
|
+
@user = Foo::User.find(1)
|
257
257
|
@user.save
|
258
258
|
@user.internal_after_save_id.should == 200
|
259
259
|
@user.internal_after_create_id.should == nil
|