cartograph 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +211 -0
- data/Rakefile +6 -0
- data/cartograph.gemspec +24 -0
- data/examples/collection_representation.rb +41 -0
- data/examples/domains.rb +54 -0
- data/examples/representation_for.rb +24 -0
- data/lib/cartograph.rb +24 -0
- data/lib/cartograph/artist.rb +34 -0
- data/lib/cartograph/dsl.rb +104 -0
- data/lib/cartograph/map.rb +91 -0
- data/lib/cartograph/property.rb +69 -0
- data/lib/cartograph/property_collection.rb +27 -0
- data/lib/cartograph/root_key.rb +19 -0
- data/lib/cartograph/sculptor.rb +40 -0
- data/lib/cartograph/version.rb +3 -0
- data/spec/lib/cartograph/artist_spec.rb +115 -0
- data/spec/lib/cartograph/dsl_spec.rb +257 -0
- data/spec/lib/cartograph/map_spec.rb +160 -0
- data/spec/lib/cartograph/property_collection_spec.rb +15 -0
- data/spec/lib/cartograph/property_spec.rb +235 -0
- data/spec/lib/cartograph/root_key_spec.rb +38 -0
- data/spec/lib/cartograph/sculptor_spec.rb +107 -0
- data/spec/spec_helper.rb +77 -0
- data/spec/support/dsl_contexts.rb +22 -0
- data/spec/support/dummy_comment.rb +2 -0
- data/spec/support/dummy_user.rb +2 -0
- metadata +132 -0
@@ -0,0 +1,257 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cartograph::DSL do
|
4
|
+
describe 'Inclusion' do
|
5
|
+
it 'gives you a class method for .cartograph' do
|
6
|
+
klass = Class.new
|
7
|
+
expect { klass.send(:include, described_class) }.to change { klass.respond_to?(:cartograph) }.to(true)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '.cartograph' do
|
12
|
+
subject(:mapping) { Class.new { include Cartograph::DSL } }
|
13
|
+
|
14
|
+
it 'yields a Cartograph::Map instance' do
|
15
|
+
expect {|b| mapping.cartograph(&b) }.to yield_with_args(Cartograph::Map.new)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns the map instance' do
|
19
|
+
expect(mapping.cartograph).to be_kind_of(Cartograph::Map)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.hash_for' do
|
24
|
+
include_context 'DSL Objects'
|
25
|
+
|
26
|
+
it 'returns the hash representation for an object' do
|
27
|
+
hash = mapped.hash_for(:create, object)
|
28
|
+
expect(hash).to eq({ 'name' => object.name })
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with a root key for the scope' do
|
32
|
+
it 'returns the hash with the root key' do
|
33
|
+
mapped.cartograph do
|
34
|
+
root_key singular: 'user', scopes: [:create]
|
35
|
+
end
|
36
|
+
hash = mapped.hash_for(:create, object)
|
37
|
+
|
38
|
+
expect(hash).to eq(
|
39
|
+
{
|
40
|
+
'user' => {
|
41
|
+
'name' => object.name
|
42
|
+
}
|
43
|
+
}
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '.hash_collection_for' do
|
50
|
+
include_context 'DSL Objects'
|
51
|
+
|
52
|
+
let(:users) { Array.new(3, object) }
|
53
|
+
|
54
|
+
subject(:parsed) do
|
55
|
+
json = mapped.represent_collection_for(:read, users)
|
56
|
+
JSON.parse(json)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'returns the objects as a collection of hashes' do
|
60
|
+
collection = mapped.hash_collection_for(:read, users)
|
61
|
+
|
62
|
+
expect(collection).to be_an(Array)
|
63
|
+
expect(collection.size).to be(3)
|
64
|
+
|
65
|
+
expect(collection[0]['id']).to eq(users[0].id)
|
66
|
+
expect(collection[0]['name']).to eq(users[0].name)
|
67
|
+
expect(collection[1]['id']).to eq(users[1].id)
|
68
|
+
expect(collection[1]['name']).to eq(users[1].name)
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with a root key' do
|
72
|
+
it "includes the root key" do
|
73
|
+
root_key_name = "the_root_key"
|
74
|
+
|
75
|
+
mapped.cartograph do
|
76
|
+
root_key plural: root_key_name, scopes: [:read]
|
77
|
+
end
|
78
|
+
|
79
|
+
collection = mapped.hash_collection_for(:read, users)
|
80
|
+
|
81
|
+
expect(collection).to be_an(Hash)
|
82
|
+
expect(collection.keys.first).to eq(root_key_name)
|
83
|
+
|
84
|
+
collection_array = collection[root_key_name]
|
85
|
+
expect(collection_array[0]['id']).to eq(users[0].id)
|
86
|
+
expect(collection_array[0]['name']).to eq(users[0].name)
|
87
|
+
expect(collection_array[1]['id']).to eq(users[1].id)
|
88
|
+
expect(collection_array[1]['name']).to eq(users[1].name)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '.representation_for' do
|
94
|
+
include_context 'DSL Objects'
|
95
|
+
|
96
|
+
it 'returns the JSON representation for an object' do
|
97
|
+
json = mapped.representation_for(:create, object)
|
98
|
+
expect(json).to eq(
|
99
|
+
{ name: object.name }.to_json
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'with a root key for the scope' do
|
104
|
+
it 'returns the json with the root key' do
|
105
|
+
mapped.cartograph do
|
106
|
+
root_key singular: 'user', scopes: [:create]
|
107
|
+
end
|
108
|
+
json = mapped.representation_for(:create, object)
|
109
|
+
|
110
|
+
expect(json).to eq(
|
111
|
+
{
|
112
|
+
user: {
|
113
|
+
name: object.name
|
114
|
+
}
|
115
|
+
}.to_json
|
116
|
+
)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '.represent_collection_for' do
|
122
|
+
include_context 'DSL Objects'
|
123
|
+
|
124
|
+
let(:users) { Array.new(3, object) }
|
125
|
+
|
126
|
+
subject(:parsed) do
|
127
|
+
json = mapped.represent_collection_for(:read, users)
|
128
|
+
JSON.parse(json)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'returns the objects as a collection' do
|
132
|
+
json = mapped.represent_collection_for(:read, users)
|
133
|
+
parsed = JSON.parse(json)
|
134
|
+
|
135
|
+
expect(parsed).to be_an(Array)
|
136
|
+
expect(parsed.size).to be(3)
|
137
|
+
|
138
|
+
expect(parsed[0]['id']).to eq(users[0].id)
|
139
|
+
expect(parsed[0]['name']).to eq(users[0].name)
|
140
|
+
expect(parsed[1]['id']).to eq(users[1].id)
|
141
|
+
expect(parsed[1]['name']).to eq(users[1].name)
|
142
|
+
end
|
143
|
+
|
144
|
+
context 'with a root key' do
|
145
|
+
it "includes the root key" do
|
146
|
+
root_key_name = "the_root_key"
|
147
|
+
|
148
|
+
mapped.cartograph do
|
149
|
+
root_key plural: root_key_name, scopes: [:read]
|
150
|
+
end
|
151
|
+
|
152
|
+
expect(parsed).to be_an(Hash)
|
153
|
+
expect(parsed.keys.first).to eq(root_key_name)
|
154
|
+
|
155
|
+
parsed_array = parsed[root_key_name]
|
156
|
+
expect(parsed_array[0]['id']).to eq(users[0].id)
|
157
|
+
expect(parsed_array[0]['name']).to eq(users[0].name)
|
158
|
+
expect(parsed_array[1]['id']).to eq(users[1].id)
|
159
|
+
expect(parsed_array[1]['name']).to eq(users[1].name)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe '.extract_single' do
|
165
|
+
include_context 'DSL Objects'
|
166
|
+
let(:json) do
|
167
|
+
{ id: 1337, name: 'Paul the octopus' }
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'returns a populated object from a JSON representation' do
|
171
|
+
extracted = mapped.extract_single(json.to_json, :read)
|
172
|
+
|
173
|
+
expect(extracted.id).to eq(1337)
|
174
|
+
expect(extracted.name).to eq('Paul the octopus')
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'with a root key in the JSON' do
|
178
|
+
let(:json) { { test: super() } }
|
179
|
+
|
180
|
+
before do
|
181
|
+
mapped.cartograph do
|
182
|
+
root_key singular: 'test', scopes: [:read]
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'traverses into the key and pulls the object from there' do
|
187
|
+
extracted = mapped.extract_single(json.to_json, :read)
|
188
|
+
|
189
|
+
expect(extracted.id).to eq(1337)
|
190
|
+
expect(extracted.name).to eq('Paul the octopus')
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
describe '.extract_into_object' do
|
196
|
+
include_context 'DSL Objects'
|
197
|
+
let(:json) do
|
198
|
+
{ id: 1337, name: 'Paul the octopus' }
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'returns a populated object from a JSON representation' do
|
202
|
+
object = DummyUser.new
|
203
|
+
mapped.extract_into_object(object, json.to_json, :read)
|
204
|
+
|
205
|
+
expect(object.id).to eq(1337)
|
206
|
+
expect(object.name).to eq('Paul the octopus')
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
describe '.extract_collection' do
|
211
|
+
include_context 'DSL Objects'
|
212
|
+
let(:json) do
|
213
|
+
[
|
214
|
+
{ id: 1337, name: 'Paul the octopus' },
|
215
|
+
{ id: 1338, name: 'Hank the octopus' }
|
216
|
+
]
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'returns a collection of objects from the json' do
|
220
|
+
extracted = mapped.extract_collection(json.to_json, :read)
|
221
|
+
|
222
|
+
expect(extracted.size).to be(2)
|
223
|
+
expect(extracted).to all(be_kind_of(DummyUser))
|
224
|
+
|
225
|
+
expect(extracted[0].id).to eq(json[0][:id])
|
226
|
+
expect(extracted[0].name).to eq(json[0][:name])
|
227
|
+
|
228
|
+
expect(extracted[1].id).to eq(json[1][:id])
|
229
|
+
expect(extracted[1].name).to eq(json[1][:name])
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'for a nested key' do
|
233
|
+
let(:json) { { users: super() } }
|
234
|
+
|
235
|
+
before do
|
236
|
+
mapped.cartograph do
|
237
|
+
root_key plural: 'users', scopes: [:read]
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'returns a collection of objects from the json' do
|
242
|
+
extracted = mapped.extract_collection(json.to_json, :read)
|
243
|
+
|
244
|
+
expect(extracted.size).to be(2)
|
245
|
+
expect(extracted).to all(be_kind_of(DummyUser))
|
246
|
+
|
247
|
+
scoped = json[:users]
|
248
|
+
|
249
|
+
expect(extracted[0].id).to eq(scoped[0][:id])
|
250
|
+
expect(extracted[0].name).to eq(scoped[0][:name])
|
251
|
+
|
252
|
+
expect(extracted[1].id).to eq(scoped[1][:id])
|
253
|
+
expect(extracted[1].name).to eq(scoped[1][:name])
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cartograph::Map do
|
4
|
+
subject(:map) { Cartograph::Map.new }
|
5
|
+
|
6
|
+
describe '#property' do
|
7
|
+
it 'adds a property to the map' do
|
8
|
+
map.property :attribute_name, scopes: [:read]
|
9
|
+
expect(map.properties.size).to be(1)
|
10
|
+
expect(map.properties.first).to be_kind_of(Cartograph::Property)
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'defining multiple properties' do
|
14
|
+
it 'adds multiple properties at the same time for the scope' do
|
15
|
+
map.property :attribute1, :attribute2, scopes: [:read]
|
16
|
+
|
17
|
+
expect(map.properties.size).to be(2)
|
18
|
+
expect(map.properties).to all(be_kind_of(Cartograph::Property))
|
19
|
+
|
20
|
+
expect(map.properties[0].name).to eq(:attribute1)
|
21
|
+
expect(map.properties[0].scopes).to eq([:read])
|
22
|
+
|
23
|
+
expect(map.properties[1].name).to eq(:attribute2)
|
24
|
+
expect(map.properties[1].scopes).to eq([:read])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#properties' do
|
30
|
+
it 'returns a PropertyCollection object' do
|
31
|
+
properties = map.properties
|
32
|
+
expect(properties).to be_kind_of(Cartograph::PropertyCollection)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#mapping' do
|
37
|
+
it 'sets the class we\'re mapping' do
|
38
|
+
map.mapping Class
|
39
|
+
expect(map.mapping).to be(Class)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#root_key' do
|
44
|
+
it 'sets the root keys' do
|
45
|
+
map.root_key singlular: 'test', scopes: [:read]
|
46
|
+
map.root_key singlular: 'test', scopes: [:create]
|
47
|
+
|
48
|
+
expect(map.root_keys.size).to be(2)
|
49
|
+
expect(map.root_keys).to all(be_kind_of(Cartograph::RootKey))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#root_key_for' do
|
54
|
+
it 'returns the first root key for the scope and type' do
|
55
|
+
map.root_key singular: 'test', scopes: [:read]
|
56
|
+
key = map.root_key_for(:read, :singular)
|
57
|
+
|
58
|
+
expect(key).to eq('test')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#dup' do
|
63
|
+
it 'performs a safe duplication of the map' do
|
64
|
+
mapped_class = Class.new
|
65
|
+
|
66
|
+
prop1 = map.property :name, scopes: [:read, :write]
|
67
|
+
prop2 = map.property :id, scopes: [:read]
|
68
|
+
map.mapping mapped_class
|
69
|
+
map.root_key singular: 'woot', plural: 'woots', scopes: [:read]
|
70
|
+
|
71
|
+
cache_key = Proc.new {}
|
72
|
+
map.cache 'hello'
|
73
|
+
map.cache_key &cache_key
|
74
|
+
|
75
|
+
new_map = map.dup
|
76
|
+
|
77
|
+
expect(new_map.properties[0]).to_not be(prop1)
|
78
|
+
expect(new_map.properties[1]).to_not be(prop2)
|
79
|
+
|
80
|
+
expect(new_map.properties).to all(be_kind_of(Cartograph::Property))
|
81
|
+
expect(new_map.properties[0].name).to eq(:name)
|
82
|
+
expect(new_map.properties[1].name).to eq(:id)
|
83
|
+
|
84
|
+
expect(new_map.mapping).to eq(mapped_class)
|
85
|
+
expect(new_map.root_keys).to eq(map.root_keys)
|
86
|
+
|
87
|
+
expect(new_map.cache).to eq(map.cache)
|
88
|
+
expect(new_map.cache_key).to eq(cache_key)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#cache' do
|
93
|
+
it "stores the caching method" do
|
94
|
+
cacher = double
|
95
|
+
map.cache cacher
|
96
|
+
|
97
|
+
expect(map.cache).to be(cacher)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'returns the cartograph cache if set' do
|
101
|
+
cacher = double('cache')
|
102
|
+
Cartograph.default_cache = cacher
|
103
|
+
|
104
|
+
expect(map.cache).to be(cacher)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'goes straight to the object if cache is overridden with false' do
|
108
|
+
cacher = double('cache')
|
109
|
+
Cartograph.default_cache = cacher
|
110
|
+
|
111
|
+
property = Cartograph::Property.new(:bunk) do
|
112
|
+
cache false
|
113
|
+
end
|
114
|
+
|
115
|
+
map.properties << property
|
116
|
+
|
117
|
+
expect(property.map.cache).to be(false)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#cache_key' do
|
122
|
+
it 'stores the cache key block' do
|
123
|
+
cache_key = Proc.new {}
|
124
|
+
map.cache_key(&cache_key)
|
125
|
+
|
126
|
+
expect(map.cache_key).to be(cache_key)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'returns the cartograph cache_key if set' do
|
130
|
+
cache_key = double('cache key')
|
131
|
+
Cartograph.default_cache_key = cache_key
|
132
|
+
|
133
|
+
expect(map.cache_key).to be(cache_key)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe 'Equality' do
|
138
|
+
specify 'duplicated maps are equal to eachother' do
|
139
|
+
map1 = Cartograph::Map.new
|
140
|
+
map1.property :something, scopes: [:read]
|
141
|
+
|
142
|
+
map2 = map1.dup
|
143
|
+
|
144
|
+
expect(map1).to eq(map2)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe '#scoped' do
|
149
|
+
it 'adds properties with the scopes defined on the block instantiation' do
|
150
|
+
map.scoped :read, :write do
|
151
|
+
property :name
|
152
|
+
property :something
|
153
|
+
end
|
154
|
+
|
155
|
+
expect(map.properties.size).to eq(2)
|
156
|
+
expect(map.properties.filter_by_scope(:read).map(&:name)).to eq([:name, :something])
|
157
|
+
expect(map.properties.filter_by_scope(:write).map(&:name)).to eq([:name, :something])
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cartograph::PropertyCollection do
|
4
|
+
describe '#filter_by_scope' do
|
5
|
+
it 'only returns properties with a certain scope attached' do
|
6
|
+
collection = Cartograph::PropertyCollection.new
|
7
|
+
collection << Cartograph::Property.new(:hello, scopes: [:read, :create])
|
8
|
+
collection << Cartograph::Property.new(:id, scopes: [:read])
|
9
|
+
|
10
|
+
filtered = collection.filter_by_scope(:create)
|
11
|
+
expect(filtered.size).to be(1)
|
12
|
+
expect(filtered.first.name).to eq(:hello)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cartograph::Property do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'initializes with an attribute name and options' do
|
6
|
+
name = :hey
|
7
|
+
options = { lol: 'whut' }
|
8
|
+
|
9
|
+
property = Cartograph::Property.new(name, options)
|
10
|
+
expect(property.name).to eq(name)
|
11
|
+
expect(property.options).to eq(options)
|
12
|
+
expect(property.key).to eq('hey')
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with a key' do
|
16
|
+
it 'sets the key' do
|
17
|
+
name = :hey
|
18
|
+
options = { key: 'Hey' }
|
19
|
+
property = Cartograph::Property.new(name, options)
|
20
|
+
|
21
|
+
expect(property.key).to eq('Hey')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with a block' do
|
26
|
+
it 'yields a map instance for the property' do
|
27
|
+
expect {|b| Cartograph::Property.new(:hello, &b) }.to yield_with_args(Cartograph::Map.new)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'with an include' do
|
32
|
+
it 'sets the map to the included mapped class' do
|
33
|
+
klass = Class.new do
|
34
|
+
include Cartograph::DSL
|
35
|
+
cartograph do
|
36
|
+
property :lol, scopes: [:read]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
property = Cartograph::Property.new(:id, scopes: [:read], include: klass)
|
41
|
+
expect(property.map).to eq(klass.cartograph)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#scopes' do
|
47
|
+
it 'returns the scopes that the property is for' do
|
48
|
+
property = Cartograph::Property.new(:name, scopes: [:read, :create])
|
49
|
+
expect(property.scopes).to include(:read, :create)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'returns an empty array when no scopes are provided' do
|
53
|
+
property = Cartograph::Property.new(:name)
|
54
|
+
expect(property.scopes).to eq( [] )
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'always casts to an array' do
|
58
|
+
property = Cartograph::Property.new(:name, scopes: :read)
|
59
|
+
expect(property.scopes).to eq [:read]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#plural?' do
|
64
|
+
it 'returns true when set to plural' do
|
65
|
+
property = Cartograph::Property.new(:name, scopes: [:read], plural: true)
|
66
|
+
expect(property).to be_plural
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns false when not set' do
|
70
|
+
property = Cartograph::Property.new(:name, scopes: [:read])
|
71
|
+
expect(property).to_not be_plural
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#value_for' do
|
76
|
+
it 'returns the value when passed an object' do
|
77
|
+
property = Cartograph::Property.new(:sammy)
|
78
|
+
object = double('object', sammy: 'cephalopod')
|
79
|
+
|
80
|
+
expect(property.value_for(object)).to eq('cephalopod')
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'for a nested property set' do
|
84
|
+
it 'returns nested properties' do
|
85
|
+
top_level = Cartograph::Property.new(:sammy) do
|
86
|
+
property :cephalopod
|
87
|
+
end
|
88
|
+
|
89
|
+
child = double('child', cephalopod: 'I will ink you')
|
90
|
+
root = double('root', sammy: child)
|
91
|
+
|
92
|
+
expect(top_level.value_for(root)).to eq('cephalopod' => child.cephalopod)
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'when it is plural' do
|
96
|
+
it 'returns a pluralized representation' do
|
97
|
+
top_level = Cartograph::Property.new(:sammy, plural: true) do
|
98
|
+
property :cephalopod
|
99
|
+
end
|
100
|
+
|
101
|
+
child1 = double('child', cephalopod: 'I will ink you')
|
102
|
+
child2 = double('child', cephalopod: 'I wont because im cool')
|
103
|
+
|
104
|
+
root = double('root', sammy: [child1, child2])
|
105
|
+
|
106
|
+
expect(top_level.value_for(root)).to eq([
|
107
|
+
{ 'cephalopod' => child1.cephalopod },
|
108
|
+
{ 'cephalopod' => child2.cephalopod }
|
109
|
+
])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when the value for the root object is nil' do
|
114
|
+
it 'returns nil' do
|
115
|
+
top_level = Cartograph::Property.new(:sammy) do
|
116
|
+
property :cephalopod
|
117
|
+
end
|
118
|
+
|
119
|
+
root = double(sammy: nil)
|
120
|
+
|
121
|
+
expect(top_level.value_for(root)).to be_nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe '#value_from' do
|
128
|
+
let(:hash) { { hello: 'world' } }
|
129
|
+
|
130
|
+
it 'retrieves the value from a hash for the property' do
|
131
|
+
property = Cartograph::Property.new(:hello)
|
132
|
+
expect(property.value_from(hash)).to eq('world')
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'for a nil object' do
|
136
|
+
it 'bails and does not try to retrieve' do
|
137
|
+
property = Cartograph::Property.new(:hello)
|
138
|
+
value = property.value_from(nil)
|
139
|
+
expect(value).to be_nil
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'string and symbol agnostic' do
|
144
|
+
let(:hash) { { 'hello' => 'world' } }
|
145
|
+
|
146
|
+
it 'retrieves the value from a hash for the property' do
|
147
|
+
property = Cartograph::Property.new(:hello)
|
148
|
+
expect(property.value_from(hash)).to eq('world')
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'for a nested property set' do
|
153
|
+
it 'returns an object with the properties set on it' do
|
154
|
+
dummy_class = OpenStruct
|
155
|
+
|
156
|
+
nested_property = Cartograph::Property.new(:hello) do
|
157
|
+
mapping dummy_class
|
158
|
+
property :id
|
159
|
+
property :name
|
160
|
+
end
|
161
|
+
|
162
|
+
hash = { hello: {
|
163
|
+
'id' => 555,
|
164
|
+
'name' => 'Buckstar'
|
165
|
+
}}
|
166
|
+
|
167
|
+
value = nested_property.value_from(hash)
|
168
|
+
expect(value).to be_kind_of(dummy_class)
|
169
|
+
expect(value.id).to eq(hash[:hello]['id'])
|
170
|
+
expect(value.name).to eq(hash[:hello]['name'])
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'returns a collection of objects when set to plural' do
|
174
|
+
dummy_class = OpenStruct
|
175
|
+
|
176
|
+
nested_property = Cartograph::Property.new(:hello, plural: true) do
|
177
|
+
mapping dummy_class
|
178
|
+
|
179
|
+
property :id
|
180
|
+
property :name
|
181
|
+
end
|
182
|
+
|
183
|
+
hash = {
|
184
|
+
hello: [{
|
185
|
+
'id' => 555,
|
186
|
+
'name' => 'Buckstar'
|
187
|
+
}, {
|
188
|
+
'id' => 556,
|
189
|
+
'name' => 'Starbuck'
|
190
|
+
}]
|
191
|
+
}
|
192
|
+
|
193
|
+
value = nested_property.value_from(hash)
|
194
|
+
expect(value).to be_kind_of(Array)
|
195
|
+
expect(value.size).to be(2)
|
196
|
+
|
197
|
+
expect(value[0].id).to eq(hash[:hello][0]['id'])
|
198
|
+
expect(value[0].name).to eq(hash[:hello][0]['name'])
|
199
|
+
|
200
|
+
expect(value[1].id).to eq(hash[:hello][1]['id'])
|
201
|
+
expect(value[1].name).to eq(hash[:hello][1]['name'])
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'when set to plural but the key is nil' do
|
205
|
+
it 'returns an empty array' do
|
206
|
+
dummy_class = Struct.new(:id, :name)
|
207
|
+
|
208
|
+
nested_property = Cartograph::Property.new(:hello, plural: true) do
|
209
|
+
mapping dummy_class
|
210
|
+
|
211
|
+
property :id
|
212
|
+
property :name
|
213
|
+
end
|
214
|
+
|
215
|
+
hash = { hello: nil }
|
216
|
+
value = nested_property.value_from(hash)
|
217
|
+
|
218
|
+
expect(value).to eq([])
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe '#dup' do
|
225
|
+
it 'copies the name, options, and map into another property' do
|
226
|
+
instance = Cartograph::Property.new(:id, scopes: [:read])
|
227
|
+
duped = instance.dup
|
228
|
+
|
229
|
+
expect(duped).to be_kind_of(Cartograph::Property)
|
230
|
+
expect(duped.name).to eq(:id)
|
231
|
+
expect(duped.options).to_not be(instance.options)
|
232
|
+
expect(duped.options).to eq(instance.options)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|