her 0.2.6 → 0.3
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.
- 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
|