acfs 0.22.2 → 0.23.0.b197
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 +14 -6
- data/README.md +41 -4
- data/lib/acfs/errors.rb +15 -0
- data/lib/acfs/model/attributes.rb +13 -7
- data/lib/acfs/model/attributes/base.rb +28 -0
- data/lib/acfs/model/attributes/boolean.rb +2 -2
- data/lib/acfs/model/attributes/date_time.rb +22 -23
- data/lib/acfs/model/attributes/float.rb +18 -20
- data/lib/acfs/model/attributes/integer.rb +18 -20
- data/lib/acfs/model/attributes/list.rb +20 -22
- data/lib/acfs/model/attributes/string.rb +18 -20
- data/lib/acfs/model/query_methods.rb +20 -7
- data/lib/acfs/version.rb +2 -2
- data/spec/acfs/model/attributes/date_time_spec.rb +16 -6
- data/spec/acfs/model/attributes/float_spec.rb +4 -6
- data/spec/acfs/model/attributes/list_spec.rb +1 -1
- data/spec/acfs/model/attributes_spec.rb +29 -16
- data/spec/acfs/model/persistance_spec.rb +5 -5
- data/spec/acfs/model/query_methods_spec.rb +37 -1
- data/spec/support/service.rb +21 -0
- metadata +18 -18
checksums.yaml
CHANGED
@@ -1,7 +1,15 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Mjc5ZTBkMmJiN2NkNzQ5YzBmYTYwZGU5ZTUzZTNhZjUzMGM3NTdhYw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZjEyMjlkZTA5MWQwYjg0MjA3ZTFjOGI0OTgwYjczNTNkYTkzMTUwYw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YTU2ZTMyMzU3MjUzNzIwNWZjNTUzNDZjMDY2NTY3N2U1YWY4NTZkOTA2OWY3
|
10
|
+
MTY3NWVkNjBkOTc3OTExMTY0NjM2ODc3MDRhNzU3NzVlZDYxMjZkM2NhNjQw
|
11
|
+
OGU0MGZmNjZiYThlODAzOWQ3MmI0ZGM3MzMzYzMzMGNmMWZiNDI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MzdlMzdiN2MyMjE5NTM0YWNlYjZjNWNmYWY5Zjg1NGU2YjFjNGM5MDZkZTBi
|
14
|
+
MmZiYmVhOGUzOTQxZDU1OGU2Zjg1YzIxZjAzNjk3MjY3NjIzMGVlMGE5YjNi
|
15
|
+
MmQwNjBjNTk3NDYyM2U4Y2FmMjc2ZjE1ZGZiYzRlOGE3ZjA0NGI=
|
data/README.md
CHANGED
@@ -138,6 +138,42 @@ Acfs has basic update support using `PUT` requests:
|
|
138
138
|
@user.persisted? # => true
|
139
139
|
```
|
140
140
|
|
141
|
+
## Resource Inheritance
|
142
|
+
|
143
|
+
Acfs provides a resource inheritance similar to ActiveRecord Single Table Inheritance. If a
|
144
|
+
`type` attribute exists and is a valid subclass of your resource they will be converted
|
145
|
+
to you subclassed resources:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class Computer < Acfs::Resource
|
149
|
+
...
|
150
|
+
end
|
151
|
+
|
152
|
+
class Pc < Computer end
|
153
|
+
class Mac < Computer end
|
154
|
+
```
|
155
|
+
|
156
|
+
With the following response on `GET /computers` the collection will contain the appropriate
|
157
|
+
subclass resources:
|
158
|
+
|
159
|
+
```json
|
160
|
+
[
|
161
|
+
{ "id": 5, "type": "Computer"},
|
162
|
+
{ "id": 6, "type": "Mac"},
|
163
|
+
{ "id": 8, "type": "Pc"}
|
164
|
+
]
|
165
|
+
```
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
@computers = Computer.all
|
169
|
+
|
170
|
+
Acfs.run
|
171
|
+
|
172
|
+
@computer[0].class # => Computer
|
173
|
+
@computer[1].class # => Mac
|
174
|
+
@computer[2].class # => Pc
|
175
|
+
```
|
176
|
+
|
141
177
|
## Stubbing
|
142
178
|
|
143
179
|
You can stub resources in applications using an Acfs service client:
|
@@ -193,10 +229,6 @@ it 'should find user number one' do
|
|
193
229
|
end
|
194
230
|
```
|
195
231
|
|
196
|
-
## Messaging (Experimental) [Depricated] {Removed}
|
197
|
-
|
198
|
-
Removed in 0.20.0. See [jgraichen/msgr](https://github.com/jgraichen/msgr) for a Rails-like messaging solution.
|
199
|
-
|
200
232
|
## Roadmap
|
201
233
|
|
202
234
|
* Update
|
@@ -224,6 +256,11 @@ Removed in 0.20.0. See [jgraichen/msgr](https://github.com/jgraichen/msgr) for a
|
|
224
256
|
7. Push to the branch (`git push origin my-new-feature`)
|
225
257
|
8. Create new Pull Request
|
226
258
|
|
259
|
+
## Contributors
|
260
|
+
|
261
|
+
* [Nicolas Fricke](https://github.com/nicolas-fricke)
|
262
|
+
* [Tino Junge](https://github.com/tino-junge)
|
263
|
+
|
227
264
|
## License
|
228
265
|
|
229
266
|
MIT License
|
data/lib/acfs/errors.rb
CHANGED
@@ -86,5 +86,20 @@ module Acfs
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
+
# Gets raised if ressource type is no valid subclass of
|
90
|
+
# parent resource. Check if the type is set to the correct
|
91
|
+
# Acfs::Resource Name
|
92
|
+
class RessourceTypeError < Error
|
93
|
+
attr_reader :base_class
|
94
|
+
attr_reader :type_name
|
95
|
+
|
96
|
+
def initialize(opts = {})
|
97
|
+
@base_class = opts.delete :base_class
|
98
|
+
@type_name = opts.delete :type_name
|
99
|
+
opts[:message] = "Recieved ressource type #{type_name} is no subclass of #{base_class}"
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
89
104
|
class RealRequestsNotAllowedError < StandardError; end
|
90
105
|
end
|
@@ -125,11 +125,11 @@ module Acfs::Model
|
|
125
125
|
# @raise [ ArgumentError ] If no attribute with given name is defined.
|
126
126
|
#
|
127
127
|
def write_attribute(name, value, opts = {})
|
128
|
-
if (
|
128
|
+
if (attr = self.class.defined_attributes[name.to_s]).nil?
|
129
129
|
raise ArgumentError.new "Unknown attribute `#{name}`."
|
130
130
|
end
|
131
131
|
|
132
|
-
write_raw_attribute name,
|
132
|
+
write_raw_attribute name, attr.cast(value), opts
|
133
133
|
end
|
134
134
|
|
135
135
|
# @api private
|
@@ -187,7 +187,15 @@ module Acfs::Model
|
|
187
187
|
# @return [ Hash{ String => Object, Proc } ] Attributes with default values.
|
188
188
|
#
|
189
189
|
def attributes
|
190
|
-
|
190
|
+
Hash.new.tap do |attrs|
|
191
|
+
defined_attributes.each do |key, attr|
|
192
|
+
attrs[key] = attr.default_value
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def defined_attributes
|
198
|
+
@attributes ||= {}.merge superclass.respond_to?(:defined_attributes) ? superclass.defined_attributes : {}
|
191
199
|
end
|
192
200
|
|
193
201
|
# @api public
|
@@ -211,11 +219,9 @@ module Acfs::Model
|
|
211
219
|
private
|
212
220
|
def define_attribute(name, type, opts = {})
|
213
221
|
name = name.to_s
|
214
|
-
|
215
|
-
default_value = type.cast default_value unless default_value.is_a? Proc or default_value.nil?
|
222
|
+
attribute = type.new opts
|
216
223
|
|
217
|
-
|
218
|
-
attribute_types[name.to_sym] = type
|
224
|
+
defined_attributes[name] = attribute
|
219
225
|
define_attribute_method name
|
220
226
|
|
221
227
|
self.send :define_method, name do
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Acfs::Model::Attributes
|
2
|
+
|
3
|
+
class Base
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize(opts = {})
|
7
|
+
@options = opts
|
8
|
+
@options.reverse_merge! allow_nil: true
|
9
|
+
end
|
10
|
+
|
11
|
+
def nil_allowed?
|
12
|
+
!!options[:allow_nil]
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_value
|
16
|
+
options[:default].is_a?(Proc) ? options[:default] : cast(options[:default])
|
17
|
+
end
|
18
|
+
|
19
|
+
def cast(obj)
|
20
|
+
return nil if obj.nil? && nil_allowed?
|
21
|
+
cast_type obj
|
22
|
+
end
|
23
|
+
|
24
|
+
def cast_type(obj)
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -16,7 +16,7 @@ module Acfs::Model
|
|
16
16
|
#
|
17
17
|
# true, on, yes
|
18
18
|
#
|
19
|
-
|
19
|
+
class Boolean < Base
|
20
20
|
|
21
21
|
TRUE_VALUES = %w(true on yes)
|
22
22
|
|
@@ -27,7 +27,7 @@ module Acfs::Model
|
|
27
27
|
# @param [Object] obj Object to cast.
|
28
28
|
# @return [TrueClass, FalseClass] Casted boolean.
|
29
29
|
#
|
30
|
-
def
|
30
|
+
def cast_type(obj)
|
31
31
|
return true if obj.is_a? TrueClass
|
32
32
|
return false if obj.is_a? FalseClass
|
33
33
|
|
@@ -1,31 +1,30 @@
|
|
1
|
-
module Acfs::Model
|
2
|
-
|
1
|
+
module Acfs::Model::Attributes
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
#
|
5
|
+
# DateTime attribute type. Use it in your model as an attribute type:
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class User
|
9
|
+
# include Acfs::Model
|
10
|
+
# attribute :name, :date_time
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class DateTime < Base
|
3
14
|
|
4
15
|
# @api public
|
5
16
|
#
|
6
|
-
#
|
17
|
+
# Cast given object to DateTime.
|
18
|
+
# Expect
|
7
19
|
#
|
8
|
-
# @
|
9
|
-
#
|
10
|
-
# include Acfs::Model
|
11
|
-
# attribute :name, :date_time
|
12
|
-
# end
|
20
|
+
# @param [Object] obj Object to cast.
|
21
|
+
# @return [DateTime] Casted object as DateTime.
|
13
22
|
#
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# Expect
|
20
|
-
#
|
21
|
-
# @param [Object] obj Object to cast.
|
22
|
-
# @return [DateTime] Casted object as DateTime.
|
23
|
-
#
|
24
|
-
def self.cast(obj)
|
25
|
-
return obj if obj.is_a? ::DateTime
|
26
|
-
return ::DateTime.iso8601(obj.iso8601) if obj.is_a? Time or obj.is_a? Date
|
27
|
-
return ::DateTime.iso8601(obj)
|
28
|
-
end
|
23
|
+
def cast_type(obj)
|
24
|
+
return nil if nil_allowed? and obj.blank?
|
25
|
+
return obj if obj.is_a? ::DateTime
|
26
|
+
return ::DateTime.iso8601(obj.iso8601) if obj.is_a? Time or obj.is_a? Date
|
27
|
+
return ::DateTime.iso8601(obj)
|
29
28
|
end
|
30
29
|
end
|
31
30
|
end
|
@@ -1,28 +1,26 @@
|
|
1
|
-
module Acfs::Model
|
2
|
-
|
1
|
+
module Acfs::Model::Attributes
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
#
|
5
|
+
# Float attribute type. Use it in your model as an attribute type:
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class User
|
9
|
+
# include Acfs::Model
|
10
|
+
# attribute :name, :float
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class Float < Base
|
3
14
|
|
4
15
|
# @api public
|
5
16
|
#
|
6
|
-
#
|
17
|
+
# Cast given object to float.
|
7
18
|
#
|
8
|
-
# @
|
9
|
-
#
|
10
|
-
# include Acfs::Model
|
11
|
-
# attribute :name, :float
|
12
|
-
# end
|
19
|
+
# @param [Object] obj Object to cast.
|
20
|
+
# @return [Float] Casted object as float.
|
13
21
|
#
|
14
|
-
|
15
|
-
|
16
|
-
# @api public
|
17
|
-
#
|
18
|
-
# Cast given object to float.
|
19
|
-
#
|
20
|
-
# @param [Object] obj Object to cast.
|
21
|
-
# @return [Float] Casted object as float.
|
22
|
-
#
|
23
|
-
def self.cast(obj)
|
24
|
-
obj.to_f
|
25
|
-
end
|
22
|
+
def cast_type(obj)
|
23
|
+
obj.to_f
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
@@ -1,28 +1,26 @@
|
|
1
|
-
module Acfs::Model
|
2
|
-
|
1
|
+
module Acfs::Model::Attributes
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
#
|
5
|
+
# Integer attribute type. Use it in your model as an attribute type:
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class User
|
9
|
+
# include Acfs::Model
|
10
|
+
# attribute :name, :integer
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class Integer < Base
|
3
14
|
|
4
15
|
# @api public
|
5
16
|
#
|
6
|
-
#
|
17
|
+
# Cast given object to integer.
|
7
18
|
#
|
8
|
-
# @
|
9
|
-
#
|
10
|
-
# include Acfs::Model
|
11
|
-
# attribute :name, :integer
|
12
|
-
# end
|
19
|
+
# @param [Object] obj Object to cast.
|
20
|
+
# @return [Fixnum] Casted object as fixnum.
|
13
21
|
#
|
14
|
-
|
15
|
-
|
16
|
-
# @api public
|
17
|
-
#
|
18
|
-
# Cast given object to integer.
|
19
|
-
#
|
20
|
-
# @param [Object] obj Object to cast.
|
21
|
-
# @return [Fixnum] Casted object as fixnum.
|
22
|
-
#
|
23
|
-
def self.cast(obj)
|
24
|
-
obj.to_i
|
25
|
-
end
|
22
|
+
def cast_type(obj)
|
23
|
+
obj.to_i
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
@@ -1,30 +1,28 @@
|
|
1
|
-
module Acfs::Model
|
2
|
-
|
1
|
+
module Acfs::Model::Attributes
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
#
|
5
|
+
# List attribute type. Use it in your model as an attribute type:
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class User
|
9
|
+
# include Acfs::Model
|
10
|
+
# attribute :name, :list
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class List < Base
|
3
14
|
|
4
15
|
# @api public
|
5
16
|
#
|
6
|
-
#
|
17
|
+
# Cast given object to a list.
|
7
18
|
#
|
8
|
-
# @
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# attribute :name, :list
|
12
|
-
# end
|
19
|
+
# @param [Object] obj Object to cast.
|
20
|
+
# @return [Fixnum] Casted object as list.
|
21
|
+
# @raise [TypeError] If object cannot be casted to a list.
|
13
22
|
#
|
14
|
-
|
15
|
-
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# Cast given object to a list.
|
19
|
-
#
|
20
|
-
# @param [Object] obj Object to cast.
|
21
|
-
# @return [Fixnum] Casted object as list.
|
22
|
-
# @raise [TypeError] If object cannot be casted to a list.
|
23
|
-
#
|
24
|
-
def self.cast(obj)
|
25
|
-
return obj.to_a if obj.respond_to? :to_a
|
26
|
-
raise TypeError.new "Cannot cast #{obj.inspect} to array."
|
27
|
-
end
|
23
|
+
def cast_type(obj)
|
24
|
+
return obj.to_a if obj.respond_to? :to_a
|
25
|
+
raise TypeError.new "Cannot cast #{obj.inspect} to array."
|
28
26
|
end
|
29
27
|
end
|
30
28
|
end
|
@@ -1,28 +1,26 @@
|
|
1
|
-
module Acfs::Model
|
2
|
-
|
1
|
+
module Acfs::Model::Attributes
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
#
|
5
|
+
# String attribute type. Use it in your model as an attribute type:
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class User
|
9
|
+
# include Acfs::Model
|
10
|
+
# attribute :name, :string
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
class String < Base
|
3
14
|
|
4
15
|
# @api public
|
5
16
|
#
|
6
|
-
#
|
17
|
+
# Cast given object to string.
|
7
18
|
#
|
8
|
-
# @
|
9
|
-
#
|
10
|
-
# include Acfs::Model
|
11
|
-
# attribute :name, :string
|
12
|
-
# end
|
19
|
+
# @param [Object] obj Object to cast.
|
20
|
+
# @return [String] Casted string.
|
13
21
|
#
|
14
|
-
|
15
|
-
|
16
|
-
# @api public
|
17
|
-
#
|
18
|
-
# Cast given object to string.
|
19
|
-
#
|
20
|
-
# @param [Object] obj Object to cast.
|
21
|
-
# @return [String] Casted string.
|
22
|
-
#
|
23
|
-
def self.cast(obj)
|
24
|
-
obj.to_s
|
25
|
-
end
|
22
|
+
def cast_type(obj)
|
23
|
+
obj.to_s
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
@@ -76,10 +76,7 @@ module Acfs::Model
|
|
76
76
|
|
77
77
|
operation :list, params: params do |data|
|
78
78
|
data.each do |obj|
|
79
|
-
collection <<
|
80
|
-
m.attributes = obj
|
81
|
-
m.loaded!
|
82
|
-
end
|
79
|
+
collection << create_resource(obj)
|
83
80
|
end
|
84
81
|
collection.loaded!
|
85
82
|
block.call collection unless block.nil?
|
@@ -91,14 +88,13 @@ module Acfs::Model
|
|
91
88
|
|
92
89
|
private
|
93
90
|
def find_single(id, opts, &block)
|
94
|
-
model = self.new
|
91
|
+
model = SimpleDelegator.new self.new
|
95
92
|
|
96
93
|
opts[:params] ||= {}
|
97
94
|
opts[:params].merge!({ id: id })
|
98
95
|
|
99
96
|
operation :read, opts do |data|
|
100
|
-
model.
|
101
|
-
model.loaded!
|
97
|
+
model.__setobj__ create_resource data, origin: model.__getobj__
|
102
98
|
block.call model unless block.nil?
|
103
99
|
end
|
104
100
|
|
@@ -119,6 +115,23 @@ module Acfs::Model
|
|
119
115
|
end
|
120
116
|
end
|
121
117
|
end
|
118
|
+
|
119
|
+
def create_resource(data, opts = {})
|
120
|
+
type = data.delete 'type'
|
121
|
+
klass = resource_class_lookup(type)
|
122
|
+
(opts[:origin].is_a?(klass) ? opts[:origin] : klass.new).tap do |m|
|
123
|
+
m.attributes = data
|
124
|
+
m.loaded!
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def resource_class_lookup(type)
|
129
|
+
return self if type.nil?
|
130
|
+
klass = type.camelize.constantize
|
131
|
+
raise Acfs::RessourceTypeError, type_name: type, base_class: self unless klass <= self
|
132
|
+
klass
|
133
|
+
end
|
134
|
+
|
122
135
|
end
|
123
136
|
end
|
124
137
|
end
|
data/lib/acfs/version.rb
CHANGED
@@ -2,44 +2,54 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Acfs::Model::Attributes::DateTime do
|
4
4
|
let(:model) { Class.new.tap { |c| c.send :include, Acfs::Model }}
|
5
|
+
let(:params) { {} }
|
6
|
+
subject { Acfs::Model::Attributes::DateTime.new params }
|
5
7
|
|
6
8
|
describe 'cast' do
|
7
9
|
it 'should return same object, if obj is already of DateTime class' do
|
8
10
|
date_time = DateTime.now
|
9
|
-
retval =
|
11
|
+
retval = subject.cast(date_time)
|
10
12
|
expect(retval).to be == date_time
|
11
13
|
end
|
12
14
|
|
13
15
|
it 'should return parsed object, if obj is of Time class' do
|
14
16
|
time = Time.now
|
15
|
-
retval =
|
17
|
+
retval = subject.cast(time)
|
16
18
|
expect(retval).to be == DateTime.iso8601(time.iso8601)
|
17
19
|
end
|
18
20
|
|
19
21
|
it 'should return parsed object, if obj is of Date class' do
|
20
22
|
date = Date.today
|
21
|
-
retval =
|
23
|
+
retval = subject.cast(date)
|
22
24
|
expect(retval).to be == DateTime.iso8601(date.iso8601)
|
23
25
|
end
|
24
26
|
|
25
27
|
it 'should return parsed object, if obj is of String class in ISO-8601 format' do
|
26
28
|
date_time_string = DateTime.now.iso8601
|
27
|
-
retval =
|
29
|
+
retval = subject.cast(date_time_string)
|
28
30
|
expect(retval).to be == DateTime.iso8601(date_time_string)
|
29
31
|
end
|
30
32
|
|
31
33
|
it 'should raise an error if obj is of String class not in valid ISO-8601 format' do
|
32
34
|
malformed_string = 'qwe123'
|
33
35
|
expect {
|
34
|
-
|
36
|
+
subject.cast(malformed_string)
|
35
37
|
}.to raise_error ArgumentError
|
36
38
|
end
|
37
39
|
|
38
40
|
it 'should raise an error if obj is of wrong class (Fixnum)' do
|
39
41
|
fixnum = 12
|
40
42
|
expect {
|
41
|
-
|
43
|
+
subject.cast(fixnum)
|
42
44
|
}.to raise_error TypeError
|
43
45
|
end
|
46
|
+
|
47
|
+
context 'with allow_nil option' do
|
48
|
+
let(:params) { {allow_nil: true} }
|
49
|
+
|
50
|
+
it 'should accept empty string as nil' do
|
51
|
+
expect(subject.cast('')).to eq nil
|
52
|
+
end
|
53
|
+
end
|
44
54
|
end
|
45
55
|
end
|
@@ -2,21 +2,19 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Acfs::Model::Attributes::Float do
|
4
4
|
let(:model) { Class.new.tap { |c| c.send :include, Acfs::Model }}
|
5
|
+
subject { Acfs::Model::Attributes::Float.new }
|
5
6
|
|
6
7
|
describe 'cast' do
|
7
8
|
it 'should return same object, if obj is already of float class' do
|
8
|
-
|
9
|
-
expect(retval).to be == 1.3
|
9
|
+
expect(subject.cast(1.3)).to be == 1.3
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'should return parsed object, if obj is of Fixnum class' do
|
13
|
-
|
14
|
-
expect(retval).to be == 7.0
|
13
|
+
expect(subject.cast(7)).to be == 7.0
|
15
14
|
end
|
16
15
|
|
17
16
|
it 'should return parsed object, if obj is of String class containing a float' do
|
18
|
-
|
19
|
-
expect(retval).to be == 1.7
|
17
|
+
expect(subject.cast('1.7')).to be == 1.7
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Acfs::Model::Attributes::List do
|
4
4
|
let(:model) { Class.new.tap { |c| c.send :include, Acfs::Model }}
|
5
|
-
subject { Acfs::Model::Attributes::List }
|
5
|
+
subject { Acfs::Model::Attributes::List.new }
|
6
6
|
|
7
7
|
describe '.cast' do
|
8
8
|
context 'with array' do
|
@@ -115,29 +115,42 @@ describe Acfs::Model::Attributes do
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
|
-
describe '
|
119
|
-
|
120
|
-
model
|
118
|
+
describe 'class' do
|
119
|
+
describe '#attribute' do
|
120
|
+
it 'should add an attribute to model attribute list' do
|
121
|
+
model.send :attribute, :name, :string
|
121
122
|
|
122
|
-
|
123
|
-
|
123
|
+
expect(model.attributes).to be == { :name => nil }.stringify_keys
|
124
|
+
end
|
124
125
|
|
125
|
-
|
126
|
-
|
126
|
+
it 'should accept a default value' do
|
127
|
+
model.send :attribute, :name, :string, default: 'John'
|
127
128
|
|
128
|
-
|
129
|
-
|
129
|
+
expect(model.attributes).to be == { :name => 'John' }.stringify_keys
|
130
|
+
end
|
130
131
|
|
131
|
-
|
132
|
-
|
132
|
+
it 'should accept an symbolic type' do
|
133
|
+
model.send :attribute, :age, :integer, default: '12'
|
133
134
|
|
134
|
-
|
135
|
-
|
135
|
+
expect(model.attributes).to be == { :age => 12 }.stringify_keys
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should accept an class type' do
|
139
|
+
model.send :attribute, :age, Acfs::Model::Attributes::Integer, default: '12'
|
136
140
|
|
137
|
-
|
138
|
-
|
141
|
+
expect(model.attributes).to be == { :age => 12 }.stringify_keys
|
142
|
+
end
|
139
143
|
|
140
|
-
|
144
|
+
context 'allow nil option' do
|
145
|
+
it 'should allow nil as value' do
|
146
|
+
model.send :attribute, :updated_at, Acfs::Model::Attributes::DateTime, default: DateTime.new, allow_nil: true
|
147
|
+
resource = model.new
|
148
|
+
expect(resource.updated_at).to eq DateTime.new
|
149
|
+
|
150
|
+
resource.updated_at = ''
|
151
|
+
expect(resource.updated_at).to eq nil
|
152
|
+
end
|
153
|
+
end
|
141
154
|
end
|
142
155
|
end
|
143
156
|
end
|
@@ -113,7 +113,7 @@ describe Acfs::Model::Persistence do
|
|
113
113
|
|
114
114
|
it 'should be frozen after DELETE' do
|
115
115
|
model.delete!
|
116
|
-
expect(model).to be_frozen
|
116
|
+
expect(model.__getobj__).to be_frozen
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
@@ -127,12 +127,12 @@ describe Acfs::Model::Persistence do
|
|
127
127
|
end
|
128
128
|
|
129
129
|
it 'should save resource' do
|
130
|
-
expect(model).to receive(:save).with({})
|
130
|
+
expect(model.__getobj__).to receive(:save).with({})
|
131
131
|
model.update_attributes name: 'Idefix'
|
132
132
|
end
|
133
133
|
|
134
134
|
it 'should pass second hash to save' do
|
135
|
-
expect(model).to receive(:save).with({ bla: 'blub' })
|
135
|
+
expect(model.__getobj__).to receive(:save).with({ bla: 'blub' })
|
136
136
|
model.update_attributes({ name: 'Idefix' }, { bla: 'blub' })
|
137
137
|
end
|
138
138
|
end
|
@@ -147,12 +147,12 @@ describe Acfs::Model::Persistence do
|
|
147
147
|
end
|
148
148
|
|
149
149
|
it 'should save resource' do
|
150
|
-
expect(model).to receive(:save!).with({})
|
150
|
+
expect(model.__getobj__).to receive(:save!).with({})
|
151
151
|
model.update_attributes! name: 'Idefix'
|
152
152
|
end
|
153
153
|
|
154
154
|
it 'should pass second hash to save' do
|
155
|
-
expect(model).to receive(:save!).with({ bla: 'blub' })
|
155
|
+
expect(model.__getobj__).to receive(:save!).with({ bla: 'blub' })
|
156
156
|
model.update_attributes!({ name: 'Idefix' }, { bla: 'blub' })
|
157
157
|
end
|
158
158
|
end
|
@@ -20,7 +20,7 @@ describe Acfs::Model::QueryMethods do
|
|
20
20
|
it 'should invoke callback after model is loaded' do
|
21
21
|
proc = Proc.new { }
|
22
22
|
proc.should_receive(:call) do |user|
|
23
|
-
expect(user).to
|
23
|
+
expect(user.__getobj__).to equal @user.__getobj__
|
24
24
|
expect(user).to be_loaded
|
25
25
|
end
|
26
26
|
|
@@ -100,4 +100,40 @@ describe Acfs::Model::QueryMethods do
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
103
|
+
|
104
|
+
describe '.all' do
|
105
|
+
let(:computer) { Computer }
|
106
|
+
let(:pc) { PC }
|
107
|
+
let(:mac) { Mac }
|
108
|
+
before do
|
109
|
+
stub_request(:get, 'http://computers.example.org/computers').to_return response([{ id: 1, type: 'PC' }, { id: 2, type: 'Computer' }, { id: 3, type: 'Mac' }])
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'with resource type inheritance' do
|
113
|
+
it 'should create appropriate subclass resources' do
|
114
|
+
@computers = Computer.all
|
115
|
+
|
116
|
+
expect(@computers).to_not be_loaded
|
117
|
+
|
118
|
+
Acfs.run
|
119
|
+
|
120
|
+
expect(@computers).to be_loaded
|
121
|
+
expect(@computers).to have(3).items
|
122
|
+
expect(@computers[0]).to be_a PC
|
123
|
+
expect(@computers[1]).to be_a Computer
|
124
|
+
expect(@computers[2]).to be_a Mac
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'with invalid type set' do
|
128
|
+
before do
|
129
|
+
stub_request(:get, 'http://computers.example.org/computers').to_return response([{ id: 1, type: 'MyUser' }, { id: 2, type: 'Computer' }, { id: 3, type: 'Mac' }])
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should raise error if type is no subclass' do
|
133
|
+
Computer.all
|
134
|
+
expect { Acfs.run }.to raise_error(Acfs::RessourceTypeError)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
103
139
|
end
|
data/spec/support/service.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
|
2
2
|
Acfs.configure do
|
3
3
|
locate :user_service, 'http://users.example.org'
|
4
|
+
locate :computer_service, 'http://computers.example.org'
|
4
5
|
locate :comments, 'http://comments.example.org'
|
5
6
|
end
|
6
7
|
|
@@ -47,6 +48,26 @@ class Comment < Acfs::Resource
|
|
47
48
|
attribute :text, :string
|
48
49
|
end
|
49
50
|
|
51
|
+
class ComputerService < Acfs::Service
|
52
|
+
use Acfs::Middleware::MessagePackDecoder
|
53
|
+
use Acfs::Middleware::JsonDecoder
|
54
|
+
use Acfs::Middleware::JsonEncoder
|
55
|
+
end
|
56
|
+
|
57
|
+
class Computer < Acfs::Resource
|
58
|
+
service ComputerService, path: 'computers'
|
59
|
+
|
60
|
+
attribute :id, :integer
|
61
|
+
end
|
62
|
+
|
63
|
+
class PC < Computer
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
class Mac < Computer
|
68
|
+
|
69
|
+
end
|
70
|
+
|
50
71
|
# DRAFT: Singular resource
|
51
72
|
#class Singular < Acfs::Resource
|
52
73
|
# service UserService, singular: true
|
metadata
CHANGED
@@ -1,97 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acfs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.23.0.b197
|
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-09-
|
11
|
+
date: 2013-09-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - '>='
|
17
|
+
- - ! '>='
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - '>='
|
24
|
+
- - ! '>='
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - '>='
|
31
|
+
- - ! '>='
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '3.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - '>='
|
38
|
+
- - ! '>='
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '3.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: actionpack
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - '>='
|
45
|
+
- - ! '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '3.1'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - '>='
|
52
|
+
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: multi_json
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - '>='
|
59
|
+
- - ! '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - '>='
|
66
|
+
- - ! '>='
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: typhoeus
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - '>='
|
73
|
+
- - ! '>='
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - '>='
|
80
|
+
- - ! '>='
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rack
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - '>='
|
87
|
+
- - ! '>='
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - '>='
|
94
|
+
- - ! '>='
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
@@ -145,6 +145,7 @@ files:
|
|
145
145
|
- lib/acfs/middleware/print.rb
|
146
146
|
- lib/acfs/model.rb
|
147
147
|
- lib/acfs/model/attributes.rb
|
148
|
+
- lib/acfs/model/attributes/base.rb
|
148
149
|
- lib/acfs/model/attributes/boolean.rb
|
149
150
|
- lib/acfs/model/attributes/date_time.rb
|
150
151
|
- lib/acfs/model/attributes/float.rb
|
@@ -211,14 +212,14 @@ require_paths:
|
|
211
212
|
- lib
|
212
213
|
required_ruby_version: !ruby/object:Gem::Requirement
|
213
214
|
requirements:
|
214
|
-
- - '>='
|
215
|
+
- - ! '>='
|
215
216
|
- !ruby/object:Gem::Version
|
216
217
|
version: '0'
|
217
218
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
218
219
|
requirements:
|
219
|
-
- - '
|
220
|
+
- - ! '>'
|
220
221
|
- !ruby/object:Gem::Version
|
221
|
-
version:
|
222
|
+
version: 1.3.1
|
222
223
|
requirements: []
|
223
224
|
rubyforge_project:
|
224
225
|
rubygems_version: 2.0.3
|
@@ -252,4 +253,3 @@ test_files:
|
|
252
253
|
- spec/spec_helper.rb
|
253
254
|
- spec/support/response.rb
|
254
255
|
- spec/support/service.rb
|
255
|
-
has_rdoc:
|