representable 2.4.0.rc3 → 2.4.0.rc4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +7 -2
- data/Rakefile +6 -0
- data/lib/representable.rb +21 -17
- data/lib/representable/binding.rb +3 -2
- data/lib/representable/definition.rb +1 -1
- data/lib/representable/deprecations.rb +31 -5
- data/lib/representable/deserializer.rb +24 -34
- data/lib/representable/hash/collection.rb +9 -2
- data/lib/representable/hash_methods.rb +2 -2
- data/lib/representable/parse_strategies.rb +6 -7
- data/lib/representable/pipeline.rb +12 -1
- data/lib/representable/pipeline_factories.rb +9 -2
- data/lib/representable/serializer.rb +3 -3
- data/lib/representable/version.rb +1 -1
- data/test-with-deprecations/as_test.rb +65 -0
- data/test-with-deprecations/benchmarking.rb +83 -0
- data/test-with-deprecations/binding_test.rb +46 -0
- data/test-with-deprecations/blaaaaaaaa_test.rb +69 -0
- data/test-with-deprecations/cached_test.rb +147 -0
- data/test-with-deprecations/class_test.rb +119 -0
- data/test-with-deprecations/coercion_test.rb +52 -0
- data/test-with-deprecations/config/inherit_test.rb +135 -0
- data/test-with-deprecations/config_test.rb +122 -0
- data/test-with-deprecations/decorator_scope_test.rb +28 -0
- data/test-with-deprecations/decorator_test.rb +96 -0
- data/test-with-deprecations/default_test.rb +34 -0
- data/test-with-deprecations/defaults_options_test.rb +93 -0
- data/test-with-deprecations/definition_test.rb +264 -0
- data/test-with-deprecations/example.rb +310 -0
- data/test-with-deprecations/examples/object.rb +31 -0
- data/test-with-deprecations/exec_context_test.rb +93 -0
- data/test-with-deprecations/features_test.rb +70 -0
- data/test-with-deprecations/filter_test.rb +57 -0
- data/test-with-deprecations/for_collection_test.rb +74 -0
- data/test-with-deprecations/generic_test.rb +116 -0
- data/test-with-deprecations/getter_setter_test.rb +21 -0
- data/test-with-deprecations/hash_bindings_test.rb +87 -0
- data/test-with-deprecations/hash_test.rb +160 -0
- data/test-with-deprecations/heritage_test.rb +62 -0
- data/test-with-deprecations/if_test.rb +79 -0
- data/test-with-deprecations/include_exclude_test.rb +88 -0
- data/test-with-deprecations/inherit_test.rb +159 -0
- data/test-with-deprecations/inline_test.rb +272 -0
- data/test-with-deprecations/instance_test.rb +266 -0
- data/test-with-deprecations/is_representable_test.rb +77 -0
- data/test-with-deprecations/json_test.rb +355 -0
- data/test-with-deprecations/lonely_test.rb +239 -0
- data/test-with-deprecations/mongoid_test.rb +31 -0
- data/test-with-deprecations/nested_test.rb +115 -0
- data/test-with-deprecations/object_test.rb +60 -0
- data/{test/---deserialize-pipeline_test.rb → test-with-deprecations/parse_pipeline_test.rb} +29 -2
- data/test-with-deprecations/parse_strategy_test.rb +279 -0
- data/{test → test-with-deprecations}/pass_options_test.rb +0 -0
- data/test-with-deprecations/pipeline_test.rb +277 -0
- data/test-with-deprecations/populator_test.rb +105 -0
- data/test-with-deprecations/prepare_test.rb +67 -0
- data/test-with-deprecations/private_options_test.rb +18 -0
- data/test-with-deprecations/reader_writer_test.rb +19 -0
- data/test-with-deprecations/realistic_benchmark.rb +115 -0
- data/test-with-deprecations/render_nil_test.rb +21 -0
- data/test-with-deprecations/represent_test.rb +88 -0
- data/test-with-deprecations/representable_test.rb +511 -0
- data/test-with-deprecations/schema_test.rb +148 -0
- data/test-with-deprecations/serialize_deserialize_test.rb +33 -0
- data/test-with-deprecations/skip_test.rb +81 -0
- data/test-with-deprecations/stringify_hash_test.rb +41 -0
- data/test-with-deprecations/test_helper.rb +135 -0
- data/test-with-deprecations/test_helper_test.rb +25 -0
- data/test-with-deprecations/uncategorized_test.rb +67 -0
- data/test-with-deprecations/user_options_test.rb +15 -0
- data/test-with-deprecations/wrap_test.rb +152 -0
- data/test-with-deprecations/xml_bindings_test.rb +62 -0
- data/test-with-deprecations/xml_test.rb +503 -0
- data/test-with-deprecations/yaml_test.rb +162 -0
- data/test/as_test.rb +3 -3
- data/test/cached_test.rb +2 -2
- data/test/class_test.rb +5 -5
- data/test/exec_context_test.rb +2 -2
- data/test/filter_test.rb +1 -1
- data/test/getter_setter_test.rb +4 -4
- data/test/if_test.rb +2 -2
- data/test/include_exclude_test.rb +88 -0
- data/test/instance_test.rb +15 -15
- data/test/lonely_test.rb +18 -2
- data/test/object_test.rb +4 -4
- data/test/parse_pipeline_test.rb +64 -0
- data/test/parse_strategy_test.rb +3 -3
- data/test/pipeline_test.rb +8 -12
- data/test/prepare_test.rb +2 -3
- data/test/reader_writer_test.rb +3 -3
- data/test/representable_test.rb +12 -48
- data/test/serialize_deserialize_test.rb +9 -9
- data/test/skip_test.rb +11 -11
- data/test/test_helper.rb +2 -0
- data/test/uncategorized_test.rb +10 -10
- data/test/user_options_test.rb +15 -0
- data/test/wrap_test.rb +1 -1
- metadata +65 -4
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'representable/coercion'
|
3
|
+
|
4
|
+
class VirtusCoercionTest < MiniTest::Spec
|
5
|
+
representer! do
|
6
|
+
include Representable::Coercion
|
7
|
+
|
8
|
+
property :title # no coercion.
|
9
|
+
property :length, :type => Float
|
10
|
+
|
11
|
+
property :band, :class => OpenStruct do
|
12
|
+
property :founded, :type => Integer
|
13
|
+
end
|
14
|
+
|
15
|
+
collection :songs, :class => OpenStruct do
|
16
|
+
property :ok, :type => Virtus::Attribute::Boolean
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
let (:album) { OpenStruct.new(:title => "Dire Straits", :length => 41.34,
|
21
|
+
:band => OpenStruct.new(:founded => "1977"),
|
22
|
+
:songs => [OpenStruct.new(:ok => 1), OpenStruct.new(:ok => 0)]) }
|
23
|
+
|
24
|
+
it { album.extend(representer).to_hash.must_equal({"title"=>"Dire Straits", "length"=>41.34, "band"=>{"founded"=>1977}, "songs"=>[{"ok"=>true}, {"ok"=>false}]}) }
|
25
|
+
|
26
|
+
it {
|
27
|
+
album = OpenStruct.new
|
28
|
+
album.extend(representer)
|
29
|
+
album.from_hash({"title"=>"Dire Straits", "length"=>"41.34", "band"=>{"founded"=>"1977"}, "songs"=>[{"ok"=>1}, {"ok"=>0}]})
|
30
|
+
|
31
|
+
# it
|
32
|
+
album.length.must_equal 41.34
|
33
|
+
album.band.founded.must_equal 1977
|
34
|
+
album.songs[0].ok.must_equal true
|
35
|
+
}
|
36
|
+
|
37
|
+
|
38
|
+
describe "with user :parse_filter and :render_filter" do
|
39
|
+
representer! do
|
40
|
+
include Representable::Coercion
|
41
|
+
|
42
|
+
property :length, :type => Float,
|
43
|
+
:parse_filter => lambda { |input, options| "#{input}.1" }, # happens BEFORE coercer.
|
44
|
+
:render_filter => lambda { |fragment,*| "#{fragment}.1" }
|
45
|
+
end
|
46
|
+
|
47
|
+
# user's :parse_filter(s) are run before coercion.
|
48
|
+
it { OpenStruct.new.extend(representer).from_hash("length"=>"1").length.must_equal 1.1 }
|
49
|
+
# user's :render_filter(s) are run before coercion.
|
50
|
+
it { OpenStruct.new(:length=>1).extend(representer).to_hash.must_equal({"length" => 1.1}) }
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# tests defining representers in modules, decorators and classes and the inheritance when combined.
|
4
|
+
|
5
|
+
class ConfigInheritTest < MiniTest::Spec
|
6
|
+
def assert_cloned(child, parent, property)
|
7
|
+
child_def = child.representable_attrs.get(property)
|
8
|
+
parent_def = parent.representable_attrs.get(property)
|
9
|
+
|
10
|
+
child_def.merge!(:alias => property)
|
11
|
+
|
12
|
+
child_def[:alias].wont_equal parent_def[:alias]
|
13
|
+
child_def.object_id.wont_equal parent_def.object_id
|
14
|
+
end
|
15
|
+
# class Object
|
16
|
+
|
17
|
+
# end
|
18
|
+
module GenreModule
|
19
|
+
include Representable::Hash
|
20
|
+
property :genre
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# in Decorator ------------------------------------------------
|
25
|
+
class Decorator < Representable::Decorator
|
26
|
+
include Representable::Hash
|
27
|
+
property :title
|
28
|
+
property :artist do
|
29
|
+
property :id
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it { Decorator.definitions.keys.must_equal ["title", "artist"] }
|
34
|
+
|
35
|
+
# in inheriting Decorator
|
36
|
+
|
37
|
+
class InheritingDecorator < Decorator
|
38
|
+
property :location
|
39
|
+
end
|
40
|
+
|
41
|
+
it { InheritingDecorator.definitions.keys.must_equal ["title", "artist", "location"] }
|
42
|
+
it { assert_cloned(InheritingDecorator, Decorator, "title") }
|
43
|
+
it do
|
44
|
+
InheritingDecorator.representable_attrs.get(:artist).representer_module.object_id.wont_equal Decorator.representable_attrs.get(:artist).representer_module.object_id
|
45
|
+
end
|
46
|
+
|
47
|
+
# in inheriting and including Decorator
|
48
|
+
|
49
|
+
class InheritingAndIncludingDecorator < Decorator
|
50
|
+
include GenreModule
|
51
|
+
property :location
|
52
|
+
end
|
53
|
+
|
54
|
+
it { InheritingAndIncludingDecorator.definitions.keys.must_equal ["title", "artist", "genre", "location"] }
|
55
|
+
it { assert_cloned(InheritingAndIncludingDecorator, GenreModule, :genre) }
|
56
|
+
|
57
|
+
|
58
|
+
# in module ---------------------------------------------------
|
59
|
+
module Module
|
60
|
+
include Representable
|
61
|
+
property :title
|
62
|
+
end
|
63
|
+
|
64
|
+
it { Module.definitions.keys.must_equal ["title"] }
|
65
|
+
|
66
|
+
|
67
|
+
# in module including module
|
68
|
+
module SubModule
|
69
|
+
include Representable
|
70
|
+
include Module
|
71
|
+
|
72
|
+
property :location
|
73
|
+
end
|
74
|
+
|
75
|
+
it { SubModule.definitions.keys.must_equal ["title", "location"] }
|
76
|
+
it { assert_cloned(SubModule, Module, :title) }
|
77
|
+
|
78
|
+
# including preserves order
|
79
|
+
module IncludingModule
|
80
|
+
include Representable
|
81
|
+
property :genre
|
82
|
+
include Module
|
83
|
+
|
84
|
+
property :location
|
85
|
+
end
|
86
|
+
|
87
|
+
it { IncludingModule.definitions.keys.must_equal ["genre", "title", "location"] }
|
88
|
+
|
89
|
+
|
90
|
+
# included in class -------------------------------------------
|
91
|
+
class Class
|
92
|
+
include Representable
|
93
|
+
include IncludingModule
|
94
|
+
end
|
95
|
+
|
96
|
+
it { Class.definitions.keys.must_equal ["genre", "title", "location"] }
|
97
|
+
it { assert_cloned(Class, IncludingModule, :title) }
|
98
|
+
it { assert_cloned(Class, IncludingModule, :location) }
|
99
|
+
it { assert_cloned(Class, IncludingModule, :genre) }
|
100
|
+
|
101
|
+
# included in class with order
|
102
|
+
class DefiningClass
|
103
|
+
include Representable
|
104
|
+
property :street_cred
|
105
|
+
include IncludingModule
|
106
|
+
end
|
107
|
+
|
108
|
+
it { DefiningClass.definitions.keys.must_equal ["street_cred", "genre", "title", "location"] }
|
109
|
+
|
110
|
+
# in class
|
111
|
+
class RepresenterClass
|
112
|
+
include Representable
|
113
|
+
property :title
|
114
|
+
end
|
115
|
+
|
116
|
+
it { RepresenterClass.definitions.keys.must_equal ["title"] }
|
117
|
+
|
118
|
+
|
119
|
+
# in inheriting class
|
120
|
+
class InheritingClass < RepresenterClass
|
121
|
+
include Representable
|
122
|
+
property :location
|
123
|
+
end
|
124
|
+
|
125
|
+
it { InheritingClass.definitions.keys.must_equal ["title", "location"] }
|
126
|
+
it { assert_cloned(InheritingClass, RepresenterClass, :title) }
|
127
|
+
|
128
|
+
# in inheriting class and including
|
129
|
+
class InheritingAndIncludingClass < RepresenterClass
|
130
|
+
property :location
|
131
|
+
include GenreModule
|
132
|
+
end
|
133
|
+
|
134
|
+
it { InheritingAndIncludingClass.definitions.keys.must_equal ["title", "location", "genre"] }
|
135
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ConfigTest < MiniTest::Spec
|
4
|
+
subject { Representable::Config.new(Representable::Definition) }
|
5
|
+
PunkRock = Class.new
|
6
|
+
Definition = Representable::Definition
|
7
|
+
|
8
|
+
describe "wrapping" do
|
9
|
+
it "returns false per default" do
|
10
|
+
assert_equal nil, subject.wrap_for("Punk", nil)
|
11
|
+
end
|
12
|
+
|
13
|
+
# it "infers a printable class name if set to true" do
|
14
|
+
# subject.wrap = true
|
15
|
+
# assert_equal "punk_rock", subject.wrap_for(PunkRock, nil)
|
16
|
+
# end
|
17
|
+
|
18
|
+
# it "can be set explicitely" do
|
19
|
+
# subject.wrap = "Descendents"
|
20
|
+
# assert_equal "Descendents", subject.wrap_for(PunkRock, nil)
|
21
|
+
# end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#[]" do
|
25
|
+
# does return nil for non-existent
|
26
|
+
it { subject[:hello].must_equal nil }
|
27
|
+
end
|
28
|
+
|
29
|
+
# describe "#[]" do
|
30
|
+
# before { subject.add(:title, {:me => true}) }
|
31
|
+
|
32
|
+
# it { subject[:unknown].must_equal nil }
|
33
|
+
# it { subject.get(:title)[:me].must_equal true }
|
34
|
+
# it { subject["title"][:me].must_equal true }
|
35
|
+
# end
|
36
|
+
|
37
|
+
# []=
|
38
|
+
# []=(... inherit: true)
|
39
|
+
# forwarded to Config#definitions
|
40
|
+
# that goes to ConfigDefinitionsTest
|
41
|
+
describe "#add" do
|
42
|
+
describe "returns" do
|
43
|
+
it do
|
44
|
+
# #add returns Definition.`
|
45
|
+
subject = Representable::Config.new(Representable::Definition).add(:title, {:me => true})
|
46
|
+
|
47
|
+
subject.must_be_kind_of Representable::Definition
|
48
|
+
subject[:me].must_equal true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
before { subject.add(:title, {:me => true}) }
|
53
|
+
|
54
|
+
# must be kind of Definition
|
55
|
+
it { subject.size.must_equal 1 }
|
56
|
+
it { subject.get(:title).name.must_equal "title" }
|
57
|
+
it { subject.get(:title)[:me].must_equal true }
|
58
|
+
|
59
|
+
# this is actually tested in context in inherit_test.
|
60
|
+
it "overrides former definition" do
|
61
|
+
subject.add(:title, {:peer => Module})
|
62
|
+
subject.get(:title)[:me].must_equal nil
|
63
|
+
subject.get(:title)[:peer].must_equal Module
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "inherit: true" do
|
67
|
+
before {
|
68
|
+
subject.add(:title, {:me => true})
|
69
|
+
subject.add(:title, {:peer => Module, :inherit => true})
|
70
|
+
}
|
71
|
+
|
72
|
+
it { subject.get(:title)[:me].must_equal true }
|
73
|
+
it { subject.get(:title)[:peer].must_equal Module }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
describe "#remove" do
|
79
|
+
subject { Representable::Config.new(Representable::Definition) }
|
80
|
+
|
81
|
+
it do
|
82
|
+
subject.add(:title, {:me => true})
|
83
|
+
subject.add(:genre, {})
|
84
|
+
subject.get(:genre).must_be_kind_of Representable::Definition
|
85
|
+
|
86
|
+
subject.remove(:genre)
|
87
|
+
subject.get(:genre).must_equal nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
describe "#each" do
|
93
|
+
before { subject.add(:title, {:me => true}) }
|
94
|
+
|
95
|
+
it "what" do
|
96
|
+
definitions = []
|
97
|
+
subject.each { |dfn| definitions << dfn }
|
98
|
+
definitions.size.must_equal 1
|
99
|
+
definitions[0][:me].must_equal true
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#options" do
|
104
|
+
it { subject.options.must_equal({}) }
|
105
|
+
it do
|
106
|
+
subject.options[:namespacing] = true
|
107
|
+
subject.options[:namespacing].must_equal true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "#get" do
|
112
|
+
subject { Representable::Config.new(Representable::Definition) }
|
113
|
+
|
114
|
+
it do
|
115
|
+
title = subject.add(:title, {})
|
116
|
+
length = subject.add(:length, {})
|
117
|
+
|
118
|
+
subject.get(:title).must_equal title
|
119
|
+
subject.get(:length).must_equal length
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# TODO: remove in 2.0.
|
4
|
+
class DecoratorScopeTest < MiniTest::Spec
|
5
|
+
representer! do
|
6
|
+
property :title, :getter => lambda { |*| title_from_representer }, :decorator_scope => true
|
7
|
+
end
|
8
|
+
|
9
|
+
let (:representer_with_method) {
|
10
|
+
Module.new do
|
11
|
+
include Representable::Hash
|
12
|
+
property :title, :decorator_scope => true
|
13
|
+
def title; "Crystal Planet"; end
|
14
|
+
end
|
15
|
+
}
|
16
|
+
|
17
|
+
it "executes lambdas in represented context" do
|
18
|
+
Class.new do
|
19
|
+
def title_from_representer
|
20
|
+
"Sounds Of Silence"
|
21
|
+
end
|
22
|
+
end.new.extend(representer).to_hash.must_equal({"title"=>"Sounds Of Silence"})
|
23
|
+
end
|
24
|
+
|
25
|
+
it "executes method in represented context" do
|
26
|
+
Object.new.extend(representer_with_method).to_hash.must_equal({"title"=>"Crystal Planet"})
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DecoratorTest < MiniTest::Spec
|
4
|
+
class SongRepresentation < Representable::Decorator
|
5
|
+
include Representable::JSON
|
6
|
+
property :name
|
7
|
+
end
|
8
|
+
|
9
|
+
class AlbumRepresentation < Representable::Decorator
|
10
|
+
include Representable::JSON
|
11
|
+
|
12
|
+
collection :songs, :class => Song, :extend => SongRepresentation
|
13
|
+
end
|
14
|
+
|
15
|
+
let (:song) { Song.new("Mama, I'm Coming Home") }
|
16
|
+
let (:album) { Album.new([song]) }
|
17
|
+
|
18
|
+
describe "inheritance" do
|
19
|
+
let (:inherited_decorator) do
|
20
|
+
Class.new(AlbumRepresentation) do
|
21
|
+
property :best_song
|
22
|
+
end.new(Album.new([song], "Stand Up"))
|
23
|
+
end
|
24
|
+
|
25
|
+
it { inherited_decorator.to_hash.must_equal({"songs"=>[{"name"=>"Mama, I'm Coming Home"}], "best_song"=>"Stand Up"}) }
|
26
|
+
end
|
27
|
+
|
28
|
+
let (:decorator) { AlbumRepresentation.new(album) }
|
29
|
+
|
30
|
+
it "renders" do
|
31
|
+
decorator.to_hash.must_equal({"songs"=>[{"name"=>"Mama, I'm Coming Home"}]})
|
32
|
+
album.wont_respond_to :to_hash
|
33
|
+
song.wont_respond_to :to_hash # DISCUSS: weak test, how to assert blank slate?
|
34
|
+
# no @representable_attrs in decorated objects
|
35
|
+
song.instance_variable_get(:@representable_attrs).must_equal nil
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#from_hash" do
|
39
|
+
it "returns represented" do
|
40
|
+
decorator.from_hash({"songs"=>[{"name"=>"Mama, I'm Coming Home"}]}).must_equal album
|
41
|
+
end
|
42
|
+
|
43
|
+
it "parses" do
|
44
|
+
decorator.from_hash({"songs"=>[{"name"=>"Atomic Garden"}]})
|
45
|
+
album.songs.first.must_be_kind_of Song
|
46
|
+
album.songs.must_equal [Song.new("Atomic Garden")]
|
47
|
+
album.wont_respond_to :to_hash
|
48
|
+
song.wont_respond_to :to_hash # DISCUSS: weak test, how to assert blank slate?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "#decorated" do
|
53
|
+
it "is aliased to #represented" do
|
54
|
+
AlbumRepresentation.prepare(album).decorated.must_equal album
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
describe "inline decorators" do
|
60
|
+
representer!(decorator: true) do
|
61
|
+
collection :songs, :class => Song do
|
62
|
+
property :name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it "does not pollute represented" do
|
67
|
+
representer.new(album).from_hash({"songs"=>[{"name"=>"Atomic Garden"}]})
|
68
|
+
|
69
|
+
# no @representable_attrs in decorated objects
|
70
|
+
song.instance_variable_get(:@representable_attrs).must_equal nil
|
71
|
+
album.instance_variable_get(:@representable_attrs).must_equal nil
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
require "uber/inheritable_attr"
|
77
|
+
class InheritanceWithDecoratorTest < MiniTest::Spec
|
78
|
+
class Twin
|
79
|
+
extend Uber::InheritableAttr
|
80
|
+
inheritable_attr :representer_class
|
81
|
+
self.representer_class = Class.new(Representable::Decorator){ include Representable::Hash }
|
82
|
+
end
|
83
|
+
|
84
|
+
class Album < Twin
|
85
|
+
representer_class.property :title # Twin.representer_class.clone
|
86
|
+
end
|
87
|
+
|
88
|
+
class Song < Twin # Twin.representer_class.clone
|
89
|
+
end
|
90
|
+
|
91
|
+
it do
|
92
|
+
Twin.representer_class.definitions.size.must_equal 0
|
93
|
+
Album.representer_class.definitions.size.must_equal 1
|
94
|
+
Song.representer_class.definitions.size.must_equal 0
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class DefaultTest < MiniTest::Spec
|
4
|
+
Song = Struct.new(:id, :title)
|
5
|
+
|
6
|
+
representer! do
|
7
|
+
property :id
|
8
|
+
property :title, default: "Huber Breeze" #->(options) { options[:default] }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#from_hash" do
|
12
|
+
let (:song) { Song.new.extend(representer) }
|
13
|
+
|
14
|
+
it { song.from_hash({}).must_equal Song.new(nil, "Huber Breeze") }
|
15
|
+
# default doesn't apply when empty string.
|
16
|
+
it { song.from_hash({"title"=>""}).must_equal Song.new(nil, "") }
|
17
|
+
it { song.from_hash({"title"=>nil}).must_equal Song.new(nil, nil) }
|
18
|
+
it { song.from_hash({"title"=>"Blindfold"}).must_equal Song.new(nil, "Blindfold") }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#to_json" do
|
22
|
+
it "uses :default when not available from object" do
|
23
|
+
Song.new.extend(representer).to_hash.must_equal({"title"=>"Huber Breeze"})
|
24
|
+
end
|
25
|
+
|
26
|
+
it "uses value from represented object when present" do
|
27
|
+
Song.new(nil, "After The War").extend(representer).to_hash.must_equal({"title"=>"After The War"})
|
28
|
+
end
|
29
|
+
|
30
|
+
it "uses value from represented object when emtpy string" do
|
31
|
+
Song.new(nil, "").extend(representer).to_hash.must_equal({"title"=>""})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|