representable 1.5.3 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/{CHANGES.textile → CHANGES.md} +17 -0
- data/Gemfile +1 -1
- data/README.md +24 -3
- data/TODO +11 -3
- data/lib/representable.rb +37 -117
- data/lib/representable/coercion.rb +29 -4
- data/lib/representable/config.rb +52 -0
- data/lib/representable/decorator.rb +8 -7
- data/lib/representable/decorator/coercion.rb +2 -57
- data/lib/representable/definition.rb +1 -0
- data/lib/representable/feature/readable_writeable.rb +1 -1
- data/lib/representable/hash.rb +5 -0
- data/lib/representable/hash/collection.rb +38 -0
- data/lib/representable/hash_methods.rb +2 -2
- data/lib/representable/json.rb +5 -0
- data/lib/representable/json/collection.rb +3 -28
- data/lib/representable/mapper.rb +78 -0
- data/lib/representable/version.rb +1 -1
- data/lib/representable/xml.rb +15 -10
- data/lib/representable/xml/collection.rb +7 -25
- data/lib/representable/yaml.rb +16 -11
- data/test/coercion_test.rb +95 -66
- data/test/decorator_test.rb +10 -0
- data/test/inheritance_test.rb +21 -0
- data/test/json_test.rb +7 -7
- data/test/representable_test.rb +146 -26
- data/test/test_helper.rb +1 -0
- data/test/yaml_test.rb +1 -2
- metadata +26 -44
data/test/coercion_test.rb
CHANGED
@@ -3,82 +3,111 @@ require 'representable/coercion'
|
|
3
3
|
require 'representable/decorator/coercion'
|
4
4
|
|
5
5
|
class VirtusCoercionTest < MiniTest::Spec
|
6
|
-
class Song # note that we
|
7
|
-
attr_accessor :title
|
6
|
+
class Song # note that we have to define accessors for the properties here.
|
7
|
+
attr_accessor :title, :composed_at, :track
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
# it "coerces when rendering" do
|
29
|
-
# song = Song.new
|
30
|
-
# song.title = "Scarified"
|
31
|
-
# song.to_json.must_equal ''
|
32
|
-
# end
|
10
|
+
let (:date) { DateTime.parse("Fri, 18 Nov 1983 00:00:00 +0000") }
|
11
|
+
|
12
|
+
describe "on object level" do
|
13
|
+
module SongRepresenter
|
14
|
+
include Representable::JSON
|
15
|
+
include Representable::Coercion
|
16
|
+
property :composed_at, :type => DateTime
|
17
|
+
property :track, :type => Integer
|
18
|
+
property :title # no coercion.
|
19
|
+
end
|
20
|
+
|
21
|
+
it "coerces properties in #from_json" do
|
22
|
+
song = Song.new.extend(SongRepresenter).from_json('{"composed_at":"November 18th, 1983","track":"18","title":"Scarified"}')
|
23
|
+
song.composed_at.must_equal date
|
24
|
+
song.track.must_equal 18
|
25
|
+
song.title.must_equal "Scarified"
|
33
26
|
end
|
34
27
|
|
28
|
+
it "coerces when rendering" do
|
29
|
+
song = Song.new.extend(SongRepresenter)
|
30
|
+
song.title = "Scarified"
|
31
|
+
song.composed_at = "Fri, 18 Nov 1983"
|
35
32
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
song.to_hash.must_equal({"title" => "Scarified", "composed_at" => date})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "on class level" do
|
38
|
+
class ImmigrantSong
|
39
|
+
include Representable::JSON
|
40
|
+
include Representable::Coercion
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
end
|
42
|
+
property :composed_at, :type => DateTime, :default => "May 12th, 2012"
|
43
|
+
property :track, :type => Integer
|
44
44
|
|
45
|
-
|
46
|
-
|
47
|
-
assert_equal DateTime.parse("Fri, 18 Nov 1983 00:00:00 +0000"), song.composed_at
|
48
|
-
assert_equal 18, song.track
|
49
|
-
end
|
45
|
+
attr_accessor :composed_at, :track
|
46
|
+
end
|
50
47
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
end
|
48
|
+
it "coerces into the provided type" do
|
49
|
+
song = ImmigrantSong.new.from_json("{\"composed_at\":\"November 18th, 1983\",\"track\":\"18\"}")
|
50
|
+
song.composed_at.must_equal date
|
51
|
+
song.track.must_equal 18
|
56
52
|
end
|
57
53
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
include Representable::Decorator::Coercion
|
62
|
-
|
63
|
-
property :composed_at, :type => DateTime
|
64
|
-
property :title
|
65
|
-
end
|
66
|
-
|
67
|
-
it "coerces when parsing" do
|
68
|
-
song = SongRepresentation.new(OpenStruct.new).from_json("{\"composed_at\":\"November 18th, 1983\", \"title\": \"Scarified\"}")
|
69
|
-
song.must_be_kind_of OpenStruct
|
70
|
-
song.composed_at.must_equal DateTime.parse("Fri, 18 Nov 1983")
|
71
|
-
song.title.must_equal "Scarified"
|
72
|
-
end
|
73
|
-
|
74
|
-
it "coerces when rendering" do
|
75
|
-
SongRepresentation.new(
|
76
|
-
OpenStruct.new(
|
77
|
-
:composed_at => "November 18th, 1983",
|
78
|
-
:title => "Scarified"
|
79
|
-
)
|
80
|
-
).to_hash.must_equal({"composed_at"=>DateTime.parse("Fri, 18 Nov 1983"), "title"=>"Scarified"})
|
81
|
-
end
|
54
|
+
it "respects the :default options" do
|
55
|
+
song = ImmigrantSong.new.from_json("{}")
|
56
|
+
song.composed_at.must_equal DateTime.parse("Mon, 12 May 2012 00:00:00 +0000")
|
82
57
|
end
|
83
58
|
end
|
59
|
+
|
60
|
+
describe "on decorator" do
|
61
|
+
class SongRepresentation < Representable::Decorator
|
62
|
+
include Representable::JSON
|
63
|
+
include Representable::Coercion
|
64
|
+
|
65
|
+
property :composed_at, :type => DateTime
|
66
|
+
property :title
|
67
|
+
end
|
68
|
+
|
69
|
+
it "coerces when parsing" do
|
70
|
+
song = SongRepresentation.new(OpenStruct.new).from_json("{\"composed_at\":\"November 18th, 1983\", \"title\": \"Scarified\"}")
|
71
|
+
song.must_be_kind_of OpenStruct
|
72
|
+
song.composed_at.must_equal date
|
73
|
+
song.title.must_equal "Scarified"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "coerses with inherited decorator" do
|
77
|
+
song = Class.new(SongRepresentation).new(OpenStruct.new).from_json("{\"composed_at\":\"November 18th, 1983\", \"title\": \"Scarified\"}")
|
78
|
+
song.composed_at.must_equal date
|
79
|
+
end
|
80
|
+
|
81
|
+
it "coerces when rendering" do
|
82
|
+
SongRepresentation.new(
|
83
|
+
OpenStruct.new(
|
84
|
+
:composed_at => "November 18th, 1983",
|
85
|
+
:title => "Scarified"
|
86
|
+
)
|
87
|
+
).to_hash.must_equal({"composed_at"=>date, "title"=>"Scarified"})
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# DISCUSS: do we actually wanna have accessors in a decorator/module? i guess the better idea is to let coercion happen through from_/to_,
|
92
|
+
# only, to make it as simple as possible.
|
93
|
+
# describe "without serialization/deserialization" do
|
94
|
+
# let (:coercer_class) do
|
95
|
+
# class SongCoercer < Representable::Decorator
|
96
|
+
# include Representable::Decorator::Coercion
|
97
|
+
|
98
|
+
# property :composed_at, :type => DateTime
|
99
|
+
# property :title
|
100
|
+
|
101
|
+
# self
|
102
|
+
# end
|
103
|
+
# end
|
104
|
+
|
105
|
+
# it "coerces when setting" do
|
106
|
+
# coercer = coercer_class.new(song = OpenStruct.new)
|
107
|
+
# coercer.composed_at = "November 18th, 1983"
|
108
|
+
# #coercer.title = "Scarified"
|
109
|
+
|
110
|
+
# song.composed_at.must_equal date
|
111
|
+
# end
|
112
|
+
# end
|
84
113
|
end
|
data/test/decorator_test.rb
CHANGED
@@ -17,6 +17,16 @@ class DecoratorTest < MiniTest::Spec
|
|
17
17
|
let (:album) { Album.new([song]) }
|
18
18
|
let (:decorator) { AlbumRepresentation.new(album) }
|
19
19
|
|
20
|
+
describe "inheritance" do
|
21
|
+
let (:inherited_decorator) do
|
22
|
+
Class.new(AlbumRepresentation) do
|
23
|
+
property :best_song
|
24
|
+
end.new(Album.new([song], "Stand Up"))
|
25
|
+
end
|
26
|
+
|
27
|
+
it { inherited_decorator.to_hash.must_equal({"songs"=>[{"name"=>"Mama, I'm Coming Home"}], "best_song"=>"Stand Up"}) }
|
28
|
+
end
|
29
|
+
|
20
30
|
it "renders" do
|
21
31
|
decorator.to_hash.must_equal({"songs"=>[{"name"=>"Mama, I'm Coming Home"}]})
|
22
32
|
album.wont_respond_to :to_hash
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class InheritanceTest < MiniTest::Spec
|
4
|
+
let (:decorator) do
|
5
|
+
Class.new(Representable::Decorator) do
|
6
|
+
property :title
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Decorator.new.representable_attrs != Decorator.representable_attrs
|
11
|
+
it "doesn't clone for instantiated decorator" do
|
12
|
+
instance = decorator.new(Object.new)
|
13
|
+
instance.send(:representable_attrs).first.options[:instance] = true
|
14
|
+
|
15
|
+
# we didn't clone and thereby change the original config:
|
16
|
+
instance.send(:representable_attrs).to_s.must_equal decorator.representable_attrs.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
# TODO: ? (performance?)
|
20
|
+
# more tests on cloning
|
21
|
+
end
|
data/test/json_test.rb
CHANGED
@@ -144,13 +144,13 @@ module JsonTest
|
|
144
144
|
end
|
145
145
|
end
|
146
146
|
|
147
|
-
describe "#representable_bindings_for" do
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
147
|
+
# describe "#representable_bindings_for" do
|
148
|
+
# it "returns bindings for each property" do
|
149
|
+
# bins = @band.send(:representable_bindings_for, Representable::JSON::PropertyBinding, {})
|
150
|
+
# assert_equal 2, bins.size
|
151
|
+
# assert_equal "name", bins.first.name
|
152
|
+
# end
|
153
|
+
# end
|
154
154
|
end
|
155
155
|
|
156
156
|
|
data/test/representable_test.rb
CHANGED
@@ -2,7 +2,7 @@ require 'test_helper'
|
|
2
2
|
|
3
3
|
class RepresentableTest < MiniTest::Spec
|
4
4
|
class Band
|
5
|
-
include Representable
|
5
|
+
include Representable::Hash
|
6
6
|
property :name
|
7
7
|
attr_accessor :name
|
8
8
|
end
|
@@ -92,7 +92,6 @@ class RepresentableTest < MiniTest::Spec
|
|
92
92
|
|
93
93
|
assert parent.representable_attrs.first != child.representable_attrs.first, "definitions shouldn't be identical"
|
94
94
|
end
|
95
|
-
|
96
95
|
end
|
97
96
|
end
|
98
97
|
|
@@ -172,6 +171,12 @@ class RepresentableTest < MiniTest::Spec
|
|
172
171
|
assert_equal "friends", band.representable_attrs.last.from
|
173
172
|
end
|
174
173
|
end
|
174
|
+
|
175
|
+
representer! {}
|
176
|
+
|
177
|
+
it "returns the Definition instance" do
|
178
|
+
representer.property(:name).must_be_kind_of Representable::Definition
|
179
|
+
end
|
175
180
|
end
|
176
181
|
|
177
182
|
describe "#collection" do
|
@@ -242,36 +247,36 @@ class RepresentableTest < MiniTest::Spec
|
|
242
247
|
end
|
243
248
|
|
244
249
|
it "copies values from document to object" do
|
245
|
-
@band.
|
250
|
+
@band.from_hash({"name"=>"No One's Choice", "groupies"=>2})
|
246
251
|
assert_equal "No One's Choice", @band.name
|
247
252
|
assert_equal 2, @band.groupies
|
248
253
|
end
|
249
254
|
|
250
255
|
it "accepts :exclude option" do
|
251
|
-
@band.
|
256
|
+
@band.from_hash({"name"=>"No One's Choice", "groupies"=>2}, {:exclude => [:groupies]})
|
252
257
|
assert_equal "No One's Choice", @band.name
|
253
258
|
assert_equal nil, @band.groupies
|
254
259
|
end
|
255
260
|
|
256
261
|
it "accepts :include option" do
|
257
|
-
@band.
|
262
|
+
@band.from_hash({"name"=>"No One's Choice", "groupies"=>2}, :include => [:groupies])
|
258
263
|
assert_equal 2, @band.groupies
|
259
264
|
assert_equal nil, @band.name
|
260
265
|
end
|
261
266
|
|
262
267
|
it "ignores non-writeable properties" do
|
263
268
|
@band = Class.new(Band) { property :name; collection :founders, :writeable => false; attr_accessor :founders }.new
|
264
|
-
@band.
|
269
|
+
@band.from_hash("name" => "Iron Maiden", "groupies" => 2, "founders" => ["Steve Harris"])
|
265
270
|
assert_equal "Iron Maiden", @band.name
|
266
271
|
assert_equal nil, @band.founders
|
267
272
|
end
|
268
273
|
|
269
274
|
it "always returns the represented" do
|
270
|
-
assert_equal @band, @band.
|
275
|
+
assert_equal @band, @band.from_hash({"name"=>"Nofx"})
|
271
276
|
end
|
272
277
|
|
273
278
|
it "includes false attributes" do
|
274
|
-
@band.
|
279
|
+
@band.from_hash({"groupies"=>false})
|
275
280
|
assert_equal false, @band.groupies
|
276
281
|
end
|
277
282
|
|
@@ -279,14 +284,15 @@ class RepresentableTest < MiniTest::Spec
|
|
279
284
|
@band.instance_eval do
|
280
285
|
def name=(*); raise "I should never be called!"; end
|
281
286
|
end
|
282
|
-
@band.
|
287
|
+
@band.from_hash({})
|
283
288
|
end
|
284
289
|
|
290
|
+
# FIXME: do we need this test with XML _and_ JSON?
|
285
291
|
it "ignores (no-default) properties not present in the incoming document" do
|
286
|
-
{ Representable::
|
287
|
-
Representable::XML => [xml(%{<band/>})
|
292
|
+
{ Representable::Hash => [:from_hash, {}],
|
293
|
+
Representable::XML => [:from_xml, xml(%{<band/>}).to_s]
|
288
294
|
}.each do |format, config|
|
289
|
-
nested_repr = Module.new do # this module is never applied.
|
295
|
+
nested_repr = Module.new do # this module is never applied. # FIXME: can we make that a simpler test?
|
290
296
|
include format
|
291
297
|
property :created_at
|
292
298
|
end
|
@@ -297,7 +303,7 @@ class RepresentableTest < MiniTest::Spec
|
|
297
303
|
end
|
298
304
|
|
299
305
|
@band = Band.new.extend(repr)
|
300
|
-
@band.
|
306
|
+
@band.send(config.first, config.last)
|
301
307
|
assert_equal nil, @band.name, "Failed in #{format}"
|
302
308
|
end
|
303
309
|
end
|
@@ -348,16 +354,16 @@ class RepresentableTest < MiniTest::Spec
|
|
348
354
|
end
|
349
355
|
|
350
356
|
it "compiles document from properties in object" do
|
351
|
-
assert_equal({"name"=>"No One's Choice", "groupies"=>2}, @band.
|
357
|
+
assert_equal({"name"=>"No One's Choice", "groupies"=>2}, @band.to_hash)
|
352
358
|
end
|
353
359
|
|
354
360
|
it "accepts :exclude option" do
|
355
|
-
hash = @band.
|
361
|
+
hash = @band.to_hash({:exclude => [:groupies]})
|
356
362
|
assert_equal({"name"=>"No One's Choice"}, hash)
|
357
363
|
end
|
358
364
|
|
359
365
|
it "accepts :include option" do
|
360
|
-
hash = @band.
|
366
|
+
hash = @band.to_hash({:include => [:groupies]})
|
361
367
|
assert_equal({"groupies"=>2}, hash)
|
362
368
|
end
|
363
369
|
|
@@ -366,18 +372,18 @@ class RepresentableTest < MiniTest::Spec
|
|
366
372
|
@band.name = "Iron Maiden"
|
367
373
|
@band.founder_ids = [1,2,3]
|
368
374
|
|
369
|
-
hash = @band.
|
375
|
+
hash = @band.to_hash
|
370
376
|
assert_equal({"name" => "Iron Maiden"}, hash)
|
371
377
|
end
|
372
378
|
|
373
379
|
it "does not write nil attributes" do
|
374
380
|
@band.groupies = nil
|
375
|
-
assert_equal({"name"=>"No One's Choice"}, @band.
|
381
|
+
assert_equal({"name"=>"No One's Choice"}, @band.to_hash)
|
376
382
|
end
|
377
383
|
|
378
384
|
it "writes false attributes" do
|
379
385
|
@band.groupies = false
|
380
|
-
assert_equal({"name"=>"No One's Choice","groupies"=>false}, @band.
|
386
|
+
assert_equal({"name"=>"No One's Choice","groupies"=>false}, @band.to_hash)
|
381
387
|
end
|
382
388
|
|
383
389
|
describe "when :render_nil is true" do
|
@@ -390,7 +396,7 @@ class RepresentableTest < MiniTest::Spec
|
|
390
396
|
|
391
397
|
@band.extend(mod) # FIXME: use clean object.
|
392
398
|
@band.groupies = nil
|
393
|
-
hash = @band.
|
399
|
+
hash = @band.to_hash
|
394
400
|
assert_equal({"name"=>"No One's Choice", "groupies" => nil}, hash)
|
395
401
|
end
|
396
402
|
|
@@ -403,7 +409,7 @@ class RepresentableTest < MiniTest::Spec
|
|
403
409
|
|
404
410
|
@band.extend(mod) # FIXME: use clean object.
|
405
411
|
@band.groupies = nil
|
406
|
-
hash = @band.
|
412
|
+
hash = @band.to_hash
|
407
413
|
assert_equal({"name"=>"No One's Choice", "groupies" => nil}, hash)
|
408
414
|
end
|
409
415
|
end
|
@@ -422,6 +428,63 @@ class RepresentableTest < MiniTest::Spec
|
|
422
428
|
end
|
423
429
|
end
|
424
430
|
|
431
|
+
describe "inline representers" do
|
432
|
+
let (:song) { Song.new("Alive") }
|
433
|
+
let (:request) { representer.prepare(OpenStruct.new(:song => song)) }
|
434
|
+
|
435
|
+
{
|
436
|
+
:hash => [Representable::Hash, {"song"=>{"name"=>"Alive"}}, {"song"=>{"name"=>"You've Taken Everything"}}],
|
437
|
+
:json => [Representable::JSON, "{\"song\":{\"name\":\"Alive\"}}", "{\"song\":{\"name\":\"You've Taken Everything\"}}"],
|
438
|
+
:xml => [Representable::XML, "<open_struct>\n <song>\n <name>Alive</name>\n </song>\n</open_struct>", "<open_struct><song><name>You've Taken Everything</name></song>/open_struct>"],
|
439
|
+
:yaml => [Representable::YAML, "---\nsong:\n name: Alive\n", "---\nsong:\n name: You've Taken Everything\n"],
|
440
|
+
}.each do |format, cfg|
|
441
|
+
mod, output, input = cfg
|
442
|
+
|
443
|
+
describe "[#{format}] with :class" do
|
444
|
+
representer!(mod) do
|
445
|
+
property :song, :class => Song do
|
446
|
+
property :name
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
it { request.send("to_#{format}").must_equal output }
|
451
|
+
it { request.send("from_#{format}", input).song.name.must_equal "You've Taken Everything"}
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
describe "without :class" do
|
456
|
+
representer! do
|
457
|
+
property :song do
|
458
|
+
property :name
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
it { request.to_hash.must_equal({"song"=>{"name"=>"Alive"}}) }
|
463
|
+
end
|
464
|
+
|
465
|
+
describe "decorator" do
|
466
|
+
let (:representer) do
|
467
|
+
Class.new(Representable::Decorator) do
|
468
|
+
include Representable::Hash
|
469
|
+
|
470
|
+
property :song, :class => Song do
|
471
|
+
property :name
|
472
|
+
end
|
473
|
+
|
474
|
+
self
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
it { request.to_hash.must_equal({"song"=>{"name"=>"Alive"}}) }
|
479
|
+
it { request.from_hash({"song"=>{"name"=>"You've Taken Everything"}}).song.name.must_equal "You've Taken Everything"}
|
480
|
+
|
481
|
+
it "uses an inline decorator" do
|
482
|
+
request.to_hash
|
483
|
+
song.wont_be_kind_of Representable
|
484
|
+
end
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
425
488
|
describe ":if" do
|
426
489
|
before do
|
427
490
|
@pop = Class.new(PopBand) { attr_accessor :fame }
|
@@ -430,21 +493,21 @@ class RepresentableTest < MiniTest::Spec
|
|
430
493
|
it "respects property when condition true" do
|
431
494
|
@pop.class_eval { property :fame, :if => lambda { true } }
|
432
495
|
band = @pop.new
|
433
|
-
band.
|
496
|
+
band.from_hash({"fame"=>"oh yes"})
|
434
497
|
assert_equal "oh yes", band.fame
|
435
498
|
end
|
436
499
|
|
437
500
|
it "ignores property when condition false" do
|
438
501
|
@pop.class_eval { property :fame, :if => lambda { false } }
|
439
502
|
band = @pop.new
|
440
|
-
band.
|
503
|
+
band.from_hash({"fame"=>"oh yes"})
|
441
504
|
assert_equal nil, band.fame
|
442
505
|
end
|
443
506
|
|
444
507
|
it "ignores property when :exclude'ed even when condition is true" do
|
445
508
|
@pop.class_eval { property :fame, :if => lambda { true } }
|
446
509
|
band = @pop.new
|
447
|
-
band.
|
510
|
+
band.from_hash({"fame"=>"oh yes"}, {:exclude => [:fame]})
|
448
511
|
assert_equal nil, band.fame
|
449
512
|
end
|
450
513
|
|
@@ -452,7 +515,7 @@ class RepresentableTest < MiniTest::Spec
|
|
452
515
|
@pop.class_eval { property :fame, :if => lambda { groupies } }
|
453
516
|
band = @pop.new
|
454
517
|
band.groupies = true
|
455
|
-
band.
|
518
|
+
band.from_hash({"fame"=>"oh yes"})
|
456
519
|
assert_equal "oh yes", band.fame
|
457
520
|
end
|
458
521
|
|
@@ -793,11 +856,68 @@ class RepresentableTest < MiniTest::Spec
|
|
793
856
|
end
|
794
857
|
end
|
795
858
|
|
796
|
-
describe "clone" do
|
859
|
+
describe "#clone" do
|
797
860
|
it "clones all definitions" do
|
798
861
|
subject << Object.new
|
799
862
|
assert subject.first != subject.clone.first
|
800
863
|
end
|
801
864
|
end
|
865
|
+
|
866
|
+
describe "Config inheritance" do
|
867
|
+
# TODO: this section will soon be moved to uber.
|
868
|
+
describe "inheritance when including" do
|
869
|
+
# TODO: test all the below issues AND if cloning works.
|
870
|
+
module TestMethods
|
871
|
+
def representer_for(modules=[Representable], &block)
|
872
|
+
Module.new do
|
873
|
+
extend TestMethods
|
874
|
+
include *modules
|
875
|
+
module_exec(&block)
|
876
|
+
end
|
877
|
+
end
|
878
|
+
end
|
879
|
+
include TestMethods
|
880
|
+
|
881
|
+
it "inherits to uninitialized child" do
|
882
|
+
representer_for do # child
|
883
|
+
include(representer_for do # parent
|
884
|
+
representable_attrs.inheritable_array(:links) << "bar"
|
885
|
+
end)
|
886
|
+
end.representable_attrs.inheritable_array(:links).must_equal(["bar"])
|
887
|
+
end
|
888
|
+
|
889
|
+
it "works with uninitialized parent" do
|
890
|
+
representer_for do # child
|
891
|
+
representable_attrs.inheritable_array(:links) << "bar"
|
892
|
+
|
893
|
+
include(representer_for do # parent
|
894
|
+
end)
|
895
|
+
end.representable_attrs.inheritable_array(:links).must_equal(["bar"])
|
896
|
+
end
|
897
|
+
|
898
|
+
it "inherits when both are initialized" do
|
899
|
+
representer_for do # child
|
900
|
+
representable_attrs.inheritable_array(:links) << "bar"
|
901
|
+
|
902
|
+
include(representer_for do # parent
|
903
|
+
representable_attrs.inheritable_array(:links) << "stadium"
|
904
|
+
end)
|
905
|
+
end.representable_attrs.inheritable_array(:links).must_equal(["bar", "stadium"])
|
906
|
+
end
|
907
|
+
|
908
|
+
it "clones parent inheritables" do # FIXME: actually we don't clone here!
|
909
|
+
representer_for do # child
|
910
|
+
representable_attrs.inheritable_array(:links) << "bar"
|
911
|
+
|
912
|
+
include(parent = representer_for do # parent
|
913
|
+
representable_attrs.inheritable_array(:links) << "stadium"
|
914
|
+
end)
|
915
|
+
|
916
|
+
parent.representable_attrs.inheritable_array(:links) << "park" # modify parent array.
|
917
|
+
|
918
|
+
end.representable_attrs.inheritable_array(:links).must_equal(["bar", "stadium"])
|
919
|
+
end
|
920
|
+
end
|
921
|
+
end
|
802
922
|
end
|
803
923
|
end
|