acfs 0.45.0 → 0.50.0

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.
Files changed (34) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +34 -0
  3. data/README.md +0 -1
  4. data/acfs.gemspec +3 -3
  5. data/lib/acfs/middleware/json.rb +1 -1
  6. data/lib/acfs/middleware/msgpack.rb +1 -1
  7. data/lib/acfs/resource/attributes/base.rb +10 -18
  8. data/lib/acfs/resource/attributes/boolean.rb +10 -6
  9. data/lib/acfs/resource/attributes/date_time.rb +7 -8
  10. data/lib/acfs/resource/attributes/dict.rb +15 -5
  11. data/lib/acfs/resource/attributes/float.rb +11 -3
  12. data/lib/acfs/resource/attributes/integer.rb +7 -7
  13. data/lib/acfs/resource/attributes/list.rb +13 -4
  14. data/lib/acfs/resource/attributes/string.rb +3 -3
  15. data/lib/acfs/resource/attributes/uuid.rb +8 -15
  16. data/lib/acfs/resource/attributes.rb +11 -37
  17. data/lib/acfs/resource/dirty.rb +3 -15
  18. data/lib/acfs/resource/query_methods.rb +5 -2
  19. data/lib/acfs/resource/validation.rb +4 -2
  20. data/lib/acfs/response/formats.rb +1 -1
  21. data/lib/acfs/service/middleware/stack.rb +38 -9
  22. data/lib/acfs/version.rb +1 -1
  23. data/spec/acfs/resource/attributes/boolean_spec.rb +40 -9
  24. data/spec/acfs/resource/attributes/date_time_spec.rb +29 -35
  25. data/spec/acfs/resource/attributes/dict_spec.rb +54 -29
  26. data/spec/acfs/resource/attributes/float_spec.rb +48 -9
  27. data/spec/acfs/resource/attributes/integer_spec.rb +23 -8
  28. data/spec/acfs/resource/attributes/list_spec.rb +43 -19
  29. data/spec/acfs/resource/attributes/uuid_spec.rb +31 -54
  30. data/spec/acfs/resource/attributes_spec.rb +10 -24
  31. data/spec/acfs/resource/query_methods_spec.rb +10 -3
  32. data/spec/acfs/response/formats_spec.rb +3 -3
  33. data/spec/spec_helper.rb +1 -1
  34. metadata +9 -10
@@ -1,55 +1,49 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Acfs::Resource::Attributes::DateTime do
4
- let(:model) { Class.new Acfs::Resource }
5
- let(:params) { {} }
6
- subject { Acfs::Resource::Attributes::DateTime.new params }
4
+ let(:type) { Acfs::Resource::Attributes::DateTime.new }
7
5
 
8
- describe 'cast' do
9
- it 'should return same object, if obj is already of DateTime class' do
10
- date_time = DateTime.now
11
- retval = subject.cast(date_time)
12
- expect(retval).to be == date_time
6
+ describe '#cast' do
7
+ subject { -> { type.cast value } }
8
+
9
+ context 'with nil' do
10
+ let(:value) { nil }
11
+ it { expect(subject.call).to eq nil }
13
12
  end
14
13
 
15
- it 'should return parsed object, if obj is of Time class' do
16
- time = Time.now
17
- retval = subject.cast(time)
18
- expect(retval).to be == DateTime.iso8601(time.iso8601)
14
+ context 'with empty string' do
15
+ let(:value) { '' }
16
+ it { expect(subject.call).to eq nil }
19
17
  end
20
18
 
21
- it 'should return parsed object, if obj is of Date class' do
22
- date = Date.today
23
- retval = subject.cast(date)
24
- expect(retval).to be == DateTime.iso8601(date.iso8601)
19
+ context 'with blank string' do
20
+ let(:value) { " \t" }
21
+ it { expect(subject.call).to eq nil }
25
22
  end
26
23
 
27
- it 'should return parsed object, if obj is of String class in ISO-8601 format' do
28
- date_time_string = DateTime.now.iso8601
29
- retval = subject.cast(date_time_string)
30
- expect(retval).to be == DateTime.iso8601(date_time_string)
24
+ context 'with DateTime' do
25
+ let(:value) { DateTime.now }
26
+ it { expect(subject.call).to eq value }
31
27
  end
32
28
 
33
- it 'should raise an error if obj is of String class not in valid ISO-8601 format' do
34
- malformed_string = 'qwe123'
35
- expect do
36
- subject.cast(malformed_string)
37
- end.to raise_error ArgumentError
29
+ context 'with Time' do
30
+ let(:value) { Time.now }
31
+ it { expect(subject.call).to eq value.to_datetime }
38
32
  end
39
33
 
40
- it 'should raise an error if obj is of wrong class (Fixnum)' do
41
- fixnum = 12
42
- expect do
43
- subject.cast(fixnum)
44
- end.to raise_error TypeError
34
+ context 'with Date' do
35
+ let(:value) { Date.today }
36
+ it { expect(subject.call).to eq value.to_datetime }
45
37
  end
46
38
 
47
- context 'with allow_nil option' do
48
- let(:params) { {allow_nil: true} }
39
+ context 'with ISO8601' do
40
+ let(:value) { DateTime.now.iso8601 }
41
+ it { expect(subject.call.iso8601).to eq value }
42
+ end
49
43
 
50
- it 'should accept empty string as nil' do
51
- expect(subject.cast('')).to eq nil
52
- end
44
+ context 'with invalid string' do
45
+ let(:value) { 'qwe123' }
46
+ it { is_expected.to raise_error ArgumentError }
53
47
  end
54
48
  end
55
49
  end
@@ -1,50 +1,75 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Acfs::Resource::Attributes::Dict do
4
- let(:model) { Class.new(Acfs::Resource) }
5
- subject { Acfs::Resource::Attributes::Dict.new }
4
+ let(:type) { Acfs::Resource::Attributes::Dict.new }
6
5
 
7
- describe '.cast' do
8
- context 'with hash' do
9
- let(:sample) { {3 => true, 'asfd' => 4} }
6
+ describe '#cast' do
7
+ subject { -> { type.cast value } }
10
8
 
11
- it 'should return unmodified hash' do
12
- expect(subject.cast(sample)).to be sample
13
- end
9
+ context 'with nil' do
10
+ let(:value) { nil }
11
+ it { expect(subject.call).to eq nil }
12
+ end
13
+
14
+ context 'with blank string (I)' do
15
+ let(:value) { '' }
16
+ it { expect(subject.call).to eq Hash.new }
17
+ end
18
+
19
+ context 'with blank string (II)' do
20
+ let(:value) { " \t" }
21
+ it { expect(subject.call).to eq Hash.new }
22
+ end
23
+
24
+ context 'with hash' do
25
+ let(:value) { {3 => true, abc: 4} }
26
+ it { expect(subject.call).to eq value }
14
27
  end
15
28
 
16
- context 'with not hashable object' do
17
- let(:sample) { Object.new }
29
+ context 'with non hashable object' do
30
+ let(:value) { Object.new }
31
+ it { is_expected.to raise_error TypeError }
32
+ end
18
33
 
19
- it 'should raise a TypeError' do
20
- expect do
21
- subject.cast(sample)
22
- end.to raise_error TypeError
34
+ context 'with hashable object (I)' do
35
+ let(:value) do
36
+ Class.new do
37
+ def to_hash
38
+ {id: object_id}
39
+ end
40
+ end.new
23
41
  end
42
+
43
+ it { expect(subject.call).to eq id: value.object_id }
24
44
  end
25
45
 
26
- context 'with hashable object' do
27
- let(:sample) do
28
- o = Object.new
29
- class << o
46
+ context 'with hashable object (II)' do
47
+ let(:value) do
48
+ Class.new do
30
49
  def to_h
31
- {3 => 4, 'test' => true}
50
+ {id: object_id}
32
51
  end
33
- end
34
- o
52
+ end.new
35
53
  end
36
54
 
37
- it 'should cast object to hash' do
38
- expect(subject.cast(sample)).to eq 3 => 4, 'test' => true
39
- end
55
+ it { expect(subject.call).to eq id: value.object_id }
40
56
  end
41
57
 
42
- context 'with hash subclass' do
43
- let(:sample) { HashWithIndifferentAccess.new :test => :foo, 34 => 12 }
44
-
45
- it 'should return obj unmodified' do
46
- expect(subject.cast(sample)).to be sample
58
+ context 'with serializable object' do
59
+ let(:value) do
60
+ Class.new do
61
+ def serializable_hash
62
+ {id: object_id}
63
+ end
64
+ end.new
47
65
  end
66
+
67
+ it { expect(subject.call).to eq id: value.object_id }
68
+ end
69
+
70
+ context 'with hash subclass object' do
71
+ let(:value) { HashWithIndifferentAccess.new test: :foo }
72
+ it { expect(subject.call).to be value }
48
73
  end
49
74
  end
50
75
  end
@@ -1,20 +1,59 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Acfs::Resource::Attributes::Float do
4
- let(:model) { Class.new Acfs::Resource }
5
- subject { described_class.new }
4
+ let(:type) { Acfs::Resource::Attributes::Float.new }
6
5
 
7
- describe 'cast' do
8
- it 'should return same object, if obj is already of float class' do
9
- expect(subject.cast(1.3)).to be == 1.3
6
+ describe '#cast' do
7
+ subject { -> { type.cast value } }
8
+
9
+ context 'with nil' do
10
+ let(:value) { nil }
11
+ it { expect(subject.call).to eq nil }
12
+ end
13
+
14
+ context 'with blank string (I)' do
15
+ let(:value) { '' }
16
+ it { expect(subject.call).to eq 0.0 }
17
+ end
18
+
19
+ context 'with blank string (II)' do
20
+ let(:value) { " \t" }
21
+ it { expect(subject.call).to eq 0.0 }
22
+ end
23
+
24
+ context 'with float' do
25
+ let(:value) { 1.7 }
26
+ it { expect(subject.call).to eq 1.7 }
27
+ end
28
+
29
+ context 'with Infinity' do
30
+ let(:value) { 'Infinity' }
31
+ it { expect(subject.call).to eq ::Float::INFINITY }
32
+ end
33
+
34
+ context 'with -Infinity' do
35
+ let(:value) { '-Infinity' }
36
+ it { expect(subject.call).to eq -::Float::INFINITY }
37
+ end
38
+
39
+ context 'with NaN' do
40
+ let(:value) { 'NaN' }
41
+ it { expect(subject.call).to be_nan }
42
+ end
43
+
44
+ context 'with fixnum' do
45
+ let(:value) { 1 }
46
+ it { expect(subject.call).to eq 1.0 }
10
47
  end
11
48
 
12
- it 'should return parsed object, if obj is of Fixnum class' do
13
- expect(subject.cast(7)).to be == 7.0
49
+ context 'with valid string' do
50
+ let(:value) { '1.7' }
51
+ it { expect(subject.call).to eq 1.7 }
14
52
  end
15
53
 
16
- it 'should return parsed object, if obj is of String class containing a float' do
17
- expect(subject.cast('1.7')).to be == 1.7
54
+ context 'with invalid string (I)' do
55
+ let(:value) { '1.7a' }
56
+ it { is_expected.to raise_error ArgumentError }
18
57
  end
19
58
  end
20
59
  end
@@ -1,19 +1,34 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Acfs::Resource::Attributes::Integer do
4
- subject { Acfs::Resource::Attributes::Integer.new }
4
+ let(:type) { Acfs::Resource::Attributes::Integer.new }
5
5
 
6
- describe 'cast' do
7
- it 'should cast integer strings' do
8
- expect(subject.cast('123')).to eq 123
6
+ describe '#cast' do
7
+ subject { -> { type.cast value } }
8
+
9
+ context 'with nil' do
10
+ let(:value) { nil }
11
+ it { expect(subject.call).to eq nil }
12
+ end
13
+
14
+ context 'with empty string' do
15
+ let(:value) { '' }
16
+ it { expect(subject.call).to eq 0 }
17
+ end
18
+
19
+ context 'with blank string' do
20
+ let(:value) { " \t" }
21
+ it { expect(subject.call).to eq 0 }
9
22
  end
10
23
 
11
- it 'should cast empty string (backward compatibility)' do
12
- expect(subject.cast('')).to eq 0
24
+ context 'with string' do
25
+ let(:value) { '123' }
26
+ it { expect(subject.call).to eq 123 }
13
27
  end
14
28
 
15
- it 'should not cast invalid integers' do
16
- expect { subject.cast 'abc' }.to raise_error TypeError
29
+ context 'with invalid string' do
30
+ let(:value) { '123a' }
31
+ it { is_expected.to raise_error ArgumentError }
17
32
  end
18
33
  end
19
34
  end
@@ -1,34 +1,58 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Acfs::Resource::Attributes::List do
4
- let(:model) { Class.new Acfs::Resource }
5
- subject { described_class.new }
4
+ let(:type) { Acfs::Resource::Attributes::List.new }
6
5
 
7
- describe '.cast' do
8
- context 'with array' do
9
- let(:sample) { %w(abc cde efg) }
6
+ describe '#cast' do
7
+ subject { -> { type.cast value } }
10
8
 
11
- it 'should return unmodified array' do
12
- expect(subject.cast(sample)).to be == %w(abc cde efg)
13
- end
9
+ context 'with nil' do
10
+ let(:value) { nil }
11
+ it { expect(subject.call).to eq nil }
14
12
  end
15
13
 
16
- context 'with not listable object' do
17
- let(:sample) { Object.new }
14
+ context 'with blank string (I)' do
15
+ let(:value) { '' }
16
+ it { expect(subject.call).to eq Array.new }
17
+ end
18
18
 
19
- it 'should raise a TypeError' do
20
- expect do
21
- subject.cast(sample)
22
- end.to raise_error TypeError
23
- end
19
+ context 'with blank string (II)' do
20
+ let(:value) { " \t" }
21
+ it { expect(subject.call).to eq Array.new }
24
22
  end
25
23
 
26
- context 'with listable object' do
27
- let(:sample) { 5..10 }
24
+ context 'with array' do
25
+ let(:value) { %w(abc cde efg) }
26
+ it { expect(subject.call).to eq value }
27
+ end
28
28
 
29
- it 'should cast object to array' do
30
- expect(subject.cast(sample)).to be == [5, 6, 7, 8, 9, 10]
29
+ context 'with convertable object (I)' do
30
+ let(:value) do
31
+ Class.new do
32
+ def to_ary
33
+ [1, 2, 3]
34
+ end
35
+ end.new
31
36
  end
37
+
38
+ it { expect(subject.call).to eq [1, 2, 3] }
39
+ end
40
+
41
+ context 'with convertable object (II)' do
42
+ let(:value) do
43
+ Class.new do
44
+ def to_a
45
+ [1, 2, 3]
46
+ end
47
+ end.new
48
+ end
49
+
50
+ it { expect(subject.call).to eq [1, 2, 3] }
51
+ end
52
+
53
+ context 'with non castable object' do
54
+ let(:value) { Object.new }
55
+ it { expect(subject.call).to eq [value] }
32
56
  end
33
57
  end
34
58
  end
@@ -1,63 +1,40 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Acfs::Resource::Attributes::UUID do
4
- let(:model) { Class.new Acfs::Resource }
5
- let(:params) { {} }
6
- let(:instance) { described_class.new params }
7
- subject { instance }
8
-
9
- describe '#cast_type' do
10
- let(:param) { '450b7a40-94ad-11e3-baa8-0800200c9a66' }
11
- let(:action) { instance.cast param }
12
- subject { action }
13
-
14
- context 'with String as param' do
15
- context 'with valid UUID' do
16
- let(:param) { '450b7a40-94ad-11e3-baa8-0800200c9a66' }
17
- it { should be_a String }
18
- it { should eq param }
19
- end
20
-
21
- context 'with invalid UUID' do
22
- subject { -> { action } }
23
-
24
- context 'with random non-empty string' do
25
- let(:param) { 'invalid string' }
26
- it { should raise_error ArgumentError }
27
- end
28
-
29
- context 'with UUID string containing invalid characters' do
30
- let(:param) { 'xxxxxxxx-yyyy-11e3-baa8-0800200c9a66' }
31
- it { should raise_error ArgumentError }
32
- end
33
-
34
- context 'with empty string' do
35
- let(:param) { '' }
36
-
37
- context 'with allow_nil option' do
38
- let(:params) { {allow_nil: true} }
39
- subject { action }
40
- it { should eq nil }
41
- end
42
-
43
- context 'without allow_nil option' do
44
- let(:params) { {allow_nil: false} }
45
- it { should raise_error ArgumentError }
46
- end
47
- end
48
- end
4
+ let(:type) { Acfs::Resource::Attributes::UUID.new }
5
+
6
+ describe '#cast' do
7
+ subject { -> { type.cast(value) } }
8
+
9
+ context 'with nil' do
10
+ let(:value) { nil }
11
+ it { expect(subject.call).to eq nil }
49
12
  end
50
13
 
51
- context 'with non-String as param' do
52
- subject { -> { action } }
14
+ context 'with empty string' do
15
+ let(:value) { '' }
16
+ it { expect(subject.call).to eq nil }
17
+ end
18
+
19
+ context 'with blank string' do
20
+ let(:value) { " \t" }
21
+ it { expect(subject.call).to eq nil }
22
+ end
23
+
24
+ context 'with string UUID' do
25
+ let(:value) { '450b7a40-94ad-11e3-baa8-0800200c9a66' }
26
+ it { expect(subject.call).to be_a String }
27
+ it { expect(subject.call).to eq value }
28
+ end
29
+
30
+ context 'with invalid string' do
31
+ let(:value) { 'invalid string' }
32
+ it { is_expected.to raise_error TypeError, /invalid UUID/i }
33
+ end
53
34
 
54
- invalid_params = {fixnum: 1, float: 3.2, symbol: :invalid, boolean: true}
55
- invalid_params.each do |type, incorrect_param|
56
- context "with #{type} as param" do
57
- let(:param) { incorrect_param }
58
- it { should raise_error ArgumentError }
59
- end
60
- end
35
+ context 'with invalid UUID' do
36
+ let(:value) { 'xxxxxxxx-yyyy-11e3-baa8-0800200c9a66' }
37
+ it { is_expected.to raise_error TypeError, /invalid UUID/i }
61
38
  end
62
39
  end
63
40
  end
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe Acfs::Resource::Attributes do
4
4
  let(:model) { Class.new Acfs::Resource }
5
+ let(:submodel) { Class.new model }
5
6
 
6
7
  describe '#initialize' do
7
8
  before { model.attribute :name, :string, default: 'John' }
@@ -137,7 +138,7 @@ describe Acfs::Resource::Attributes do
137
138
  end
138
139
 
139
140
  describe 'class' do
140
- describe '#attribute' do
141
+ describe '#attributes' do
141
142
  it 'should add an attribute to model attribute list' do
142
143
  model.send :attribute, :name, :string
143
144
 
@@ -150,42 +151,27 @@ describe Acfs::Resource::Attributes do
150
151
  expect(model.attributes.symbolize_keys).to eq name: 'John'
151
152
  end
152
153
 
153
- it 'should accept an symbolic type' do
154
+ it 'should accept a symbolic type' do
154
155
  model.send :attribute, :age, :integer, default: '12'
155
156
 
156
157
  expect(model.attributes.symbolize_keys).to eq age: 12
157
158
  end
158
159
 
159
- it 'should accept an class type' do
160
+ it 'should accept a class type' do
160
161
  model.send :attribute, :age, Acfs::Resource::Attributes::Integer,
161
162
  default: '12'
162
163
 
163
164
  expect(model.attributes.symbolize_keys).to eq age: 12
164
165
  end
165
166
 
166
- context 'allow nil option' do
167
- it 'should allow nil as value' do
168
- model.send :attribute, :updated_at, :date_time,
169
- default: DateTime.new, allow_nil: true
170
-
171
- resource = model.new
172
- expect(resource.updated_at).to eq DateTime.new
173
-
174
- resource.updated_at = ''
175
- expect(resource.updated_at).to eq nil
167
+ context 'on inherited resources' do
168
+ before do
169
+ model.attribute :age, :integer, default: 5
170
+ submodel.attribute :born_at, :date_time
176
171
  end
177
- end
178
-
179
- context 'allow blank option' do
180
- it 'should allow blank as value' do
181
- model.send :attribute, :updated_at, :date_time,
182
- default: DateTime.new, allow_blank: true
183
-
184
- resource = model.new
185
- expect(resource.updated_at).to eq DateTime.new
186
172
 
187
- resource.updated_at = ''
188
- expect(resource.updated_at).to eq nil
173
+ it 'includes superclass attributes' do
174
+ expect(submodel.attributes.keys).to match_array %w(age born_at)
189
175
  end
190
176
  end
191
177
  end
@@ -519,14 +519,21 @@ describe Acfs::Resource::QueryMethods do
519
519
  end
520
520
 
521
521
  it 'should iterate all pages' do
522
- indecies = []
522
+ indices = []
523
523
  model.each_item do |item|
524
524
  expect(item).to be_a MyUser
525
- indecies << item.id
525
+ indices << item.id
526
526
  end
527
527
  Acfs.run
528
528
 
529
- expect(indecies).to eq [1, 2, 3, 4, 5]
529
+ expect(indices).to eq [1, 2, 3, 4, 5]
530
+ end
531
+
532
+ it 'should pass the collection to the provided block' do
533
+ model.each_item do |_item, collection|
534
+ expect(collection).to be_a Acfs::Collection
535
+ end
536
+ Acfs.run
530
537
  end
531
538
  end
532
539
  end
@@ -12,7 +12,7 @@ describe Acfs::Response::Formats do
12
12
  let(:headers) { {} }
13
13
 
14
14
  it "should fallback on 'text/plain'" do
15
- expect(response.content_type).to be == Mime::TEXT
15
+ expect(response.content_type).to be == Mime[:text]
16
16
  end
17
17
  end
18
18
 
@@ -21,7 +21,7 @@ describe Acfs::Response::Formats do
21
21
 
22
22
  describe '#content_type' do
23
23
  it 'should return Mime::JSON' do
24
- expect(response.content_type).to be == Mime::JSON
24
+ expect(response.content_type).to be == Mime[:json]
25
25
  end
26
26
  end
27
27
 
@@ -36,7 +36,7 @@ describe Acfs::Response::Formats do
36
36
 
37
37
  describe '#content_type' do
38
38
  it 'should return Mime::JSON' do
39
- expect(response.content_type).to be == Mime::JSON
39
+ expect(response.content_type).to be == Mime[:json]
40
40
  end
41
41
  end
42
42
 
data/spec/spec_helper.rb CHANGED
@@ -9,7 +9,7 @@ if ENV['CI'] || (defined?(:RUBY_ENGINE) && RUBY_ENGINE != 'rbx')
9
9
  end
10
10
 
11
11
  require 'bundler'
12
- Bundler.require
12
+ Bundler.require(:default, :test)
13
13
 
14
14
  require 'acfs'
15
15
  require 'webmock/rspec'