representable 3.2.0 → 3.3.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +17 -10
- data/.github/workflows/ci_jruby.yml +21 -0
- data/.github/workflows/ci_truffleruby.yml +19 -0
- data/CHANGES.md +5 -0
- data/Gemfile +1 -1
- data/README.md +0 -1
- data/lib/representable/hash/binding.rb +1 -0
- data/lib/representable/json.rb +14 -2
- data/lib/representable/version.rb +1 -1
- data/lib/representable/xml/binding.rb +0 -7
- data/lib/representable/xml.rb +7 -0
- data/representable.gemspec +1 -3
- data/test/as_test.rb +8 -13
- data/test/benchmarking.rb +20 -25
- data/test/binding_test.rb +13 -5
- data/test/cached_test.rb +55 -35
- data/test/class_test.rb +46 -33
- data/test/coercion_test.rb +29 -19
- data/test/config/inherit_test.rb +12 -17
- data/test/config_test.rb +5 -7
- data/test/decorator_scope_test.rb +13 -11
- data/test/decorator_test.rb +11 -11
- data/test/default_test.rb +2 -2
- data/test/defaults_options_test.rb +37 -9
- data/test/definition_test.rb +10 -12
- data/test/examples/example.rb +43 -38
- data/test/examples/object.rb +7 -6
- data/test/exec_context_test.rb +18 -23
- data/test/features_test.rb +29 -10
- data/test/filter_test.rb +29 -20
- data/test/for_collection_test.rb +12 -15
- data/test/generic_test.rb +15 -22
- data/test/getter_setter_test.rb +11 -6
- data/test/hash_bindings_test.rb +21 -12
- data/test/hash_test.rb +53 -38
- data/test/heritage_test.rb +0 -1
- data/test/if_test.rb +25 -21
- data/test/include_exclude_test.rb +24 -16
- data/test/inherit_test.rb +114 -27
- data/test/inline_test.rb +42 -33
- data/test/instance_test.rb +151 -109
- data/test/is_representable_test.rb +19 -17
- data/test/json_test.rb +48 -46
- data/test/lonely_test.rb +35 -33
- data/test/nested_test.rb +16 -19
- data/test/object_test.rb +6 -6
- data/test/option_test.rb +10 -8
- data/test/parse_pipeline_test.rb +21 -15
- data/test/pipeline_test.rb +144 -108
- data/test/populator_test.rb +18 -15
- data/test/prepare_test.rb +15 -17
- data/test/private_options_test.rb +3 -2
- data/test/reader_writer_test.rb +4 -4
- data/test/realistic_benchmark.rb +21 -27
- data/test/render_nil_test.rb +1 -1
- data/test/represent_test.rb +14 -18
- data/test/representable_test.rb +86 -53
- data/test/schema_test.rb +51 -21
- data/test/serialize_deserialize_test.rb +14 -14
- data/test/skip_test.rb +39 -28
- data/test/stringify_hash_test.rb +29 -31
- data/test/test_helper.rb +31 -25
- data/test/test_helper_test.rb +7 -7
- data/test/uncategorized_test.rb +20 -15
- data/test/user_options_test.rb +12 -3
- data/test/wrap_test.rb +27 -17
- data/test/xml_assertions.rb +29 -0
- data/test/xml_bindings_test.rb +5 -8
- data/test/xml_namespace_test.rb +46 -39
- data/test/xml_test.rb +109 -88
- data/test/yaml_test.rb +73 -51
- metadata +7 -32
data/test/for_collection_test.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
|
-
class ForCollectionTest <
|
|
3
|
+
class ForCollectionTest < Minitest::Spec
|
|
4
4
|
module SongRepresenter
|
|
5
5
|
include Representable::JSON
|
|
6
6
|
|
|
@@ -10,28 +10,26 @@ class ForCollectionTest < MiniTest::Spec
|
|
|
10
10
|
let(:songs) { [Song.new("Days Go By"), Song.new("Can't Take Them All")] }
|
|
11
11
|
let(:json) { "[{\"name\":\"Days Go By\"},{\"name\":\"Can't Take Them All\"}]" }
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
# Module.for_collection
|
|
15
14
|
# Decorator.for_collection
|
|
16
15
|
for_formats(
|
|
17
|
-
:hash => [Representable::Hash, out=[{"name" => "Days Go By"}, {"name"=>"Can't Take Them All"}], out],
|
|
18
|
-
:json => [Representable::JSON, out="[{\"name\":\"Days Go By\"},{\"name\":\"Can't Take Them All\"}]", out]
|
|
16
|
+
:hash => [Representable::Hash, out = [{"name" => "Days Go By"}, {"name"=>"Can't Take Them All"}], out],
|
|
17
|
+
:json => [Representable::JSON, out = "[{\"name\":\"Days Go By\"},{\"name\":\"Can't Take Them All\"}]", out]
|
|
19
18
|
# :xml => [Representable::XML, out="<a><song></song><song></song></a>", out]
|
|
20
19
|
) do |format, mod, output, input|
|
|
21
|
-
|
|
22
20
|
describe "Module::for_collection [#{format}]" do
|
|
23
21
|
let(:format) { format }
|
|
24
22
|
|
|
25
|
-
let(:representer)
|
|
23
|
+
let(:representer) do
|
|
26
24
|
Module.new do
|
|
27
25
|
include mod
|
|
28
|
-
property :name
|
|
26
|
+
property :name # , :as => :title
|
|
29
27
|
|
|
30
28
|
collection_representer :class => Song
|
|
31
29
|
|
|
32
30
|
# self.representation_wrap = :songs if format == :xml
|
|
33
31
|
end
|
|
34
|
-
|
|
32
|
+
end
|
|
35
33
|
|
|
36
34
|
it { render(songs.extend(representer.for_collection)).must_equal_document output }
|
|
37
35
|
it { render(representer.for_collection.prepare(songs)).must_equal_document output }
|
|
@@ -42,28 +40,27 @@ class ForCollectionTest < MiniTest::Spec
|
|
|
42
40
|
describe "Module::for_collection without configuration [#{format}]" do
|
|
43
41
|
let(:format) { format }
|
|
44
42
|
|
|
45
|
-
let(:representer)
|
|
43
|
+
let(:representer) do
|
|
46
44
|
Module.new do
|
|
47
45
|
include mod
|
|
48
46
|
property :name
|
|
49
47
|
end
|
|
50
|
-
|
|
48
|
+
end
|
|
51
49
|
|
|
52
50
|
# rendering works out of the box, no config necessary
|
|
53
51
|
it { render(songs.extend(representer.for_collection)).must_equal_document output }
|
|
54
52
|
end
|
|
55
53
|
|
|
56
|
-
|
|
57
54
|
describe "Decorator::for_collection [#{format}]" do
|
|
58
55
|
let(:format) { format }
|
|
59
|
-
let(:representer)
|
|
56
|
+
let(:representer) do
|
|
60
57
|
Class.new(Representable::Decorator) do
|
|
61
58
|
include mod
|
|
62
59
|
property :name
|
|
63
60
|
|
|
64
61
|
collection_representer :class => Song
|
|
65
62
|
end
|
|
66
|
-
|
|
63
|
+
end
|
|
67
64
|
|
|
68
65
|
it { render(representer.for_collection.new(songs)).must_equal_document output }
|
|
69
66
|
it { _(parse(representer.for_collection.new([]), input)).must_equal songs }
|
|
@@ -71,4 +68,4 @@ class ForCollectionTest < MiniTest::Spec
|
|
|
71
68
|
end
|
|
72
69
|
|
|
73
70
|
# with module including module
|
|
74
|
-
end
|
|
71
|
+
end
|
data/test/generic_test.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
# TODO: rename/restructure to CollectionTest.
|
|
4
|
+
class GenericTest < Minitest::Spec
|
|
4
5
|
let(:new_album) { OpenStruct.new.extend(representer) }
|
|
5
6
|
let(:album) { OpenStruct.new(:songs => ["Fuck Armageddon"]).extend(representer) }
|
|
6
7
|
let(:song) { OpenStruct.new(:title => "Resist Stance") }
|
|
7
|
-
let(:song_representer) { Module.new
|
|
8
|
-
|
|
8
|
+
let(:song_representer) { Module.new { include Representable::Hash; property :title } }
|
|
9
9
|
|
|
10
10
|
describe "::collection" do
|
|
11
11
|
representer! do
|
|
@@ -23,14 +23,12 @@ class GenericTest < MiniTest::Spec # TODO: rename/restructure to CollectionTest.
|
|
|
23
23
|
_(album.songs).must_equal ["Fuck Armageddon"] # when the collection is not present in the incoming hash, this propery stays untouched.
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
|
|
27
26
|
# when collection is nil, it doesn't get rendered:
|
|
28
27
|
for_formats(
|
|
29
28
|
:hash => [Representable::Hash, {}],
|
|
30
|
-
:xml => [Representable::XML, "<
|
|
31
|
-
:yaml => [Representable::YAML, "--- {}\n"]
|
|
32
|
-
) do |format, mod, output,
|
|
33
|
-
|
|
29
|
+
:xml => [Representable::XML, "<album></album>"],
|
|
30
|
+
:yaml => [Representable::YAML, "--- {}\n"] # FIXME: this doesn't look right.
|
|
31
|
+
) do |format, mod, output, _input|
|
|
34
32
|
describe "nil collections" do
|
|
35
33
|
let(:format) { format }
|
|
36
34
|
|
|
@@ -50,10 +48,9 @@ class GenericTest < MiniTest::Spec # TODO: rename/restructure to CollectionTest.
|
|
|
50
48
|
# when collection is set but empty, render the empty collection.
|
|
51
49
|
for_formats(
|
|
52
50
|
:hash => [Representable::Hash, {"songs" => []}],
|
|
53
|
-
|
|
54
|
-
:yaml => [Representable::YAML, "---\nsongs: []\n"]
|
|
55
|
-
) do |format, mod, output,
|
|
56
|
-
|
|
51
|
+
# :xml => [Representable::XML, "<open_struct><songs/></open_struct>"],
|
|
52
|
+
:yaml => [Representable::YAML, "---\nsongs: []\n"]
|
|
53
|
+
) do |format, mod, output, _input|
|
|
57
54
|
describe "empty collections" do
|
|
58
55
|
let(:format) { format }
|
|
59
56
|
|
|
@@ -70,14 +67,12 @@ class GenericTest < MiniTest::Spec # TODO: rename/restructure to CollectionTest.
|
|
|
70
67
|
end
|
|
71
68
|
end
|
|
72
69
|
|
|
73
|
-
|
|
74
70
|
# when collection is [], suppress rendering when render_empty: false.
|
|
75
71
|
for_formats(
|
|
76
72
|
:hash => [Representable::Hash, {}],
|
|
77
|
-
|
|
78
|
-
:yaml => [Representable::YAML, "--- {}\n"]
|
|
79
|
-
) do |format, mod, output,
|
|
80
|
-
|
|
73
|
+
# :xml => [Representable::XML, "<open_struct><songs/></open_struct>"],
|
|
74
|
+
:yaml => [Representable::YAML, "--- {}\n"]
|
|
75
|
+
) do |format, mod, output, _input|
|
|
81
76
|
describe "render_empty [#{format}]" do
|
|
82
77
|
let(:format) { format }
|
|
83
78
|
|
|
@@ -93,14 +88,12 @@ class GenericTest < MiniTest::Spec # TODO: rename/restructure to CollectionTest.
|
|
|
93
88
|
end
|
|
94
89
|
end
|
|
95
90
|
|
|
96
|
-
|
|
97
91
|
# wrap_test
|
|
98
92
|
for_formats(
|
|
99
|
-
:hash => [Representable::Hash, {}]
|
|
93
|
+
:hash => [Representable::Hash, {}]
|
|
100
94
|
# :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>"],
|
|
101
95
|
# :yaml => [Representable::YAML, "---\nsong:\n name: Alive\n", "---\nsong:\n name: You've Taken Everything\n"],
|
|
102
96
|
) do |format, mod, input|
|
|
103
|
-
|
|
104
97
|
describe "parsing [#{format}] with wrap where wrap is missing" do
|
|
105
98
|
representer!(:module => mod) do
|
|
106
99
|
self.representation_wrap = :song
|
|
@@ -113,4 +106,4 @@ class GenericTest < MiniTest::Spec # TODO: rename/restructure to CollectionTest.
|
|
|
113
106
|
end
|
|
114
107
|
end
|
|
115
108
|
end
|
|
116
|
-
end
|
|
109
|
+
end
|
data/test/getter_setter_test.rb
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
3
|
class GetterSetterTest < BaseTest
|
|
4
4
|
representer! do
|
|
5
5
|
property :name, # key under :name.
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
:getter => ->(user_options:, **) { "#{user_options[:welcome]} #{song_name}" },
|
|
7
|
+
:setter => ->(user_options:, input:, **) { self.song_name = "#{user_options[:welcome]} #{input}" }
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
subject { Struct.new(:song_name).new("Mony Mony").extend(representer) }
|
|
11
11
|
|
|
12
12
|
it "uses :getter when rendering" do
|
|
13
|
-
subject.instance_eval { def name;
|
|
13
|
+
subject.instance_eval { def name; fail; end }
|
|
14
14
|
_(subject.to_hash(user_options: {welcome: "Hi"})).must_equal({"name" => "Hi Mony Mony"})
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
it "uses :setter when parsing" do
|
|
18
|
-
subject.instance_eval { def name=(*);
|
|
19
|
-
_(
|
|
18
|
+
subject.instance_eval { def name=(*); fail; end; self }
|
|
19
|
+
_(
|
|
20
|
+
subject.from_hash(
|
|
21
|
+
{"name" => "Eyes Without A Face"},
|
|
22
|
+
user_options: {welcome: "Hello"}
|
|
23
|
+
).song_name
|
|
24
|
+
).must_equal "Hello Eyes Without A Face"
|
|
20
25
|
end
|
|
21
26
|
end
|
data/test/hash_bindings_test.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
|
-
class HashBindingTest <
|
|
3
|
+
class HashBindingTest < Minitest::Spec
|
|
4
4
|
module SongRepresenter
|
|
5
5
|
include Representable::JSON
|
|
6
6
|
property :name
|
|
@@ -11,7 +11,6 @@ class HashBindingTest < MiniTest::Spec
|
|
|
11
11
|
include SongRepresenter
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
|
|
15
14
|
describe "PropertyBinding" do
|
|
16
15
|
describe "#read" do
|
|
17
16
|
before do
|
|
@@ -19,7 +18,8 @@ class HashBindingTest < MiniTest::Spec
|
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
it "returns fragment if present" do
|
|
22
|
-
assert_equal "Stick The Flag Up Your Goddamn Ass, You Sonofabitch",
|
|
21
|
+
assert_equal "Stick The Flag Up Your Goddamn Ass, You Sonofabitch",
|
|
22
|
+
@property.read({"song" => "Stick The Flag Up Your Goddamn Ass, You Sonofabitch"}, "song")
|
|
23
23
|
assert_equal "", @property.read({"song" => ""}, "song")
|
|
24
24
|
assert_nil @property.read({"song" => nil}, "song")
|
|
25
25
|
end
|
|
@@ -28,10 +28,12 @@ class HashBindingTest < MiniTest::Spec
|
|
|
28
28
|
assert_equal Representable::Binding::FragmentNotFound, @property.read({}, "song")
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
+
it "will not fail if given an empty hash value and will return FRAGMENT_NOT_FOUND" do
|
|
32
|
+
assert_equal Representable::Binding::FragmentNotFound, @property.read(nil, "song")
|
|
33
|
+
end
|
|
31
34
|
end
|
|
32
35
|
end
|
|
33
36
|
|
|
34
|
-
|
|
35
37
|
describe "CollectionBinding" do
|
|
36
38
|
describe "with plain text items" do
|
|
37
39
|
before do
|
|
@@ -50,9 +52,6 @@ class HashBindingTest < MiniTest::Spec
|
|
|
50
52
|
end
|
|
51
53
|
end
|
|
52
54
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
55
|
describe "HashBinding" do
|
|
57
56
|
describe "with plain text items" do
|
|
58
57
|
before do
|
|
@@ -60,19 +59,30 @@ class HashBindingTest < MiniTest::Spec
|
|
|
60
59
|
end
|
|
61
60
|
|
|
62
61
|
it "extracts with #read" do
|
|
63
|
-
assert_equal(
|
|
62
|
+
assert_equal(
|
|
63
|
+
{"first" => "The Gargoyle", "second" => "Bronx"},
|
|
64
|
+
@property.read({"songs" => {"first" => "The Gargoyle", "second" => "Bronx"}}, "songs")
|
|
65
|
+
)
|
|
64
66
|
end
|
|
65
67
|
|
|
66
68
|
it "inserts with #write" do
|
|
67
69
|
doc = {}
|
|
68
|
-
assert_equal(
|
|
70
|
+
assert_equal(
|
|
71
|
+
{"first" => "The Gargoyle", "second" => "Bronx"},
|
|
72
|
+
@property.write(doc, {"first" => "The Gargoyle", "second" => "Bronx"}, "songs")
|
|
73
|
+
)
|
|
69
74
|
assert_equal({"songs"=>{"first" => "The Gargoyle", "second" => "Bronx"}}, doc)
|
|
70
75
|
end
|
|
71
76
|
end
|
|
72
77
|
|
|
73
78
|
describe "with objects" do
|
|
74
79
|
before do
|
|
75
|
-
@property = Representable::Hash::Binding.new(
|
|
80
|
+
@property = Representable::Hash::Binding.new(
|
|
81
|
+
Representable::Definition.new(
|
|
82
|
+
:songs, :hash => true, :class => Song,
|
|
83
|
+
:extend => SongRepresenter
|
|
84
|
+
)
|
|
85
|
+
)
|
|
76
86
|
end
|
|
77
87
|
|
|
78
88
|
it "doesn't change the represented hash in #write" do
|
|
@@ -82,6 +92,5 @@ class HashBindingTest < MiniTest::Spec
|
|
|
82
92
|
assert_equal({"first" => song}, hash)
|
|
83
93
|
end
|
|
84
94
|
end
|
|
85
|
-
|
|
86
95
|
end
|
|
87
96
|
end
|
data/test/hash_test.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
3
|
class HashPublicMethodsTest < Minitest::Spec
|
|
4
4
|
#---
|
|
@@ -9,7 +9,7 @@ class HashPublicMethodsTest < Minitest::Spec
|
|
|
9
9
|
property :name
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
let(:data) { {"id"=>1,"name"=>"Rancid"} }
|
|
12
|
+
let(:data) { {"id" => 1, "name" => "Rancid"} }
|
|
13
13
|
|
|
14
14
|
it { _(BandRepresenter.new(Band.new).from_hash(data)[:id, :name]).must_equal [1, "Rancid"] }
|
|
15
15
|
it { _(BandRepresenter.new(Band.new).parse(data)[:id, :name]).must_equal [1, "Rancid"] }
|
|
@@ -22,7 +22,7 @@ class HashPublicMethodsTest < Minitest::Spec
|
|
|
22
22
|
it { _(BandRepresenter.new(band).render).must_equal data }
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
class HashWithScalarPropertyTest <
|
|
25
|
+
class HashWithScalarPropertyTest < Minitest::Spec
|
|
26
26
|
Album = Struct.new(:title)
|
|
27
27
|
|
|
28
28
|
representer! do
|
|
@@ -37,7 +37,6 @@ class HashWithScalarPropertyTest < MiniTest::Spec
|
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
-
|
|
41
40
|
describe "#from_hash" do
|
|
42
41
|
it "parses plain property" do
|
|
43
42
|
_(album.extend(representer).from_hash("title" => "This Song Is Recycled").title).must_equal "This Song Is Recycled"
|
|
@@ -52,8 +51,7 @@ class HashWithScalarPropertyTest < MiniTest::Spec
|
|
|
52
51
|
end
|
|
53
52
|
end
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
class HashWithTypedPropertyTest < MiniTest::Spec
|
|
54
|
+
class HashWithTypedPropertyTest < Minitest::Spec
|
|
57
55
|
Album = Struct.new(:best_song)
|
|
58
56
|
|
|
59
57
|
representer! do
|
|
@@ -85,7 +83,7 @@ class HashWithTypedPropertyTest < MiniTest::Spec
|
|
|
85
83
|
|
|
86
84
|
# nested blank hash creates blank object when not populated.
|
|
87
85
|
it do
|
|
88
|
-
album = Album.new#(Song.new("Pre-medicated Murder"))
|
|
86
|
+
album = Album.new # (Song.new("Pre-medicated Murder"))
|
|
89
87
|
album.extend(representer).from_hash("best_song" => {})
|
|
90
88
|
_(album.best_song.name).must_be_nil
|
|
91
89
|
end
|
|
@@ -100,7 +98,7 @@ class HashWithTypedPropertyTest < MiniTest::Spec
|
|
|
100
98
|
end
|
|
101
99
|
|
|
102
100
|
# TODO: move to AsTest.
|
|
103
|
-
class HashWithTypedPropertyAndAs <
|
|
101
|
+
class HashWithTypedPropertyAndAs < Minitest::Spec
|
|
104
102
|
representer! do
|
|
105
103
|
property :song, :class => Song, :as => :hit do
|
|
106
104
|
property :name
|
|
@@ -112,29 +110,27 @@ class HashWithTypedPropertyAndAs < MiniTest::Spec
|
|
|
112
110
|
it { _(album.to_hash).must_equal("hit" => {"name" => "Liar"}) }
|
|
113
111
|
it { _(album.from_hash("hit" => {"name" => "Go With Me"})).must_equal OpenStruct.new(:song => Song.new("Go With Me")) }
|
|
114
112
|
end
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
class HashWithTypedCollectionTest < MiniTest::Spec
|
|
113
|
+
# # describe "FIXME COMBINE WITH ABOVE with :extend and :as" do
|
|
114
|
+
# # hash_song = Module.new do
|
|
115
|
+
# # include Representable::XML
|
|
116
|
+
# # self.representation_wrap = :song
|
|
117
|
+
# # property :name
|
|
118
|
+
# # end
|
|
119
|
+
|
|
120
|
+
# # let(:hash_album) { Module.new do
|
|
121
|
+
# # include Representable::XML
|
|
122
|
+
# # self.representation_wrap = :album
|
|
123
|
+
# # property :song, :extend => hash_song, :class => Song, :as => :hit
|
|
124
|
+
# # end }
|
|
125
|
+
|
|
126
|
+
# # let(:album) { OpenStruct.new(:song => Song.new("Liar")).extend(hash_album) }
|
|
127
|
+
|
|
128
|
+
# # it { album.to_xml.must_equal_xml("<album><hit><name>Liar</name></hit></album>") }
|
|
129
|
+
# # #it { album.from_hash("hit" => {"name" => "Go With Me"}).must_equal OpenStruct.new(:song => Song.new("Go With Me")) }
|
|
130
|
+
# # end
|
|
131
|
+
# end
|
|
132
|
+
|
|
133
|
+
class HashWithTypedCollectionTest < Minitest::Spec
|
|
138
134
|
Album = Struct.new(:songs)
|
|
139
135
|
|
|
140
136
|
representer! do
|
|
@@ -148,35 +144,54 @@ class HashWithTypedCollectionTest < MiniTest::Spec
|
|
|
148
144
|
|
|
149
145
|
describe "#to_hash" do
|
|
150
146
|
it "renders collection of typed property" do
|
|
151
|
-
_(album.extend(representer).to_hash).must_equal(
|
|
147
|
+
_(album.extend(representer).to_hash).must_equal(
|
|
148
|
+
"songs" => [
|
|
149
|
+
{"name" => "Liar", "track" => 1},
|
|
150
|
+
{"name" => "What I Know", "track" => 2}
|
|
151
|
+
]
|
|
152
|
+
)
|
|
152
153
|
end
|
|
153
154
|
end
|
|
154
155
|
|
|
155
156
|
describe "#from_hash" do
|
|
156
157
|
it "parses collection of typed property" do
|
|
157
|
-
_(
|
|
158
|
-
|
|
158
|
+
_(
|
|
159
|
+
album.extend(representer).from_hash(
|
|
160
|
+
"songs" => [
|
|
161
|
+
{"name" => "One Shot Deal", "track" => 4},
|
|
162
|
+
{
|
|
163
|
+
"name" => "Three Way Dance",
|
|
164
|
+
"track" => 5
|
|
165
|
+
}
|
|
166
|
+
]
|
|
167
|
+
)
|
|
168
|
+
).must_equal Album.new([Song.new("One Shot Deal", 4), Song.new("Three Way Dance", 5)])
|
|
159
169
|
end
|
|
160
170
|
end
|
|
161
171
|
end
|
|
162
172
|
|
|
163
|
-
class HashWithScalarCollectionTest <
|
|
173
|
+
class HashWithScalarCollectionTest < Minitest::Spec
|
|
164
174
|
Album = Struct.new(:songs)
|
|
165
175
|
representer! { collection :songs }
|
|
166
176
|
|
|
167
177
|
let(:album) { Album.new(["Jackhammer", "Terrible Man"]) }
|
|
168
178
|
|
|
169
|
-
|
|
170
179
|
describe "#to_hash" do
|
|
171
180
|
it "renders a block style list per default" do
|
|
172
181
|
_(album.extend(representer).to_hash).must_equal("songs" => ["Jackhammer", "Terrible Man"])
|
|
173
182
|
end
|
|
174
183
|
end
|
|
175
184
|
|
|
176
|
-
|
|
177
185
|
describe "#from_hash" do
|
|
178
186
|
it "parses a block style list" do
|
|
179
|
-
_(
|
|
187
|
+
_(
|
|
188
|
+
album.extend(representer).from_hash(
|
|
189
|
+
"songs" => [
|
|
190
|
+
"Off Key Melody",
|
|
191
|
+
"Sinking"
|
|
192
|
+
]
|
|
193
|
+
)
|
|
194
|
+
).must_equal Album.new(["Off Key Melody", "Sinking"])
|
|
180
195
|
end
|
|
181
196
|
end
|
|
182
197
|
end
|
data/test/heritage_test.rb
CHANGED
data/test/if_test.rb
CHANGED
|
@@ -1,35 +1,38 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "test_helper"
|
|
2
2
|
|
|
3
|
-
class IfTest <
|
|
4
|
-
let(:band_class)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
class IfTest < Minitest::Spec
|
|
4
|
+
let(:band_class) do
|
|
5
|
+
Class.new do
|
|
6
|
+
include Representable::Hash
|
|
7
|
+
attr_accessor :fame
|
|
8
|
+
|
|
9
|
+
self
|
|
10
|
+
end
|
|
11
|
+
end
|
|
9
12
|
|
|
10
13
|
it "respects property when condition true" do
|
|
11
|
-
band_class.class_eval { property :fame, :if =>
|
|
14
|
+
band_class.class_eval { property :fame, :if => ->(*) { true } }
|
|
12
15
|
band = band_class.new
|
|
13
16
|
band.from_hash({"fame"=>"oh yes"})
|
|
14
17
|
assert_equal "oh yes", band.fame
|
|
15
18
|
end
|
|
16
19
|
|
|
17
20
|
it "ignores property when condition false" do
|
|
18
|
-
band_class.class_eval { property :fame, :if =>
|
|
21
|
+
band_class.class_eval { property :fame, :if => ->(*) { false } }
|
|
19
22
|
band = band_class.new
|
|
20
23
|
band.from_hash({"fame"=>"oh yes"})
|
|
21
24
|
assert_nil band.fame
|
|
22
25
|
end
|
|
23
26
|
|
|
24
27
|
it "ignores property when :exclude'ed even when condition is true" do
|
|
25
|
-
band_class.class_eval { property :fame, :if =>
|
|
28
|
+
band_class.class_eval { property :fame, :if => ->(*) { true } }
|
|
26
29
|
band = band_class.new
|
|
27
30
|
band.from_hash({"fame"=>"oh yes"}, {:exclude => [:fame]})
|
|
28
31
|
assert_nil band.fame
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
it "executes block in instance context" do
|
|
32
|
-
band_class.class_eval { property :fame, :if =>
|
|
35
|
+
band_class.class_eval { property :fame, :if => ->(*) { groupies }; attr_accessor :groupies }
|
|
33
36
|
band = band_class.new
|
|
34
37
|
band.groupies = true
|
|
35
38
|
band.from_hash({"fame"=>"oh yes"})
|
|
@@ -38,7 +41,7 @@ class IfTest < MiniTest::Spec
|
|
|
38
41
|
|
|
39
42
|
describe "executing :if lambda in represented instance context" do
|
|
40
43
|
representer! do
|
|
41
|
-
property :label, :if =>
|
|
44
|
+
property :label, :if => ->(*) { signed_contract }
|
|
42
45
|
end
|
|
43
46
|
|
|
44
47
|
subject { OpenStruct.new(:signed_contract => false, :label => "Fat") }
|
|
@@ -48,23 +51,24 @@ class IfTest < MiniTest::Spec
|
|
|
48
51
|
end
|
|
49
52
|
|
|
50
53
|
it "represents when true" do
|
|
51
|
-
subject.signed_contract= true
|
|
54
|
+
subject.signed_contract = true
|
|
52
55
|
_(subject.extend(representer).to_hash).must_equal({"label"=>"Fat"})
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
it "works with decorator" do
|
|
56
59
|
rpr = representer
|
|
57
|
-
_(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
_(
|
|
61
|
+
Class.new(Representable::Decorator) {
|
|
62
|
+
include Representable::Hash
|
|
63
|
+
include rpr
|
|
64
|
+
}.new(subject).to_hash
|
|
65
|
+
).must_equal({})
|
|
61
66
|
end
|
|
62
67
|
end
|
|
63
68
|
|
|
64
|
-
|
|
65
69
|
describe "propagating user options to the block" do
|
|
66
70
|
representer! do
|
|
67
|
-
property :name, :if =>
|
|
71
|
+
property :name, :if => ->(opts) { opts[:user_options][:include_name] }
|
|
68
72
|
end
|
|
69
73
|
subject { OpenStruct.new(:name => "Outbound").extend(representer) }
|
|
70
74
|
|
|
@@ -73,7 +77,7 @@ class IfTest < MiniTest::Spec
|
|
|
73
77
|
end
|
|
74
78
|
|
|
75
79
|
it "passes user options to block" do
|
|
76
|
-
_(subject.to_hash(user_options: {
|
|
80
|
+
_(subject.to_hash(user_options: {include_name: true})).must_equal({"name" => "Outbound"})
|
|
77
81
|
end
|
|
78
82
|
end
|
|
79
|
-
end
|
|
83
|
+
end
|
|
@@ -17,30 +17,34 @@ class IncludeExcludeTest < Minitest::Spec
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
let(:song) { Song.new("Listless", Artist.new("7yearsbadluck", 1
|
|
20
|
+
let(:song) { Song.new("Listless", Artist.new("7yearsbadluck", 1)) }
|
|
21
21
|
let(:decorator) { representer.new(song) }
|
|
22
22
|
|
|
23
23
|
describe "#from_hash" do
|
|
24
24
|
it "accepts :exclude option" do
|
|
25
|
-
decorator.from_hash({"title"=>"Don't Smile In Trouble", "artist"=>{"id"=>2}}, exclude: [:title])
|
|
25
|
+
decorator.from_hash({"title" => "Don't Smile In Trouble", "artist" => {"id"=>2}}, exclude: [:title])
|
|
26
26
|
|
|
27
27
|
_(song.title).must_equal "Listless"
|
|
28
28
|
_(song.artist).must_equal Artist.new(nil, 2)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "accepts :include option" do
|
|
32
|
-
decorator.from_hash({"title"=>"Don't Smile In Trouble", "artist"=>{"id"=>2}}, include: [:title])
|
|
32
|
+
decorator.from_hash({"title" => "Don't Smile In Trouble", "artist" => {"id"=>2}}, include: [:title])
|
|
33
33
|
|
|
34
34
|
_(song.title).must_equal "Don't Smile In Trouble"
|
|
35
35
|
_(song.artist).must_equal Artist.new("7yearsbadluck", 1)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
it "accepts nested :exclude/:include option" do
|
|
39
|
-
decorator.from_hash(
|
|
39
|
+
decorator.from_hash(
|
|
40
|
+
{
|
|
41
|
+
"title" => "Don't Smile In Trouble",
|
|
42
|
+
"artist" => {"name" => "Foo", "id" => 2, "songs" => [{"id" => 1, "title" => "Listless"}]}
|
|
43
|
+
},
|
|
40
44
|
exclude: [:title],
|
|
41
|
-
artist:
|
|
45
|
+
artist: {
|
|
42
46
|
exclude: [:id],
|
|
43
|
-
songs:
|
|
47
|
+
songs: {include: [:title]}
|
|
44
48
|
}
|
|
45
49
|
)
|
|
46
50
|
|
|
@@ -51,7 +55,7 @@ class IncludeExcludeTest < Minitest::Spec
|
|
|
51
55
|
|
|
52
56
|
describe "#to_hash" do
|
|
53
57
|
it "accepts :exclude option" do
|
|
54
|
-
_(decorator.to_hash(exclude: [:title])).must_equal({"artist"=>{"name"=>"7yearsbadluck", "id"=>1}})
|
|
58
|
+
_(decorator.to_hash(exclude: [:title])).must_equal({"artist"=>{"name" => "7yearsbadluck", "id" => 1}})
|
|
55
59
|
end
|
|
56
60
|
|
|
57
61
|
it "accepts :include option" do
|
|
@@ -61,13 +65,15 @@ class IncludeExcludeTest < Minitest::Spec
|
|
|
61
65
|
it "accepts nested :exclude/:include option" do
|
|
62
66
|
decorator = representer.new(Song.new("Listless", Artist.new("7yearsbadluck", 1, [Song.new("C.O.A.B.I.E.T.L.")])))
|
|
63
67
|
|
|
64
|
-
_(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
68
|
+
_(
|
|
69
|
+
decorator.to_hash(
|
|
70
|
+
exclude: [:title],
|
|
71
|
+
artist: {
|
|
72
|
+
exclude: [:id],
|
|
73
|
+
songs: {include: [:title]}
|
|
74
|
+
}
|
|
75
|
+
)
|
|
76
|
+
).must_equal({"artist"=>{"name" => "7yearsbadluck", "songs" => [{"title"=>"C.O.A.B.I.E.T.L."}]}})
|
|
71
77
|
end
|
|
72
78
|
end
|
|
73
79
|
|
|
@@ -82,7 +88,9 @@ class IncludeExcludeTest < Minitest::Spec
|
|
|
82
88
|
|
|
83
89
|
# FIXME: we should test all representable-options (:include, :exclude, ?)
|
|
84
90
|
|
|
85
|
-
_(
|
|
86
|
-
|
|
91
|
+
_(
|
|
92
|
+
Cover.new("Roxanne", Cover.new("Roxanne (Don't Put On The Red Light)")).extend(cover_rpr)
|
|
93
|
+
.to_hash(:include => [:original])
|
|
94
|
+
).must_equal({"original"=>{"title"=>"Roxanne (Don't Put On The Red Light)"}})
|
|
87
95
|
end
|
|
88
96
|
end
|