trailblazer 2.0.7 → 2.1.0.beta1

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.
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