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,181 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# Change tracking is done at the attribute object level
|
4
|
+
# via SimpleMapper::Attribute methods +changed?+ and +changed!+,
|
5
|
+
# but the basic attribute object depends on the +simple_mapper_changes+
|
6
|
+
# hash attribute provided by SimpleMapper::Attributes to including classes.
|
7
|
+
#
|
8
|
+
# The unit tests mock out this interdependency, so we need this simple
|
9
|
+
# integration test to verify the basics.
|
10
|
+
class AttributeChangeTrackingTest < Test::Unit::TestCase
|
11
|
+
context 'Objects built using SimpleMapper::Attributes' do
|
12
|
+
setup do
|
13
|
+
@class = Class.new do
|
14
|
+
include SimpleMapper::Attributes
|
15
|
+
maps :a
|
16
|
+
maps :b
|
17
|
+
end
|
18
|
+
@values = {:a => 'A', :b => 'B'}
|
19
|
+
@instance = @class.new(@values.clone)
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'indicate no change on attribute objects for not-newly-assigned attributes' do
|
23
|
+
assert_equal false, @class.simple_mapper.attributes[:a].changed?(@instance)
|
24
|
+
assert_equal false, @class.simple_mapper.attributes[:b].changed?(@instance)
|
25
|
+
end
|
26
|
+
|
27
|
+
should 'indicate no change on instance via :attribute_changed? for not-newly-assigned attributes' do
|
28
|
+
assert_equal false, @instance.attribute_changed?(:a)
|
29
|
+
assert_equal false, @instance.attribute_changed?(:b)
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'indicate change on attribute objects for newly-assigned attributes' do
|
33
|
+
@instance.a = 'something else'
|
34
|
+
assert_equal true, @class.simple_mapper.attributes[:a].changed?(@instance)
|
35
|
+
assert_equal false, @class.simple_mapper.attributes[:b].changed?(@instance)
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'indicate change on instance via :attribute_changed? for newly-assigned attributes' do
|
39
|
+
@instance.a = 'something else'
|
40
|
+
assert_equal true, @instance.attribute_changed?(:a)
|
41
|
+
assert_equal false, @instance.attribute_changed?(:b)
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'indicate change on nested attribute if nested attribute has a newly-assigned member' do
|
45
|
+
@class.maps :nested do
|
46
|
+
maps :inner_a
|
47
|
+
maps :inner_b
|
48
|
+
end
|
49
|
+
assert_equal false, @instance.attribute_changed?(:nested)
|
50
|
+
@instance.nested.inner_a = 'foo'
|
51
|
+
assert_equal true, @instance.attribute_changed?(:nested)
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when converting :to_simple with :changed' do
|
55
|
+
should 'result in an empty hash if no attributes have been changed' do
|
56
|
+
assert_equal({}, @instance.to_simple(:changed => true))
|
57
|
+
end
|
58
|
+
|
59
|
+
should 'result in hash with one member if only one member was changed' do
|
60
|
+
@instance.a = new_a = 'new a'
|
61
|
+
assert_equal({:a => new_a}, @instance.to_simple(:changed => true))
|
62
|
+
end
|
63
|
+
|
64
|
+
should 'result in hash with multiple members if multiple members were changed' do
|
65
|
+
@instance.a = new_a = 'new_a'
|
66
|
+
@instance.b = new_b = 'new_b'
|
67
|
+
assert_equal({:a => new_a, :b => new_b}, @instance.to_simple(:changed => true))
|
68
|
+
end
|
69
|
+
|
70
|
+
should 'result in nested hash if the class has nested attributes' do
|
71
|
+
@class.maps :nested do
|
72
|
+
maps :inner_a
|
73
|
+
maps :inner_b
|
74
|
+
end
|
75
|
+
@instance.a = new_a = 'new_a'
|
76
|
+
@instance.nested.inner_a = new_inner_a = 'new_inner_a'
|
77
|
+
assert_equal({:a => new_a, :nested => {:inner_a => new_inner_a}}, @instance.to_simple(:changed => true))
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'and a hash collection attribute' do
|
81
|
+
setup do
|
82
|
+
@collection_class = Class.new(SimpleMapper::Attribute) do
|
83
|
+
include SimpleMapper::Attribute::Collection
|
84
|
+
|
85
|
+
def prefix
|
86
|
+
'__'
|
87
|
+
end
|
88
|
+
|
89
|
+
def member_key?(key)
|
90
|
+
key.to_s[0..1] == prefix
|
91
|
+
end
|
92
|
+
|
93
|
+
def from_simple_key(key)
|
94
|
+
key.to_s.sub(prefix, '').to_sym
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_simple_key(key)
|
98
|
+
(prefix + key.to_s).to_sym
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
@class.maps :collection, :attribute_class => @collection_class
|
103
|
+
@instance = @class.new(@values.clone)
|
104
|
+
end
|
105
|
+
|
106
|
+
should 'have no output for the collection if no members were changed' do
|
107
|
+
@instance.a = new_a = 'new_a'
|
108
|
+
assert_equal({:a => new_a}, @instance.to_simple(:changed => true))
|
109
|
+
end
|
110
|
+
|
111
|
+
should 'have output for items added to the collection' do
|
112
|
+
@instance.collection[:first] = 'first'
|
113
|
+
@instance.collection[:second] = 'second'
|
114
|
+
@instance.collection[:third] = 'third'
|
115
|
+
assert_equal(
|
116
|
+
{
|
117
|
+
:__first => 'first',
|
118
|
+
:__second => 'second',
|
119
|
+
:__third => 'third',
|
120
|
+
},
|
121
|
+
@instance.to_simple(:changed => true)
|
122
|
+
)
|
123
|
+
end
|
124
|
+
|
125
|
+
should 'have output for items altered in the collection' do
|
126
|
+
@instance = @class.new(:__first => 'first', :__second => 'second', :__third => 'third')
|
127
|
+
@instance.collection[:second] = 'new second'
|
128
|
+
@instance.collection.delete(:third)
|
129
|
+
@instance.collection[:fourth] = 'fourth'
|
130
|
+
assert_equal(
|
131
|
+
{:__second => 'new second',
|
132
|
+
:__third => nil,
|
133
|
+
:__fourth => 'fourth'},
|
134
|
+
@instance.to_simple(:changed => true)
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'with mapped members' do
|
139
|
+
setup do
|
140
|
+
@mapped_collection_class = Class.new(@collection_class) do
|
141
|
+
def prefix
|
142
|
+
'--'
|
143
|
+
end
|
144
|
+
end
|
145
|
+
@class.maps :mapped_collection, :attribute_class => @mapped_collection_class do
|
146
|
+
maps :name
|
147
|
+
maps :id, :type => :simple_uuid, :default => :from_type
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
should 'have output for items added to collection' do
|
152
|
+
@instance.mapped_collection[:me] = @instance.mapped_collection.build(:name => 'me')
|
153
|
+
@instance.mapped_collection[:you] = @instance.mapped_collection.build(:name => 'you')
|
154
|
+
expected = {
|
155
|
+
:'--me' => {:name => 'me', :id => @instance.mapped_collection[:me].id},
|
156
|
+
:'--you' => {:name => 'you', :id => @instance.mapped_collection[:you].id},
|
157
|
+
}
|
158
|
+
assert_equal expected, @instance.to_simple(:changed => true)
|
159
|
+
end
|
160
|
+
|
161
|
+
should 'have output for items removed from collection' do
|
162
|
+
@instance = @class.new(:'--me' => {:name => 'me'}, :'--you' => {:name => 'you'})
|
163
|
+
@instance.mapped_collection.delete(:you)
|
164
|
+
assert_equal({:'--you' => nil}, @instance.to_simple(:changed => true))
|
165
|
+
end
|
166
|
+
|
167
|
+
should 'have output for all attributes in replaced member' do
|
168
|
+
@instance = @class.new(:'--me' => {:name => 'me'})
|
169
|
+
@instance.mapped_collection[:me] = @instance.mapped_collection.build
|
170
|
+
assert_equal({:'--me' => {:name => nil, :id => @instance.mapped_collection[:me].id}}, @instance.to_simple(:changed => true))
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'and an array collection attribute' do
|
176
|
+
setup do
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class AttributeMetaInteractionTest < Test::Unit::TestCase
|
4
|
+
context 'Object attribute / meta attribute method' do
|
5
|
+
setup do
|
6
|
+
@class = Class.new do
|
7
|
+
include SimpleMapper::Attributes
|
8
|
+
maps :foo
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'read_source_attribute' do
|
13
|
+
setup do
|
14
|
+
@instance = @class.new(:foo => 'Foo!')
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'return the attribute specified from the source hash' do
|
18
|
+
assert_equal 'Foo!', @instance.read_source_attribute(:foo)
|
19
|
+
end
|
20
|
+
|
21
|
+
should 'return the attribute from source even if updated locally' do
|
22
|
+
@instance.write_attribute(:foo, 'Blah!')
|
23
|
+
assert_equal 'Blah!', @instance.read_attribute(:foo)
|
24
|
+
assert_equal 'Foo!', @instance.read_source_attribute(:foo)
|
25
|
+
end
|
26
|
+
|
27
|
+
should 'return the source attribute via string key if symbol key does not exist' do
|
28
|
+
@class.maps :some_attr
|
29
|
+
@instance = @class.new('foo' => 'Foo!', :some_attr => 'Some Attr')
|
30
|
+
assert_equal 'Foo!', @instance.read_attribute(:foo)
|
31
|
+
assert_equal 'Some Attr', @instance.read_attribute(:some_attr)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'read_attribute' do
|
36
|
+
setup do
|
37
|
+
@instance = @class.new(:foo => 'Foo!', :some_attr => 'Some Attr')
|
38
|
+
end
|
39
|
+
|
40
|
+
should 'return the source attribute by default' do
|
41
|
+
assert_equal 'Foo!', @instance.read_attribute(:foo)
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'return the updated attribute if one exists' do
|
45
|
+
@instance.write_attribute(:foo, 'Blah!')
|
46
|
+
assert_equal 'Blah!', @instance.read_attribute(:foo)
|
47
|
+
end
|
48
|
+
|
49
|
+
should 'return the attribute default if source attribute is nil' do
|
50
|
+
@instance = @class.new
|
51
|
+
@instance.attribute_object_for(:foo).expects(:default_value).with(@instance).returns('foo default')
|
52
|
+
result = @instance.read_attribute(:foo)
|
53
|
+
assert_equal 'foo default', result
|
54
|
+
end
|
55
|
+
|
56
|
+
context 'with a type converter' do
|
57
|
+
setup do
|
58
|
+
@expected_out = '_foo_'
|
59
|
+
@expected_in = 'Foo!'
|
60
|
+
@type_a = mock('type_a')
|
61
|
+
@type_a.expects(:decode).with(@expected_in).returns(@expected_out)
|
62
|
+
@class.simple_mapper.attributes[:foo].type = @type_a
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'transform the source attribute' do
|
66
|
+
assert_equal @expected_out, @instance.read_attribute(:foo)
|
67
|
+
end
|
68
|
+
|
69
|
+
should 'transform the default value if no source value is defined' do
|
70
|
+
@instance = @class.new
|
71
|
+
@instance.attribute_object_for(:foo).default = :get_default
|
72
|
+
@instance.stubs(:get_default).returns(@expected_in)
|
73
|
+
assert_equal @expected_out, @instance.read_attribute(:foo)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with a type name' do
|
78
|
+
setup do
|
79
|
+
foo_type = mock('foo_type')
|
80
|
+
foo_class = foo_type.class
|
81
|
+
@expected_in = 'Foo!'
|
82
|
+
@expected_out = 'Foo on Ewe!'
|
83
|
+
foo_type.expects(:decode).once.with(@expected_in).returns(@expected_out)
|
84
|
+
SimpleMapper::Attributes.stubs(:types).with.returns({:foo_type => {
|
85
|
+
:name => :foo_type,
|
86
|
+
:expected_type => foo_class,
|
87
|
+
:converter => foo_type,
|
88
|
+
}})
|
89
|
+
@class.simple_mapper.attributes[:foo].type = :foo_type
|
90
|
+
end
|
91
|
+
|
92
|
+
should 'transform the source attribute if a type name was specified' do
|
93
|
+
assert_equal @expected_out, @instance.read_attribute(:foo)
|
94
|
+
end
|
95
|
+
|
96
|
+
should 'transform the default value if the source is nil' do
|
97
|
+
@instance = @class.new
|
98
|
+
@instance.attribute_object_for(:foo).default = :get_default
|
99
|
+
@instance.stubs(:get_default).returns(@expected_in)
|
100
|
+
assert_equal @expected_out, @instance.read_attribute(:foo)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
should 'not transform the source attr if it is already of the expected type' do
|
105
|
+
foo_type = mock('foo too type')
|
106
|
+
foo_type.expects(:decode).never
|
107
|
+
SimpleMapper::Attributes.expects(:type_for).with(:foo_type).returns({
|
108
|
+
:name => :foo_type,
|
109
|
+
:expected_type => String,
|
110
|
+
:converter => foo_type,
|
111
|
+
})
|
112
|
+
@class.simple_mapper.attributes[:foo].type = :foo_type
|
113
|
+
assert_equal 'Foo!', @instance.read_attribute(:foo)
|
114
|
+
end
|
115
|
+
|
116
|
+
should 'not transform a written attribute when type was specified' do
|
117
|
+
type_a = mock('type_a')
|
118
|
+
type_a.expects(:decode).never
|
119
|
+
@class.simple_mapper.attributes[:foo].type = type_a
|
120
|
+
@instance.write_attribute(:foo, 'blahblah')
|
121
|
+
assert_equal 'blahblah', @instance.read_attribute(:foo)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'get_attribute_default' do
|
126
|
+
setup do
|
127
|
+
@instance = @class.new(:foo => 'foo')
|
128
|
+
end
|
129
|
+
|
130
|
+
should 'return nil if the attribute has no default specified' do
|
131
|
+
@class.maps :without_default
|
132
|
+
assert_equal nil, @instance.get_attribute_default(:without_default)
|
133
|
+
end
|
134
|
+
|
135
|
+
should 'invoke specified default symbol on instance if attr has default specified' do
|
136
|
+
@class.maps :with_default, :default => :some_default
|
137
|
+
@instance.expects(:some_default).once.with.returns('the default value')
|
138
|
+
assert_equal 'the default value', @instance.get_attribute_default(:with_default)
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'with :default of :from_type' do
|
142
|
+
setup do
|
143
|
+
@expected_val = 'some default value'
|
144
|
+
@name = :with_default
|
145
|
+
@type = stub('type', :name => :type_name, :decode => :foo, :encode => :foo2)
|
146
|
+
@type.expects(:default).once.with.returns(@expected_val)
|
147
|
+
end
|
148
|
+
|
149
|
+
should 'invoke :default on type converter if default is :from_type and :type is object' do
|
150
|
+
@class.maps :with_default, :type => @type, :default => :from_type
|
151
|
+
assert_equal @expected_val, @instance.get_attribute_default(:with_default)
|
152
|
+
end
|
153
|
+
|
154
|
+
should 'invoke :default on registered type if default is :from_type and :type is registered' do
|
155
|
+
begin
|
156
|
+
SimpleMapper::Attributes.stubs(:types).with.returns({@name => {
|
157
|
+
:name => @name,
|
158
|
+
:expected_class => @type.class,
|
159
|
+
:converter => @type}})
|
160
|
+
@class.maps :with_default, :type => @name, :default => :from_type
|
161
|
+
assert_equal @expected_val, @instance.get_attribute_default(:with_default)
|
162
|
+
ensure
|
163
|
+
SimpleMapper::Attributes.types.delete @type.name
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# basic end-to-end tests for the SimpleMapper::Attribute::Pattern attribute class.
|
4
|
+
class AttributePatternIntegrationTest < Test::Unit::TestCase
|
5
|
+
context 'A SimpleMapper::Attribute::Pattern attribute' do
|
6
|
+
setup do
|
7
|
+
@target_class = SimpleMapper::Attribute::Pattern
|
8
|
+
@class = Class.new do
|
9
|
+
include SimpleMapper::Attributes
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'with simple values' do
|
14
|
+
setup do
|
15
|
+
@class.maps :simple, :attribute_class => @target_class, :pattern => /^simple_/
|
16
|
+
@class.maps :float, :attribute_class => @target_class, :pattern => /^float_/, :type => :float
|
17
|
+
@simple = {:simple_a => 'a', :simple_b => 'b', :simple_c => 'c'}
|
18
|
+
@float = {:float_a => 1.0, :float_b => 100.1, :float_c => 99.99999}
|
19
|
+
@object = @class.new( @simple.merge( @float.inject({}) {|h, kv| h[kv[0]] = kv[1].to_s; h} ) ) end
|
20
|
+
|
21
|
+
should 'map untyped pairs to the patterned collection attribute' do
|
22
|
+
assert_equal @simple, @object.simple
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'map typed pairs to the patterned collection attribute' do
|
26
|
+
assert_equal @float, @object.float
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'map untyped instance values back to simple structure using to_simple' do
|
30
|
+
result = @object.to_simple || {}
|
31
|
+
assert_equal @simple, result.reject {|k, v| ! /^simple_/.match(k.to_s)}
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'map typed instance values back to simple structure using to_simple' do
|
35
|
+
result = @object.to_simple || {}
|
36
|
+
assert_equal(@float.inject({}) {|h, pair| h[pair[0]] = pair[1].to_s; h},
|
37
|
+
result.reject {|k, v| ! /^float_/.match(k.to_s)})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with a nested mapper' do
|
42
|
+
setup do
|
43
|
+
@class.maps :not_nested
|
44
|
+
@class.maps :nested, :attribute_class => @target_class, :pattern => /^nested_/ do
|
45
|
+
maps :foo
|
46
|
+
maps :bar
|
47
|
+
end
|
48
|
+
|
49
|
+
@input = {:nested_a => {:foo => 'foo_a', :bar => 'bar_a'},
|
50
|
+
:nested_b => {:foo => 'foo_b', :bar => 'bar_b'},
|
51
|
+
:nested_c => {:foo => 'foo_c', :bar => 'bar_c'},
|
52
|
+
:not_nested => 'blah'}
|
53
|
+
@object = @class.new(@input)
|
54
|
+
end
|
55
|
+
|
56
|
+
should 'convert nested source values to type defined by block per item in patterned collection attribute' do
|
57
|
+
result = @object.nested.inject({}) do |hash, keyval|
|
58
|
+
hash[keyval[0]] = {:foo => keyval[1].foo, :bar => keyval[1].bar}
|
59
|
+
hash
|
60
|
+
end
|
61
|
+
expected = @input.clone
|
62
|
+
expected.delete :not_nested
|
63
|
+
assert_equal expected, result
|
64
|
+
end
|
65
|
+
|
66
|
+
should 'still map simple attributes too' do
|
67
|
+
assert_equal @input[:not_nested], @object.not_nested.to_s
|
68
|
+
end
|
69
|
+
|
70
|
+
should 'map nested objects back to nested simple structures with to_simple' do
|
71
|
+
expected = @input.reject {|k, v| ! /^nested_/.match(k.to_s)}
|
72
|
+
result = @object.to_simple || {}
|
73
|
+
assert_equal(expected, result.reject {|k, v| ! /^nested/.match(k.to_s)})
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# The :to_simple method of the SimpleMapper::Attributes
|
4
|
+
# module ultimately depends on the :to_simple
|
5
|
+
# implementation of the attribute objects for a given
|
6
|
+
# mapper class.
|
7
|
+
#
|
8
|
+
# Consequently, the integration test is necessary,
|
9
|
+
# as other :to_simple tests at the unit level rely on
|
10
|
+
# mocks for this interdependency.
|
11
|
+
class ToSimpleTest < Test::Unit::TestCase
|
12
|
+
context "The mapper's :to_simple method" do
|
13
|
+
setup do
|
14
|
+
@class = Class.new do
|
15
|
+
include SimpleMapper::Attributes
|
16
|
+
maps :no_type
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
should 'return a hash with key/value per known attribute' do
|
21
|
+
@class.maps :other
|
22
|
+
@instance = @class.new( :no_type => 'no type', :other => 'Other!' )
|
23
|
+
assert_equal( {:no_type => 'no type', :other => 'Other!'}, @instance.to_simple )
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'return hash whose key/value pairs follow attribute state' do
|
27
|
+
@class.maps :other
|
28
|
+
@instance = @class.new( :no_type => 'original', :other => 'original' )
|
29
|
+
@instance.other = 'updated'
|
30
|
+
assert_equal({:no_type => 'original', :other => 'updated'}, @instance.to_simple)
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'map attributes to specified keys in returned hash' do
|
34
|
+
@class.maps :other, :key => :alt_key
|
35
|
+
@instance = @class.new
|
36
|
+
@instance.no_type = 'no type'
|
37
|
+
@instance.other = 'alt key'
|
38
|
+
assert_equal({:no_type => 'no type', :alt_key => 'alt key'}, @instance.to_simple)
|
39
|
+
end
|
40
|
+
|
41
|
+
should 'return a hash with strings for keys when :string_keys option is true' do
|
42
|
+
@class.maps :other, :key => :alt_key
|
43
|
+
@instance = @class.new
|
44
|
+
@instance.no_type = 'no type'
|
45
|
+
@instance.other = 'alt key'
|
46
|
+
assert_equal({'no_type' => 'no type', 'alt_key' => 'alt key'},
|
47
|
+
@instance.to_simple(:string_keys => true))
|
48
|
+
end
|
49
|
+
|
50
|
+
should 'encode typed attribute values for converter types' do
|
51
|
+
@type = Object.new
|
52
|
+
@type.instance_eval do
|
53
|
+
def encode(value)
|
54
|
+
"encoded: #{value}"
|
55
|
+
end
|
56
|
+
def decode(value)
|
57
|
+
value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
@class.maps :typed, :type => @type
|
61
|
+
@instance = @class.new( :typed => 'typed!' )
|
62
|
+
assert_equal 'encoded: typed!', @instance.to_simple[:typed]
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'encode typed attribute values for registered types' do
|
66
|
+
@type = mock('type')
|
67
|
+
@type.expects(:encode).once.with('typed!').returns('encoded!')
|
68
|
+
@type.stubs(:decode).returns('typed!')
|
69
|
+
SimpleMapper::Attributes.expects(:type_for).with(:type).at_least_once.returns({
|
70
|
+
:name => :type,
|
71
|
+
:expected_type => @type.class,
|
72
|
+
:converter => @type,
|
73
|
+
})
|
74
|
+
@class.maps :typed, :type => :type
|
75
|
+
@instance = @class.new( :typed => 'typed!' )
|
76
|
+
assert_equal 'encoded!', @instance.to_simple[:typed]
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'with :defined argument' do
|
80
|
+
should 'return a hash with key/value per defined attribute' do
|
81
|
+
@class.maps :undefined
|
82
|
+
assert_equal({:no_type => 'nt'}, @class.new({:no_type => 'nt'}).to_simple(:defined => true))
|
83
|
+
end
|
84
|
+
|
85
|
+
should 'return an empty hash if no attributes were set' do
|
86
|
+
assert_equal({}, @class.new.to_simple(:defined => true))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'with :changes argument' do
|
91
|
+
setup do
|
92
|
+
@class.maps :other
|
93
|
+
@instance = @class.new({:typed => 'typed', :other => 'other'})
|
94
|
+
end
|
95
|
+
|
96
|
+
should 'return an empty hash if no attributes were changed' do
|
97
|
+
assert_equal({}, @instance.to_simple(:changed => true))
|
98
|
+
end
|
99
|
+
|
100
|
+
should 'return a hash of only the key/value pairs that were changed' do
|
101
|
+
@instance.other = 'udder'
|
102
|
+
@instance.class.simple_mapper.attributes[:other].stubs(:changed?).with(@instance).returns(true)
|
103
|
+
assert_equal({:other => 'udder'}, @instance.to_simple(:changed => true))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'with an attribute value that uses a mapper' do
|
108
|
+
setup do
|
109
|
+
@class.maps :other do; end
|
110
|
+
@instance = @class.new({:no_type => 'no type',
|
111
|
+
:other => {}})
|
112
|
+
@mock = @instance.other
|
113
|
+
end
|
114
|
+
|
115
|
+
should 'invoke to_simple on attribute value rather than encode' do
|
116
|
+
@mock.expects(:to_simple).returns('to simple')
|
117
|
+
assert_equal({:no_type => 'no type', :other => 'to simple'},
|
118
|
+
@instance.to_simple)
|
119
|
+
end
|
120
|
+
|
121
|
+
should 'pass outer to_simple arguments along to inner to_simple' do
|
122
|
+
options = {:foo => 'floppy', :foot => 'fungi'}
|
123
|
+
@mock.expects(:to_simple).with(options).returns(nil)
|
124
|
+
@instance.to_simple(options)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|