simple_mapper 0.0.1
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.
- 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
|