trailblazer 2.0.7 → 2.1.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 +5 -5
- data/.gitignore +1 -0
- data/.rubocop-https---raw-githubusercontent-com-trailblazer-meta-master-rubocop-yml +101 -0
- data/.rubocop.yml +20 -0
- data/.rubocop_todo.yml +556 -0
- data/.travis.yml +6 -10
- data/CHANGES.md +83 -1
- data/COMM-LICENSE +46 -75
- data/CONTRIBUTING.md +179 -0
- data/Gemfile +0 -27
- data/{LICENSE.txt → LICENSE} +4 -4
- data/README.md +39 -138
- data/Rakefile +2 -19
- data/lib/trailblazer.rb +3 -17
- data/lib/trailblazer/version.rb +3 -1
- data/test/test_helper.rb +12 -3
- data/trailblazer.gemspec +10 -14
- metadata +22 -147
- data/doc/Trb-The-Stack.png +0 -0
- data/doc/operation-2017.png +0 -0
- data/doc/trb.jpg +0 -0
- data/lib/trailblazer/dsl.rb +0 -47
- data/lib/trailblazer/operation/auto_inject.rb +0 -47
- data/lib/trailblazer/operation/callback.rb +0 -35
- data/lib/trailblazer/operation/contract.rb +0 -46
- data/lib/trailblazer/operation/guard.rb +0 -18
- data/lib/trailblazer/operation/model.rb +0 -60
- data/lib/trailblazer/operation/module.rb +0 -29
- data/lib/trailblazer/operation/nested.rb +0 -113
- data/lib/trailblazer/operation/persist.rb +0 -10
- data/lib/trailblazer/operation/policy.rb +0 -35
- data/lib/trailblazer/operation/procedural/contract.rb +0 -15
- data/lib/trailblazer/operation/procedural/validate.rb +0 -22
- data/lib/trailblazer/operation/pundit.rb +0 -38
- data/lib/trailblazer/operation/representer.rb +0 -31
- data/lib/trailblazer/operation/rescue.rb +0 -21
- data/lib/trailblazer/operation/test.rb +0 -17
- data/lib/trailblazer/operation/validate.rb +0 -68
- data/lib/trailblazer/operation/wrap.rb +0 -25
- data/test/docs/auto_inject_test.rb +0 -30
- data/test/docs/contract_test.rb +0 -525
- data/test/docs/dry_test.rb +0 -31
- data/test/docs/fast_test.rb +0 -164
- data/test/docs/guard_test.rb +0 -169
- data/test/docs/macro_test.rb +0 -36
- data/test/docs/model_test.rb +0 -75
- data/test/docs/nested_test.rb +0 -334
- data/test/docs/operation_test.rb +0 -408
- data/test/docs/policy_test.rb +0 -2
- data/test/docs/pundit_test.rb +0 -133
- data/test/docs/representer_test.rb +0 -268
- data/test/docs/rescue_test.rb +0 -154
- data/test/docs/wrap_test.rb +0 -183
- data/test/gemfiles/Gemfile.ruby-1.9 +0 -3
- data/test/gemfiles/Gemfile.ruby-2.0 +0 -12
- data/test/gemfiles/Gemfile.ruby-2.3 +0 -12
- data/test/module_test.rb +0 -100
- data/test/operation/callback_test.rb +0 -70
- data/test/operation/contract_test.rb +0 -420
- data/test/operation/dsl/callback_test.rb +0 -106
- data/test/operation/dsl/contract_test.rb +0 -294
- data/test/operation/dsl/representer_test.rb +0 -169
- data/test/operation/model_test.rb +0 -60
- data/test/operation/params_test.rb +0 -36
- data/test/operation/persist_test.rb +0 -44
- data/test/operation/pipedream_test.rb +0 -59
- data/test/operation/pipetree_test.rb +0 -104
- data/test/operation/present_test.rb +0 -24
- data/test/operation/pundit_test.rb +0 -104
- data/test/operation/representer_test.rb +0 -254
- data/test/operation/resolver_test.rb +0 -47
- data/test/operation_test.rb +0 -143
data/test/docs/nested_test.rb
DELETED
@@ -1,334 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class DocsNestedOperationTest < Minitest::Spec
|
4
|
-
Song = Struct.new(:id, :title) do
|
5
|
-
def self.find(id)
|
6
|
-
return new(1, "Bristol") if id == 1
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
#---
|
11
|
-
#- nested operations
|
12
|
-
#:edit
|
13
|
-
class Edit < Trailblazer::Operation
|
14
|
-
extend Contract::DSL
|
15
|
-
|
16
|
-
contract do
|
17
|
-
property :title
|
18
|
-
end
|
19
|
-
|
20
|
-
step Model( Song, :find )
|
21
|
-
step Contract::Build()
|
22
|
-
end
|
23
|
-
#:edit end
|
24
|
-
|
25
|
-
# step Nested( Edit ) #, "policy.default" => self["policy.create"]
|
26
|
-
#:update
|
27
|
-
class Update < Trailblazer::Operation
|
28
|
-
step Nested( Edit )
|
29
|
-
step Contract::Validate()
|
30
|
-
step Contract::Persist( method: :sync )
|
31
|
-
end
|
32
|
-
#:update end
|
33
|
-
|
34
|
-
puts Update["pipetree"].inspect(style: :rows)
|
35
|
-
|
36
|
-
#-
|
37
|
-
# Edit allows grabbing model and contract
|
38
|
-
it do
|
39
|
-
#:edit-call
|
40
|
-
result = Edit.(id: 1)
|
41
|
-
|
42
|
-
result["model"] #=> #<Song id=1, title=\"Bristol\">
|
43
|
-
result["contract.default"] #=> #<Reform::Form ..>
|
44
|
-
#:edit-call end
|
45
|
-
result.inspect("model").must_equal %{<Result:true [#<struct DocsNestedOperationTest::Song id=1, title=\"Bristol\">] >}
|
46
|
-
result["contract.default"].model.must_equal result["model"]
|
47
|
-
end
|
48
|
-
|
49
|
-
#-
|
50
|
-
# Update also allows grabbing model and contract
|
51
|
-
it do
|
52
|
-
#:update-call
|
53
|
-
result = Update.(id: 1, title: "Call It A Night")
|
54
|
-
|
55
|
-
result["model"] #=> #<Song id=1 , title=\"Call It A Night\">
|
56
|
-
result["contract.default"] #=> #<Reform::Form ..>
|
57
|
-
#:update-call end
|
58
|
-
result.inspect("model").must_equal %{<Result:true [#<struct DocsNestedOperationTest::Song id=1, title=\"Call It A Night\">] >}
|
59
|
-
result["contract.default"].model.must_equal result["model"]
|
60
|
-
end
|
61
|
-
|
62
|
-
#-
|
63
|
-
# Edit is successful.
|
64
|
-
it do
|
65
|
-
result = Update.({ id: 1, title: "Miami" }, "current_user" => Module)
|
66
|
-
result.inspect("model").must_equal %{<Result:true [#<struct DocsNestedOperationTest::Song id=1, title="Miami">] >}
|
67
|
-
end
|
68
|
-
|
69
|
-
# Edit fails
|
70
|
-
it do
|
71
|
-
Update.(id: 2).inspect("model").must_equal %{<Result:false [nil] >}
|
72
|
-
end
|
73
|
-
|
74
|
-
#---
|
75
|
-
#- shared data
|
76
|
-
class B < Trailblazer::Operation
|
77
|
-
success ->(options) { options["can.B.see.it?"] = options["this.should.not.be.visible.in.B"] }
|
78
|
-
success ->(options) { options["can.B.see.current_user?"] = options["current_user"] }
|
79
|
-
success ->(options) { options["can.B.see.params?"] = options["params"] }
|
80
|
-
success ->(options) { options["can.B.see.A.class.data?"] = options["A.class.data"] }
|
81
|
-
end
|
82
|
-
|
83
|
-
class A < Trailblazer::Operation
|
84
|
-
self["A.class.data"] = true
|
85
|
-
|
86
|
-
success ->(options) { options["this.should.not.be.visible.in.B"] = true }
|
87
|
-
step Nested( B )
|
88
|
-
end
|
89
|
-
|
90
|
-
# mutual data from A doesn't bleed into B.
|
91
|
-
it { A.()["can.B.see.it?"].must_equal nil }
|
92
|
-
it { A.()["this.should.not.be.visible.in.B"].must_equal true }
|
93
|
-
# runtime dependencies are visible in B.
|
94
|
-
it { A.({}, "current_user" => Module)["can.B.see.current_user?"].must_equal Module }
|
95
|
-
it { A.({ a: 1 })["can.B.see.params?"].must_equal({ a: 1 }) }
|
96
|
-
# class data from A doesn't bleed into B.
|
97
|
-
it { A.()["can.B.see.A.class.data?"].must_equal nil }
|
98
|
-
|
99
|
-
|
100
|
-
# cr_result = Create.({}, "result" => result)
|
101
|
-
# puts cr_result["model"]
|
102
|
-
# puts cr_result["contract.default"]
|
103
|
-
|
104
|
-
#---
|
105
|
-
#- Nested( .., input: )
|
106
|
-
class C < Trailblazer::Operation
|
107
|
-
self["C.class.data"] = true
|
108
|
-
|
109
|
-
success ->(options) { options["this.should.not.be.visible.in.B"] = true }
|
110
|
-
|
111
|
-
step Nested( B, input: ->(options, runtime_data:, mutable_data:, **) {
|
112
|
-
runtime_data.merge( "this.should.not.be.visible.in.B" => mutable_data["this.should.not.be.visible.in.B"] )
|
113
|
-
} )
|
114
|
-
end
|
115
|
-
|
116
|
-
it { C.()["can.B.see.it?"].must_equal true }
|
117
|
-
it { C.()["this.should.not.be.visible.in.B"].must_equal true } # this IS visible since we use :input!
|
118
|
-
it { C.({}, "current_user" => Module)["can.B.see.current_user?"].must_equal Module }
|
119
|
-
it { C.()["can.B.see.A.class.data?"].must_equal nil }
|
120
|
-
end
|
121
|
-
|
122
|
-
class NestedInput < Minitest::Spec
|
123
|
-
#:input-multiply
|
124
|
-
class Multiplier < Trailblazer::Operation
|
125
|
-
step ->(options, x:, y:, **) { options["product"] = x*y }
|
126
|
-
end
|
127
|
-
#:input-multiply end
|
128
|
-
|
129
|
-
#:input-pi
|
130
|
-
class MultiplyByPi < Trailblazer::Operation
|
131
|
-
step ->(options) { options["pi_constant"] = 3.14159 }
|
132
|
-
step Nested( Multiplier, input: ->(options, mutable_data:, runtime_data:, **) do
|
133
|
-
{ "y" => mutable_data["pi_constant"],
|
134
|
-
"x" => runtime_data["x"] }
|
135
|
-
end )
|
136
|
-
end
|
137
|
-
#:input-pi end
|
138
|
-
|
139
|
-
it { MultiplyByPi.({}, "x" => 9).inspect("product").must_equal %{<Result:true [28.27431] >} }
|
140
|
-
|
141
|
-
it do
|
142
|
-
#:input-result
|
143
|
-
result = MultiplyByPi.({}, "x" => 9)
|
144
|
-
result["product"] #=> [28.27431]
|
145
|
-
#:input-result end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
class NestedInputCallable < Minitest::Spec
|
150
|
-
Multiplier = NestedInput::Multiplier
|
151
|
-
|
152
|
-
#:input-callable
|
153
|
-
class MyInput
|
154
|
-
extend Uber::Callable
|
155
|
-
|
156
|
-
def self.call(options, mutable_data:, runtime_data:, **)
|
157
|
-
{
|
158
|
-
"y" => mutable_data["pi_constant"],
|
159
|
-
"x" => runtime_data["x"]
|
160
|
-
}
|
161
|
-
end
|
162
|
-
end
|
163
|
-
#:input-callable end
|
164
|
-
|
165
|
-
#:input-callable-op
|
166
|
-
class MultiplyByPi < Trailblazer::Operation
|
167
|
-
step ->(options) { options["pi_constant"] = 3.14159 }
|
168
|
-
step Nested( Multiplier, input: MyInput )
|
169
|
-
end
|
170
|
-
#:input-callable-op end
|
171
|
-
|
172
|
-
it { MultiplyByPi.({}, "x" => 9).inspect("product").must_equal %{<Result:true [28.27431] >} }
|
173
|
-
end
|
174
|
-
|
175
|
-
#---
|
176
|
-
#- Nested( .., output: )
|
177
|
-
class NestedOutput < Minitest::Spec
|
178
|
-
Edit = DocsNestedOperationTest::Edit
|
179
|
-
|
180
|
-
#:output
|
181
|
-
class Update < Trailblazer::Operation
|
182
|
-
step Nested( Edit, output: ->(options, mutable_data:, **) do
|
183
|
-
{
|
184
|
-
"contract.my" => mutable_data["contract.default"],
|
185
|
-
"model" => mutable_data["model"]
|
186
|
-
}
|
187
|
-
end )
|
188
|
-
step Contract::Validate( name: "my" )
|
189
|
-
step Contract::Persist( method: :sync, name: "my" )
|
190
|
-
end
|
191
|
-
#:output end
|
192
|
-
|
193
|
-
it { Update.( id: 1, title: "Call It A Night" ).inspect("model", "contract.default").must_equal %{<Result:true [#<struct DocsNestedOperationTest::Song id=1, title=\"Call It A Night\">, nil] >} }
|
194
|
-
|
195
|
-
it do
|
196
|
-
result = Update.( id: 1, title: "Call It A Night" )
|
197
|
-
|
198
|
-
result["model"] #=> #<Song id=1 , title=\"Call It A Night\">
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
class NestedClassLevelTest < Minitest::Spec
|
203
|
-
#:class-level
|
204
|
-
class New < Trailblazer::Operation
|
205
|
-
step ->(options) { options["class"] = true }, before: "operation.new"
|
206
|
-
step ->(options) { options["x"] = true }
|
207
|
-
end
|
208
|
-
|
209
|
-
class Create < Trailblazer::Operation
|
210
|
-
step Nested( New )
|
211
|
-
step ->(options) { options["y"] = true }
|
212
|
-
end
|
213
|
-
#:class-level end
|
214
|
-
|
215
|
-
it { Create.().inspect("x", "y").must_equal %{<Result:true [true, true] >} }
|
216
|
-
it { Create.(); Create["class"].must_equal nil }
|
217
|
-
end
|
218
|
-
|
219
|
-
#---
|
220
|
-
# Nested( ->{} )
|
221
|
-
class NestedWithCallableTest < Minitest::Spec
|
222
|
-
Song = Struct.new(:id, :title)
|
223
|
-
|
224
|
-
class X < Trailblazer::Operation
|
225
|
-
step ->(options, params:, **) { options["params.original"] = params }
|
226
|
-
step ->(options) { options["x"] = true }
|
227
|
-
end
|
228
|
-
|
229
|
-
class Y < Trailblazer::Operation
|
230
|
-
step ->(options) { options["y"] = true }
|
231
|
-
end
|
232
|
-
|
233
|
-
class A < Trailblazer::Operation
|
234
|
-
step ->(options) { options["z"] = true }
|
235
|
-
step Nested( ->(options, *) { options["class"] } )
|
236
|
-
end
|
237
|
-
|
238
|
-
it { A.({ a: 1 }, "class" => X).inspect("x", "y", "z", "params.original").must_equal "<Result:true [true, nil, true, {:a=>1}] >" }
|
239
|
-
it { A.({}, "class" => Y).inspect("x", "y", "z").must_equal "<Result:true [nil, true, true] >" }
|
240
|
-
# it { Create.({}).inspect("x", "y", "z").must_equal "<Result:true [nil, true, true] >" }
|
241
|
-
|
242
|
-
class Song
|
243
|
-
module Contract
|
244
|
-
class Create < Reform::Form
|
245
|
-
property :title
|
246
|
-
end
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
User = Struct.new(:is_admin) do
|
251
|
-
def admin?
|
252
|
-
!! is_admin
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
class Create < Trailblazer::Operation
|
257
|
-
step Nested( ->(options, current_user:nil, **) { current_user.admin? ? Admin : NeedsModeration })
|
258
|
-
|
259
|
-
class NeedsModeration < Trailblazer::Operation
|
260
|
-
step Model( Song, :new )
|
261
|
-
step Contract::Build( constant: Song::Contract::Create )
|
262
|
-
step Contract::Validate()
|
263
|
-
step :notify_moderator!
|
264
|
-
|
265
|
-
def notify_moderator!(options, **)
|
266
|
-
#~noti
|
267
|
-
options["x"] = true
|
268
|
-
#~noti end
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
class Admin < Trailblazer::Operation # TODO: test if current_user is passed in.
|
273
|
-
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
let (:admin) { User.new(true) }
|
278
|
-
let (:anonymous) { User.new(false) }
|
279
|
-
|
280
|
-
it { Create.({}, "current_user" => anonymous).inspect("x").must_equal %{<Result:true [true] >} }
|
281
|
-
it { Create.({}, "current_user" => admin) .inspect("x").must_equal %{<Result:true [nil] >} }
|
282
|
-
|
283
|
-
#---
|
284
|
-
#:method
|
285
|
-
class Update < Trailblazer::Operation
|
286
|
-
step Nested( :build! )
|
287
|
-
|
288
|
-
def build!(options, current_user:nil, **)
|
289
|
-
current_user.admin? ? Create::Admin : Create::NeedsModeration
|
290
|
-
end
|
291
|
-
end
|
292
|
-
#:method end
|
293
|
-
|
294
|
-
it { Update.({}, "current_user" => anonymous).inspect("x").must_equal %{<Result:true [true] >} }
|
295
|
-
it { Update.({}, "current_user" => admin) .inspect("x").must_equal %{<Result:true [nil] >} }
|
296
|
-
|
297
|
-
#---
|
298
|
-
#:callable-builder
|
299
|
-
class MyBuilder
|
300
|
-
extend Uber::Callable
|
301
|
-
|
302
|
-
def self.call(options, current_user:nil, **)
|
303
|
-
current_user.admin? ? Create::Admin : Create::NeedsModeration
|
304
|
-
end
|
305
|
-
end
|
306
|
-
#:callable-builder end
|
307
|
-
|
308
|
-
#:callable
|
309
|
-
class Delete < Trailblazer::Operation
|
310
|
-
step Nested( MyBuilder )
|
311
|
-
# ..
|
312
|
-
end
|
313
|
-
#:callable end
|
314
|
-
|
315
|
-
it { Delete.({}, "current_user" => anonymous).inspect("x").must_equal %{<Result:true [true] >} }
|
316
|
-
it { Delete.({}, "current_user" => admin) .inspect("x").must_equal %{<Result:true [nil] >} }
|
317
|
-
end
|
318
|
-
|
319
|
-
# builder: Nested + deviate to left if nil / skip_track if true
|
320
|
-
|
321
|
-
#---
|
322
|
-
# automatic :name
|
323
|
-
class NestedNameTest < Minitest::Spec
|
324
|
-
class Create < Trailblazer::Operation
|
325
|
-
class Present < Trailblazer::Operation
|
326
|
-
# ...
|
327
|
-
end
|
328
|
-
|
329
|
-
step Nested( Present )
|
330
|
-
# ...
|
331
|
-
end
|
332
|
-
|
333
|
-
it { Create["pipetree"].inspect.must_equal %{[>operation.new,>Nested(NestedNameTest::Create::Present)]} }
|
334
|
-
end
|
data/test/docs/operation_test.rb
DELETED
@@ -1,408 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class DocsOperationExampleTest < Minitest::Spec
|
4
|
-
Song = Struct.new(:id, :title, :created_by) do
|
5
|
-
def save; true; end
|
6
|
-
end
|
7
|
-
User = Struct.new(:name)
|
8
|
-
|
9
|
-
#:invocation-dep
|
10
|
-
class Create < Trailblazer::Operation
|
11
|
-
step Model( Song, :new )
|
12
|
-
step :assign_current_user!
|
13
|
-
# ..
|
14
|
-
def assign_current_user!(options)
|
15
|
-
options["model"].created_by = options["current_user"]
|
16
|
-
end
|
17
|
-
end
|
18
|
-
#:invocation-dep end
|
19
|
-
|
20
|
-
it do
|
21
|
-
current_user = User.new("Ema")
|
22
|
-
#:invocation-dep-call
|
23
|
-
result = Create.( { title: "Roxanne" }, "current_user" => current_user )
|
24
|
-
#:invocation-dep-call end
|
25
|
-
|
26
|
-
#:invocation-dep-res
|
27
|
-
result["current_user"] #=> #<User name="Ema">
|
28
|
-
result["model"] #=> #<Song id=nil, title=nil, created_by=#<User name="Ema">>
|
29
|
-
#:invocation-dep-res end
|
30
|
-
end
|
31
|
-
|
32
|
-
it { Create.({ title: "Roxanne" }, "current_user" => Module).inspect("model").must_equal %{<Result:true [#<struct DocsOperationExampleTest::Song id=nil, title=nil, created_by=Module>] >} }
|
33
|
-
|
34
|
-
#:op
|
35
|
-
class Song::Create < Trailblazer::Operation
|
36
|
-
extend Contract::DSL
|
37
|
-
|
38
|
-
contract do
|
39
|
-
property :title
|
40
|
-
validates :title, presence: true
|
41
|
-
end
|
42
|
-
|
43
|
-
step Model( Song, :new )
|
44
|
-
step :assign_current_user!
|
45
|
-
step Contract::Build()
|
46
|
-
step Contract::Validate( )
|
47
|
-
failure :log_error!
|
48
|
-
step Contract::Persist( )
|
49
|
-
|
50
|
-
def log_error!(options)
|
51
|
-
# ..
|
52
|
-
end
|
53
|
-
|
54
|
-
def assign_current_user!(options)
|
55
|
-
options["model"].created_by =
|
56
|
-
options["current_user"]
|
57
|
-
end
|
58
|
-
end
|
59
|
-
#:op end
|
60
|
-
|
61
|
-
it { Song::Create.({ }).inspect("model").must_equal %{<Result:false [#<struct DocsOperationExampleTest::Song id=nil, title=nil, created_by=nil>] >} }
|
62
|
-
it { Song::Create.({ title: "Nothin'" }, "current_user"=>Module).inspect("model").must_equal %{<Result:true [#<struct DocsOperationExampleTest::Song id=nil, title="Nothin'", created_by=Module>] >} }
|
63
|
-
end
|
64
|
-
|
65
|
-
class DndTest < Minitest::Spec
|
66
|
-
class Create < Trailblazer::Operation
|
67
|
-
step :authorize!
|
68
|
-
failure :auth_err!
|
69
|
-
step :save!
|
70
|
-
failure Wrap
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
class DocsResultTest < Minitest::Spec
|
75
|
-
Song = Struct.new(:id, :title, :created_by) do
|
76
|
-
def save; true; end
|
77
|
-
end
|
78
|
-
|
79
|
-
#:step-options
|
80
|
-
class Song::Create < Trailblazer::Operation
|
81
|
-
step :model!
|
82
|
-
step :assign!
|
83
|
-
step :validate!
|
84
|
-
|
85
|
-
def model!(options, current_user:, **)
|
86
|
-
options["model"] = Song.new
|
87
|
-
options["model"].created_by = current_user
|
88
|
-
end
|
89
|
-
|
90
|
-
def assign!(*, params:, model:, **)
|
91
|
-
model.title= params[:title]
|
92
|
-
end
|
93
|
-
|
94
|
-
#:step-val
|
95
|
-
def validate!(options, model:, **)
|
96
|
-
options["result.validate"] = ( model.created_by && model.title )
|
97
|
-
end
|
98
|
-
#:step-val end
|
99
|
-
end
|
100
|
-
#:step-options end
|
101
|
-
|
102
|
-
it do
|
103
|
-
current_user = Struct.new(:email).new("nick@trailblazer.to")
|
104
|
-
#:step-res
|
105
|
-
result = Song::Create.({ title: "Roxanne" }, "current_user" => current_user)
|
106
|
-
|
107
|
-
result["model"] #=> #<Song title="Roxanne", "created_by"=<User ...>
|
108
|
-
result["result.validate"] #=> true
|
109
|
-
#:step-res end
|
110
|
-
|
111
|
-
result.inspect("current_user", "model").must_equal %{<Result:true [#<struct email=\"nick@trailblazer.to\">, #<struct DocsResultTest::Song id=nil, title="Roxanne", created_by=#<struct email=\"nick@trailblazer.to\">>] >}
|
112
|
-
|
113
|
-
#:step-binary
|
114
|
-
result.success? #=> true
|
115
|
-
result.failure? #=> falsee
|
116
|
-
#:step-binary end
|
117
|
-
|
118
|
-
#:step-dep
|
119
|
-
result["current_user"] #=> <User ...>
|
120
|
-
#:step-dep end
|
121
|
-
|
122
|
-
#:step-inspect
|
123
|
-
result.inspect("current_user", "model") #=> "<Result:true [#<User email=\"nick@tra... "
|
124
|
-
#:step-inspect end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
class DocsDependencyTest < Minitest::Spec
|
129
|
-
Song = Struct.new(:id, :title, :created_by) do
|
130
|
-
def save; true; end
|
131
|
-
end
|
132
|
-
Hit = Struct.new(:id)
|
133
|
-
|
134
|
-
#:dep-op
|
135
|
-
class Song::Create < Trailblazer::Operation
|
136
|
-
self["my.model.class"] = Song
|
137
|
-
|
138
|
-
#~dep-pipe
|
139
|
-
step :model!
|
140
|
-
|
141
|
-
def model!(options, **)
|
142
|
-
options["my.model"] = # setting runtime data.
|
143
|
-
options["my.model.class"].new # reading class data at runtime.
|
144
|
-
end
|
145
|
-
#~dep-pipe end
|
146
|
-
end
|
147
|
-
#:dep-op end
|
148
|
-
|
149
|
-
it do
|
150
|
-
#:dep-op-class
|
151
|
-
Song::Create["my.model.class"] #=> Song
|
152
|
-
#:dep-op-class end
|
153
|
-
|
154
|
-
#:dep-op-res
|
155
|
-
result = Song::Create.({})
|
156
|
-
|
157
|
-
result["my.model.class"] #=> Song
|
158
|
-
result["my.model"] #=> #<Song title=nil>
|
159
|
-
#:dep-op-res end
|
160
|
-
|
161
|
-
Song::Create["my.model.class"].must_equal Song
|
162
|
-
result["my.model.class"].must_equal Song
|
163
|
-
result["my.model"].inspect.must_equal %{#<struct DocsDependencyTest::Song id=nil, title=nil, created_by=nil>}
|
164
|
-
end
|
165
|
-
|
166
|
-
it do
|
167
|
-
#:dep-di
|
168
|
-
result = Song::Create.({}, "my.model.class" => Hit)
|
169
|
-
|
170
|
-
result["my.model"] #=> #<Hit id=nil>
|
171
|
-
#:dep-di end
|
172
|
-
result["my.model"].inspect.must_equal %{#<struct DocsDependencyTest::Hit id=nil>}
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
class DocsOperationAPIExampleTest < Minitest::Spec
|
179
|
-
Song = Struct.new(:id, :title, :created_by) do
|
180
|
-
def save; true; end
|
181
|
-
end
|
182
|
-
|
183
|
-
class MyContract < Reform::Form
|
184
|
-
property :title
|
185
|
-
validates :title, presence: true
|
186
|
-
end
|
187
|
-
|
188
|
-
#:op-api
|
189
|
-
class Song::Create < Trailblazer::Operation
|
190
|
-
step Model( Song, :new )
|
191
|
-
step :assign_current_user!
|
192
|
-
step Contract::Build( constant: MyContract )
|
193
|
-
step Contract::Validate()
|
194
|
-
failure :log_error!
|
195
|
-
step Contract::Persist()
|
196
|
-
|
197
|
-
def log_error!(options)
|
198
|
-
# ..
|
199
|
-
end
|
200
|
-
|
201
|
-
def assign_current_user!(options)
|
202
|
-
options["model"].created_by =
|
203
|
-
options["current_user"]
|
204
|
-
end
|
205
|
-
end
|
206
|
-
#:op-api end
|
207
|
-
|
208
|
-
it { Song::Create.({ }).inspect("model").must_equal %{<Result:false [#<struct DocsOperationAPIExampleTest::Song id=nil, title=nil, created_by=nil>] >} }
|
209
|
-
it { Song::Create.({ title: "Nothin'" }, "current_user"=>Module).inspect("model").must_equal %{<Result:true [#<struct DocsOperationAPIExampleTest::Song id=nil, title="Nothin'", created_by=Module>] >} }
|
210
|
-
end
|
211
|
-
|
212
|
-
|
213
|
-
class DocsOperationInheritanceTest < Minitest::Spec
|
214
|
-
Song = Struct.new(:id, :title, :created_by) do
|
215
|
-
def save; true; end
|
216
|
-
end
|
217
|
-
|
218
|
-
class MyContract < Reform::Form
|
219
|
-
property :title
|
220
|
-
validates :title, presence: true
|
221
|
-
end
|
222
|
-
|
223
|
-
#:inh-new
|
224
|
-
class New < Trailblazer::Operation
|
225
|
-
step Model( Song, :new )
|
226
|
-
step Contract::Build( constant: MyContract )
|
227
|
-
end
|
228
|
-
#:inh-new end
|
229
|
-
|
230
|
-
puts New["pipetree"].inspect(style: :row)
|
231
|
-
=begin
|
232
|
-
#:inh-new-pipe
|
233
|
-
0 =======================>>operation.new
|
234
|
-
1 ==========================&model.build
|
235
|
-
2 =======================>contract.build
|
236
|
-
#:inh-new-pipe end
|
237
|
-
=end
|
238
|
-
|
239
|
-
#:inh-create
|
240
|
-
class Create < New
|
241
|
-
step Contract::Validate()
|
242
|
-
step Contract::Persist()
|
243
|
-
end
|
244
|
-
#:inh-create end
|
245
|
-
|
246
|
-
puts Create["pipetree"].inspect(style: :row)
|
247
|
-
=begin
|
248
|
-
#:inh-create-pipe
|
249
|
-
0 =======================>>operation.new
|
250
|
-
1 ==========================&model.build
|
251
|
-
2 =======================>contract.build
|
252
|
-
3 ==============&contract.default.params
|
253
|
-
4 ============&contract.default.validate
|
254
|
-
5 =========================&persist.save
|
255
|
-
#:inh-create-pipe end
|
256
|
-
=end
|
257
|
-
|
258
|
-
module MyApp
|
259
|
-
end
|
260
|
-
|
261
|
-
#:override-app
|
262
|
-
module MyApp::Operation
|
263
|
-
class New < Trailblazer::Operation
|
264
|
-
extend Contract::DSL
|
265
|
-
|
266
|
-
contract do
|
267
|
-
property :title
|
268
|
-
end
|
269
|
-
|
270
|
-
step Model( nil, :new )
|
271
|
-
step Contract::Build()
|
272
|
-
end
|
273
|
-
end
|
274
|
-
#:override-app end
|
275
|
-
|
276
|
-
#:override-new
|
277
|
-
class Song::New < MyApp::Operation::New
|
278
|
-
step Model( Song, :new ), override: true
|
279
|
-
end
|
280
|
-
#:override-new end
|
281
|
-
|
282
|
-
puts Song::New["pipetree"].inspect(style: :row)
|
283
|
-
=begin
|
284
|
-
#:override-pipe
|
285
|
-
Song::New["pipetree"].inspect(style: :row)
|
286
|
-
0 =======================>>operation.new
|
287
|
-
1 ==========================&model.build
|
288
|
-
2 =======================>contract.build
|
289
|
-
#:override-pipe end
|
290
|
-
=end
|
291
|
-
|
292
|
-
it do
|
293
|
-
Song::New["pipetree"].inspect.must_equal %{[>operation.new,>model.build,>contract.build]}
|
294
|
-
Song::New.().inspect("model").must_equal %{<Result:true [#<struct DocsOperationInheritanceTest::Song id=nil, title=nil, created_by=nil>] >}
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
class DocsOperationStepOptionsTest < Minitest::Spec
|
299
|
-
Song = Struct.new(:title) do
|
300
|
-
def self.find_by(*)
|
301
|
-
nil
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
class AutomaticNameTest < Minitest::Spec
|
306
|
-
#:name-auto
|
307
|
-
class New < Trailblazer::Operation
|
308
|
-
step Model( Song, :new )
|
309
|
-
end
|
310
|
-
#:name-auto end
|
311
|
-
|
312
|
-
puts New["pipetree"].inspect(style: :row)
|
313
|
-
=begin
|
314
|
-
#:name-auto-pipe
|
315
|
-
0 =======================>>operation.new
|
316
|
-
1 ==========================&model.build
|
317
|
-
#:name-auto-pipe end
|
318
|
-
=end
|
319
|
-
|
320
|
-
#:replace-inh
|
321
|
-
class Update < New
|
322
|
-
step Model(Song, :find_by), replace: "model.build"
|
323
|
-
end
|
324
|
-
#:replace-inh end
|
325
|
-
|
326
|
-
puts Update["pipetree"].inspect(style: :row)
|
327
|
-
=begin
|
328
|
-
#:replace-inh-pipe
|
329
|
-
0 =======================>>operation.new
|
330
|
-
2 ==========================&model.build
|
331
|
-
#:replace-inh-pipe end
|
332
|
-
=end
|
333
|
-
|
334
|
-
it { Update.({}).inspect("model").must_equal %{<Result:false [nil] >} }
|
335
|
-
|
336
|
-
|
337
|
-
# #:delete-inh
|
338
|
-
# class Noop < New
|
339
|
-
# step nil, delete: "model.build"
|
340
|
-
# end
|
341
|
-
# #:delete-inh end
|
342
|
-
|
343
|
-
# puts "yo"
|
344
|
-
# puts Update["pipetree"].inspect(style: :row)
|
345
|
-
# =begin
|
346
|
-
# #:delete-inh-pipe
|
347
|
-
# 0 =======================>>operation.new
|
348
|
-
# 2 ==========================&model.build
|
349
|
-
# #:delete-inh-pipe end
|
350
|
-
# =end
|
351
|
-
|
352
|
-
# it { Noop.({}).inspect("model").must_equal %{<Result:false [nil] >} }
|
353
|
-
end
|
354
|
-
|
355
|
-
class ManualNameTest < Minitest::Spec
|
356
|
-
#:name-manu
|
357
|
-
class New < Trailblazer::Operation
|
358
|
-
step Model( Song, :new ), name: "build.song.model"
|
359
|
-
step :validate_params!, name: "my.params.validate"
|
360
|
-
# ..
|
361
|
-
end
|
362
|
-
#:name-manu end
|
363
|
-
|
364
|
-
puts New["pipetree"].inspect(style: :row)
|
365
|
-
=begin
|
366
|
-
#:name-manu-pipe
|
367
|
-
0 =======================>>operation.new
|
368
|
-
1 =====================&build.song.model
|
369
|
-
2 ===================&my.params.validate
|
370
|
-
#:name-manu-pipe end
|
371
|
-
=end
|
372
|
-
end
|
373
|
-
|
374
|
-
class BeforeTest < Minitest::Spec
|
375
|
-
#:pos-before
|
376
|
-
class New < Trailblazer::Operation
|
377
|
-
step Model( Song, :new )
|
378
|
-
step :validate_params!, before: "model.build"
|
379
|
-
# ..
|
380
|
-
end
|
381
|
-
#:pos-before end
|
382
|
-
|
383
|
-
puts New["pipetree"].inspect(style: :row)
|
384
|
-
=begin
|
385
|
-
#:pos-before-pipe
|
386
|
-
0 =======================>>operation.new
|
387
|
-
1 =====================&validate_params!
|
388
|
-
2 ==========================&model.build
|
389
|
-
#:pos-before-pipe end
|
390
|
-
=end
|
391
|
-
|
392
|
-
#:pos-inh
|
393
|
-
class Create < New
|
394
|
-
step :policy!, after: "operation.new"
|
395
|
-
end
|
396
|
-
#:pos-inh end
|
397
|
-
|
398
|
-
puts Create["pipetree"].inspect(style: :row)
|
399
|
-
=begin
|
400
|
-
#:pos-inh-pipe
|
401
|
-
0 =======================>>operation.new
|
402
|
-
1 ==============================&policy!
|
403
|
-
2 =====================&validate_params!
|
404
|
-
3 ==========================&model.build
|
405
|
-
#:pos-inh-pipe end
|
406
|
-
=end
|
407
|
-
end
|
408
|
-
end
|