simple_mapper 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +165 -0
- data/Rakefile.rb +11 -0
- data/lib/simple_mapper.rb +8 -0
- data/lib/simple_mapper/attribute.rb +119 -0
- data/lib/simple_mapper/attribute/collection.rb +130 -0
- data/lib/simple_mapper/attribute/pattern.rb +19 -0
- data/lib/simple_mapper/attributes.rb +196 -0
- data/lib/simple_mapper/attributes/types.rb +224 -0
- data/lib/simple_mapper/change_hash.rb +14 -0
- data/lib/simple_mapper/collection.rb +169 -0
- data/lib/simple_mapper/exceptions.rb +10 -0
- data/test/integration/attribute_change_tracking_test.rb +181 -0
- data/test/integration/attribute_meta_interaction_test.rb +169 -0
- data/test/integration/attribute_pattern_test.rb +77 -0
- data/test/integration/to_simple_test.rb +128 -0
- data/test/test_helper.rb +11 -0
- data/test/unit/attribute_collection_test.rb +379 -0
- data/test/unit/attribute_pattern_test.rb +55 -0
- data/test/unit/attribute_test.rb +419 -0
- data/test/unit/attributes_test.rb +561 -0
- data/test/unit/collection_array_test.rb +194 -0
- data/test/unit/collection_hash_test.rb +139 -0
- data/test/unit/types_test.rb +314 -0
- metadata +140 -0
@@ -0,0 +1,561 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AttributesTest < Test::Unit::TestCase
|
4
|
+
def stub_out_attributes(klass, *attrs)
|
5
|
+
attrs.each do |attr|
|
6
|
+
attr_obj = klass.simple_mapper.attributes[attr]
|
7
|
+
attr_obj.stubs(:changed?)
|
8
|
+
attr_obj.stubs(:changed!)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'A SimpleMapper::Attributes::Manager' do
|
13
|
+
setup do
|
14
|
+
@instance = SimpleMapper::Attributes::Manager.new
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'has an empty attributes hash' do
|
18
|
+
assert @instance.respond_to?(:attributes)
|
19
|
+
assert_equal({}, @instance.attributes)
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'has an applies_to attribute' do
|
23
|
+
assert @instance.respond_to?(:applies_to)
|
24
|
+
assert_equal nil, @instance.applies_to
|
25
|
+
@instance.applies_to = self
|
26
|
+
assert_equal self, @instance.applies_to
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'allows specification of applies_to through constructor' do
|
30
|
+
@instance = @instance.class.new(self.class)
|
31
|
+
assert_equal self.class, @instance.applies_to
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when creating an anonymous mapper' do
|
35
|
+
should 'return a class that is mapper-enabled' do
|
36
|
+
result = @instance.create_anonymous_mapper
|
37
|
+
assert_equal Class, result.class
|
38
|
+
assert result.respond_to?(:maps)
|
39
|
+
assert result.new.respond_to?(:to_simple)
|
40
|
+
assert result.respond_to?(:decode)
|
41
|
+
# decode should just wrap the constructor
|
42
|
+
assert_equal result, result.decode.class
|
43
|
+
end
|
44
|
+
|
45
|
+
should 'eval a block within the context of the anonymous class' do
|
46
|
+
result = @instance.create_anonymous_mapper do
|
47
|
+
def self.platypus; 'platypus?'; end
|
48
|
+
def walrus; 'walrus?'; end
|
49
|
+
end
|
50
|
+
assert_equal 'platypus?', result.platypus
|
51
|
+
assert_equal 'walrus?', result.new.walrus
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when installing attributes should' do
|
56
|
+
setup do
|
57
|
+
@class = Class.new
|
58
|
+
@instance.applies_to = @class
|
59
|
+
@object = @instance.create_attribute(:some_attribute)
|
60
|
+
@instance.install_attribute(:some_attribute, @object)
|
61
|
+
end
|
62
|
+
|
63
|
+
should 'allow addition of instance attribute to applies_to' do
|
64
|
+
assert @class.new.respond_to?(:some_attribute)
|
65
|
+
assert @class.new.respond_to?(:some_attribute=)
|
66
|
+
end
|
67
|
+
|
68
|
+
should 'install attribute reader wrapping the read_attribute method' do
|
69
|
+
@mapper_instance = @class.new
|
70
|
+
@mapper_instance.expects(:read_attribute).with(:some_attribute).once
|
71
|
+
@mapper_instance.some_attribute
|
72
|
+
end
|
73
|
+
|
74
|
+
should 'install attribute writer wrapping the write_attribute method' do
|
75
|
+
@mapper_instance = @class.new
|
76
|
+
@mapper_instance.expects(:write_attribute).with(:some_attribute, :some_value).once
|
77
|
+
@mapper_instance.some_attribute = :some_value
|
78
|
+
end
|
79
|
+
|
80
|
+
should 'add attribute object to attributes list' do
|
81
|
+
attribs = @instance.attributes.inject({}) do |a, kvp|
|
82
|
+
key, val = kvp
|
83
|
+
a[key] = [ val.key, val.class ]
|
84
|
+
a
|
85
|
+
end
|
86
|
+
assert_equal({
|
87
|
+
:some_attribute => [:some_attribute, SimpleMapper::Attribute],
|
88
|
+
},
|
89
|
+
attribs)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when creating new attributes should' do
|
94
|
+
setup do
|
95
|
+
@class = Class.new
|
96
|
+
@instance.applies_to = @class
|
97
|
+
end
|
98
|
+
|
99
|
+
should 'pass :type option through to attribute object' do
|
100
|
+
type_a = mock('type_a')
|
101
|
+
attrib = @instance.create_attribute(:attrib, :type => type_a)
|
102
|
+
assert_equal type_a, attrib.type
|
103
|
+
end
|
104
|
+
|
105
|
+
should 'pass :key option through if provided' do
|
106
|
+
attrib = @instance.create_attribute(:attrib, :key => :not_attrib)
|
107
|
+
assert_equal :not_attrib, attrib.key
|
108
|
+
end
|
109
|
+
|
110
|
+
should 'default the attribute class to SimpleMapper::Attribute' do
|
111
|
+
assert_equal SimpleMapper::Attribute, @instance.create_attribute(:some_attr).class
|
112
|
+
end
|
113
|
+
|
114
|
+
should 'allow specification of attribute class via the :attribute_class option' do
|
115
|
+
attr_class = Class.new(SimpleMapper::Attribute)
|
116
|
+
attrib = @instance.create_attribute(:some_attr, :attribute_class => attr_class)
|
117
|
+
assert_equal attr_class, attrib.class
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'SimpleMapper::Attributes module' do
|
123
|
+
setup do
|
124
|
+
@class = Class.new do
|
125
|
+
include SimpleMapper::Attributes
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
context 'types registry' do
|
130
|
+
setup do
|
131
|
+
@fake_type = stub('fake_type')
|
132
|
+
@fake_expected_type = Class.new { attr_accessor :value }
|
133
|
+
@fake_type_symbol = :fake_for_test
|
134
|
+
@fake_registry_entry = {:name => @fake_type_symbol,
|
135
|
+
:expected_type => @fake_expected_type,
|
136
|
+
:converter => @fake_type,}
|
137
|
+
end
|
138
|
+
|
139
|
+
should 'provide a types registry hash' do
|
140
|
+
assert_equal Hash, SimpleMapper::Attributes.types.class
|
141
|
+
end
|
142
|
+
|
143
|
+
should 'provide type registration through :register_type' do
|
144
|
+
SimpleMapper::Attributes.register_type(@fake_type_symbol,
|
145
|
+
@fake_expected_type,
|
146
|
+
@fake_type)
|
147
|
+
|
148
|
+
assert_equal(@fake_registry_entry,
|
149
|
+
SimpleMapper::Attributes.types[@fake_type_symbol])
|
150
|
+
end
|
151
|
+
|
152
|
+
should 'allow lookup of type info by name' do
|
153
|
+
SimpleMapper::Attributes.register_type(@fake_type_symbol,
|
154
|
+
@fake_expected_type,
|
155
|
+
@fake_type)
|
156
|
+
assert_equal(@fake_registry_entry,
|
157
|
+
SimpleMapper::Attributes.type_for(@fake_type_symbol))
|
158
|
+
end
|
159
|
+
|
160
|
+
should 'return nil on type lookup for unknown type' do
|
161
|
+
assert_equal nil, SimpleMapper::Attributes.type_for(:i_do_not_exist)
|
162
|
+
end
|
163
|
+
|
164
|
+
teardown do
|
165
|
+
SimpleMapper::Attributes.types.delete @fake_type_symbol
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'inclusion should' do
|
170
|
+
should 'provide a maps class method' do
|
171
|
+
assert @class.respond_to?(:maps)
|
172
|
+
end
|
173
|
+
|
174
|
+
should 'provide a simple_mapper attribute manager' do
|
175
|
+
assert @class.respond_to?(:simple_mapper)
|
176
|
+
assert_equal SimpleMapper::Attributes::Manager, @class.simple_mapper.class
|
177
|
+
assert_equal @class, @class.simple_mapper.applies_to
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
should 'return an empty hash for to_simple on an instance with no attributes' do
|
182
|
+
assert_equal({}, @class.new.to_simple)
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'to_simple instance method' do
|
186
|
+
setup do
|
187
|
+
@class.maps :a
|
188
|
+
@class.maps :b
|
189
|
+
@attrib_a = @class.simple_mapper.attributes[:a]
|
190
|
+
@attrib_b = @class.simple_mapper.attributes[:b]
|
191
|
+
# traditional mocking is not sufficiently
|
192
|
+
# expressive for this, so we'll just implement
|
193
|
+
# methods directly.
|
194
|
+
@options = {}
|
195
|
+
[@attrib_a, @attrib_b].each do |attr|
|
196
|
+
attr.instance_eval do
|
197
|
+
def to_simple(obj, container, options = {})
|
198
|
+
# like an expectation; verifies that
|
199
|
+
# options are passed along properly
|
200
|
+
raise Exception unless options == obj.expected_options
|
201
|
+
container[key] = obj.read_attribute(name)
|
202
|
+
container
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
@values = {:a => 'A', :b => 'B'}
|
207
|
+
@instance = @class.new(@values.clone)
|
208
|
+
@instance.stubs(:expected_options).returns(@options)
|
209
|
+
end
|
210
|
+
|
211
|
+
should 'accumulate results from :to_simple on each attribute object' do
|
212
|
+
@attrib_a.expects(:changed?).never
|
213
|
+
@attrib_b.expects(:changed?).never
|
214
|
+
assert_equal @values, @instance.to_simple(@options)
|
215
|
+
end
|
216
|
+
|
217
|
+
should 'accumulate results from :to_simple on changed attributes only when :changed => true is passed' do
|
218
|
+
expectation = @values.clone
|
219
|
+
expectation.delete :b
|
220
|
+
@attrib_a.expects(:changed?).with(@instance).returns(true)
|
221
|
+
@attrib_b.expects(:changed?).with(@instance).returns(false)
|
222
|
+
@options[:changed] = true
|
223
|
+
assert_equal expectation, @instance.to_simple(@options)
|
224
|
+
end
|
225
|
+
|
226
|
+
should 'return values of all attributes and propagate :all option from :to_simple when :all_changed? is true on receiver and :changed is true' do
|
227
|
+
@instance.stubs(:all_changed?).returns(true)
|
228
|
+
@attrib_a.stubs(:changed?).with(@instance).returns(true)
|
229
|
+
@sttrib_b.stubs(:changed?).with(@instance).returns(false)
|
230
|
+
opt = @options.clone
|
231
|
+
opt[:changed] = true
|
232
|
+
@options[:all] = true
|
233
|
+
assert_equal @values.clone, @instance.to_simple(opt)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'simpler_mapper_source' do
|
238
|
+
should 'provide an empty hash by default' do
|
239
|
+
@instance = @class.new
|
240
|
+
assert_equal({}, @instance.simple_mapper_source)
|
241
|
+
end
|
242
|
+
|
243
|
+
should 'provide the source hash with which the instance was created' do
|
244
|
+
values = {:foo => 'foo', :boo => 'boo'}
|
245
|
+
@instance = @class.new(values)
|
246
|
+
assert_equal values, @instance.simple_mapper_source
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context 'instance method' do
|
251
|
+
setup do
|
252
|
+
@instance = @class.new
|
253
|
+
@class.maps :foo
|
254
|
+
stub_out_attributes @class, :foo
|
255
|
+
end
|
256
|
+
|
257
|
+
context 'reset_attribute should' do
|
258
|
+
should 'restore the specified attribute to its source value' do
|
259
|
+
@instance = @class.new
|
260
|
+
@class.simple_mapper.attributes[:foo].expects(:source_value).with(@instance).once.returns('Foo!')
|
261
|
+
|
262
|
+
@instance.write_attribute(:foo, 'new val')
|
263
|
+
assert_equal 'new val', @instance.read_attribute(:foo)
|
264
|
+
@instance.reset_attribute(:foo)
|
265
|
+
assert_equal 'Foo!', @instance.read_attribute(:foo)
|
266
|
+
end
|
267
|
+
|
268
|
+
should 'clear the changed? status of the specified attribute' do
|
269
|
+
@instance = @class.new
|
270
|
+
seq = sequence('change states')
|
271
|
+
attrib = @class.simple_mapper.attributes[:foo]
|
272
|
+
attrib.expects(:changed!).with(@instance, true).once.in_sequence(seq).returns(true)
|
273
|
+
attrib.expects(:changed!).with(@instance, false).once.in_sequence(seq).returns(false)
|
274
|
+
@instance.write_attribute(:foo, 'new val')
|
275
|
+
@instance.reset_attribute(:foo)
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# keep me
|
280
|
+
context 'transform_source_attribute' do
|
281
|
+
setup do
|
282
|
+
@instance = @class.new(:foo => 'foo')
|
283
|
+
end
|
284
|
+
|
285
|
+
should 'delegate source value transformation to underlying attribute object' do
|
286
|
+
@class.simple_mapper.attributes[:foo].expects(:transformed_source_value).with(@instance).returns(:foopy)
|
287
|
+
result = @instance.transform_source_attribute(:foo)
|
288
|
+
assert_equal :foopy, result
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
# keep me
|
293
|
+
context 'read_source_attribute' do
|
294
|
+
setup do
|
295
|
+
@instance = @class.new(:foo => 'Foo!')
|
296
|
+
end
|
297
|
+
|
298
|
+
should 'delegate source value retrieval to the underlying attribute object' do
|
299
|
+
@class.simple_mapper.attributes[:foo].expects(:source_value).with(@instance).returns('foo')
|
300
|
+
result = @instance.read_source_attribute(:foo)
|
301
|
+
assert_equal 'foo', result
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'write_attribute should' do
|
306
|
+
should 'set the attribute as an instance variable' do
|
307
|
+
@instance.write_attribute(:foo, 'Foo!')
|
308
|
+
assert_equal 'Foo!', @instance.instance_variable_get(:@foo)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context 'get_attribute_default' do
|
313
|
+
should 'delegate default value to attribute object' do
|
314
|
+
@class.maps :with_default, :default => :foo
|
315
|
+
@class.simple_mapper.attributes[:with_default].expects(:default_value).once.with(@instance).returns(:expected_default)
|
316
|
+
result = @instance.get_attribute_default(:with_default)
|
317
|
+
assert_equal :expected_default, result
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
context 'freeze' do
|
322
|
+
setup do
|
323
|
+
@instance = @class.new(:foo => @value = 'foo')
|
324
|
+
end
|
325
|
+
|
326
|
+
should 'prevent further attribute writes' do
|
327
|
+
@instance.freeze
|
328
|
+
assert_raises(RuntimeError) { @instance.foo = :x }
|
329
|
+
# verify that value is unchanged
|
330
|
+
assert_equal @value, @instance.foo
|
331
|
+
end
|
332
|
+
|
333
|
+
should 'allow attribute reads' do
|
334
|
+
@instance.freeze
|
335
|
+
assert_equal @value, @instance.foo
|
336
|
+
end
|
337
|
+
|
338
|
+
should 'support per-attribute handling via :freeze_for per attribute' do
|
339
|
+
@class.maps :foo2
|
340
|
+
@class.maps :foo3
|
341
|
+
[:foo, :foo2, :foo3].each do |attrib|
|
342
|
+
@instance.attribute_object_for(attrib).expects(:freeze_for).with(@instance)
|
343
|
+
end
|
344
|
+
@instance.freeze
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
context 'frozen?' do
|
349
|
+
setup do
|
350
|
+
@instance = @class.new(:foo => 'foo')
|
351
|
+
end
|
352
|
+
|
353
|
+
should 'default to false' do
|
354
|
+
assert_equal false, @instance.frozen?
|
355
|
+
end
|
356
|
+
|
357
|
+
should 'be true after a :freeze call' do
|
358
|
+
@instance.freeze
|
359
|
+
assert_equal true, @instance.frozen?
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
context 'change tracking' do
|
365
|
+
setup do
|
366
|
+
@class.maps :change_me
|
367
|
+
@class.maps :do_not_change_me
|
368
|
+
@instance = @class.new(:change_me => 'change me', :do_not_change_me => 'no changing')
|
369
|
+
end
|
370
|
+
|
371
|
+
should 'automatically instantiate an empty ChangeHash per instance' do
|
372
|
+
assert_equal(SimpleMapper::ChangeHash.new, @instance.simple_mapper_changes)
|
373
|
+
@other = @class.new
|
374
|
+
assert_equal(SimpleMapper::ChangeHash.new, @other.simple_mapper_changes)
|
375
|
+
assert_not_equal @instance.simple_mapper_changes.object_id, @other.simple_mapper_changes.object_id
|
376
|
+
end
|
377
|
+
|
378
|
+
should 'indicate an attribute is unchanged if it has not been assigned, based on attribute object' do
|
379
|
+
@instance.class.simple_mapper.attributes[:change_me].expects(:changed?).with(@instance).returns(false)
|
380
|
+
assert_equal false, @instance.attribute_changed?(:change_me)
|
381
|
+
end
|
382
|
+
|
383
|
+
should 'mark an attribute as changed once it has been assigned to' do
|
384
|
+
@instance.class.simple_mapper.attributes[:change_me].expects(:changed!).with(@instance, true)
|
385
|
+
@instance.change_me = 'Thou art changed'
|
386
|
+
end
|
387
|
+
|
388
|
+
should 'mark an attribute as changed via the :attribute_changed! method' do
|
389
|
+
@instance.class.simple_mapper.attributes[:change_me].expects(:changed!).with(@instance, true)
|
390
|
+
@instance.attribute_changed! :change_me
|
391
|
+
end
|
392
|
+
|
393
|
+
should 'flag all_changed on change tracking hash through :all_changed! method' do
|
394
|
+
@instance.simple_mapper_changes.expects(:all_changed!).with().returns(true)
|
395
|
+
@instance.all_changed!
|
396
|
+
end
|
397
|
+
|
398
|
+
should "return value of change-tracking hash's :all for :all_changed?" do
|
399
|
+
@instance.simple_mapper_changes.stubs(:all).returns(true)
|
400
|
+
assert_equal true, @instance.all_changed?
|
401
|
+
@instance.simple_mapper_changes.stubs(:all).returns(false)
|
402
|
+
assert_equal false, @instance.all_changed?
|
403
|
+
end
|
404
|
+
|
405
|
+
should 'return all attributes as changed when change-tracker marked with all' do
|
406
|
+
@instance.simple_mapper_changes.stubs(:all).returns(true)
|
407
|
+
attribs = @instance.changed_attributes.sort_by {|x| x.to_s}
|
408
|
+
expected = @instance.class.simple_mapper.attributes.keys.sort_by {|x| x.to_s}
|
409
|
+
assert_equal expected, attribs
|
410
|
+
end
|
411
|
+
|
412
|
+
context 'when nothing has been assigned' do
|
413
|
+
setup do
|
414
|
+
@instance.class.simple_mapper.attributes.each do |key, attr|
|
415
|
+
attr.expects(:changed?).with(@instance).returns(false)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
should 'return empty list for :changed_attributes' do
|
420
|
+
assert_equal [], @instance.changed_attributes
|
421
|
+
end
|
422
|
+
|
423
|
+
should 'return false for :changed?' do
|
424
|
+
assert_equal false, @instance.changed?
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
context 'when one attribute is marked as changed' do
|
429
|
+
setup do
|
430
|
+
@instance.class.simple_mapper.attributes.each do |key, attr|
|
431
|
+
attr.expects(:changed?).with(@instance).returns(key == :change_me ? true : false)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
should 'return single-item list for :changed_attributes when an attribute is marked as changed' do
|
436
|
+
assert_equal [:change_me], @instance.changed_attributes
|
437
|
+
end
|
438
|
+
|
439
|
+
should 'return true for :changed?' do
|
440
|
+
assert @instance.changed?
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
context 'when multiple attributes are marked as changed' do
|
445
|
+
setup do
|
446
|
+
@changes = [:change_me, :do_not_change_me]
|
447
|
+
@instance.class.simple_mapper.attributes.each do |key, attr|
|
448
|
+
attr.expects(:changed?).with(@instance).returns(@changes.include?(key) ? true : false)
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
should 'return two-item list for :changed_attributes when both attrs were assigned' do
|
453
|
+
assert_equal(@changes, @instance.changed_attributes.sort_by {|sym| sym.to_s})
|
454
|
+
end
|
455
|
+
|
456
|
+
should 'return true for :changed' do
|
457
|
+
assert @instance.changed?
|
458
|
+
end
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
context 'maps method should' do
|
463
|
+
should 'install an attribute reader on the class' do
|
464
|
+
instance = @class.new
|
465
|
+
assert ! instance.respond_to?(:some_attr)
|
466
|
+
@class.maps :some_attr
|
467
|
+
assert instance.respond_to?(:some_attr)
|
468
|
+
end
|
469
|
+
|
470
|
+
should 'install an attribute writer on the class' do
|
471
|
+
instance = @class.new
|
472
|
+
assert ! instance.respond_to?(:some_attr=)
|
473
|
+
@class.maps :some_attr
|
474
|
+
assert instance.respond_to?(:some_attr=)
|
475
|
+
end
|
476
|
+
|
477
|
+
should 'place an Attribute instance in the class manager attributes hash' do
|
478
|
+
@class.maps :some_attr
|
479
|
+
@class.maps :some_other_attr
|
480
|
+
attr_class = SimpleMapper::Attribute
|
481
|
+
attribs = @class.simple_mapper.attributes.inject({}) do |a, kvp|
|
482
|
+
key, val = kvp
|
483
|
+
a[key] = [ val.key, val.class ]
|
484
|
+
a
|
485
|
+
end
|
486
|
+
assert_equal({
|
487
|
+
:some_attr => [:some_attr, attr_class],
|
488
|
+
:some_other_attr => [:some_other_attr, attr_class],
|
489
|
+
},
|
490
|
+
attribs)
|
491
|
+
end
|
492
|
+
|
493
|
+
should 'accept a :type option that carries over to the Attribute instance' do
|
494
|
+
type_a = stub('type_a')
|
495
|
+
@class.maps :foo, :type => type_a
|
496
|
+
type_b = stub('type_b')
|
497
|
+
@class.maps :bar, :type => type_b
|
498
|
+
|
499
|
+
assert_equal type_a, @class.simple_mapper.attributes[:foo].type
|
500
|
+
assert_equal type_b, @class.simple_mapper.attributes[:bar].type
|
501
|
+
end
|
502
|
+
|
503
|
+
should 'create an anonymous mapper as the type when given a block' do
|
504
|
+
@class.maps :outer do; end
|
505
|
+
assert @class.simple_mapper.attributes[:outer].type.respond_to?(:maps)
|
506
|
+
assert @class.simple_mapper.attributes[:outer].type.respond_to?(:new)
|
507
|
+
assert @class.simple_mapper.attributes[:outer].type.respond_to?(:decode)
|
508
|
+
end
|
509
|
+
|
510
|
+
should 'assign anonymous mapper as the mapper of the attribute object when given a block' do
|
511
|
+
mapper = stub('mapper')
|
512
|
+
@class.simple_mapper.expects(:create_anonymous_mapper).returns(mapper)
|
513
|
+
@class.maps :outer do; end
|
514
|
+
assert_equal mapper, @class.simple_mapper.attributes[:outer].mapper
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
context 'with full nested mappers' do
|
520
|
+
setup do
|
521
|
+
@class = Class.new do
|
522
|
+
include SimpleMapper::Attributes
|
523
|
+
maps :id
|
524
|
+
maps :email
|
525
|
+
maps :home_address do
|
526
|
+
maps :address
|
527
|
+
maps :city
|
528
|
+
maps :state
|
529
|
+
maps :zip
|
530
|
+
end
|
531
|
+
end
|
532
|
+
@source = {:id => 'foo',
|
533
|
+
:email => 'aardvark@pyongyang.yumm.com',
|
534
|
+
:home_address => {
|
535
|
+
:address => '54 Gorgeous Gorge Parkway',
|
536
|
+
:city => 'Here',
|
537
|
+
:state => 'TX',
|
538
|
+
:zip => '04435'}}
|
539
|
+
@instance = @class.new(@source)
|
540
|
+
end
|
541
|
+
|
542
|
+
should 'map to instance appropriately' do
|
543
|
+
assert_equal @class, @instance.class
|
544
|
+
assert_equal @source[:id], @instance.id
|
545
|
+
assert_equal @source[:email], @instance.email
|
546
|
+
assert_equal @source[:home_address][:address], @instance.home_address.address
|
547
|
+
assert_equal @source[:home_address][:city], @instance.home_address.city
|
548
|
+
assert_equal @source[:home_address][:state], @instance.home_address.state
|
549
|
+
assert_equal @source[:home_address][:zip], @instance.home_address.zip
|
550
|
+
end
|
551
|
+
|
552
|
+
should 'map back to simple structure' do
|
553
|
+
assert_equal @source, @instance.to_simple
|
554
|
+
end
|
555
|
+
|
556
|
+
should 'freeze nested mappers when frozen from containing object' do
|
557
|
+
@instance.freeze
|
558
|
+
assert_equal true, @instance.home_address.frozen?
|
559
|
+
end
|
560
|
+
end
|
561
|
+
end
|