@@ -6,9 +6,20 @@ module ActiveModel
6
6
class AttributeRegistrationTest < ActiveModel ::TestCase
7
7
MyType = Class . new ( Type ::Value )
8
8
Type . register ( MyType . name . to_sym , MyType )
9
+
9
10
TYPE_1 = MyType . new ( precision : 1 )
10
11
TYPE_2 = MyType . new ( precision : 2 )
11
12
13
+ MyDecorator = DelegateClass ( Type ::Value ) do
14
+ attr_reader :name
15
+ alias :cast_type :__getobj__
16
+
17
+ def initialize ( name , cast_type )
18
+ super ( cast_type )
19
+ @name = name
20
+ end
21
+ end
22
+
12
23
test "attributes can be registered" do
13
24
attributes = default_attributes_for { attribute :foo , TYPE_1 }
14
25
assert_same TYPE_1 , attributes [ "foo" ] . type
@@ -52,12 +63,12 @@ class AttributeRegistrationTest < ActiveModel::TestCase
52
63
assert_not_predicate attributes [ "bar" ] , :came_from_user?
53
64
end
54
65
55
- test "attribute_types reflects registered attribute types" do
66
+ test ":: attribute_types reflects registered attribute types" do
56
67
klass = class_with { attribute :foo , TYPE_1 }
57
68
assert_same TYPE_1 , klass . attribute_types [ "foo" ]
58
69
end
59
70
60
- test "attribute_types returns the default type when key is missing" do
71
+ test ":: attribute_types returns the default type when key is missing" do
61
72
klass = class_with { attribute :foo , TYPE_1 }
62
73
assert_equal Type ::Value . new , klass . attribute_types [ "bar" ]
63
74
end
@@ -137,6 +148,90 @@ class AttributeRegistrationTest < ActiveModel::TestCase
137
148
assert_nil parent . _default_attributes [ "bar" ] . value
138
149
end
139
150
151
+ test "::decorate_attributes decorates specified attributes" do
152
+ attributes = default_attributes_for do
153
+ attribute :foo , TYPE_1
154
+ attribute :bar , TYPE_2
155
+ attribute :qux , TYPE_2
156
+ decorate_attributes ( [ :foo , :bar ] ) { |name , type | MyDecorator . new ( name , type ) }
157
+ end
158
+
159
+ assert_instance_of MyDecorator , attributes [ "foo" ] . type
160
+ assert_equal "foo" , attributes [ "foo" ] . type . name
161
+ assert_same TYPE_1 , attributes [ "foo" ] . type . cast_type
162
+
163
+ assert_instance_of MyDecorator , attributes [ "bar" ] . type
164
+ assert_equal "bar" , attributes [ "bar" ] . type . name
165
+ assert_same TYPE_2 , attributes [ "bar" ] . type . cast_type
166
+
167
+ assert_same TYPE_2 , attributes [ "qux" ] . type
168
+ end
169
+
170
+ test "::decorate_attributes decorates all attributes when none are specified" do
171
+ attributes = default_attributes_for do
172
+ attribute :foo , TYPE_1
173
+ attribute :bar , TYPE_2
174
+ decorate_attributes { |name , type | MyDecorator . new ( name , type ) }
175
+ end
176
+
177
+ assert_same TYPE_1 , attributes [ "foo" ] . type . cast_type
178
+ assert_same TYPE_2 , attributes [ "bar" ] . type . cast_type
179
+ end
180
+
181
+ test "::decorate_attributes supports conditional decoration" do
182
+ attributes = default_attributes_for do
183
+ attribute :foo , TYPE_1
184
+ attribute :bar , TYPE_2
185
+ decorate_attributes { |name , type | MyDecorator . new ( name , type ) if name . match? ( /oo/ ) }
186
+ end
187
+
188
+ assert_same TYPE_1 , attributes [ "foo" ] . type . cast_type
189
+ assert_same TYPE_2 , attributes [ "bar" ] . type
190
+ end
191
+
192
+ test "::decorate_attributes stacks decorators" do
193
+ attributes = default_attributes_for do
194
+ attribute :foo , TYPE_1
195
+ decorate_attributes { |name , type | MyDecorator . new ( "#{ name } 1" , type ) }
196
+ decorate_attributes { |name , type | MyDecorator . new ( "#{ name } 2" , type ) }
197
+ end
198
+
199
+ assert_instance_of MyDecorator , attributes [ "foo" ] . type
200
+ assert_equal "foo2" , attributes [ "foo" ] . type . name
201
+
202
+ assert_instance_of MyDecorator , attributes [ "foo" ] . type . cast_type
203
+ assert_equal "foo1" , attributes [ "foo" ] . type . cast_type . name
204
+
205
+ assert_same TYPE_1 , attributes [ "foo" ] . type . cast_type . cast_type
206
+ end
207
+
208
+ test "superclass attribute types can be decorated" do
209
+ parent = class_with do
210
+ attribute :foo , TYPE_1
211
+ end
212
+
213
+ child = class_with ( parent ) do
214
+ decorate_attributes { |name , type | MyDecorator . new ( name , type ) }
215
+ end
216
+
217
+ assert_instance_of MyDecorator , child . _default_attributes [ "foo" ] . type
218
+ assert_same TYPE_1 , child . _default_attributes [ "foo" ] . type . cast_type
219
+ assert_same TYPE_1 , parent . _default_attributes [ "foo" ] . type
220
+ end
221
+
222
+ test "re-registering an attribute overrides previous decorators" do
223
+ parent = class_with do
224
+ attribute :foo , TYPE_1
225
+ decorate_attributes { |name , type | MyDecorator . new ( name , type ) }
226
+ end
227
+
228
+ child = class_with ( parent ) do
229
+ attribute :foo , TYPE_1
230
+ end
231
+
232
+ assert_same TYPE_1 , child . _default_attributes [ "foo" ] . type
233
+ end
234
+
140
235
private
141
236
def class_with ( base_class = nil , &block )
142
237
Class . new ( *base_class ) do
0 commit comments