cartograph 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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