representable 2.4.0.rc2 → 2.4.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +6 -1
- data/Gemfile +1 -1
- data/lib/representable/deprecations.rb +1 -1
- data/lib/representable/deserializer.rb +3 -5
- data/lib/representable/hash_methods.rb +1 -1
- data/lib/representable/insert.rb +10 -3
- data/lib/representable/parse_strategies.rb +5 -3
- data/lib/representable/pipeline_factories.rb +3 -3
- data/lib/representable/serializer.rb +1 -1
- data/lib/representable/version.rb +1 -1
- data/test/pipeline_test.rb +37 -19
- data/test/populator_test.rb +31 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f9cc279171577dec367b7910ae42b4d4f8b6240
|
4
|
+
data.tar.gz: 193116e06652a35c3fa5bd5124a401d51c8d5c7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14296a6fb55202f2c747cbe0a77e97a3bef8f82673eae9467cd290243dd0ed438f3ffe5fbbf7ec53728818b91459774f18e7141117d9788bd497218ad4899325
|
7
|
+
data.tar.gz: 35a26662c16e844cb9944cdf06cb9a5014c266f53568e714d0f37e49922076cc200e1126fb554dc13a2a0115a97479ea5ddce300bf3d6663148f9adf9ef108c8
|
data/CHANGES.md
CHANGED
@@ -44,8 +44,13 @@ and it suddenly is super simple to understand
|
|
44
44
|
* Removed `Binding@represented` (which was never public anyway). Use `Binding#represented`.
|
45
45
|
* Changed signature: `Binding#get(represented:)`. In now needs a hash `{represented: ..}`.
|
46
46
|
|
47
|
-
# 2.4.0.
|
47
|
+
# 2.4.0.rc3
|
48
48
|
|
49
|
+
* `CreateObject` no longer invokes `AssignFragment`. This is now part of the official parse pipeline.
|
50
|
+
|
51
|
+
# 2.4.0.rc4
|
52
|
+
|
53
|
+
* `Set` is `SetValue`. `Get` is `GetValue`.
|
49
54
|
* Use Declarative's `::build_definition` interface instead of overwriting `::property`.
|
50
55
|
|
51
56
|
# 2.3.0
|
data/Gemfile
CHANGED
@@ -84,7 +84,7 @@ module Representable::Binding::Deprecation
|
|
84
84
|
|
85
85
|
def get(options={}) # DISCUSS: evluate if we really need this.
|
86
86
|
warn "[Representable] Binding#get is deprecated."
|
87
|
-
self[:getter] ? Representable::Getter.(nil, options.merge(binding: self)) : Representable::
|
87
|
+
self[:getter] ? Representable::Getter.(nil, options.merge(binding: self)) : Representable::GetValue.(nil, options.merge(binding: self))
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
@@ -20,7 +20,7 @@ module Representable
|
|
20
20
|
end
|
21
21
|
|
22
22
|
OverwriteOnNil = ->(input, options) do
|
23
|
-
input.nil? ? (
|
23
|
+
input.nil? ? (SetValue.(input, options); Pipeline::Stop) : input
|
24
24
|
end
|
25
25
|
|
26
26
|
Default = ->(input, options) do
|
@@ -38,8 +38,6 @@ module Representable
|
|
38
38
|
module Function
|
39
39
|
class CreateObject
|
40
40
|
def call(input, options)
|
41
|
-
AssignFragment.(input, options)
|
42
|
-
|
43
41
|
instance_for(input, options) || class_for(input, options)
|
44
42
|
end
|
45
43
|
|
@@ -99,8 +97,8 @@ module Representable
|
|
99
97
|
options[:binding][:parse_filter].(input, options)
|
100
98
|
end
|
101
99
|
|
102
|
-
Setter
|
103
|
-
|
100
|
+
Setter = ->(input, options) { options[:binding].evaluate_option(:setter, input, options) }
|
101
|
+
SetValue = ->(input, options) { options[:binding].send(:exec_context, options).send(options[:binding].setter, input) }
|
104
102
|
|
105
103
|
|
106
104
|
Stop = ->(*) { Pipeline::Stop }
|
@@ -4,7 +4,7 @@ module Representable
|
|
4
4
|
hash = filter_keys_for!(represented, options) # FIXME: this modifies options and replicates logic from Representable.
|
5
5
|
bin = representable_map(options, format).first
|
6
6
|
|
7
|
-
Collect::Hash[*bin.default_render_fragment_functions].
|
7
|
+
Collect::Hash[*bin.default_render_fragment_functions].(hash, {doc: doc, user_options: options, binding: bin, represented: represented, decorator: self})
|
8
8
|
end
|
9
9
|
|
10
10
|
def update_properties_from(doc, options, format)
|
data/lib/representable/insert.rb
CHANGED
@@ -16,12 +16,19 @@ module Representable
|
|
16
16
|
arr[index] = Collect[*Pipeline::Insert.(func, new_func, replace: old_func)]
|
17
17
|
end
|
18
18
|
|
19
|
-
arr[index] = new_func if
|
19
|
+
arr[index] = new_func if func==old_func
|
20
20
|
}
|
21
21
|
end
|
22
22
|
|
23
|
-
def delete!(arr,
|
24
|
-
arr.delete(
|
23
|
+
def delete!(arr, removed_func)
|
24
|
+
arr.delete(removed_func)
|
25
|
+
|
26
|
+
# TODO: make nice.
|
27
|
+
arr.each_with_index { |func, index|
|
28
|
+
if func.is_a?(Collect)
|
29
|
+
arr[index] = Collect[*Pipeline::Insert.(func, removed_func, delete: true)]
|
30
|
+
end
|
31
|
+
}
|
25
32
|
end
|
26
33
|
end
|
27
34
|
end
|
@@ -1,8 +1,6 @@
|
|
1
1
|
module Representable
|
2
2
|
class Populator
|
3
3
|
FindOrInstantiate = ->(input, options) {
|
4
|
-
AssignFragment.(input, options)
|
5
|
-
|
6
4
|
binding = options[:binding]
|
7
5
|
|
8
6
|
object_class = binding[:class].(input, options)
|
@@ -18,13 +16,17 @@ module Representable
|
|
18
16
|
object
|
19
17
|
}
|
20
18
|
|
19
|
+
# pipeline: [StopOnExcluded, AssignName, ReadFragment, StopOnNotFound, OverwriteOnNil, AssignFragment, #<Representable::Function::CreateObject:0x9805a44>, #<Representable::Function::Decorate:0x9805a1c>, Deserialize, Set]
|
20
|
+
|
21
21
|
def self.apply!(options)
|
22
22
|
return unless populator = options[:populator]
|
23
23
|
|
24
24
|
options[:parse_pipeline] = ->(input, options) do
|
25
25
|
pipeline = Pipeline[*parse_functions] # TODO: AssignFragment
|
26
|
-
pipeline = Pipeline::Insert.(pipeline,
|
26
|
+
pipeline = Pipeline::Insert.(pipeline, SetValue, delete: true) # remove the setter function.
|
27
27
|
pipeline = Pipeline::Insert.(pipeline, populator, replace: CreateObject) # let the populator do CreateObject's job.
|
28
|
+
# puts pipeline.extend(Representable::Pipeline::Debug).inspect
|
29
|
+
pipeline
|
28
30
|
end
|
29
31
|
end
|
30
32
|
end
|
@@ -44,7 +44,7 @@ module Representable
|
|
44
44
|
functions << Stop if self[:readable]==false
|
45
45
|
functions << StopOnExcluded
|
46
46
|
functions << If if self[:if]
|
47
|
-
functions << (self[:getter] ? Getter :
|
47
|
+
functions << (self[:getter] ? Getter : GetValue)
|
48
48
|
functions << Writer if self[:writer]
|
49
49
|
functions << RenderFilter if self[:render_filter].any?
|
50
50
|
functions << RenderDefault if has_default?
|
@@ -64,7 +64,7 @@ module Representable
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def default_parse_fragment_functions
|
67
|
-
functions = []
|
67
|
+
functions = [AssignFragment]
|
68
68
|
functions << SkipParse if self[:skip_parse]
|
69
69
|
|
70
70
|
if typed?
|
@@ -82,7 +82,7 @@ module Representable
|
|
82
82
|
def default_post_functions
|
83
83
|
funcs = []
|
84
84
|
funcs << ParseFilter if self[:parse_filter].any?
|
85
|
-
funcs << (self[:setter] ? Setter :
|
85
|
+
funcs << (self[:setter] ? Setter : SetValue)
|
86
86
|
end
|
87
87
|
end
|
88
88
|
end
|
@@ -3,7 +3,7 @@ module Representable
|
|
3
3
|
options[:binding].evaluate_option(:getter, input, options)
|
4
4
|
end
|
5
5
|
|
6
|
-
|
6
|
+
GetValue = ->(input, options) { options[:binding].send(:exec_context, options).send(options[:binding].getter) }
|
7
7
|
|
8
8
|
Writer = ->(input, options) do
|
9
9
|
options[:binding].evaluate_option(:writer, input, options)
|
data/test/pipeline_test.rb
CHANGED
@@ -77,7 +77,7 @@ class PipelineTest < MiniTest::Spec
|
|
77
77
|
it "rendering scalar property" do
|
78
78
|
doc = {}
|
79
79
|
P[
|
80
|
-
R::
|
80
|
+
R::GetValue,
|
81
81
|
R::StopOnSkipable,
|
82
82
|
R::AssignName,
|
83
83
|
R::WriteFragment
|
@@ -93,7 +93,7 @@ class PipelineTest < MiniTest::Spec
|
|
93
93
|
R::StopOnNotFound,
|
94
94
|
R::OverwriteOnNil,
|
95
95
|
# R::SkipParse,
|
96
|
-
R::
|
96
|
+
R::SetValue,
|
97
97
|
].extend(P::Debug).(doc={"title"=>"Eruption"}, {represented: song=Song.new("Lime Green"), binding: title, doc: doc}).must_equal "Eruption"
|
98
98
|
song.title.must_equal "Eruption"
|
99
99
|
end
|
@@ -116,7 +116,7 @@ class PipelineTest < MiniTest::Spec
|
|
116
116
|
it "rendering typed property" do
|
117
117
|
doc = {}
|
118
118
|
P[
|
119
|
-
R::
|
119
|
+
R::GetValue,
|
120
120
|
R::StopOnSkipable,
|
121
121
|
R::StopOnNil,
|
122
122
|
R::SkipRender,
|
@@ -136,10 +136,11 @@ class PipelineTest < MiniTest::Spec
|
|
136
136
|
R::StopOnNotFound,
|
137
137
|
R::OverwriteOnNil,
|
138
138
|
# R::SkipParse,
|
139
|
+
R::AssignFragment,
|
139
140
|
R::CreateObject,
|
140
141
|
R::Decorate,
|
141
142
|
R::Deserialize,
|
142
|
-
R::
|
143
|
+
R::SetValue,
|
143
144
|
].extend(P::Debug).(doc={"artist"=>{"name"=>"Doobie Brothers"}}, {represented: song_model, binding: artist, doc: doc, user_options: {}}).must_equal model=Artist.new("Doobie Brothers")
|
144
145
|
song_model.artist.must_equal model
|
145
146
|
end
|
@@ -155,7 +156,7 @@ class PipelineTest < MiniTest::Spec
|
|
155
156
|
it "render scalar collection" do
|
156
157
|
doc = {}
|
157
158
|
P[
|
158
|
-
R::
|
159
|
+
R::GetValue,
|
159
160
|
R::StopOnSkipable,
|
160
161
|
R::Collect[
|
161
162
|
R::SkipRender,
|
@@ -176,7 +177,7 @@ class PipelineTest < MiniTest::Spec
|
|
176
177
|
it "render typed collection" do
|
177
178
|
doc = {}
|
178
179
|
P[
|
179
|
-
R::
|
180
|
+
R::GetValue,
|
180
181
|
R::StopOnSkipable,
|
181
182
|
R::Collect[
|
182
183
|
R::SkipRender,
|
@@ -201,12 +202,13 @@ let (:album_model) { Album.new(nil, [Artist.new("Diesel Boy"), Artist.new("Van H
|
|
201
202
|
R::OverwriteOnNil,
|
202
203
|
# R::SkipParse,
|
203
204
|
R::Collect[
|
205
|
+
R::AssignFragment,
|
204
206
|
R::SkipRender,
|
205
207
|
R::CreateObject,
|
206
208
|
R::Decorate,
|
207
209
|
R::Deserialize,
|
208
210
|
],
|
209
|
-
R::
|
211
|
+
R::SetValue,
|
210
212
|
].extend(P::Debug).(doc, {represented: album_model, binding: artists, doc: doc, user_options: {}}).must_equal([Artist.new("Diesel Boy"), Artist.new("Van Halen")])
|
211
213
|
|
212
214
|
album_model.artists.must_equal([Artist.new("Diesel Boy"), Artist.new("Van Halen")])
|
@@ -214,7 +216,7 @@ let (:album_model) { Album.new(nil, [Artist.new("Diesel Boy"), Artist.new("Van H
|
|
214
216
|
|
215
217
|
# TODO: test with arrays, too, not "only" Pipeline instances.
|
216
218
|
describe "#Insert Pipeline[], Function, replace: OldFunction" do
|
217
|
-
let (:pipeline) { P[R::
|
219
|
+
let (:pipeline) { P[R::GetValue, R::StopOnSkipable, R::StopOnNil] }
|
218
220
|
|
219
221
|
it "returns Pipeline instance when passing in Pipeline instance" do
|
220
222
|
P::Insert.(pipeline, R::Default, replace: R::StopOnSkipable).must_be_instance_of(R::Pipeline)
|
@@ -222,8 +224,8 @@ let (:album_model) { Album.new(nil, [Artist.new("Diesel Boy"), Artist.new("Van H
|
|
222
224
|
|
223
225
|
it "replaces if exists" do
|
224
226
|
# pipeline.insert!(R::Default, replace: R::StopOnSkipable)
|
225
|
-
P::Insert.(pipeline, R::Default, replace: R::StopOnSkipable).must_equal P[R::
|
226
|
-
pipeline.must_equal P[R::
|
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]
|
227
229
|
end
|
228
230
|
|
229
231
|
it "replaces Function instance" do
|
@@ -234,26 +236,42 @@ let (:album_model) { Album.new(nil, [Artist.new("Diesel Boy"), Artist.new("Van H
|
|
234
236
|
|
235
237
|
it "does not replace when not existing" do
|
236
238
|
P::Insert.(pipeline, R::Default, replace: R::Prepare)
|
237
|
-
pipeline.must_equal P[R::
|
239
|
+
pipeline.must_equal P[R::GetValue, R::StopOnSkipable, R::StopOnNil]
|
238
240
|
end
|
239
241
|
|
240
242
|
it "applies on nested Collect" do
|
241
|
-
pipeline = P[R::
|
243
|
+
pipeline = P[R::GetValue, R::Collect[R::GetValue, R::StopOnSkipable], R::StopOnNil]
|
242
244
|
|
243
|
-
P::Insert.(pipeline, R::Default, replace: R::StopOnSkipable).extend(P::Debug).inspect.must_equal "Pipeline[
|
244
|
-
pipeline.must_equal P[R::
|
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]
|
245
247
|
|
246
248
|
|
247
|
-
P::Insert.(pipeline, R::Default, replace: R::StopOnNil).extend(P::Debug).inspect.must_equal "Pipeline[
|
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]"
|
248
266
|
end
|
249
267
|
end
|
250
268
|
|
251
|
-
describe "Insert
|
252
|
-
let(:pipeline) { P[R::
|
269
|
+
describe "Insert.(delete: true) with Collect" do
|
270
|
+
let(:pipeline) { P[R::GetValue, R::Collect[R::GetValue, R::StopOnSkipable], R::StopOnNil] }
|
253
271
|
|
254
272
|
it do
|
255
|
-
P::Insert.(pipeline, R::
|
256
|
-
pipeline.extend(P::Debug).inspect.must_equal "Pipeline[
|
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]"
|
257
275
|
end
|
258
276
|
end
|
259
277
|
end
|
data/test/populator_test.rb
CHANGED
@@ -1,6 +1,35 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
|
-
class
|
3
|
+
class PopulatorTest < Minitest::Spec
|
4
|
+
Song = Struct.new(:id)
|
5
|
+
Artist = Struct.new(:name)
|
6
|
+
Album = Struct.new(:songs, :artist)
|
7
|
+
|
8
|
+
describe "populator: ->{}" do
|
9
|
+
representer! do
|
10
|
+
collection :songs, populator: ->(input, options) { options[:represented].songs << song = Song.new; song } do
|
11
|
+
property :id
|
12
|
+
end
|
13
|
+
|
14
|
+
property :artist, populator: ->(input, options) { options[:represented].artist = Artist.new } do
|
15
|
+
property :name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
let (:album) { Album.new([]) }
|
20
|
+
|
21
|
+
it do
|
22
|
+
album.extend(representer).from_hash("songs"=>[{"id"=>1}, {"id"=>2}], "artist"=>{"name"=>"Waste"})
|
23
|
+
album.inspect.must_equal "#<struct PopulatorTest::Album songs=[#<struct PopulatorTest::Song id=1>, #<struct PopulatorTest::Song id=2>], artist=#<struct PopulatorTest::Artist name=\"Waste\">>"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "populator: ->{}, " do
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class PopulatorFindOrInstantiateTest < Minitest::Spec
|
4
33
|
Song = Struct.new(:id, :title, :uid) do
|
5
34
|
def self.find_by(attributes={})
|
6
35
|
return new(1, "Resist Stan", "abcd") if attributes[:id]==1# we should return the same object here
|
@@ -26,7 +55,7 @@ class PopulatorFindOrInstantiateTest < MiniTest::Spec
|
|
26
55
|
end
|
27
56
|
end
|
28
57
|
|
29
|
-
let (:album) { Composer.new.extend(representer) }
|
58
|
+
let (:album) { Composer.new.extend(representer).extend(Representable::Debug) }
|
30
59
|
|
31
60
|
it "finds by :id and creates new without :id" do
|
32
61
|
album.from_hash({"song"=>{"id" => 1, "title"=>"Resist Stance"}})
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: representable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.4.0.
|
4
|
+
version: 2.4.0.rc3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uber
|