acfs 0.20.0 → 0.21.0.b185
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.
- checksums.yaml +4 -4
- data/.travis.yml +17 -10
- data/CHANGELOG.md +6 -0
- data/README.md +1 -5
- data/acfs.gemspec +2 -0
- data/lib/acfs.rb +17 -24
- data/lib/acfs/errors.rb +52 -29
- data/lib/acfs/model.rb +35 -36
- data/lib/acfs/model/attributes.rb +2 -2
- data/lib/acfs/model/persistence.rb +55 -6
- data/lib/acfs/model/validation.rb +13 -0
- data/lib/acfs/stub.rb +1 -1
- data/lib/acfs/version.rb +1 -1
- data/spec/acfs/model/attributes_spec.rb +1 -1
- data/spec/acfs/model/persistance_spec.rb +57 -3
- data/spec/acfs/model/validation_spec.rb +54 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/support/service.rb +12 -6
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 24c2d64318701de68d4bebf2c0454ae17222f41e
|
4
|
+
data.tar.gz: 7b058dbf9ce187553aa1a41420b3792b96f4b8f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2b103a60ada7149b1f58c79ffaad1f2419116040742217933819840b940b7f17ffa7a03294835b87ad346a33509c996b33872efd845b59fece94ce72bf265e8
|
7
|
+
data.tar.gz: 425866d67a2dd571cfd1e5dcb9519616720bf7059ec58004dd4ab61f06f94cf508385448dd9f1674937701e95ffb40ec05f4763803eae403ae5170f1611c39d8
|
data/.travis.yml
CHANGED
@@ -1,15 +1,22 @@
|
|
1
1
|
language: ruby
|
2
2
|
bundler_args: --without development
|
3
3
|
rvm:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
- 2.0.0
|
5
|
+
- 1.9.3
|
6
|
+
- jruby
|
7
|
+
- rbx-19mode
|
9
8
|
gemfile:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
- gemfiles/Gemfile.rails-4-0
|
10
|
+
- gemfiles/Gemfile.rails-3-2
|
11
|
+
- gemfiles/Gemfile.rails-3-1
|
14
12
|
services:
|
15
|
-
|
13
|
+
- rabbitmq
|
14
|
+
deploy:
|
15
|
+
provider: rubygems
|
16
|
+
api_key:
|
17
|
+
secure: gNudZK0JaRRweudmkpdkJjUMydItTSW5cXjpYdYCfahqd/cD0xPjxotr2TCHrJibfVauoT/PytbQWcP3jnOYytp6oS0up5Y+uKpGmbqVYx/rZvShWALszcBs71lUh/IZpDXNHc+yo/01HCn10/uQUFRtrjWgMwHtHxXb09xE4wQ=
|
18
|
+
gem: acfs
|
19
|
+
on:
|
20
|
+
branch: master
|
21
|
+
repo: jgraichen/acfs
|
22
|
+
rvm: 2.0.0
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -15,7 +15,7 @@ Acfs covers model and service abstraction, convenient query and filter methods,
|
|
15
15
|
|
16
16
|
Add this line to your application's Gemfile:
|
17
17
|
|
18
|
-
gem 'acfs', '~> 0.
|
18
|
+
gem 'acfs', '~> 0.21.0'
|
19
19
|
|
20
20
|
**Note:** Acfs is under development. I'll try to avoid changes to the public API but internal APIs may change quite often.
|
21
21
|
|
@@ -212,10 +212,6 @@ Removed in 0.20.0. See [jgraichen/msgr](https://github.com/jgraichen/msgr) for a
|
|
212
212
|
* Rails responders providing REST operations with integrated ETag,
|
213
213
|
Modified Headers, conflict detection, ...
|
214
214
|
* Pagination? Filtering? (If service API provides such features.)
|
215
|
-
* Messaging Queue support for services and models
|
216
|
-
* Allow triggering messages on resource events (CRUD)
|
217
|
-
* Abstract messages into objects
|
218
|
-
* Middleware stack for messages?
|
219
215
|
* Documentation
|
220
216
|
|
221
217
|
## Contributing
|
data/acfs.gemspec
CHANGED
data/lib/acfs.rb
CHANGED
@@ -4,35 +4,30 @@ require 'active_support/core_ext/class'
|
|
4
4
|
require 'active_support/core_ext/string'
|
5
5
|
require 'active_support/core_ext/module'
|
6
6
|
|
7
|
-
require 'acfs/version'
|
8
|
-
require 'acfs/errors'
|
9
|
-
require 'acfs/global'
|
10
|
-
|
11
7
|
module Acfs
|
12
8
|
extend ActiveSupport::Autoload
|
9
|
+
require 'acfs/version'
|
10
|
+
require 'acfs/errors'
|
11
|
+
require 'acfs/global'
|
12
|
+
|
13
|
+
require 'acfs/collection'
|
14
|
+
require 'acfs/configuration'
|
15
|
+
require 'acfs/model'
|
16
|
+
require 'acfs/operation'
|
17
|
+
require 'acfs/request'
|
18
|
+
require 'acfs/resource'
|
19
|
+
require 'acfs/response'
|
20
|
+
require 'acfs/runner'
|
21
|
+
require 'acfs/service'
|
22
|
+
|
13
23
|
extend Global
|
14
24
|
|
15
|
-
autoload :Collection
|
16
|
-
autoload :Model
|
17
|
-
autoload :Request
|
18
|
-
autoload :Response
|
19
|
-
autoload :Service
|
20
25
|
autoload :Stub
|
21
|
-
autoload :Operation
|
22
|
-
autoload :Runner
|
23
|
-
autoload :Configuration
|
24
|
-
|
25
|
-
module Messaging
|
26
|
-
extend ActiveSupport::Autoload
|
27
|
-
|
28
|
-
autoload :Client
|
29
|
-
autoload :Receiver
|
30
|
-
end
|
31
26
|
|
32
27
|
module Middleware
|
33
28
|
extend ActiveSupport::Autoload
|
29
|
+
require 'acfs/middleware/base'
|
34
30
|
|
35
|
-
autoload :Base
|
36
31
|
autoload :Print
|
37
32
|
autoload :Logger
|
38
33
|
autoload :JsonDecoder
|
@@ -42,10 +37,8 @@ module Acfs
|
|
42
37
|
end
|
43
38
|
|
44
39
|
module Adapter
|
45
|
-
|
46
|
-
|
47
|
-
autoload :Base
|
48
|
-
autoload :Typhoeus
|
40
|
+
require 'acfs/adapter/base'
|
41
|
+
require 'acfs/adapter/typhoeus'
|
49
42
|
end
|
50
43
|
end
|
51
44
|
|
data/lib/acfs/errors.rb
CHANGED
@@ -3,46 +3,52 @@ module Acfs
|
|
3
3
|
# Acfs base error.
|
4
4
|
#
|
5
5
|
class Error < StandardError
|
6
|
+
def initialize(opts = {}, message = nil)
|
7
|
+
opts.merge! message: message if message
|
8
|
+
super opts[:message]
|
9
|
+
end
|
6
10
|
end
|
7
11
|
|
8
12
|
# Response error containing the responsible response object.
|
9
13
|
#
|
10
14
|
class ErroneousResponse < Error
|
11
|
-
|
15
|
+
attr_reader :response
|
12
16
|
|
13
|
-
def initialize(
|
14
|
-
|
15
|
-
message = ''
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
17
|
+
def initialize(opts = {})
|
18
|
+
@response = opts[:response]
|
19
|
+
message = 'Received erroneous response'
|
20
|
+
if response
|
21
|
+
message << ": #{response.code}"
|
22
|
+
if response.data
|
23
|
+
message << "\n with content:\n "
|
24
|
+
message << response.data.map{|k,v| "#{k.inspect}: #{v.inspect}"}.join("\n ")
|
25
|
+
end
|
26
|
+
if response.headers.any?
|
27
|
+
message << "\n with headers:\n "
|
28
|
+
message << response.headers.map{|k,v| "#{k}: #{v}"}.join("\n ")
|
29
|
+
end
|
30
|
+
message << "\nbased on request: #{response.request.method.upcase} #{response.request.url} #{response.request.format}"
|
31
|
+
if response.request.data
|
32
|
+
message << "\n with content:\n "
|
33
|
+
message << response.request.data.map{|k,v| "#{k.inspect}: #{v.inspect}"}.join("\n ")
|
34
|
+
end
|
35
|
+
if response.request.headers.any?
|
36
|
+
message << "\n with headers:\n "
|
37
|
+
message << response.request.headers.map{|k,v| "#{k}: #{v}"}.join("\n ")
|
38
|
+
end
|
29
39
|
end
|
30
|
-
|
31
|
-
message << "\n with headers:\n "
|
32
|
-
message << response.request.headers.map{|k,v| "#{k}: #{v}"}.join("\n ")
|
33
|
-
end
|
34
|
-
super message
|
40
|
+
super opts, message
|
35
41
|
end
|
36
42
|
end
|
37
43
|
|
38
44
|
class AmbiguousStubError < Error
|
39
45
|
attr_reader :stubs, :operation
|
40
46
|
|
41
|
-
def initialize(
|
42
|
-
@stubs = stubs
|
43
|
-
@operation = operation
|
47
|
+
def initialize(opts = {})
|
48
|
+
@stubs = opts.delete :stubs
|
49
|
+
@operation = opts.delete :operation
|
44
50
|
|
45
|
-
super 'Ambiguous stubs.'
|
51
|
+
super opts, 'Ambiguous stubs.'
|
46
52
|
end
|
47
53
|
|
48
54
|
end
|
@@ -53,10 +59,27 @@ module Acfs
|
|
53
59
|
end
|
54
60
|
|
55
61
|
class InvalidResource < ErroneousResponse
|
56
|
-
|
62
|
+
attr_reader :errors, :resource
|
63
|
+
|
64
|
+
def initialize(opts = {})
|
65
|
+
@errors = opts.delete :errors
|
66
|
+
@resource = opts.delete :resource
|
67
|
+
super
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# A ResourceNotLoaded error will be thrown when calling some
|
72
|
+
# modifing methods on not loaded resources as it is usally
|
73
|
+
# unwanted to call e.g. `update_attributes` on a not loaded
|
74
|
+
# resource.
|
75
|
+
# Correct solution is to first run `Acfs.run` to fetch the
|
76
|
+
# resource and then update the resource.
|
77
|
+
#
|
78
|
+
class ResourceNotLoaded < Error
|
79
|
+
attr_reader :resource
|
57
80
|
|
58
|
-
def initialize(
|
59
|
-
|
81
|
+
def initialize(opts = {})
|
82
|
+
@resource = opts.delete :resource
|
60
83
|
super
|
61
84
|
end
|
62
85
|
end
|
data/lib/acfs/model.rb
CHANGED
@@ -1,44 +1,43 @@
|
|
1
1
|
require 'active_model'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require 'acfs/model/
|
7
|
-
require 'acfs/model/
|
8
|
-
require 'acfs/model/
|
9
|
-
require 'acfs/model/
|
10
|
-
require 'acfs/model/
|
11
|
-
require 'acfs/model/
|
3
|
+
# @api public
|
4
|
+
#
|
5
|
+
module Acfs::Model
|
6
|
+
require 'acfs/model/attributes'
|
7
|
+
require 'acfs/model/dirty'
|
8
|
+
require 'acfs/model/loadable'
|
9
|
+
require 'acfs/model/locatable'
|
10
|
+
require 'acfs/model/operational'
|
11
|
+
require 'acfs/model/persistence'
|
12
|
+
require 'acfs/model/query_methods'
|
13
|
+
require 'acfs/model/relations'
|
14
|
+
require 'acfs/model/service'
|
15
|
+
require 'acfs/model/validation'
|
12
16
|
|
13
|
-
|
17
|
+
extend ActiveSupport::Concern
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
included do
|
20
|
+
if ActiveModel::VERSION::MAJOR >= 4
|
21
|
+
include ActiveModel::Model
|
22
|
+
else
|
23
|
+
extend ActiveModel::Naming
|
24
|
+
extend ActiveModel::Translation
|
25
|
+
include ActiveModel::Conversion
|
26
|
+
include ActiveModel::Validations
|
19
27
|
|
20
|
-
|
21
|
-
|
22
|
-
include ActiveModel::Model
|
23
|
-
else
|
24
|
-
extend ActiveModel::Naming
|
25
|
-
extend ActiveModel::Translation
|
26
|
-
include ActiveModel::Conversion
|
27
|
-
include ActiveModel::Validations
|
28
|
-
|
29
|
-
require 'acfs/model/initialization'
|
30
|
-
include Model::Initialization
|
31
|
-
end
|
32
|
-
|
33
|
-
include Model::Attributes
|
34
|
-
include Model::Loadable
|
35
|
-
include Model::Persistence
|
36
|
-
include Model::Locatable
|
37
|
-
include Model::Operational
|
38
|
-
include Model::QueryMethods
|
39
|
-
include Model::Relations
|
40
|
-
include Model::Service
|
41
|
-
include Model::Dirty
|
28
|
+
require 'acfs/model/initialization'
|
29
|
+
include Initialization
|
42
30
|
end
|
31
|
+
|
32
|
+
include Attributes
|
33
|
+
include Loadable
|
34
|
+
include Persistence
|
35
|
+
include Locatable
|
36
|
+
include Operational
|
37
|
+
include QueryMethods
|
38
|
+
include Relations
|
39
|
+
include Service
|
40
|
+
include Dirty
|
41
|
+
include Validation
|
43
42
|
end
|
44
43
|
end
|
@@ -187,7 +187,7 @@ module Acfs::Model
|
|
187
187
|
# @return [ Hash{ String => Object, Proc } ] Attributes with default values.
|
188
188
|
#
|
189
189
|
def attributes
|
190
|
-
@attributes ||= {}
|
190
|
+
@attributes ||= {}.merge superclass.respond_to?(:attributes) ? superclass.attributes : {}
|
191
191
|
end
|
192
192
|
|
193
193
|
# @api public
|
@@ -205,7 +205,7 @@ module Acfs::Model
|
|
205
205
|
# @return [ Hash{ Symbol => Class } ] Attributes and their types.
|
206
206
|
#
|
207
207
|
def attribute_types
|
208
|
-
@attribute_types ||= {}
|
208
|
+
@attribute_types ||= {}.merge superclass.respond_to?(:attribute_types) ? superclass.attribute_types : {}
|
209
209
|
end
|
210
210
|
|
211
211
|
private
|
@@ -26,7 +26,7 @@ module Acfs
|
|
26
26
|
# user2.save
|
27
27
|
# user2.persisted? # => true
|
28
28
|
#
|
29
|
-
# @return [
|
29
|
+
# @return [Boolean] True if resource has no changes and is not newly created, false otherwise.
|
30
30
|
#
|
31
31
|
def persisted?
|
32
32
|
!new? && !changed?
|
@@ -36,7 +36,7 @@ module Acfs
|
|
36
36
|
#
|
37
37
|
# Return true if model is a new record and was not saved yet.
|
38
38
|
#
|
39
|
-
# @return [
|
39
|
+
# @return [Boolean] True if resource is newly created, false otherwise.
|
40
40
|
#
|
41
41
|
def new?
|
42
42
|
read_attribute(:id).nil?
|
@@ -52,7 +52,7 @@ module Acfs
|
|
52
52
|
#
|
53
53
|
# Saving a resource is a synchronous operation.
|
54
54
|
#
|
55
|
-
# @return [
|
55
|
+
# @return [Boolean] True if save operation was successful, false otherwise.
|
56
56
|
# @see #save! See #save! for available options.
|
57
57
|
#
|
58
58
|
def save(*args)
|
@@ -79,8 +79,6 @@ module Acfs
|
|
79
79
|
# @see #save
|
80
80
|
#
|
81
81
|
def save!(opts = {})
|
82
|
-
#raise ::Acfs::InvalidResource errors: errors.to_a unless valid?
|
83
|
-
|
84
82
|
opts[:data] = attributes unless opts[:data]
|
85
83
|
|
86
84
|
operation (new? ? :create : :update), opts do |data|
|
@@ -88,13 +86,60 @@ module Acfs
|
|
88
86
|
end
|
89
87
|
end
|
90
88
|
|
89
|
+
# @api public
|
90
|
+
#
|
91
|
+
# Update attributes with given data and save resource.
|
92
|
+
#
|
93
|
+
# Saving a resource is a synchronous operation.
|
94
|
+
#
|
95
|
+
# @param [Hash] attrs Hash with attributes to write.
|
96
|
+
# @param [Hash] opts Options passed to `save`.
|
97
|
+
#
|
98
|
+
# @return [Boolean] True if save operation was successful, false otherwise.
|
99
|
+
#
|
100
|
+
# @see #save
|
101
|
+
# @see #attributes=
|
102
|
+
# @see #update_attributes!
|
103
|
+
#
|
104
|
+
def update_attributes(attrs, opts = {})
|
105
|
+
check_loaded! opts
|
106
|
+
|
107
|
+
self.attributes = attrs
|
108
|
+
save opts
|
109
|
+
end
|
110
|
+
|
111
|
+
# @api public
|
112
|
+
#
|
113
|
+
# Update attributes with given data and save resource.
|
114
|
+
#
|
115
|
+
# Saving a resource is a synchronous operation.
|
116
|
+
#
|
117
|
+
# @param [Hash] attrs Hash with attributes to write.
|
118
|
+
# @param [Hash] opts Options passed to `save!`.
|
119
|
+
#
|
120
|
+
# @raise [Acfs::InvalidResource]
|
121
|
+
# If remote services respond with 422 response. Will fill errors with data from response
|
122
|
+
# @raise [Acfs::ErroneousResponse]
|
123
|
+
# If remote service respond with not successful response.
|
124
|
+
#
|
125
|
+
# @see #save!
|
126
|
+
# @see #attributes=
|
127
|
+
# @see #update_attributes
|
128
|
+
#
|
129
|
+
def update_attributes!(attrs, opts = {})
|
130
|
+
check_loaded! opts
|
131
|
+
|
132
|
+
self.attributes = attrs
|
133
|
+
save! opts
|
134
|
+
end
|
135
|
+
|
91
136
|
# @api public
|
92
137
|
#
|
93
138
|
# Destroy resource by sending a DELETE request.
|
94
139
|
#
|
95
140
|
# Deleting a resource is a synchronous operation.
|
96
141
|
#
|
97
|
-
# @return [
|
142
|
+
# @return [Boolean]
|
98
143
|
# @see #delete!
|
99
144
|
#
|
100
145
|
def delete(opts = {})
|
@@ -186,6 +231,10 @@ module Acfs
|
|
186
231
|
self.attributes = data
|
187
232
|
loaded!
|
188
233
|
end
|
234
|
+
|
235
|
+
def check_loaded!(opts = {})
|
236
|
+
raise ResourceNotLoaded, resource: self unless loaded? or opts[:force]
|
237
|
+
end
|
189
238
|
end
|
190
239
|
end
|
191
240
|
end
|
data/lib/acfs/stub.rb
CHANGED
@@ -98,7 +98,7 @@ module Acfs
|
|
98
98
|
|
99
99
|
accepted_stubs = stubs.select { |stub| stub.accept? op }
|
100
100
|
|
101
|
-
raise AmbiguousStubError.new accepted_stubs, op if accepted_stubs.size > 1
|
101
|
+
raise AmbiguousStubError.new stubs: accepted_stubs, operation: op if accepted_stubs.size > 1
|
102
102
|
|
103
103
|
accepted_stubs.first
|
104
104
|
end
|
data/lib/acfs/version.rb
CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe Acfs::Model::Persistence do
|
4
4
|
let(:model_class) { MyUser }
|
5
5
|
before do
|
6
|
-
@get_stub = stub_request(:get, 'http://users.example.org/users/1').to_return response({ id: 1, name:
|
6
|
+
@get_stub = stub_request(:get, 'http://users.example.org/users/1').to_return response({ id: 1, name: 'Anon', age: 12 })
|
7
7
|
|
8
8
|
@patch_stub = stub_request(:put, 'http://users.example.org/users/1')
|
9
9
|
.with(body: '{"id":1,"name":"Idefix","age":12}')
|
@@ -71,6 +71,20 @@ describe Acfs::Model::Persistence do
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
context 'unloaded model' do
|
75
|
+
let!(:model) { model_class.find 1 }
|
76
|
+
|
77
|
+
describe '#update_attributes' do
|
78
|
+
subject { -> { model.update_attributes name: 'John' } }
|
79
|
+
it { expect{ subject.call }.to raise_error Acfs::ResourceNotLoaded }
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#update_attributes!' do
|
83
|
+
subject { -> { model.update_attributes! name: 'John' } }
|
84
|
+
it { expect{ subject.call }.to raise_error Acfs::ResourceNotLoaded }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
74
88
|
context 'loaded model' do
|
75
89
|
context 'without changes' do
|
76
90
|
let(:model) { model_class.find 1 }
|
@@ -102,6 +116,46 @@ describe Acfs::Model::Persistence do
|
|
102
116
|
expect(model).to be_frozen
|
103
117
|
end
|
104
118
|
end
|
119
|
+
|
120
|
+
describe '#update_atributes!' do
|
121
|
+
let(:model) { model_class.find 1 }
|
122
|
+
before { model; Acfs.run }
|
123
|
+
|
124
|
+
it 'should set attributes' do
|
125
|
+
model.update_attributes name: 'Idefix'
|
126
|
+
expect(model.attributes.symbolize_keys).to eq id: 1, name: 'Idefix', age: 12
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should save resource' do
|
130
|
+
expect(model).to receive(:save).with({})
|
131
|
+
model.update_attributes name: 'Idefix'
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should pass second hash to save' do
|
135
|
+
expect(model).to receive(:save).with({ bla: 'blub' })
|
136
|
+
model.update_attributes({ name: 'Idefix' }, { bla: 'blub' })
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe '#update_atributes' do
|
141
|
+
let(:model) { model_class.find 1 }
|
142
|
+
before { model; Acfs.run }
|
143
|
+
|
144
|
+
it 'should set attributes' do
|
145
|
+
model.update_attributes! name: 'Idefix'
|
146
|
+
expect(model.attributes.symbolize_keys).to eq id: 1, name: 'Idefix', age: 12
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should save resource' do
|
150
|
+
expect(model).to receive(:save!).with({})
|
151
|
+
model.update_attributes! name: 'Idefix'
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should pass second hash to save' do
|
155
|
+
expect(model).to receive(:save!).with({ bla: 'blub' })
|
156
|
+
model.update_attributes!({ name: 'Idefix' }, { bla: 'blub' })
|
157
|
+
end
|
158
|
+
end
|
105
159
|
end
|
106
160
|
|
107
161
|
describe '.create!' do
|
@@ -125,7 +179,7 @@ describe Acfs::Model::Persistence do
|
|
125
179
|
|
126
180
|
it 'should raise an error' do
|
127
181
|
expect { model_class.create! data }.to raise_error ::Acfs::InvalidResource do |error|
|
128
|
-
expect(error.errors).to be == { name:
|
182
|
+
expect(error.errors).to be == { name: %w(required) }.stringify_keys
|
129
183
|
end
|
130
184
|
end
|
131
185
|
end
|
@@ -157,7 +211,7 @@ describe Acfs::Model::Persistence do
|
|
157
211
|
|
158
212
|
it 'should contain error hash' do
|
159
213
|
model = model_class.create data
|
160
|
-
expect(model.errors.to_hash).to be == { name:
|
214
|
+
expect(model.errors.to_hash).to be == { name: %w(required) }.stringify_keys
|
161
215
|
end
|
162
216
|
end
|
163
217
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Acfs::Model::Validation do
|
4
|
+
let(:params) { {} }
|
5
|
+
let(:model) { MyUserWithValidations.new params }
|
6
|
+
|
7
|
+
describe '#valid?' do
|
8
|
+
context 'with valid attributes' do
|
9
|
+
let(:params) { {name: 'john smith', age: 24} }
|
10
|
+
subject { model }
|
11
|
+
|
12
|
+
it { should be_valid }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with invalid attributes' do
|
16
|
+
let(:params) { {name: 'invname'} }
|
17
|
+
subject { model }
|
18
|
+
|
19
|
+
it { should_not be_valid }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#errors' do
|
24
|
+
context 'with valid attributes' do
|
25
|
+
let(:params) { {name: 'john smith', age: 24} }
|
26
|
+
before { model.valid? }
|
27
|
+
subject { model.errors }
|
28
|
+
|
29
|
+
it { should be_empty }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with invalid attributes' do
|
33
|
+
let(:params) { {name: 'john'} }
|
34
|
+
before { model.valid? }
|
35
|
+
subject { model.errors }
|
36
|
+
|
37
|
+
it { should_not be_empty }
|
38
|
+
it { should have(2).items }
|
39
|
+
|
40
|
+
it 'should contain a list of error messages' do
|
41
|
+
expect(subject.to_hash).to eq age: ["can't be blank"], name: ['is invalid']
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#save!' do
|
47
|
+
context 'with invalid attributes' do
|
48
|
+
let(:params) { {name: 'john'} }
|
49
|
+
subject { -> { model.save! } }
|
50
|
+
|
51
|
+
it { expect { subject.call }.to raise_error Acfs::InvalidResource }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -21,7 +21,7 @@ RSpec.configure do |config|
|
|
21
21
|
# order dependency and want to debug it, you can fix the order by providing
|
22
22
|
# the seed, which is printed after each run.
|
23
23
|
# --seed 1234
|
24
|
-
config.order =
|
24
|
+
config.order = 'random'
|
25
25
|
|
26
26
|
config.expect_with :rspec do |c|
|
27
27
|
# Only allow expect syntax
|
data/spec/support/service.rb
CHANGED
@@ -16,8 +16,7 @@ class CommentService < Acfs::Service
|
|
16
16
|
use Acfs::Middleware::JsonDecoder
|
17
17
|
end
|
18
18
|
|
19
|
-
class MyUser
|
20
|
-
include Acfs::Model
|
19
|
+
class MyUser < Acfs::Resource
|
21
20
|
service UserService, path: 'users'
|
22
21
|
|
23
22
|
attribute :id, :integer
|
@@ -25,16 +24,23 @@ class MyUser
|
|
25
24
|
attribute :age, :integer
|
26
25
|
end
|
27
26
|
|
28
|
-
class
|
29
|
-
|
27
|
+
class MyUserInherited < MyUser
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
class MyUserWithValidations < MyUser
|
32
|
+
validates_presence_of :name, :age
|
33
|
+
validates_format_of :name, with: /\A\w+\s+\w+.?\z/
|
34
|
+
end
|
35
|
+
|
36
|
+
class Session < Acfs::Resource
|
30
37
|
service UserService
|
31
38
|
|
32
39
|
attribute :id, :string
|
33
40
|
attribute :user, :integer
|
34
41
|
end
|
35
42
|
|
36
|
-
class Comment
|
37
|
-
include Acfs::Model
|
43
|
+
class Comment < Acfs::Resource
|
38
44
|
service CommentService
|
39
45
|
|
40
46
|
attribute :id, :integer
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acfs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0.b185
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Graichen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-08-
|
11
|
+
date: 2013-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -160,6 +160,7 @@ files:
|
|
160
160
|
- lib/acfs/model/query_methods.rb
|
161
161
|
- lib/acfs/model/relations.rb
|
162
162
|
- lib/acfs/model/service.rb
|
163
|
+
- lib/acfs/model/validation.rb
|
163
164
|
- lib/acfs/operation.rb
|
164
165
|
- lib/acfs/request.rb
|
165
166
|
- lib/acfs/request/callbacks.rb
|
@@ -187,6 +188,7 @@ files:
|
|
187
188
|
- spec/acfs/model/locatable_spec.rb
|
188
189
|
- spec/acfs/model/persistance_spec.rb
|
189
190
|
- spec/acfs/model/query_methods_spec.rb
|
191
|
+
- spec/acfs/model/validation_spec.rb
|
190
192
|
- spec/acfs/request/callbacks_spec.rb
|
191
193
|
- spec/acfs/request_spec.rb
|
192
194
|
- spec/acfs/response/formats_spec.rb
|
@@ -214,9 +216,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
214
216
|
version: '0'
|
215
217
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
216
218
|
requirements:
|
217
|
-
- - '
|
219
|
+
- - '>'
|
218
220
|
- !ruby/object:Gem::Version
|
219
|
-
version:
|
221
|
+
version: 1.3.1
|
220
222
|
requirements: []
|
221
223
|
rubyforge_project:
|
222
224
|
rubygems_version: 2.0.3
|
@@ -237,6 +239,7 @@ test_files:
|
|
237
239
|
- spec/acfs/model/locatable_spec.rb
|
238
240
|
- spec/acfs/model/persistance_spec.rb
|
239
241
|
- spec/acfs/model/query_methods_spec.rb
|
242
|
+
- spec/acfs/model/validation_spec.rb
|
240
243
|
- spec/acfs/request/callbacks_spec.rb
|
241
244
|
- spec/acfs/request_spec.rb
|
242
245
|
- spec/acfs/response/formats_spec.rb
|
@@ -249,4 +252,3 @@ test_files:
|
|
249
252
|
- spec/spec_helper.rb
|
250
253
|
- spec/support/response.rb
|
251
254
|
- spec/support/service.rb
|
252
|
-
has_rdoc:
|