yaks 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +65 -5
- data/README.md +38 -8
- data/Rakefile +33 -0
- data/lib/yaks/breaking_changes.rb +22 -0
- data/lib/yaks/collection_mapper.rb +18 -21
- data/lib/yaks/collection_resource.rb +19 -5
- data/lib/yaks/config/dsl.rb +78 -0
- data/lib/yaks/config.rb +37 -63
- data/lib/yaks/default_policy.rb +27 -9
- data/lib/yaks/{serializer → format}/collection_json.rb +7 -3
- data/lib/yaks/{serializer → format}/hal.rb +14 -4
- data/lib/yaks/{serializer → format}/json_api.rb +22 -4
- data/lib/yaks/{serializer.rb → format.rb} +5 -5
- data/lib/yaks/fp/hash_updatable.rb +17 -0
- data/lib/yaks/fp/updatable.rb +15 -0
- data/lib/yaks/mapper/association.rb +24 -21
- data/lib/yaks/mapper/association_mapper.rb +42 -0
- data/lib/yaks/mapper/attribute.rb +17 -0
- data/lib/yaks/mapper/class_methods.rb +0 -1
- data/lib/yaks/mapper/config.rb +8 -28
- data/lib/yaks/mapper/has_many.rb +8 -3
- data/lib/yaks/mapper/has_one.rb +1 -1
- data/lib/yaks/mapper/link.rb +13 -13
- data/lib/yaks/mapper.rb +28 -32
- data/lib/yaks/null_resource.rb +1 -0
- data/lib/yaks/resource.rb +15 -5
- data/lib/yaks/version.rb +1 -1
- data/lib/yaks.rb +16 -10
- data/spec/acceptance/acceptance_spec.rb +16 -17
- data/spec/acceptance/json_shared_examples.rb +8 -0
- data/spec/acceptance/models.rb +2 -2
- data/spec/integration/map_to_resource_spec.rb +3 -3
- data/spec/json/confucius.collection.json +39 -0
- data/spec/json/confucius.hal.json +7 -4
- data/spec/json/confucius.json_api.json +1 -1
- data/spec/spec_helper.rb +6 -0
- data/spec/support/classes_for_policy_testing.rb +36 -0
- data/spec/support/shared_contexts.rb +1 -1
- data/spec/unit/yaks/collection_mapper_spec.rb +34 -9
- data/spec/unit/yaks/collection_resource_spec.rb +4 -4
- data/spec/unit/yaks/config/dsl_spec.rb +91 -0
- data/spec/unit/yaks/config_spec.rb +10 -6
- data/spec/unit/yaks/default_policy/derive_mapper_from_object_spec.rb +80 -0
- data/spec/unit/yaks/default_policy_spec.rb +50 -0
- data/spec/unit/yaks/{serializer → format}/hal_spec.rb +1 -1
- data/spec/unit/yaks/format/json_api_spec.rb +42 -0
- data/spec/unit/yaks/format_spec.rb +12 -0
- data/spec/unit/yaks/fp/hash_updatable_spec.rb +22 -0
- data/spec/unit/yaks/fp/updatable_spec.rb +22 -0
- data/spec/unit/yaks/mapper/association_mapper_spec.rb +60 -0
- data/spec/unit/yaks/mapper/association_spec.rb +96 -41
- data/spec/unit/yaks/mapper/attribute_spec.rb +20 -0
- data/spec/unit/yaks/mapper/class_methods_spec.rb +49 -10
- data/spec/unit/yaks/mapper/config_spec.rb +25 -50
- data/spec/unit/yaks/mapper/has_many_spec.rb +33 -5
- data/spec/unit/yaks/mapper/has_one_spec.rb +32 -17
- data/spec/unit/yaks/mapper/link_spec.rb +44 -12
- data/spec/unit/yaks/mapper_spec.rb +45 -17
- data/spec/unit/yaks/resource_spec.rb +41 -7
- data/yaks.gemspec +7 -1
- metadata +72 -21
- data/examples/hal01.rb +0 -126
- data/examples/jsonapi01.rb +0 -68
- data/examples/jsonapi02.rb +0 -62
- data/examples/jsonapi03.rb +0 -86
- data/spec/support/serializers.rb +0 -14
- data/spec/unit/yaks/serializer_spec.rb +0 -12
@@ -14,45 +14,6 @@ RSpec.describe Yaks::Mapper::Config do
|
|
14
14
|
its(:associations) { should eql [:c] }
|
15
15
|
end
|
16
16
|
|
17
|
-
describe '#updated' do
|
18
|
-
context 'with no updates' do
|
19
|
-
let(:config) {
|
20
|
-
super()
|
21
|
-
.type('foo')
|
22
|
-
.attributes(:a, :b, :c)
|
23
|
-
.link(:foo, 'http://bar')
|
24
|
-
.has_many(:bars)
|
25
|
-
}
|
26
|
-
|
27
|
-
it 'should update attributes' do
|
28
|
-
expect(config.updated(attributes: [:foo])).to eql described_class.new(
|
29
|
-
'foo',
|
30
|
-
[:foo],
|
31
|
-
[Yaks::Mapper::Link.new(:foo, 'http://bar', {})],
|
32
|
-
[Yaks::Mapper::HasMany.new(:bars, Undefined, Undefined, Undefined)]
|
33
|
-
)
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'should update links' do
|
37
|
-
expect(config.updated(links: [:foo])).to eql described_class.new(
|
38
|
-
'foo',
|
39
|
-
[:a, :b, :c],
|
40
|
-
[:foo],
|
41
|
-
[Yaks::Mapper::HasMany.new(:bars, Undefined, Undefined, Undefined)]
|
42
|
-
)
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'should update associations' do
|
46
|
-
expect(config.updated(associations: [:foo])).to eql described_class.new(
|
47
|
-
'foo',
|
48
|
-
[:a, :b, :c],
|
49
|
-
[Yaks::Mapper::Link.new(:foo, 'http://bar', {})],
|
50
|
-
[:foo]
|
51
|
-
)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
17
|
describe '#attributes' do
|
57
18
|
context 'an empty config' do
|
58
19
|
it 'should return an empty attributes list' do
|
@@ -61,8 +22,11 @@ RSpec.describe Yaks::Mapper::Config do
|
|
61
22
|
end
|
62
23
|
|
63
24
|
it 'should add attributes' do
|
64
|
-
expect(config.attributes(:foo, :bar, :baz).attributes)
|
65
|
-
.
|
25
|
+
expect(config.attributes(:foo, :bar, :baz).attributes).to eq [
|
26
|
+
Yaks::Mapper::Attribute.new(:foo),
|
27
|
+
Yaks::Mapper::Attribute.new(:bar),
|
28
|
+
Yaks::Mapper::Attribute.new(:baz)
|
29
|
+
]
|
66
30
|
end
|
67
31
|
|
68
32
|
it 'should be chainable' do
|
@@ -71,7 +35,11 @@ RSpec.describe Yaks::Mapper::Config do
|
|
71
35
|
.attributes(:foo, :bar)
|
72
36
|
.attributes(:baz)
|
73
37
|
.attributes
|
74
|
-
).to eq [
|
38
|
+
).to eq [
|
39
|
+
Yaks::Mapper::Attribute.new(:foo),
|
40
|
+
Yaks::Mapper::Attribute.new(:bar),
|
41
|
+
Yaks::Mapper::Attribute.new(:baz)
|
42
|
+
]
|
75
43
|
end
|
76
44
|
end
|
77
45
|
|
@@ -117,7 +85,7 @@ RSpec.describe Yaks::Mapper::Config do
|
|
117
85
|
|
118
86
|
it 'should have the association configured' do
|
119
87
|
expect(config.associations).to eq [
|
120
|
-
Yaks::Mapper::HasOne.new(:mother, Yaks::Mapper
|
88
|
+
Yaks::Mapper::HasOne.new(name: :mother, mapper: Yaks::Mapper)
|
121
89
|
]
|
122
90
|
end
|
123
91
|
end
|
@@ -127,7 +95,7 @@ RSpec.describe Yaks::Mapper::Config do
|
|
127
95
|
|
128
96
|
it 'should have undefined mapper, rel, collection_mapper' do
|
129
97
|
expect(config.associations).to eq [
|
130
|
-
Yaks::Mapper::HasOne.new(:mother
|
98
|
+
Yaks::Mapper::HasOne.new(name: :mother)
|
131
99
|
]
|
132
100
|
end
|
133
101
|
end
|
@@ -137,7 +105,7 @@ RSpec.describe Yaks::Mapper::Config do
|
|
137
105
|
|
138
106
|
it 'should have the rel' do
|
139
107
|
expect(config.associations).to eq [
|
140
|
-
Yaks::Mapper::HasOne.new(:mother,
|
108
|
+
Yaks::Mapper::HasOne.new(name: :mother, rel: '/api/rels/mother')
|
141
109
|
]
|
142
110
|
end
|
143
111
|
|
@@ -150,7 +118,7 @@ RSpec.describe Yaks::Mapper::Config do
|
|
150
118
|
|
151
119
|
it 'should have the association configured' do
|
152
120
|
expect(config.associations).to eq [
|
153
|
-
Yaks::Mapper::HasMany.new(:shoes, Yaks::Mapper
|
121
|
+
Yaks::Mapper::HasMany.new(name: :shoes, mapper: Yaks::Mapper)
|
154
122
|
]
|
155
123
|
end
|
156
124
|
end
|
@@ -160,7 +128,7 @@ RSpec.describe Yaks::Mapper::Config do
|
|
160
128
|
|
161
129
|
it 'should have undefined mapper, rel, collection_mapper' do
|
162
130
|
expect(config.associations).to eq [
|
163
|
-
Yaks::Mapper::HasMany.new(:shoes
|
131
|
+
Yaks::Mapper::HasMany.new(name: :shoes)
|
164
132
|
]
|
165
133
|
end
|
166
134
|
end
|
@@ -170,12 +138,19 @@ RSpec.describe Yaks::Mapper::Config do
|
|
170
138
|
|
171
139
|
it 'should have the association configured' do
|
172
140
|
expect(config.associations).to eq [
|
173
|
-
Yaks::Mapper::HasMany.new(:shoes,
|
141
|
+
Yaks::Mapper::HasMany.new(name: :shoes, collection_mapper: :a_collection_mapper)
|
174
142
|
]
|
175
143
|
end
|
176
144
|
end
|
177
145
|
end
|
178
146
|
|
147
|
+
describe "#type" do
|
148
|
+
it "should update the type" do
|
149
|
+
config = config().type :shoe
|
150
|
+
expect(config.type).to be :shoe
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
179
154
|
context 'multiple associations' do
|
180
155
|
let(:config) {
|
181
156
|
subject
|
@@ -184,8 +159,8 @@ RSpec.describe Yaks::Mapper::Config do
|
|
184
159
|
}
|
185
160
|
|
186
161
|
it 'should have them all present' do
|
187
|
-
expect(config.associations).to include Yaks::Mapper::HasOne.new(:mother
|
188
|
-
expect(config.associations).to include Yaks::Mapper::HasMany.new(:shoes
|
162
|
+
expect(config.associations).to include Yaks::Mapper::HasOne.new(name: :mother)
|
163
|
+
expect(config.associations).to include Yaks::Mapper::HasMany.new(name: :shoes)
|
189
164
|
end
|
190
165
|
end
|
191
166
|
end
|
@@ -19,10 +19,10 @@ RSpec.describe Yaks::Mapper::HasMany do
|
|
19
19
|
its(:singular_name) { should eq 'shoe' }
|
20
20
|
|
21
21
|
let(:closet) {
|
22
|
-
|
22
|
+
fake(
|
23
23
|
:shoes => [
|
24
|
-
|
25
|
-
|
24
|
+
fake(size: 9, color: :blue),
|
25
|
+
fake(size: 11.5, color: :red),
|
26
26
|
]
|
27
27
|
)
|
28
28
|
}
|
@@ -35,14 +35,42 @@ RSpec.describe Yaks::Mapper::HasMany do
|
|
35
35
|
Yaks::Resource.new(type: 'shoe', attributes: {:size => 9, :color => :blue}),
|
36
36
|
Yaks::Resource.new(type: 'shoe', attributes: {:size => 11.5, :color => :red})
|
37
37
|
],
|
38
|
-
|
38
|
+
collection_rel: 'rel:shoes'
|
39
39
|
)
|
40
40
|
)
|
41
41
|
end
|
42
42
|
|
43
|
+
it 'should map nil to a NullResource collection' do
|
44
|
+
expect(closet_mapper.call(fake(shoes: nil)).subresources).to eql(
|
45
|
+
'http://foo/shoes' => Yaks::NullResource.new(collection: true)
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'without an explicit mapper' do
|
50
|
+
let(:dress_mapper) {
|
51
|
+
Class.new(Yaks::Mapper) { type 'dress' ; attributes :color }
|
52
|
+
}
|
53
|
+
|
54
|
+
before do
|
55
|
+
closet_mapper_class.class_eval do
|
56
|
+
has_many :dresses
|
57
|
+
end
|
58
|
+
|
59
|
+
stub(closet_mapper.policy).derive_mapper_from_association(any_args) do
|
60
|
+
dress_mapper
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should derive it from policy' do
|
65
|
+
expect(closet_mapper.policy).to equal policy
|
66
|
+
closet_mapper.call(fake(shoes: [], dresses: [fake(color: 'blue')]))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
43
71
|
describe '#collection_mapper' do
|
44
72
|
let(:collection_mapper) { Yaks::Undefined }
|
45
|
-
subject(:has_many) { described_class.new(:name, :mapper, :rel, collection_mapper) }
|
73
|
+
subject(:has_many) { described_class.new(name: :name, mapper: :mapper, rel: :rel, collection_mapper: collection_mapper) }
|
46
74
|
|
47
75
|
context 'when the collection mapper is undefined' do
|
48
76
|
it 'should derive one from collection and policy' do
|
@@ -1,35 +1,50 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe Yaks::Mapper::HasOne do
|
4
|
+
include_context 'yaks context'
|
5
|
+
|
4
6
|
AuthorMapper = Class.new(Yaks::Mapper) { attributes :name }
|
5
7
|
|
6
|
-
subject(:has_one)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
double(
|
12
|
-
Yaks::DefaultPolicy,
|
13
|
-
derive_type_from_mapper_class: 'author',
|
14
|
-
derive_mapper_from_association: AuthorMapper
|
8
|
+
subject(:has_one) do
|
9
|
+
described_class.new(
|
10
|
+
name: :author,
|
11
|
+
mapper: association_mapper,
|
12
|
+
rel: 'http://rel'
|
15
13
|
)
|
16
|
-
|
17
|
-
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:association_mapper) { AuthorMapper }
|
17
|
+
let(:name) { 'William S. Burroughs' }
|
18
|
+
let(:author) { fake(:name => name) }
|
19
|
+
|
20
|
+
fake(:policy,
|
21
|
+
derive_type_from_mapper_class: 'author',
|
22
|
+
derive_mapper_from_association: AuthorMapper
|
23
|
+
){ Yaks::DefaultPolicy }
|
18
24
|
|
19
25
|
its(:singular_name) { should eq 'author' }
|
20
26
|
|
21
27
|
it 'should map to a single Resource' do
|
22
|
-
expect(has_one.map_resource(author,
|
28
|
+
expect(has_one.map_resource(author, yaks_context)).to eq Yaks::Resource.new(type: 'author', attributes: {name: name})
|
23
29
|
end
|
24
30
|
|
25
31
|
context 'with no mapper specified' do
|
26
|
-
|
32
|
+
subject(:subresource) { has_one.add_to_resource(Yaks::Resource.new, parent_mapper, yaks_context) }
|
33
|
+
let(:association_mapper) { Yaks::Undefined }
|
34
|
+
fake(:parent_mapper) { Yaks::Mapper }
|
35
|
+
|
36
|
+
before do
|
37
|
+
stub(parent_mapper).load_association(:author) { author }
|
38
|
+
end
|
27
39
|
|
28
40
|
it 'should derive one based on policy' do
|
29
|
-
expect(
|
30
|
-
|
31
|
-
|
32
|
-
|
41
|
+
expect(subresource).to eql(
|
42
|
+
Yaks::Resource.new(
|
43
|
+
subresources: {
|
44
|
+
'http://rel' => Yaks::Resource.new(type: 'author', attributes: {name: name})
|
45
|
+
}
|
46
|
+
)
|
47
|
+
)
|
33
48
|
end
|
34
49
|
|
35
50
|
end
|
@@ -11,8 +11,43 @@ RSpec.describe Yaks::Mapper::Link do
|
|
11
11
|
|
12
12
|
its(:template_variables) { should eq [:x, :y] }
|
13
13
|
its(:uri_template) { should eq URITemplate.new(template) }
|
14
|
-
its(:expand?) { should be true }
|
15
14
|
|
15
|
+
let(:object) { Struct.new(:x, :y, :returns_nil).new(3, 4, nil) }
|
16
|
+
|
17
|
+
let(:mapper_class) do
|
18
|
+
Class.new(Yaks::Mapper) do
|
19
|
+
type 'foo'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:mapper) do
|
24
|
+
mapper_class.new(yaks_context).tap do |mapper|
|
25
|
+
mapper.call(object) # set @object
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#add_to_resource' do
|
30
|
+
it 'should add itself to the resource' do
|
31
|
+
expect(link.add_to_resource(Yaks::Resource.new, mapper, yaks_context)).to eql(
|
32
|
+
Yaks::Resource.new(links: [Yaks::Resource::Link.new(:next, "/foo/bar/3/4", {})])
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with a link function returning nothing' do
|
37
|
+
let(:template) { :link_computer }
|
38
|
+
before do
|
39
|
+
mapper_class.class_eval do
|
40
|
+
def link_computer ; end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should not render the link' do
|
45
|
+
expect(link.add_to_resource(Yaks::Resource.new, mapper, yaks_context)).to eql(
|
46
|
+
Yaks::Resource.new
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
16
51
|
|
17
52
|
describe '#rel?' do
|
18
53
|
it 'should return true if the relation matches' do
|
@@ -47,8 +82,6 @@ RSpec.describe Yaks::Mapper::Link do
|
|
47
82
|
it 'should keep the template in the response' do
|
48
83
|
expect(link.expand_with(->{ })).to eq '/foo/bar/{x}/{y}'
|
49
84
|
end
|
50
|
-
|
51
|
-
its(:expand?) { should be false }
|
52
85
|
end
|
53
86
|
|
54
87
|
context 'with a URI without expansion variables' do
|
@@ -81,14 +114,6 @@ RSpec.describe Yaks::Mapper::Link do
|
|
81
114
|
|
82
115
|
its(:rel) { should eq :next }
|
83
116
|
|
84
|
-
let(:object) { Struct.new(:x, :y, :returns_nil).new(3, 4, nil) }
|
85
|
-
|
86
|
-
let(:mapper) do
|
87
|
-
Yaks::Mapper.new(yaks_context).tap do |mapper|
|
88
|
-
mapper.call(object) # set @object
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
117
|
context 'with attributes' do
|
93
118
|
it 'should not have a title' do
|
94
119
|
expect(resource_link.options.key?(:title)).to be false
|
@@ -146,8 +171,15 @@ RSpec.describe Yaks::Mapper::Link do
|
|
146
171
|
context 'with a title lambda' do
|
147
172
|
let(:options) { { title: -> { "say #{mapper_method}" } } }
|
148
173
|
|
174
|
+
before do
|
175
|
+
mapper_class.class_eval do
|
176
|
+
def mapper_method
|
177
|
+
'hello'
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
149
182
|
it 'should evaluate the lambda in the context of the mapper' do
|
150
|
-
expect(mapper).to receive(:mapper_method).and_return('hello')
|
151
183
|
expect(resource_link.title).to eq 'say hello'
|
152
184
|
end
|
153
185
|
end
|
@@ -7,7 +7,8 @@ RSpec.describe Yaks::Mapper do
|
|
7
7
|
let(:resource) { mapper.call(instance) }
|
8
8
|
|
9
9
|
let(:mapper_class) { Class.new(Yaks::Mapper) { type 'foo' } }
|
10
|
-
|
10
|
+
|
11
|
+
let(:instance) { fake(foo: 'hello', bar: 'world') }
|
11
12
|
|
12
13
|
its(:env) { should equal rack_env }
|
13
14
|
|
@@ -17,7 +18,10 @@ RSpec.describe Yaks::Mapper do
|
|
17
18
|
end
|
18
19
|
|
19
20
|
it 'should make the configured attributes available on the instance' do
|
20
|
-
expect(mapper.attributes).to eq [
|
21
|
+
expect(mapper.attributes).to eq [
|
22
|
+
Yaks::Mapper::Attribute.new(:foo),
|
23
|
+
Yaks::Mapper::Attribute.new(:bar)
|
24
|
+
]
|
21
25
|
end
|
22
26
|
|
23
27
|
it 'should load them from the model' do
|
@@ -27,8 +31,8 @@ RSpec.describe Yaks::Mapper do
|
|
27
31
|
context 'with attribute filtering' do
|
28
32
|
before do
|
29
33
|
mapper_class.class_eval do
|
30
|
-
def
|
31
|
-
|
34
|
+
def attributes
|
35
|
+
super.reject {|attr| attr.name == :foo}
|
32
36
|
end
|
33
37
|
end
|
34
38
|
end
|
@@ -75,10 +79,10 @@ RSpec.describe Yaks::Mapper do
|
|
75
79
|
end
|
76
80
|
|
77
81
|
context 'with subresources' do
|
78
|
-
let(:
|
79
|
-
let(:
|
82
|
+
let(:widget) { fake(type: 'super_widget') }
|
83
|
+
let(:instance) { fake(widget: widget) }
|
80
84
|
let(:widget_mapper) { Class.new(Yaks::Mapper) { type 'widget' } }
|
81
|
-
|
85
|
+
fake(:policy) { Yaks::DefaultPolicy }
|
82
86
|
|
83
87
|
describe 'has_one' do
|
84
88
|
let(:has_one_opts) do
|
@@ -109,11 +113,13 @@ RSpec.describe Yaks::Mapper do
|
|
109
113
|
{ rel: 'http://foo.bar/rels/widgets' }
|
110
114
|
end
|
111
115
|
|
112
|
-
|
113
|
-
|
114
|
-
expect(assoc).to be_a Yaks::Mapper::HasOne
|
116
|
+
before do
|
117
|
+
stub(policy).derive_mapper_from_association(mapper.associations.first) do
|
115
118
|
widget_mapper
|
116
|
-
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should derive the mapper based on policy' do
|
117
123
|
expect(resource.subresources).to eq(
|
118
124
|
"http://foo.bar/rels/widgets" => Yaks::Resource.new(type: 'widget', attributes: {:type => "super_widget"})
|
119
125
|
)
|
@@ -125,12 +131,13 @@ RSpec.describe Yaks::Mapper do
|
|
125
131
|
{ mapper: widget_mapper }
|
126
132
|
end
|
127
133
|
|
128
|
-
|
129
|
-
|
130
|
-
expect(parent_mapper).to equal mapper
|
131
|
-
expect(assoc).to be_a Yaks::Mapper::HasOne
|
134
|
+
before do
|
135
|
+
stub(policy).derive_rel_from_association(mapper.associations.first) do
|
132
136
|
'http://rel/rel'
|
133
|
-
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should derive the rel based on policy' do
|
134
141
|
expect(resource.subresources).to eq(
|
135
142
|
"http://rel/rel" => Yaks::Resource.new(type: 'widget', attributes: {:type => "super_widget"})
|
136
143
|
)
|
@@ -140,7 +147,9 @@ RSpec.describe Yaks::Mapper do
|
|
140
147
|
context 'with the association filtered out' do
|
141
148
|
before do
|
142
149
|
mapper_class.class_eval do
|
143
|
-
def
|
150
|
+
def associations
|
151
|
+
[]
|
152
|
+
end
|
144
153
|
end
|
145
154
|
end
|
146
155
|
|
@@ -172,4 +181,23 @@ RSpec.describe Yaks::Mapper do
|
|
172
181
|
expect(mapper.call(nil)).to be_a Yaks::NullResource
|
173
182
|
end
|
174
183
|
end
|
184
|
+
|
185
|
+
context 'with a link generated by a method that returns nil' do
|
186
|
+
before do
|
187
|
+
mapper_class.class_eval do
|
188
|
+
attributes :id
|
189
|
+
link :bar_link, :link_generating_method
|
190
|
+
|
191
|
+
def link_generating_method
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should not render the link' do
|
197
|
+
expect(mapper.call(fake(id: 123))).to eql Yaks::Resource.new(
|
198
|
+
type: 'foo',
|
199
|
+
attributes: {id: 123}
|
200
|
+
)
|
201
|
+
end
|
202
|
+
end
|
175
203
|
end
|
@@ -4,13 +4,17 @@ RSpec.describe Yaks::Resource do
|
|
4
4
|
subject(:resource) { described_class.new(init_opts) }
|
5
5
|
let(:init_opts) { {} }
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
context 'with a zero-arg constructor' do
|
8
|
+
subject(:resource) { described_class.new }
|
9
|
+
|
10
|
+
its(:type) { should be_nil }
|
11
|
+
its(:attributes) { should eql({}) }
|
12
|
+
its(:links) { should eql [] }
|
13
|
+
its(:subresources) { should eql({}) }
|
14
|
+
its(:self_link) { should be_nil }
|
15
|
+
its(:null_resource?) { should be false }
|
16
|
+
its(:collection?) { should be false }
|
17
|
+
end
|
14
18
|
|
15
19
|
context 'with a type' do
|
16
20
|
let(:init_opts) { { type: 'post' } }
|
@@ -56,4 +60,34 @@ RSpec.describe Yaks::Resource do
|
|
56
60
|
it 'should act as a collection of one' do
|
57
61
|
expect(resource.each.to_a).to eql [resource]
|
58
62
|
end
|
63
|
+
|
64
|
+
describe 'persistent updates' do
|
65
|
+
let(:resource) {
|
66
|
+
Yaks::Resource.new(
|
67
|
+
attributes: {x: :y},
|
68
|
+
links: [:one],
|
69
|
+
subresources: {foo_rel: :subres}
|
70
|
+
)
|
71
|
+
}
|
72
|
+
|
73
|
+
it 'should do updates without modifying the original' do
|
74
|
+
expect(
|
75
|
+
resource
|
76
|
+
.update_attributes(foo: :bar)
|
77
|
+
.add_link(:a_link)
|
78
|
+
.add_subresource(:rel, :a_subresource)
|
79
|
+
.update_attributes(foo: :baz)
|
80
|
+
).to eq Yaks::Resource.new(
|
81
|
+
attributes: {x: :y, foo: :baz},
|
82
|
+
links: [:one, :a_link],
|
83
|
+
subresources: {foo_rel: :subres, rel: :a_subresource}
|
84
|
+
)
|
85
|
+
|
86
|
+
expect(resource).to eq Yaks::Resource.new(
|
87
|
+
attributes: {x: :y},
|
88
|
+
links: [:one],
|
89
|
+
subresources: {foo_rel: :subres}
|
90
|
+
)
|
91
|
+
end
|
92
|
+
end
|
59
93
|
end
|
data/yaks.gemspec
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require File.expand_path('../lib/yaks/version', __FILE__)
|
4
|
+
require File.expand_path('../lib/yaks/breaking_changes', __FILE__)
|
4
5
|
|
5
6
|
Gem::Specification.new do |gem|
|
6
7
|
gem.name = 'yaks'
|
@@ -17,6 +18,10 @@ Gem::Specification.new do |gem|
|
|
17
18
|
gem.test_files = `git ls-files -- spec`.split($/)
|
18
19
|
gem.extra_rdoc_files = %w[README.md]
|
19
20
|
|
21
|
+
if Yaks::BreakingChanges.key? Yaks::VERSION
|
22
|
+
gem.post_install_message = Yaks::BreakingChanges[Yaks::VERSION]
|
23
|
+
end
|
24
|
+
|
20
25
|
gem.add_runtime_dependency 'inflection' , '~> 1.0'
|
21
26
|
gem.add_runtime_dependency 'concord' , '~> 0.1.4'
|
22
27
|
gem.add_runtime_dependency 'uri_template' , '~> 0.6.0'
|
@@ -24,9 +29,10 @@ Gem::Specification.new do |gem|
|
|
24
29
|
|
25
30
|
gem.add_development_dependency 'virtus'
|
26
31
|
gem.add_development_dependency 'rspec', '~> 2.99'
|
32
|
+
gem.add_development_dependency 'bogus'
|
27
33
|
gem.add_development_dependency 'rake'
|
28
34
|
gem.add_development_dependency 'mutant-rspec'
|
29
|
-
gem.add_development_dependency 'mutant'
|
35
|
+
gem.add_development_dependency 'mutant'
|
30
36
|
gem.add_development_dependency 'rspec-its'
|
31
37
|
gem.add_development_dependency 'benchmark-ips'
|
32
38
|
end
|