trailblazer 2.0.7 → 2.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +35 -1
  3. data/Gemfile +6 -12
  4. data/README.md +3 -1
  5. data/Rakefile +6 -17
  6. data/lib/trailblazer.rb +7 -4
  7. data/lib/trailblazer/deprecation/call.rb +46 -0
  8. data/lib/trailblazer/deprecation/context.rb +43 -0
  9. data/lib/trailblazer/operation/contract.rb +40 -9
  10. data/lib/trailblazer/operation/deprecations.rb +21 -0
  11. data/lib/trailblazer/operation/guard.rb +5 -5
  12. data/lib/trailblazer/operation/model.rb +15 -10
  13. data/lib/trailblazer/operation/nested.rb +56 -85
  14. data/lib/trailblazer/operation/persist.rb +4 -2
  15. data/lib/trailblazer/operation/policy.rb +16 -7
  16. data/lib/trailblazer/operation/pundit.rb +3 -3
  17. data/lib/trailblazer/operation/representer.rb +5 -0
  18. data/lib/trailblazer/operation/rescue.rb +12 -9
  19. data/lib/trailblazer/operation/validate.rb +36 -29
  20. data/lib/trailblazer/operation/wrap.rb +49 -11
  21. data/lib/trailblazer/task.rb +20 -0
  22. data/lib/trailblazer/version.rb +1 -1
  23. data/test/benchmark.rb +63 -0
  24. data/test/deprecation/call_test.rb +42 -0
  25. data/test/deprecation/context_test.rb +19 -0
  26. data/test/docs/contract_test.rb +73 -53
  27. data/test/docs/dry_test.rb +2 -2
  28. data/test/docs/fast_test.rb +133 -13
  29. data/test/docs/guard_test.rb +28 -35
  30. data/test/docs/macro_test.rb +1 -1
  31. data/test/docs/model_test.rb +13 -13
  32. data/test/docs/nested_test.rb +54 -122
  33. data/test/docs/operation_test.rb +42 -43
  34. data/test/docs/pundit_test.rb +16 -16
  35. data/test/docs/representer_test.rb +18 -18
  36. data/test/docs/rescue_test.rb +29 -29
  37. data/test/docs/trace_test.rb +82 -0
  38. data/test/docs/wrap_test.rb +59 -26
  39. data/test/module_test.rb +75 -75
  40. data/test/nested_test.rb +293 -0
  41. data/test/operation/contract_test.rb +23 -153
  42. data/test/operation/dsl/contract_test.rb +9 -9
  43. data/test/operation/dsl/representer_test.rb +169 -169
  44. data/test/operation/model_test.rb +15 -21
  45. data/test/operation/persist_test.rb +18 -11
  46. data/test/operation/pundit_test.rb +25 -23
  47. data/test/operation/representer_test.rb +254 -254
  48. data/test/test_helper.rb +5 -2
  49. data/test/variables_test.rb +158 -0
  50. data/trailblazer.gemspec +1 -1
  51. data/untitled +33 -0
  52. metadata +25 -27
  53. data/lib/trailblazer/operation/callback.rb +0 -35
  54. data/lib/trailblazer/operation/procedural/contract.rb +0 -15
  55. data/lib/trailblazer/operation/procedural/validate.rb +0 -22
  56. data/test/operation/callback_test.rb +0 -70
  57. data/test/operation/dsl/callback_test.rb +0 -106
  58. data/test/operation/params_test.rb +0 -36
  59. data/test/operation/pipedream_test.rb +0 -59
  60. data/test/operation/pipetree_test.rb +0 -104
  61. data/test/operation/present_test.rb +0 -24
  62. data/test/operation/resolver_test.rb +0 -47
  63. data/test/operation_test.rb +0 -143
@@ -9,21 +9,24 @@ class ModelTest < Minitest::Spec
9
9
  #---
10
10
  # use Model semantics, no customizations.
11
11
  class Create < Trailblazer::Operation
12
- step Model Song, :new
12
+ step Model( Song, :new )
13
13
  end
14
14
 
15
15
  # :new new.
16
- it { Create.({})["model"].inspect.must_equal %{#<struct ModelTest::Song id=nil>} }
16
+ it { Create.(params: {})[:model].inspect.must_equal %{#<struct ModelTest::Song id=nil>} }
17
17
 
18
18
  class Update < Create
19
19
  step Model( Song, :find ), override: true
20
20
  end
21
21
 
22
+ #---
23
+ #- inheritance
24
+
22
25
  # :find it
23
- it { Update.({ id: 1 })["model"].inspect.must_equal %{#<struct ModelTest::Song id=1>} }
26
+ it { Update.(params: { id: 1 })[:model].inspect.must_equal %{#<struct ModelTest::Song id=1>} }
24
27
 
25
- #- inheritance
26
- it { Update["pipetree"].inspect.must_equal %{[>operation.new,>model.build]} }
28
+ # inherited inspect is ok
29
+ it { Trailblazer::Operation::Inspect.(Update).must_equal %{[>model.build]} }
27
30
 
28
31
  #---
29
32
  # :find_by, exceptionless.
@@ -31,30 +34,21 @@ class ModelTest < Minitest::Spec
31
34
  step Model Song, :find_by
32
35
  step :process
33
36
 
34
- def process(*); self["x"] = true end
37
+ def process(options, **); options["x"] = true end
35
38
  end
36
39
 
37
40
  # can't find model.
38
41
  #- result object, model
39
42
  it do
40
- Find.(id: nil)["result.model"].failure?.must_equal true
41
- Find.(id: nil)["x"].must_equal nil
42
- Find.(id: nil).failure?.must_equal true
43
+ Find.(params: {id: nil})["result.model"].failure?.must_equal true
44
+ Find.(params: {id: nil})["x"].must_be_nil
45
+ Find.(params: {id: nil}).failure?.must_equal true
43
46
  end
44
47
 
45
48
  #- result object, model
46
49
  it do
47
- Find.(id: 9)["result.model"].success?.must_equal true
48
- Find.(id: 9)["x"].must_equal true
49
- Find.(id: 9)["model"].inspect.must_equal %{#<struct ModelTest::Song id=9>}
50
+ Find.(params: {id: 9})["result.model"].success?.must_equal true
51
+ Find.(params: {id: 9})["x"].must_equal true
52
+ Find.(params: {id: 9})[:model].inspect.must_equal %{#<struct ModelTest::Song id=9>}
50
53
  end
51
-
52
- # #---
53
- # # creating the model before operation instantiation (ex Model::External)
54
- # class Show < Create
55
- # extend Model::BuildMethods # FIXME: how do we communicate that and prevent the include from Model[] ?
56
- # step Model( Song, :update ), before: "operation.new"
57
- # end
58
-
59
- # it { Show.({id: 1})["model"].inspect.must_equal %{#<struct ModelTest::Song id=1>} }
60
54
  end
@@ -6,26 +6,33 @@ class PersistTest < Minitest::Spec
6
6
  end
7
7
 
8
8
  class Create < Trailblazer::Operation
9
- extend Contract::DSL
10
- contract do
9
+ class Form < Reform::Form
11
10
  property :title
12
11
  end
13
12
 
13
+ class Fail1
14
+ def self.call(options, **); options["1. fail"] = "Validate" end
15
+ end
16
+
17
+ class Fail2
18
+ def self.call(options, **); options["2. fail"] = "Persist" end
19
+ end
20
+
14
21
  step Model( Song, :new )
15
- step Contract::Build()
22
+ step Contract::Build( constant: Form )
16
23
  step Contract::Validate()
17
- failure ->(options) { options["1. fail"] = "Validate" }
24
+ fail Fail1
18
25
  step Contract::Persist()
19
- failure ->(options) { options["2. fail"] = "Persist" }
26
+ fail Fail2
20
27
  end
21
28
 
22
- it { Create.(title: "In Recital")["model"].title.must_equal "In Recital" }
23
- it { Create.(title: "In Recital")["model"].saved.must_equal true }
29
+ it { Create.(params: {title: "In Recital"})[:model].title.must_equal "In Recital" }
30
+ it { Create.(params: {title: "In Recital"})[:model].saved.must_equal true }
24
31
  # failure
25
32
  it do
26
- result = Create.(title: "Fail!")
27
- result["model"].saved.must_equal nil
28
- result["model"].title.must_equal "Fail!"
33
+ result = Create.(params: {title: "Fail!"})
34
+ result[:model].saved.must_be_nil
35
+ result[:model].title.must_equal "Fail!"
29
36
  result["2. fail"].must_equal "Persist"
30
37
  result.success?.must_equal false
31
38
  end
@@ -35,7 +42,7 @@ class PersistTest < Minitest::Spec
35
42
  class Update < Create
36
43
  end
37
44
 
38
- it { Update["pipetree"].inspect.must_equal %{[>operation.new,>model.build,>contract.build,>contract.default.validate,<persist_test.rb:17,>persist.save,<persist_test.rb:19]} }
45
+ it { Operation::Inspect.( Update ).must_equal %{[>model.build,>contract.build,>contract.default.validate,<<PersistTest::Create::Fail1,>persist.save,<<PersistTest::Create::Fail2]} }
39
46
 
40
47
  #---
41
48
  it do
@@ -20,31 +20,31 @@ class PolicyTest < Minitest::Spec
20
20
  step Policy::Pundit( Auth, :only_user? )
21
21
  step :process
22
22
 
23
- def process(*)
24
- self["process"] = true
23
+ def process(options, **)
24
+ options["process"] = true
25
25
  end
26
26
  end
27
27
 
28
28
  # successful.
29
29
  it do
30
- result = Create.({}, "current_user" => Module)
30
+ result = Create.(params: {}, current_user: Module)
31
31
  result["process"].must_equal true
32
32
  #- result object, policy
33
33
  result["result.policy.default"].success?.must_equal true
34
- result["result.policy.default"]["message"].must_equal nil
35
- # result[:valid].must_equal nil
34
+ result["result.policy.default"]["message"].must_be_nil
35
+ # result[:valid].must_be_nil
36
36
  result["policy.default"].inspect.must_equal %{<Auth: user:Module, model:nil>}
37
37
  end
38
38
  # breach.
39
39
  it do
40
- result = Create.({}, "current_user" => nil)
41
- result["process"].must_equal nil
40
+ result = Create.(params: {}, current_user: nil)
41
+ result["process"].must_be_nil
42
42
  #- result object, policy
43
43
  result["result.policy.default"].success?.must_equal false
44
44
  result["result.policy.default"]["message"].must_equal "Breach"
45
45
  end
46
- # inject different policy.Condition it { Create.({}, "current_user" => Object, "policy.default.eval" => Trailblazer::Operation::Policy::Pundit::Condition.new(Auth, :user_object?))["process"].must_equal true }
47
- it { Create.({}, "current_user" => Module, "policy.default.eval" => Trailblazer::Operation::Policy::Pundit::Condition.new(Auth, :user_object?))["process"].must_equal nil }
46
+ # inject different policy.Condition it { Create.(params: {}, current_user: Object, "policy.default.eval" => Trailblazer::Operation::Policy::Pundit::Condition.new(Auth, :user_object?))["process"].must_equal true }
47
+ it { Create.(params: {}, current_user: Module, "policy.default.eval" => Trailblazer::Operation::Policy::Pundit::Condition.new(Auth, :user_object?))["process"].must_be_nil }
48
48
 
49
49
 
50
50
  #---
@@ -53,22 +53,22 @@ class PolicyTest < Minitest::Spec
53
53
  step Model( Song, :new ), before: "policy.default.eval"
54
54
  end
55
55
 
56
- it { Show["pipetree"].inspect.must_equal %{[>operation.new,>model.build,>policy.default.eval,>process]} }
56
+ it { Trailblazer::Operation::Inspect.(Show).must_equal %{[>model.build,>policy.default.eval,>process]} }
57
57
 
58
58
  # invalid because user AND model.
59
59
  it do
60
- result = Show.({}, "current_user" => Module)
61
- result["process"].must_equal nil
62
- result["model"].inspect.must_equal %{#<struct PolicyTest::Song id=nil>}
60
+ result = Show.(params: {}, current_user: Module)
61
+ result["process"].must_be_nil
62
+ result[:model].inspect.must_equal %{#<struct PolicyTest::Song id=nil>}
63
63
  # result["policy"].inspect.must_equal %{#<struct PolicyTest::Song id=nil>}
64
64
  end
65
65
 
66
66
  # valid because new policy.
67
67
  it do
68
68
  # puts Show["pipetree"].inspect
69
- result = Show.({}, "current_user" => Module, "policy.default.eval" => Trailblazer::Operation::Policy::Pundit::Condition.new(Auth, :user_and_model?))
69
+ result = Show.(params: {}, current_user: Module, "policy.default.eval" => Trailblazer::Operation::Policy::Pundit::Condition.new(Auth, :user_and_model?))
70
70
  result["process"].must_equal true
71
- result["model"].inspect.must_equal %{#<struct PolicyTest::Song id=nil>}
71
+ result[:model].inspect.must_equal %{#<struct PolicyTest::Song id=nil>}
72
72
  result["policy.default"].inspect.must_equal %{<Auth: user:Module, model:#<struct PolicyTest::Song id=nil>>}
73
73
  end
74
74
 
@@ -79,25 +79,27 @@ class PolicyTest < Minitest::Spec
79
79
  step Policy::Pundit( Auth, :user_and_model? )
80
80
  step :process
81
81
 
82
- def process(*); self["process"] = true end
82
+ def process(options, **)
83
+ options["process"] = true
84
+ end
83
85
  end
84
86
 
85
87
  # successful.
86
88
  it do
87
- result = Edit.({ id: 1 }, "current_user" => Module)
89
+ result = Edit.(params: { id: 1 }, current_user: Module)
88
90
  result["process"].must_equal true
89
- result["model"].inspect.must_equal %{#<struct PolicyTest::Song id=1>}
91
+ result[:model].inspect.must_equal %{#<struct PolicyTest::Song id=1>}
90
92
  result["result.policy.default"].success?.must_equal true
91
- result["result.policy.default"]["message"].must_equal nil
92
- # result[:valid].must_equal nil
93
+ result["result.policy.default"]["message"].must_be_nil
94
+ # result[:valid].must_be_nil
93
95
  result["policy.default"].inspect.must_equal %{<Auth: user:Module, model:#<struct PolicyTest::Song id=1>>}
94
96
  end
95
97
 
96
98
  # breach.
97
99
  it do
98
- result = Edit.({ id: 4 }, "current_user" => nil)
99
- result["model"].inspect.must_equal %{#<struct PolicyTest::Song id=4>}
100
- result["process"].must_equal nil
100
+ result = Edit.(params: { id: 4 }, current_user: nil)
101
+ result[:model].inspect.must_equal %{#<struct PolicyTest::Song id=4>}
102
+ result["process"].must_be_nil
101
103
  result["result.policy.default"].success?.must_equal false
102
104
  result["result.policy.default"]["message"].must_equal "Breach"
103
105
  end
@@ -1,254 +1,254 @@
1
- require "test_helper"
2
- require "representable/json"
3
-
4
- class RepresenterTest < MiniTest::Spec
5
- Album = Struct.new(:title, :artist)
6
- Artist = Struct.new(:name)
7
-
8
- class Create < Trailblazer::Operation
9
- include Contract::Explicit
10
- include Representer
11
- include Representer::InferFromContract
12
- attr_reader :model # FIXME: all we want is #model.
13
-
14
- contract do
15
- property :title
16
- validates :title, presence: true
17
- property :artist, populate_if_empty: Artist do
18
- property :name
19
- validates :name, presence: true
20
- end
21
- end
22
-
23
- def call(params)
24
- self["model"] = Album.new # NO artist!!!
25
- validate(params[:album], model: self["model"])
26
- self
27
- end
28
- end
29
-
30
-
31
- # Infers representer from contract, no customization.
32
- class Show < Create
33
- def call(params)
34
- self["model"] = Album.new("After The War", Artist.new("Gary Moore"))
35
- self
36
- end
37
- end
38
-
39
-
40
- # Infers representer, adds hypermedia.
41
- require "roar/json/hal"
42
- class HypermediaCreate < Create
43
- representer do
44
- include Roar::JSON::HAL
45
-
46
- link(:self) { "//album/#{represented.title}" }
47
- end
48
- end
49
-
50
- class HypermediaShow < HypermediaCreate
51
- def call(params)
52
- self["model"] = Album.new("After The War", Artist.new("Gary Moore"))
53
- self
54
- end
55
- end
56
-
57
-
58
- # rendering
59
- # generic contract -> representer
60
- it { Show.().to_json.must_equal %{{"title":"After The War","artist":{"name":"Gary Moore"}}} }
61
-
62
- # contract -> representer with hypermedia
63
- it do
64
- HypermediaShow.().to_json.must_equal %{{"title":"After The War","artist":{"name":"Gary Moore"},"_links":{"self":{"href":"//album/After The War"}}}}
65
- end
66
-
67
-
68
- # parsing
69
- it do
70
- op = Create.(album: %{{"title":"Run For Cover","artist":{"name":"Gary Moore"}}})
71
- op.contract.title.must_equal "Run For Cover"
72
- op.contract.artist.name.must_equal "Gary Moore"
73
- end
74
-
75
- it do
76
- op = HypermediaCreate.(album: %{{"title":"After The War","artist":{"name":"Gary Moore"},"_links":{"self":{"href":"//album/After The War"}}}})
77
- op.contract.title.must_equal "After The War"
78
- op.contract.artist.name.must_equal "Gary Moore"
79
- end
80
-
81
-
82
-
83
-
84
-
85
- # explicit representer set with ::representer_class=.
86
- require "roar/decorator"
87
- class JsonApiCreate < Trailblazer::Operation
88
- include Contract::Explicit
89
- include Representer
90
- attr_reader :model
91
-
92
- contract do # we still need contract as the representer writes to the contract twin.
93
- property :title
94
- end
95
-
96
- class AlbumRepresenter < Roar::Decorator
97
- include Roar::JSON
98
- property :title
99
- end
100
-
101
- # FIXME: this won't inherit, of course.
102
- # self["representer.class"] = AlbumRepresenter
103
- representer AlbumRepresenter
104
-
105
- def call(params)
106
- self["model"] = Album.new # NO artist!!!
107
- validate(params[:album], model: self["model"])
108
- self
109
- end
110
- end
111
-
112
- class JsonApiShow < JsonApiCreate
113
- def call(params)
114
- self["model"] = Album.new("After The War", Artist.new("Gary Moore"))
115
- self
116
- end
117
- end
118
-
119
- # render.
120
- it do
121
- JsonApiShow.().to_json.must_equal %{{"title":"After The War"}}
122
- end
123
-
124
- # parse.
125
- it do
126
- JsonApiCreate.(album: %{{"title":"Run For Cover"}}).contract.title.must_equal "Run For Cover"
127
- end
128
- end
129
-
130
- class InternalRepresenterAPITest < MiniTest::Spec
131
- Song = Struct.new(:id)
132
-
133
- describe "#represented" do
134
- class Show < Trailblazer::Operation
135
- include Contract::Explicit
136
- include Representer, Model
137
- model Song, :create
138
-
139
- representer do
140
- property :class
141
- end
142
-
143
- def call(*)
144
- self
145
- end
146
-
147
- def model # FIXME.
148
- self["model"]
149
- end
150
- end
151
-
152
- it "uses #model as represented, per default" do
153
- Show.({}).to_json.must_equal '{"class":"InternalRepresenterAPITest::Song"}'
154
- end
155
-
156
- class ShowContract < Show
157
- def represented
158
- "Object"
159
- end
160
- end
161
-
162
- it "can be overriden to use the contract" do
163
- ShowContract.({}).to_json.must_equal %{{"class":"String"}}
164
- end
165
- end
166
-
167
- describe "#to_json" do
168
- class OptionsShow < Trailblazer::Operation
169
- include Representer
170
-
171
- representer do
172
- property :class
173
- property :id
174
- end
175
-
176
- def to_json(*)
177
- super(self["params"])
178
- end
179
-
180
- include Model::Builder
181
- def model!(*)
182
- Song.new(1)
183
- end
184
- end
185
-
186
- it "allows to pass options to #to_json" do
187
- OptionsShow.(include: [:id]).to_json.must_equal %{{"id":1}}
188
- end
189
- end
190
- end
191
-
192
- class DifferentParseAndRenderingRepresenterTest < MiniTest::Spec
193
- Album = Struct.new(:title)
194
-
195
- # rendering
196
- class Create < Trailblazer::Operation
197
- include Contract::Explicit
198
- extend Representer::DSL
199
- include Representer::Rendering # no Deserializer::Hash here or anything.
200
-
201
- contract do
202
- property :title
203
- end
204
-
205
- representer do
206
- property :title, as: :Title
207
- end
208
-
209
- def call(params)
210
- self["model"] = Album.new
211
- validate(params) do
212
- contract.sync
213
- end
214
- self
215
- end
216
- end
217
-
218
- it do
219
- Create.(title: "The Kids").to_json.must_equal %{{"Title":"The Kids"}}
220
- end
221
-
222
- # parsing
223
- class Update < Trailblazer::Operation
224
- include Contract::Explicit
225
- extend Representer::DSL
226
- include Representer::Deserializer::Hash # no Rendering.
227
-
228
- representer do
229
- property :title, as: :Title
230
- end
231
-
232
- contract do
233
- property :title
234
- end
235
-
236
- def call(params)
237
- self["model"] = Album.new
238
-
239
- validate(params) do
240
- contract.sync
241
- end
242
-
243
- self
244
- end
245
-
246
- def to_json(*)
247
- %{{"title": "#{self["model"].title}"}}
248
- end
249
- end
250
-
251
- it do
252
- Update.("Title" => "The Kids").to_json.must_equal %{{"title": "The Kids"}}
253
- end
254
- end
1
+ # require "test_helper"
2
+ # require "representable/json"
3
+
4
+ # class RepresenterTest < MiniTest::Spec
5
+ # Album = Struct.new(:title, :artist)
6
+ # Artist = Struct.new(:name)
7
+
8
+ # class Create < Trailblazer::Operation
9
+ # include Contract
10
+ # include Representer
11
+ # include Representer::InferFromContract
12
+ # attr_reader :model # FIXME: all we want is #model.
13
+
14
+ # contract do
15
+ # property :title
16
+ # validates :title, presence: true
17
+ # property :artist, populate_if_empty: Artist do
18
+ # property :name
19
+ # validates :name, presence: true
20
+ # end
21
+ # end
22
+
23
+ # def call(params)
24
+ # self["model"] = Album.new # NO artist!!!
25
+ # validate(params[:album], model: self["model"])
26
+ # self
27
+ # end
28
+ # end
29
+
30
+
31
+ # # Infers representer from contract, no customization.
32
+ # class Show < Create
33
+ # def call(params)
34
+ # self["model"] = Album.new("After The War", Artist.new("Gary Moore"))
35
+ # self
36
+ # end
37
+ # end
38
+
39
+
40
+ # # Infers representer, adds hypermedia.
41
+ # require "roar/json/hal"
42
+ # class HypermediaCreate < Create
43
+ # representer do
44
+ # include Roar::JSON::HAL
45
+
46
+ # link(:self) { "//album/#{represented.title}" }
47
+ # end
48
+ # end
49
+
50
+ # class HypermediaShow < HypermediaCreate
51
+ # def call(params)
52
+ # self["model"] = Album.new("After The War", Artist.new("Gary Moore"))
53
+ # self
54
+ # end
55
+ # end
56
+
57
+
58
+ # # rendering
59
+ # # generic contract -> representer
60
+ # it { Show.().to_json.must_equal %{{"title":"After The War","artist":{"name":"Gary Moore"}}} }
61
+
62
+ # # contract -> representer with hypermedia
63
+ # it do
64
+ # HypermediaShow.().to_json.must_equal %{{"title":"After The War","artist":{"name":"Gary Moore"},"_links":{"self":{"href":"//album/After The War"}}}}
65
+ # end
66
+
67
+
68
+ # # parsing
69
+ # it do
70
+ # op = Create.(album: %{{"title":"Run For Cover","artist":{"name":"Gary Moore"}}})
71
+ # op.contract.title.must_equal "Run For Cover"
72
+ # op.contract.artist.name.must_equal "Gary Moore"
73
+ # end
74
+
75
+ # it do
76
+ # op = HypermediaCreate.(album: %{{"title":"After The War","artist":{"name":"Gary Moore"},"_links":{"self":{"href":"//album/After The War"}}}})
77
+ # op.contract.title.must_equal "After The War"
78
+ # op.contract.artist.name.must_equal "Gary Moore"
79
+ # end
80
+
81
+
82
+
83
+
84
+
85
+ # # explicit representer set with ::representer_class=.
86
+ # require "roar/decorator"
87
+ # class JsonApiCreate < Trailblazer::Operation
88
+ # include Contract
89
+ # include Representer
90
+ # attr_reader :model
91
+
92
+ # contract do # we still need contract as the representer writes to the contract twin.
93
+ # property :title
94
+ # end
95
+
96
+ # class AlbumRepresenter < Roar::Decorator
97
+ # include Roar::JSON
98
+ # property :title
99
+ # end
100
+
101
+ # # FIXME: this won't inherit, of course.
102
+ # # self["representer.class"] = AlbumRepresenter
103
+ # representer AlbumRepresenter
104
+
105
+ # def call(params)
106
+ # self["model"] = Album.new # NO artist!!!
107
+ # validate(params[:album], model: self["model"])
108
+ # self
109
+ # end
110
+ # end
111
+
112
+ # class JsonApiShow < JsonApiCreate
113
+ # def call(params)
114
+ # self["model"] = Album.new("After The War", Artist.new("Gary Moore"))
115
+ # self
116
+ # end
117
+ # end
118
+
119
+ # # render.
120
+ # it do
121
+ # JsonApiShow.().to_json.must_equal %{{"title":"After The War"}}
122
+ # end
123
+
124
+ # # parse.
125
+ # it do
126
+ # JsonApiCreate.(album: %{{"title":"Run For Cover"}}).contract.title.must_equal "Run For Cover"
127
+ # end
128
+ # end
129
+
130
+ # class InternalRepresenterAPITest < MiniTest::Spec
131
+ # Song = Struct.new(:id)
132
+
133
+ # describe "#represented" do
134
+ # class Show < Trailblazer::Operation
135
+ # include Contract
136
+ # include Representer, Model
137
+ # model Song, :create
138
+
139
+ # representer do
140
+ # property :class
141
+ # end
142
+
143
+ # def call(*)
144
+ # self
145
+ # end
146
+
147
+ # def model # FIXME.
148
+ # self["model"]
149
+ # end
150
+ # end
151
+
152
+ # it "uses #model as represented, per default" do
153
+ # Show.({}).to_json.must_equal '{"class":"InternalRepresenterAPITest::Song"}'
154
+ # end
155
+
156
+ # class ShowContract < Show
157
+ # def represented
158
+ # "Object"
159
+ # end
160
+ # end
161
+
162
+ # it "can be overriden to use the contract" do
163
+ # ShowContract.({}).to_json.must_equal %{{"class":"String"}}
164
+ # end
165
+ # end
166
+
167
+ # describe "#to_json" do
168
+ # class OptionsShow < Trailblazer::Operation
169
+ # include Representer
170
+
171
+ # representer do
172
+ # property :class
173
+ # property :id
174
+ # end
175
+
176
+ # def to_json(*)
177
+ # super(self["params"])
178
+ # end
179
+
180
+ # include Model::Builder
181
+ # def model!(*)
182
+ # Song.new(1)
183
+ # end
184
+ # end
185
+
186
+ # it "allows to pass options to #to_json" do
187
+ # OptionsShow.(include: [:id]).to_json.must_equal %{{"id":1}}
188
+ # end
189
+ # end
190
+ # end
191
+
192
+ # class DifferentParseAndRenderingRepresenterTest < MiniTest::Spec
193
+ # Album = Struct.new(:title)
194
+
195
+ # # rendering
196
+ # class Create < Trailblazer::Operation
197
+ # include Contract
198
+ # extend Representer::DSL
199
+ # include Representer::Rendering # no Deserializer::Hash here or anything.
200
+
201
+ # contract do
202
+ # property :title
203
+ # end
204
+
205
+ # representer do
206
+ # property :title, as: :Title
207
+ # end
208
+
209
+ # def call(params)
210
+ # self["model"] = Album.new
211
+ # validate(params) do
212
+ # contract.sync
213
+ # end
214
+ # self
215
+ # end
216
+ # end
217
+
218
+ # it do
219
+ # Create.(title: "The Kids").to_json.must_equal %{{"Title":"The Kids"}}
220
+ # end
221
+
222
+ # # parsing
223
+ # class Update < Trailblazer::Operation
224
+ # include Contract
225
+ # extend Representer::DSL
226
+ # include Representer::Deserializer::Hash # no Rendering.
227
+
228
+ # representer do
229
+ # property :title, as: :Title
230
+ # end
231
+
232
+ # contract do
233
+ # property :title
234
+ # end
235
+
236
+ # def call(params)
237
+ # self["model"] = Album.new
238
+
239
+ # validate(params) do
240
+ # contract.sync
241
+ # end
242
+
243
+ # self
244
+ # end
245
+
246
+ # def to_json(*)
247
+ # %{{"title": "#{self["model"].title}"}}
248
+ # end
249
+ # end
250
+
251
+ # it do
252
+ # Update.("Title" => "The Kids").to_json.must_equal %{{"title": "The Kids"}}
253
+ # end
254
+ # end