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,279 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
# parse_strategy: :sync
|
4
|
-
# parse_strategy: :replace
|
5
|
-
# parse_strategy: :find_or_instantiate ("expand" since we don't delete existing unmatched in target)
|
6
|
-
|
7
|
-
|
8
|
-
class ParseStrategySyncTest < BaseTest
|
9
|
-
for_formats(
|
10
|
-
:hash => [Representable::Hash, {"song"=>{"title"=>"Resist Stance"}}, {"song"=>{"title"=>"Suffer"}}],
|
11
|
-
:xml => [Representable::XML, "<open_struct><song><title>Resist Stance</title></song></open_struct>", "<open_struct><song><title>Suffer</title></song></open_struct>",],
|
12
|
-
:yaml => [Representable::YAML, "---\nsong:\n title: Resist Stance\n", "---\nsong:\n title: Suffer\n"],
|
13
|
-
) do |format, mod, output, input|
|
14
|
-
|
15
|
-
describe "[#{format}] property with parse_strategy: :sync" do # TODO: introduce :representable option?
|
16
|
-
let (:format) { format }
|
17
|
-
|
18
|
-
representer!(:module => mod, :name => :song_representer) do
|
19
|
-
property :title
|
20
|
-
self.representation_wrap = :song if format == :xml
|
21
|
-
end
|
22
|
-
|
23
|
-
representer!(:inject => :song_representer, :module => mod) do
|
24
|
-
property :song, :parse_strategy => :sync, :extend => song_representer
|
25
|
-
end
|
26
|
-
|
27
|
-
let (:hit) { hit = OpenStruct.new(:song => song).extend(representer) }
|
28
|
-
|
29
|
-
it "calls #to_hash on song instance, nothing else" do
|
30
|
-
render(hit).must_equal_document(output)
|
31
|
-
end
|
32
|
-
|
33
|
-
|
34
|
-
it "calls #from_hash on the existing song instance, nothing else" do
|
35
|
-
song_id = hit.song.object_id
|
36
|
-
|
37
|
-
parse(hit, input)
|
38
|
-
|
39
|
-
hit.song.title.must_equal "Suffer"
|
40
|
-
hit.song.object_id.must_equal song_id
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
# FIXME: there's a bug with XML and the collection name!
|
46
|
-
for_formats(
|
47
|
-
:hash => [Representable::Hash, {"songs"=>[{"title"=>"Resist Stance"}]}, {"songs"=>[{"title"=>"Suffer"}]}],
|
48
|
-
#:json => [Representable::JSON, "{\"song\":{\"name\":\"Alive\"}}", "{\"song\":{\"name\":\"You've Taken Everything\"}}"],
|
49
|
-
:xml => [Representable::XML, "<open_struct><song><title>Resist Stance</title></song></open_struct>", "<open_struct><songs><title>Suffer</title></songs></open_struct>"],
|
50
|
-
:yaml => [Representable::YAML, "---\nsongs:\n- title: Resist Stance\n", "---\nsongs:\n- title: Suffer\n"],
|
51
|
-
) do |format, mod, output, input|
|
52
|
-
|
53
|
-
describe "[#{format}] collection with :parse_strategy: :sync" do # TODO: introduce :representable option?
|
54
|
-
let (:format) { format }
|
55
|
-
representer!(:module => mod, :name => :song_representer) do
|
56
|
-
property :title
|
57
|
-
self.representation_wrap = :song if format == :xml
|
58
|
-
end
|
59
|
-
|
60
|
-
representer!(:inject => :song_representer, :module => mod) do
|
61
|
-
collection :songs, :parse_strategy => :sync, :extend => song_representer
|
62
|
-
end
|
63
|
-
|
64
|
-
let (:album) { OpenStruct.new(:songs => [song]).extend(representer) }
|
65
|
-
|
66
|
-
it "calls #to_hash on song instances, nothing else" do
|
67
|
-
render(album).must_equal_document(output)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "calls #from_hash on the existing song instance, nothing else" do
|
71
|
-
collection_id = album.songs.object_id
|
72
|
-
song = album.songs.first
|
73
|
-
song_id = song.object_id
|
74
|
-
|
75
|
-
parse(album, input)
|
76
|
-
|
77
|
-
album.songs.first.title.must_equal "Suffer"
|
78
|
-
song.title.must_equal "Suffer"
|
79
|
-
#album.songs.object_id.must_equal collection_id # TODO: don't replace!
|
80
|
-
song.object_id.must_equal song_id
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
|
-
# Sync errors, when model and incoming are not in sync.
|
87
|
-
describe ":sync with error" do
|
88
|
-
representer! do
|
89
|
-
property :song, :parse_strategy => :sync do
|
90
|
-
property :title
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# object.song is nil whereas the document contains one.
|
95
|
-
it do
|
96
|
-
assert_raises Representable::DeserializeError do
|
97
|
-
OpenStruct.new.extend(representer).from_hash({"song" => {"title" => "Perpetual"}})
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
# Lonely Collection
|
105
|
-
for_formats(
|
106
|
-
:hash => [Representable::Hash::Collection, [{"title"=>"Resist Stance"}], [{"title"=>"Suffer"}]],
|
107
|
-
# :xml => [Representable::XML, "<open_struct><song><title>Resist Stance</title></song></open_struct>", "<open_struct><songs><title>Suffer</title></songs></open_struct>"],
|
108
|
-
) do |format, mod, output, input|
|
109
|
-
|
110
|
-
describe "[#{format}] lonely collection with :parse_strategy: :sync" do # TODO: introduce :representable option?
|
111
|
-
let (:format) { format }
|
112
|
-
representer!(:module => Representable::Hash, :name => :song_representer) do
|
113
|
-
property :title
|
114
|
-
self.representation_wrap = :song if format == :xml
|
115
|
-
end
|
116
|
-
|
117
|
-
representer!(:inject => :song_representer, :module => mod) do
|
118
|
-
items :parse_strategy => :sync, :extend => song_representer
|
119
|
-
end
|
120
|
-
|
121
|
-
let (:album) { [song].extend(representer) }
|
122
|
-
|
123
|
-
it "calls #to_hash on song instances, nothing else" do
|
124
|
-
render(album).must_equal_document(output)
|
125
|
-
end
|
126
|
-
|
127
|
-
it "calls #from_hash on the existing song instance, nothing else" do
|
128
|
-
#collection_id = album.object_id
|
129
|
-
song = album.first
|
130
|
-
song_id = song.object_id
|
131
|
-
|
132
|
-
parse(album, input)
|
133
|
-
|
134
|
-
album.first.title.must_equal "Suffer"
|
135
|
-
song.title.must_equal "Suffer"
|
136
|
-
song.object_id.must_equal song_id
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
class ParseStrategyFindOrInstantiateTest < BaseTest
|
144
|
-
# parse_strategy: :find_or_instantiate
|
145
|
-
|
146
|
-
Song = Struct.new(:id, :title)
|
147
|
-
Song.class_eval do
|
148
|
-
def self.find_by(attributes={})
|
149
|
-
return new(1, "Resist Stan") if attributes[:id]==1# we should return the same object here
|
150
|
-
new
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
representer!(:name => :song_representer) do
|
155
|
-
property :title
|
156
|
-
end
|
157
|
-
|
158
|
-
|
159
|
-
describe "collection" do
|
160
|
-
representer!(:inject => :song_representer) do
|
161
|
-
collection :songs, :parse_strategy => :find_or_instantiate, :extend => song_representer, :class => Song
|
162
|
-
end
|
163
|
-
|
164
|
-
let (:album) { Struct.new(:songs).new([]).extend(representer) }
|
165
|
-
|
166
|
-
|
167
|
-
it "replaces the existing collection with a new consisting of existing items or new items" do
|
168
|
-
songs_id = album.songs.object_id
|
169
|
-
|
170
|
-
album.from_hash({"songs"=>[{"id" => 1, "title"=>"Resist Stance"}, {"title"=>"Suffer"}]})
|
171
|
-
|
172
|
-
album.songs[0].title.must_equal "Resist Stance" # note how title is updated from "Resist Stan"
|
173
|
-
album.songs[0].id.must_equal 1
|
174
|
-
album.songs[1].title.must_equal "Suffer"
|
175
|
-
album.songs[1].id.must_equal nil
|
176
|
-
|
177
|
-
album.songs.object_id.wont_equal songs_id
|
178
|
-
end
|
179
|
-
|
180
|
-
# TODO: test with existing collection
|
181
|
-
end
|
182
|
-
|
183
|
-
|
184
|
-
describe "property" do
|
185
|
-
representer!(:inject => :song_representer) do
|
186
|
-
property :song, :parse_strategy => :find_or_instantiate, :extend => song_representer, :class => Song
|
187
|
-
end
|
188
|
-
|
189
|
-
let (:album) { Struct.new(:song).new.extend(representer) }
|
190
|
-
|
191
|
-
|
192
|
-
it "finds song by id" do
|
193
|
-
album.from_hash({"song"=>{"id" => 1, "title"=>"Resist Stance"}})
|
194
|
-
|
195
|
-
album.song.title.must_equal "Resist Stance" # note how title is updated from "Resist Stan"
|
196
|
-
album.song.id.must_equal 1
|
197
|
-
end
|
198
|
-
|
199
|
-
it "creates song" do
|
200
|
-
album.from_hash({"song"=>{"title"=>"Off The Track"}})
|
201
|
-
|
202
|
-
album.song.title.must_equal "Off The Track"
|
203
|
-
album.song.id.must_equal nil
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
|
208
|
-
describe "property with dynamic :class" do
|
209
|
-
representer!(:inject => :song_representer) do
|
210
|
-
property :song, :parse_strategy => :find_or_instantiate, :extend => song_representer,
|
211
|
-
:class => lambda { |fragment, *args| fragment["class"] }
|
212
|
-
end
|
213
|
-
|
214
|
-
let (:album) { Struct.new(:song).new.extend(representer) }
|
215
|
-
|
216
|
-
|
217
|
-
it "finds song by id" do
|
218
|
-
album.from_hash({"song"=>{"id" => 1, "title"=>"Resist Stance", "class"=>Song}})
|
219
|
-
|
220
|
-
album.song.title.must_equal "Resist Stance" # note how title is updated from "Resist Stan"
|
221
|
-
album.song.id.must_equal 1
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
|
227
|
-
class ParseStrategyLambdaTest < MiniTest::Spec
|
228
|
-
Song = Struct.new(:id, :title)
|
229
|
-
Song.class_eval do
|
230
|
-
def self.find_by(attributes={})
|
231
|
-
return new(1, "Resist Stan") if attributes[:id]==1# we should return the same object here
|
232
|
-
new
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
representer!(:name => :song_representer) do
|
237
|
-
property :title
|
238
|
-
end
|
239
|
-
|
240
|
-
# property with instance: lambda, using representable's setter. # TODO: that should be handled better via my api.
|
241
|
-
describe "property parse_strategy: lambda, representable: false" do
|
242
|
-
representer! do
|
243
|
-
property :title,
|
244
|
-
:instance => lambda { |fragment, options| fragment.to_s }, # this will still call song.title= "8675309".
|
245
|
-
:representable => false # don't call object.from_hash
|
246
|
-
end
|
247
|
-
|
248
|
-
let (:song) { Song.new(nil, nil) }
|
249
|
-
it { song.extend(representer).from_hash("title" => 8675309).title.must_equal "8675309" }
|
250
|
-
end
|
251
|
-
|
252
|
-
|
253
|
-
describe "collection" do
|
254
|
-
representer!(:inject => :song_representer) do
|
255
|
-
collection :songs, :parse_strategy => lambda { |fragment, i, options|
|
256
|
-
songs << song = Song.new
|
257
|
-
song
|
258
|
-
}, :extend => song_representer
|
259
|
-
end
|
260
|
-
|
261
|
-
let (:album) { Struct.new(:songs).new([Song.new(1, "A Walk")]).extend(representer) }
|
262
|
-
|
263
|
-
|
264
|
-
it "adds to existing collection" do
|
265
|
-
songs_id = album.songs.object_id
|
266
|
-
|
267
|
-
album.from_hash({"songs"=>[{"title"=>"Resist Stance"}]})
|
268
|
-
|
269
|
-
album.songs[0].title.must_equal "A Walk" # note how title is updated from "Resist Stan"
|
270
|
-
album.songs[0].id.must_equal 1
|
271
|
-
album.songs[1].title.must_equal "Resist Stance"
|
272
|
-
album.songs[1].id.must_equal nil
|
273
|
-
|
274
|
-
album.songs.object_id.must_equal songs_id
|
275
|
-
end
|
276
|
-
|
277
|
-
# TODO: test with existing collection
|
278
|
-
end
|
279
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'test_helper'
|
2
|
-
|
3
|
-
class PassOptionsTest < BaseTest
|
4
|
-
let (:format) { :hash }
|
5
|
-
let (:song) { Struct.new(:title).new("Revolution") }
|
6
|
-
let (:prepared) { representer.prepare song }
|
7
|
-
|
8
|
-
describe "module" do
|
9
|
-
representer! do
|
10
|
-
property :title, :pass_options => true,
|
11
|
-
:as => lambda { |args| [args.binding.name, args.user_options, args.represented, args.decorator] }
|
12
|
-
end
|
13
|
-
|
14
|
-
it { render(prepared, :volume => 1).must_equal_document({["title", {:volume=>1}, prepared, prepared] => "Revolution"}) }
|
15
|
-
# it { parse(prepared, {"args" => "Wie Es Geht"}).name.must_equal "Wie Es Geht" }
|
16
|
-
end
|
17
|
-
|
18
|
-
describe "decorator" do
|
19
|
-
representer!(:decorator => true) do
|
20
|
-
property :title, :pass_options => true,
|
21
|
-
:as => lambda { |args| [args.binding.name, args.user_options, args.represented, args.decorator] }
|
22
|
-
end
|
23
|
-
|
24
|
-
it { render(prepared, :volume => 1).must_equal_document({["title", {:volume=>1}, song, prepared] => "Revolution"}) }
|
25
|
-
# it { parse(prepared, {"args" => "Wie Es Geht"}).name.must_equal "Wie Es Geht" }
|
26
|
-
end
|
27
|
-
end
|
@@ -1,277 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class PipelineTest < MiniTest::Spec
|
4
|
-
Song = Struct.new(:title, :artist)
|
5
|
-
Artist = Struct.new(:name)
|
6
|
-
Album = Struct.new(:ratings, :artists)
|
7
|
-
|
8
|
-
R = Representable
|
9
|
-
P = R::Pipeline
|
10
|
-
|
11
|
-
Getter = ->(input, options) { "Yo" }
|
12
|
-
StopOnNil = ->(input, options) { input }
|
13
|
-
SkipRender = ->(input, *) { input == "Yo" ? input : P::Stop }
|
14
|
-
|
15
|
-
Prepare = ->(input, options) { "Prepare(#{input})" }
|
16
|
-
Deserialize = ->(input, options) { "Deserialize(#{input}, #{options[:fragment]})" }
|
17
|
-
|
18
|
-
SkipParse = ->(input, options) { input }
|
19
|
-
CreateObject = ->(input, options) { OpenStruct.new }
|
20
|
-
|
21
|
-
|
22
|
-
Setter = ->(input, options) { "Setter(#{input})" }
|
23
|
-
|
24
|
-
AssignFragment = ->(input, options) { options[:fragment] = input }
|
25
|
-
|
26
|
-
it "linear" do
|
27
|
-
P[SkipParse, Setter].("doc", {fragment: 1}).must_equal "Setter(doc)"
|
28
|
-
|
29
|
-
|
30
|
-
# parse style.
|
31
|
-
P[AssignFragment, SkipParse, CreateObject, Prepare].("Bla", {}).must_equal "Prepare(#<OpenStruct>)"
|
32
|
-
|
33
|
-
|
34
|
-
# render style.
|
35
|
-
P[Getter, StopOnNil, SkipRender, Prepare, Setter].(nil, {}).
|
36
|
-
must_equal "Setter(Prepare(Yo))"
|
37
|
-
|
38
|
-
# pipeline = Representable::Pipeline[SkipParse , SetResult, ModifyResult]
|
39
|
-
# pipeline.(fragment: "yo!").must_equal "modified object from yo!"
|
40
|
-
end
|
41
|
-
|
42
|
-
Stopping = ->(input, options) { return P::Stop if options[:fragment] == "stop!"; input }
|
43
|
-
|
44
|
-
|
45
|
-
it "stopping" do
|
46
|
-
|
47
|
-
|
48
|
-
pipeline = Representable::Pipeline[SkipParse, Stopping, Prepare]
|
49
|
-
pipeline.(nil, fragment: "oy!").must_equal "Prepare()"
|
50
|
-
pipeline.(nil, fragment: "stop!").must_equal Representable::Pipeline::Stop
|
51
|
-
end
|
52
|
-
|
53
|
-
describe "Collect" do
|
54
|
-
Reverse = ->(input, options) { input.reverse }
|
55
|
-
Add = ->(input, options) { "#{input}+" }
|
56
|
-
let(:pipeline) { R::Collect[Reverse, Add] }
|
57
|
-
|
58
|
-
it { pipeline.(["yo!", "oy!"], {}).must_equal ["!oy+", "!yo+"] }
|
59
|
-
|
60
|
-
describe "Pipeline with Collect" do
|
61
|
-
let(:pipeline) { P[Reverse, R::Collect[Reverse, Add]] }
|
62
|
-
it { pipeline.(["yo!", "oy!"], {}).must_equal ["!yo+", "!oy+"] }
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
######### scalar property
|
70
|
-
|
71
|
-
let (:title) {
|
72
|
-
dfn = R::Definition.new(:title)
|
73
|
-
|
74
|
-
R::Hash::Binding.new(dfn)
|
75
|
-
}
|
76
|
-
|
77
|
-
it "rendering scalar property" do
|
78
|
-
doc = {}
|
79
|
-
P[
|
80
|
-
R::GetValue,
|
81
|
-
R::StopOnSkipable,
|
82
|
-
R::AssignName,
|
83
|
-
R::WriteFragment
|
84
|
-
].(nil, {represented: Song.new("Lime Green"), binding: title, doc: doc}).must_equal "Lime Green"
|
85
|
-
|
86
|
-
doc.must_equal({"title"=>"Lime Green"})
|
87
|
-
end
|
88
|
-
|
89
|
-
it "parsing scalar property" do
|
90
|
-
P[
|
91
|
-
R::AssignName,
|
92
|
-
R::ReadFragment,
|
93
|
-
R::StopOnNotFound,
|
94
|
-
R::OverwriteOnNil,
|
95
|
-
# R::SkipParse,
|
96
|
-
R::SetValue,
|
97
|
-
].extend(P::Debug).(doc={"title"=>"Eruption"}, {represented: song=Song.new("Lime Green"), binding: title, doc: doc}).must_equal "Eruption"
|
98
|
-
song.title.must_equal "Eruption"
|
99
|
-
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
module ArtistRepresenter
|
104
|
-
include Representable::Hash
|
105
|
-
property :name
|
106
|
-
end
|
107
|
-
|
108
|
-
let (:artist) {
|
109
|
-
dfn = R::Definition.new(:artist, extend: ArtistRepresenter, class: Artist)
|
110
|
-
|
111
|
-
R::Hash::Binding.new(dfn)
|
112
|
-
}
|
113
|
-
|
114
|
-
let (:song_model) { Song.new("Lime Green", Artist.new("Diesel Boy")) }
|
115
|
-
|
116
|
-
it "rendering typed property" do
|
117
|
-
doc = {}
|
118
|
-
P[
|
119
|
-
R::GetValue,
|
120
|
-
R::StopOnSkipable,
|
121
|
-
R::StopOnNil,
|
122
|
-
R::SkipRender,
|
123
|
-
R::Decorate,
|
124
|
-
R::Serialize,
|
125
|
-
R::AssignName,
|
126
|
-
R::WriteFragment
|
127
|
-
].extend(P::Debug).(nil, {represented: song_model, binding: artist, doc: doc, options: {}}).must_equal({"name" => "Diesel Boy"})
|
128
|
-
|
129
|
-
doc.must_equal({"artist"=>{"name"=>"Diesel Boy"}})
|
130
|
-
end
|
131
|
-
|
132
|
-
it "parsing typed property" do
|
133
|
-
P[
|
134
|
-
R::AssignName,
|
135
|
-
R::ReadFragment,
|
136
|
-
R::StopOnNotFound,
|
137
|
-
R::OverwriteOnNil,
|
138
|
-
# R::SkipParse,
|
139
|
-
R::AssignFragment,
|
140
|
-
R::CreateObject::Class,
|
141
|
-
R::Decorate,
|
142
|
-
R::Deserialize,
|
143
|
-
R::SetValue,
|
144
|
-
].extend(P::Debug).(doc={"artist"=>{"name"=>"Doobie Brothers"}}, {represented: song_model, binding: artist, doc: doc, options: {}}).must_equal model=Artist.new("Doobie Brothers")
|
145
|
-
song_model.artist.must_equal model
|
146
|
-
end
|
147
|
-
|
148
|
-
|
149
|
-
######### collection :ratings
|
150
|
-
|
151
|
-
let (:ratings) {
|
152
|
-
dfn = R::Definition.new(:ratings, collection: true)
|
153
|
-
|
154
|
-
R::Hash::Binding::Collection.new(dfn)
|
155
|
-
}
|
156
|
-
it "render scalar collection" do
|
157
|
-
doc = {}
|
158
|
-
P[
|
159
|
-
R::GetValue,
|
160
|
-
R::StopOnSkipable,
|
161
|
-
R::Collect[
|
162
|
-
R::SkipRender,
|
163
|
-
],
|
164
|
-
R::AssignName,
|
165
|
-
R::WriteFragment
|
166
|
-
].extend(P::Debug).(nil, {represented: Album.new([1,2,3]), binding: ratings, doc: doc}).must_equal([1,2,3])
|
167
|
-
|
168
|
-
doc.must_equal({"ratings"=>[1,2,3]})
|
169
|
-
end
|
170
|
-
|
171
|
-
######### collection :songs, extend: SongRepresenter
|
172
|
-
let (:artists) {
|
173
|
-
dfn = R::Definition.new(:artists, collection: true, extend: ArtistRepresenter, class: Artist)
|
174
|
-
|
175
|
-
R::Hash::Binding::Collection.new(dfn)
|
176
|
-
}
|
177
|
-
it "render typed collection" do
|
178
|
-
doc = {}
|
179
|
-
P[
|
180
|
-
R::GetValue,
|
181
|
-
R::StopOnSkipable,
|
182
|
-
R::Collect[
|
183
|
-
R::SkipRender,
|
184
|
-
R::Decorate,
|
185
|
-
R::Serialize,
|
186
|
-
],
|
187
|
-
R::AssignName,
|
188
|
-
R::WriteFragment
|
189
|
-
].extend(P::Debug).(nil, {represented: Album.new(nil, [Artist.new("Diesel Boy"), Artist.new("Van Halen")]), binding: artists, doc: doc, options: {}}).must_equal([{"name"=>"Diesel Boy"}, {"name"=>"Van Halen"}])
|
190
|
-
|
191
|
-
doc.must_equal({"artists"=>[{"name"=>"Diesel Boy"}, {"name"=>"Van Halen"}]})
|
192
|
-
end
|
193
|
-
|
194
|
-
let (:album_model) { Album.new(nil, [Artist.new("Diesel Boy"), Artist.new("Van Halen")]) }
|
195
|
-
|
196
|
-
it "parse typed collection" do
|
197
|
-
doc = {"artists"=>[{"name"=>"Diesel Boy"}, {"name"=>"Van Halen"}]}
|
198
|
-
P[
|
199
|
-
R::AssignName,
|
200
|
-
R::ReadFragment,
|
201
|
-
R::StopOnNotFound,
|
202
|
-
R::OverwriteOnNil,
|
203
|
-
# R::SkipParse,
|
204
|
-
R::Collect[
|
205
|
-
R::AssignFragment,
|
206
|
-
R::SkipRender,
|
207
|
-
R::CreateObject::Class,
|
208
|
-
R::Decorate,
|
209
|
-
R::Deserialize,
|
210
|
-
],
|
211
|
-
R::SetValue,
|
212
|
-
].extend(P::Debug).(doc, {represented: album_model, binding: artists, doc: doc, options: {}}).must_equal([Artist.new("Diesel Boy"), Artist.new("Van Halen")])
|
213
|
-
|
214
|
-
album_model.artists.must_equal([Artist.new("Diesel Boy"), Artist.new("Van Halen")])
|
215
|
-
end
|
216
|
-
|
217
|
-
# TODO: test with arrays, too, not "only" Pipeline instances.
|
218
|
-
describe "#Insert Pipeline[], Function, replace: OldFunction" do
|
219
|
-
let (:pipeline) { P[R::GetValue, R::StopOnSkipable, R::StopOnNil] }
|
220
|
-
|
221
|
-
it "returns Pipeline instance when passing in Pipeline instance" do
|
222
|
-
P::Insert.(pipeline, R::Default, replace: R::StopOnSkipable).must_be_instance_of(R::Pipeline)
|
223
|
-
end
|
224
|
-
|
225
|
-
it "replaces if exists" do
|
226
|
-
# pipeline.insert!(R::Default, replace: R::StopOnSkipable)
|
227
|
-
P::Insert.(pipeline, R::Default, replace: R::StopOnSkipable).must_equal P[R::GetValue, R::Default, R::StopOnNil]
|
228
|
-
pipeline.must_equal P[R::GetValue, R::StopOnSkipable, R::StopOnNil]
|
229
|
-
end
|
230
|
-
|
231
|
-
it "replaces Function instance" do
|
232
|
-
pipeline = P[R::Prepare, R::StopOnSkipable, R::StopOnNil]
|
233
|
-
P::Insert.(pipeline, R::Default, replace: R::Prepare).must_equal P[R::Default, R::StopOnSkipable, R::StopOnNil]
|
234
|
-
pipeline.must_equal P[R::Prepare, R::StopOnSkipable, R::StopOnNil]
|
235
|
-
end
|
236
|
-
|
237
|
-
it "does not replace when not existing" do
|
238
|
-
P::Insert.(pipeline, R::Default, replace: R::Prepare)
|
239
|
-
pipeline.must_equal P[R::GetValue, R::StopOnSkipable, R::StopOnNil]
|
240
|
-
end
|
241
|
-
|
242
|
-
it "applies on nested Collect" do
|
243
|
-
pipeline = P[R::GetValue, R::Collect[R::GetValue, R::StopOnSkipable], R::StopOnNil]
|
244
|
-
|
245
|
-
P::Insert.(pipeline, R::Default, replace: R::StopOnSkipable).extend(P::Debug).inspect.must_equal "Pipeline[GetValue, Collect[GetValue, Default], StopOnNil]"
|
246
|
-
pipeline.must_equal P[R::GetValue, R::Collect[R::GetValue, R::StopOnSkipable], R::StopOnNil]
|
247
|
-
|
248
|
-
|
249
|
-
P::Insert.(pipeline, R::Default, replace: R::StopOnNil).extend(P::Debug).inspect.must_equal "Pipeline[GetValue, Collect[GetValue, StopOnSkipable], Default]"
|
250
|
-
end
|
251
|
-
|
252
|
-
it "applies on nested Collect with Function::CreateObject" do
|
253
|
-
pipeline = P[R::GetValue, R::Collect[R::GetValue, R::CreateObject], R::StopOnNil]
|
254
|
-
|
255
|
-
P::Insert.(pipeline, R::Default, replace: R::CreateObject).extend(P::Debug).inspect.must_equal "Pipeline[GetValue, Collect[GetValue, Default], StopOnNil]"
|
256
|
-
pipeline.must_equal P[R::GetValue, R::Collect[R::GetValue, R::CreateObject], R::StopOnNil]
|
257
|
-
end
|
258
|
-
end
|
259
|
-
|
260
|
-
describe "Insert.(delete: true)" do
|
261
|
-
let(:pipeline) { P[R::GetValue, R::StopOnNil] }
|
262
|
-
|
263
|
-
it do
|
264
|
-
P::Insert.(pipeline, R::GetValue, delete: true).extend(P::Debug).inspect.must_equal "Pipeline[StopOnNil]"
|
265
|
-
pipeline.extend(P::Debug).inspect.must_equal "Pipeline[GetValue, StopOnNil]"
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
describe "Insert.(delete: true) with Collect" do
|
270
|
-
let(:pipeline) { P[R::GetValue, R::Collect[R::GetValue, R::StopOnSkipable], R::StopOnNil] }
|
271
|
-
|
272
|
-
it do
|
273
|
-
P::Insert.(pipeline, R::GetValue, delete: true).extend(P::Debug).inspect.must_equal "Pipeline[Collect[StopOnSkipable], StopOnNil]"
|
274
|
-
pipeline.extend(P::Debug).inspect.must_equal "Pipeline[GetValue, Collect[GetValue, StopOnSkipable], StopOnNil]"
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|