acfs 0.22.2 → 0.23.0.b197

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3c1129b462fe2105edbb850cfd19d2f1e9702e94
4
- data.tar.gz: 4aa5d1819e9be688eaba32d37d88c489a88e7888
5
- SHA512:
6
- metadata.gz: 611d2c58fec55d1c71c843a6381d9923f59c7efa03cbee128663456a8698e7cb6454cb0f0787dddfd1d8c66c8e057b19384e89426ae834524bbb581020cfffa9
7
- data.tar.gz: 1e960def103264283e2be8e4fac3e59139713ec24aaeb15463ec472351ea116aba837ecaf1bd9442b23b3dd5fdb34129643cf97eca2946d4622aac89cca6f616
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
@@ -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 (type = self.class.attribute_types[name.to_sym]).nil?
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, value.nil? ? nil : type.cast(value), opts
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
- @attributes ||= {}.merge superclass.respond_to?(:attributes) ? superclass.attributes : {}
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
- default_value = opts.has_key?(:default) ? opts[:default] : nil
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
- attributes[name] = default_value
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
- module Boolean
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 self.cast(obj)
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
- module Attributes
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
- # DateTime attribute type. Use it in your model as an attribute type:
17
+ # Cast given object to DateTime.
18
+ # Expect
7
19
  #
8
- # @example
9
- # class User
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
- module DateTime
15
-
16
- # @api public
17
- #
18
- # Cast given object to DateTime.
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
- module Attributes
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
- # Float attribute type. Use it in your model as an attribute type:
17
+ # Cast given object to float.
7
18
  #
8
- # @example
9
- # class User
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
- module Float
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
- module Attributes
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
- # Integer attribute type. Use it in your model as an attribute type:
17
+ # Cast given object to integer.
7
18
  #
8
- # @example
9
- # class User
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
- module Integer
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
- module Attributes
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
- # List attribute type. Use it in your model as an attribute type:
17
+ # Cast given object to a list.
7
18
  #
8
- # @example
9
- # class User
10
- # include Acfs::Model
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
- module List
15
-
16
- # @api public
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
- module Attributes
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
- # String attribute type. Use it in your model as an attribute type:
17
+ # Cast given object to string.
7
18
  #
8
- # @example
9
- # class User
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
- module String
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 << self.new.tap do |m|
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.attributes = data
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
@@ -1,8 +1,8 @@
1
1
  module Acfs
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 22
5
- PATCH = 2
4
+ MINOR = 23
5
+ PATCH = 0
6
6
  STAGE = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.')
@@ -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 = Acfs::Model::Attributes::DateTime.cast(date_time)
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 = Acfs::Model::Attributes::DateTime.cast(time)
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 = Acfs::Model::Attributes::DateTime.cast(date)
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 = Acfs::Model::Attributes::DateTime.cast(date_time_string)
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
- Acfs::Model::Attributes::DateTime.cast(malformed_string)
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
- Acfs::Model::Attributes::DateTime.cast(fixnum)
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
- retval = Acfs::Model::Attributes::Float.cast(1.3)
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
- retval = Acfs::Model::Attributes::Float.cast(7)
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
- retval = Acfs::Model::Attributes::Float.cast('1.7')
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 '.attribute' do
119
- it 'should add an attribute to model attribute list' do
120
- model.send :attribute, :name, :string
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
- expect(model.attributes).to be == { :name => nil }.stringify_keys
123
- end
123
+ expect(model.attributes).to be == { :name => nil }.stringify_keys
124
+ end
124
125
 
125
- it 'should accept a default value' do
126
- model.send :attribute, :name, :string, default: 'John'
126
+ it 'should accept a default value' do
127
+ model.send :attribute, :name, :string, default: 'John'
127
128
 
128
- expect(model.attributes).to be == { :name => 'John' }.stringify_keys
129
- end
129
+ expect(model.attributes).to be == { :name => 'John' }.stringify_keys
130
+ end
130
131
 
131
- it 'should accept an symbolic type' do
132
- model.send :attribute, :age, :integer, default: '12'
132
+ it 'should accept an symbolic type' do
133
+ model.send :attribute, :age, :integer, default: '12'
133
134
 
134
- expect(model.attributes).to be == { :age => 12 }.stringify_keys
135
- end
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
- it 'should accept an class type' do
138
- model.send :attribute, :age, Acfs::Model::Attributes::Integer, default: '12'
141
+ expect(model.attributes).to be == { :age => 12 }.stringify_keys
142
+ end
139
143
 
140
- expect(model.attributes).to be == { :age => 12 }.stringify_keys
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 be === @user
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
@@ -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.22.2
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-24 00:00:00.000000000 Z
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: '0'
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: