representable 2.4.1 → 3.0.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/.travis.yml +7 -12
- data/CHANGES.md +6 -27
- data/README.md +28 -1326
- data/lib/representable.rb +4 -14
- data/lib/representable/binding.rb +3 -7
- data/lib/representable/definition.rb +1 -2
- data/lib/representable/populator.rb +35 -0
- data/lib/representable/version.rb +1 -1
- data/test/definition_test.rb +0 -7
- data/test/exec_context_test.rb +2 -2
- data/test/instance_test.rb +0 -19
- data/test/realistic_benchmark.rb +0 -13
- data/test/representable_test.rb +0 -16
- data/test/skip_test.rb +1 -1
- data/test/test_helper.rb +0 -2
- metadata +3 -65
- data/lib/representable/deprecations.rb +0 -127
- data/lib/representable/parse_strategies.rb +0 -93
- data/test-with-deprecations/as_test.rb +0 -65
- data/test-with-deprecations/benchmarking.rb +0 -83
- data/test-with-deprecations/binding_test.rb +0 -46
- data/test-with-deprecations/blaaaaaaaa_test.rb +0 -69
- data/test-with-deprecations/cached_test.rb +0 -147
- data/test-with-deprecations/class_test.rb +0 -119
- data/test-with-deprecations/coercion_test.rb +0 -52
- data/test-with-deprecations/config/inherit_test.rb +0 -135
- data/test-with-deprecations/config_test.rb +0 -122
- data/test-with-deprecations/decorator_scope_test.rb +0 -28
- data/test-with-deprecations/decorator_test.rb +0 -96
- data/test-with-deprecations/default_test.rb +0 -34
- data/test-with-deprecations/defaults_options_test.rb +0 -93
- data/test-with-deprecations/definition_test.rb +0 -264
- data/test-with-deprecations/example.rb +0 -310
- data/test-with-deprecations/examples/object.rb +0 -31
- data/test-with-deprecations/exec_context_test.rb +0 -93
- data/test-with-deprecations/features_test.rb +0 -70
- data/test-with-deprecations/filter_test.rb +0 -57
- data/test-with-deprecations/for_collection_test.rb +0 -74
- data/test-with-deprecations/generic_test.rb +0 -116
- data/test-with-deprecations/getter_setter_test.rb +0 -21
- data/test-with-deprecations/hash_bindings_test.rb +0 -87
- data/test-with-deprecations/hash_test.rb +0 -160
- data/test-with-deprecations/heritage_test.rb +0 -62
- data/test-with-deprecations/if_test.rb +0 -79
- data/test-with-deprecations/include_exclude_test.rb +0 -88
- data/test-with-deprecations/inherit_test.rb +0 -159
- data/test-with-deprecations/inline_test.rb +0 -272
- data/test-with-deprecations/instance_test.rb +0 -266
- data/test-with-deprecations/is_representable_test.rb +0 -77
- data/test-with-deprecations/json_test.rb +0 -355
- data/test-with-deprecations/lonely_test.rb +0 -239
- data/test-with-deprecations/mongoid_test.rb +0 -31
- data/test-with-deprecations/nested_test.rb +0 -115
- data/test-with-deprecations/object_test.rb +0 -60
- data/test-with-deprecations/parse_pipeline_test.rb +0 -64
- data/test-with-deprecations/parse_strategy_test.rb +0 -279
- data/test-with-deprecations/pass_options_test.rb +0 -27
- data/test-with-deprecations/pipeline_test.rb +0 -277
- data/test-with-deprecations/populator_test.rb +0 -105
- data/test-with-deprecations/prepare_test.rb +0 -67
- data/test-with-deprecations/private_options_test.rb +0 -18
- data/test-with-deprecations/reader_writer_test.rb +0 -19
- data/test-with-deprecations/realistic_benchmark.rb +0 -115
- data/test-with-deprecations/render_nil_test.rb +0 -21
- data/test-with-deprecations/represent_test.rb +0 -88
- data/test-with-deprecations/representable_test.rb +0 -511
- data/test-with-deprecations/schema_test.rb +0 -148
- data/test-with-deprecations/serialize_deserialize_test.rb +0 -33
- data/test-with-deprecations/skip_test.rb +0 -81
- data/test-with-deprecations/stringify_hash_test.rb +0 -41
- data/test-with-deprecations/test_helper.rb +0 -135
- data/test-with-deprecations/test_helper_test.rb +0 -25
- data/test-with-deprecations/uncategorized_test.rb +0 -67
- data/test-with-deprecations/user_options_test.rb +0 -15
- data/test-with-deprecations/wrap_test.rb +0 -152
- data/test-with-deprecations/xml_bindings_test.rb +0 -62
- data/test-with-deprecations/xml_test.rb +0 -503
- data/test-with-deprecations/yaml_test.rb +0 -162
- data/test/parse_strategy_test.rb +0 -279
@@ -1,119 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class ClassTest < BaseTest
|
4
|
-
|
5
|
-
class RepresentingSong
|
6
|
-
attr_reader :name
|
7
|
-
|
8
|
-
def from_hash(doc, *args)
|
9
|
-
@name = doc["__name__"]
|
10
|
-
|
11
|
-
self # DISCUSS: do we wanna be able to return whatever we want here? this is a trick to replace the actual object
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
describe "class: ClassName, only" do
|
17
|
-
representer! do
|
18
|
-
property :song, :class => RepresentingSong # supposed this class exposes #from_hash itself.
|
19
|
-
end
|
20
|
-
|
21
|
-
it "creates fresh instance and doesn't extend" do
|
22
|
-
song = representer.prepare(OpenStruct.new).from_hash({"song" => {"__name__" => "Captured"}}).song
|
23
|
-
song.must_be_instance_of RepresentingSong
|
24
|
-
song.name.must_equal "Captured"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
|
29
|
-
describe "class: lambda, only" do
|
30
|
-
representer! do
|
31
|
-
property :song, :class => lambda { |*| RepresentingSong }
|
32
|
-
end
|
33
|
-
|
34
|
-
it "creates fresh instance and doesn't extend" do
|
35
|
-
song = representer.prepare(OpenStruct.new).from_hash({"song" => {"__name__" => "Captured"}}).song
|
36
|
-
song.must_be_instance_of RepresentingSong
|
37
|
-
song.name.must_equal "Captured"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
|
42
|
-
# this throws a DeserializationError now.
|
43
|
-
describe "lambda { nil }" do
|
44
|
-
representer! do
|
45
|
-
property :title, :class => nil
|
46
|
-
end
|
47
|
-
|
48
|
-
it do
|
49
|
-
assert_raises Representable::DeserializeError do
|
50
|
-
OpenStruct.new.extend(representer).from_hash({"title" => {}})
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
|
56
|
-
describe "lambda receiving fragment and args" do
|
57
|
-
let (:klass) { Class.new do
|
58
|
-
class << self
|
59
|
-
attr_accessor :args
|
60
|
-
end
|
61
|
-
|
62
|
-
def from_hash(*)
|
63
|
-
self.class.new
|
64
|
-
end
|
65
|
-
end }
|
66
|
-
|
67
|
-
representer!(:inject => :klass) do
|
68
|
-
_klass = klass
|
69
|
-
property :song, :class => lambda { |fragment, args| _klass.args=([fragment,args]); _klass }
|
70
|
-
end
|
71
|
-
|
72
|
-
it { representer.prepare(OpenStruct.new).from_hash({"song" => {"name" => "Captured"}}, :volume => true).song.class.args.
|
73
|
-
must_equal([{"name"=>"Captured"}, {:volume=>true}]) }
|
74
|
-
end
|
75
|
-
|
76
|
-
|
77
|
-
describe "collection: lambda receiving fragment and args" do
|
78
|
-
let (:klass) { Class.new do
|
79
|
-
class << self
|
80
|
-
attr_accessor :args
|
81
|
-
end
|
82
|
-
|
83
|
-
def from_hash(*)
|
84
|
-
self.class.new
|
85
|
-
end
|
86
|
-
end }
|
87
|
-
|
88
|
-
representer!(:inject => :klass) do
|
89
|
-
_klass = klass
|
90
|
-
collection :songs, :class => lambda { |fragment, i, args| _klass.args=([fragment,i,args]); _klass }
|
91
|
-
end
|
92
|
-
|
93
|
-
it { representer.prepare(OpenStruct.new).from_hash({"songs" => [{"name" => "Captured"}]}, :volume => true).songs.first.class.args.
|
94
|
-
must_equal([{"name"=>"Captured"}, 0, {:volume=>true}]) }
|
95
|
-
end
|
96
|
-
|
97
|
-
|
98
|
-
describe "class: implementing #from_hash" do
|
99
|
-
let(:parser) do
|
100
|
-
Class.new do
|
101
|
-
def from_hash(*)
|
102
|
-
[1,2,3,4]
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
representer!(:inject => :parser) do
|
108
|
-
property :song, :class => parser # supposed this class exposes #from_hash itself.
|
109
|
-
end
|
110
|
-
|
111
|
-
it "allows returning arbitrary objects in #from_hash" do
|
112
|
-
representer.prepare(OpenStruct.new).from_hash({"song" => 1}).song.must_equal [1,2,3,4]
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
#TODO: test fragment,
|
118
|
-
|
119
|
-
# `class: Song` only, no :extend.
|
@@ -1,52 +0,0 @@
|
|
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
|
@@ -1,135 +0,0 @@
|
|
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
|
@@ -1,122 +0,0 @@
|
|
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
|
@@ -1,28 +0,0 @@
|
|
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
|