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,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
|