trailblazer 2.1.0.beta4 → 2.1.0.beta5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +194 -502
- data/CHANGES.md +4 -0
- data/CONTRIBUTING.md +170 -0
- data/Gemfile +4 -1
- data/README.md +183 -40
- data/Rakefile +6 -2
- data/lib/trailblazer/version.rb +1 -1
- data/lib/trailblazer.rb +3 -12
- data/test/{operation/dsl → dsl}/contract_test.rb +2 -2
- data/trailblazer.gemspec +3 -3
- metadata +17 -63
- data/lib/trailblazer/operation/contract.rb +0 -82
- data/lib/trailblazer/operation/guard.rb +0 -18
- data/lib/trailblazer/operation/model.rb +0 -65
- data/lib/trailblazer/operation/nested.rb +0 -91
- data/lib/trailblazer/operation/persist.rb +0 -14
- data/lib/trailblazer/operation/policy.rb +0 -44
- data/lib/trailblazer/operation/pundit.rb +0 -38
- data/lib/trailblazer/operation/representer.rb +0 -36
- data/lib/trailblazer/operation/rescue.rb +0 -24
- data/lib/trailblazer/operation/validate.rb +0 -74
- data/lib/trailblazer/operation/wrap.rb +0 -64
- data/test/docs/contract_test.rb +0 -545
- data/test/docs/dry_test.rb +0 -31
- data/test/docs/guard_test.rb +0 -162
- data/test/docs/macro_test.rb +0 -36
- data/test/docs/model_test.rb +0 -75
- data/test/docs/nested_test.rb +0 -300
- 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 -219
- data/test/nested_test.rb +0 -293
- data/test/operation/contract_test.rb +0 -290
- data/test/operation/dsl/representer_test.rb +0 -169
- data/test/operation/model_test.rb +0 -54
- data/test/operation/persist_test.rb +0 -51
- data/test/operation/pundit_test.rb +0 -106
- data/test/operation/representer_test.rb +0 -254
@@ -1,268 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
require "representable/json"
|
3
|
-
|
4
|
-
#---
|
5
|
-
# infer
|
6
|
-
class DocsRepresenterInferTest < Minitest::Spec
|
7
|
-
Song = Struct.new(:id, :title)
|
8
|
-
|
9
|
-
#:infer
|
10
|
-
class Create < Trailblazer::Operation
|
11
|
-
class MyContract < Reform::Form
|
12
|
-
property :id
|
13
|
-
end
|
14
|
-
|
15
|
-
step Model( Song, :new )
|
16
|
-
step Contract::Build( constant: MyContract )
|
17
|
-
step Contract::Validate( representer: Representer.infer(MyContract, format: Representable::JSON) )
|
18
|
-
step Contract::Persist( method: :sync )
|
19
|
-
end
|
20
|
-
#:infer end
|
21
|
-
|
22
|
-
let (:json) { MultiJson.dump(id: 1) }
|
23
|
-
it { Create.( params: {}, document: json ).inspect(:model).must_equal %{<Result:true [#<struct DocsRepresenterInferTest::Song id=1, title=nil>] >} }
|
24
|
-
end
|
25
|
-
|
26
|
-
#---
|
27
|
-
# explicit
|
28
|
-
class DocsRepresenterExplicitTest < Minitest::Spec
|
29
|
-
Song = Struct.new(:id, :title)
|
30
|
-
|
31
|
-
#:explicit-rep
|
32
|
-
class MyRepresenter < Representable::Decorator
|
33
|
-
include Representable::JSON
|
34
|
-
property :id
|
35
|
-
end
|
36
|
-
#:explicit-rep end
|
37
|
-
|
38
|
-
#:explicit-op
|
39
|
-
class Create < Trailblazer::Operation
|
40
|
-
class MyContract < Reform::Form
|
41
|
-
property :id
|
42
|
-
end
|
43
|
-
|
44
|
-
step Model( Song, :new )
|
45
|
-
step Contract::Build( constant: MyContract )
|
46
|
-
step Contract::Validate( representer: MyRepresenter ) # :representer
|
47
|
-
step Contract::Persist( method: :sync )
|
48
|
-
end
|
49
|
-
#:explicit-op end
|
50
|
-
|
51
|
-
let (:json) { MultiJson.dump(id: 1) }
|
52
|
-
it { Create.(params: {}, document: json).inspect(:model).must_equal %{<Result:true [#<struct DocsRepresenterExplicitTest::Song id=1, title=nil>] >} }
|
53
|
-
it do
|
54
|
-
#:explicit-call
|
55
|
-
Create.(params: {}, document: '{"id": 1}')
|
56
|
-
#:explicit-call end
|
57
|
-
end
|
58
|
-
|
59
|
-
#- render
|
60
|
-
it do
|
61
|
-
#:render
|
62
|
-
result = Create.( params: {}, document: '{"id": 1}' )
|
63
|
-
json = result["representer.default.class"].new(result[:model]).to_json
|
64
|
-
json #=> '{"id":1}'
|
65
|
-
#:render end
|
66
|
-
json.must_equal '{"id":1}'
|
67
|
-
end
|
68
|
-
|
69
|
-
#-
|
70
|
-
# with dependency injection
|
71
|
-
# overriding the JSON representer with an XML one.
|
72
|
-
#:di-rep
|
73
|
-
require "representable/xml"
|
74
|
-
|
75
|
-
class MyXMLRepresenter < Representable::Decorator
|
76
|
-
include Representable::XML
|
77
|
-
property :id
|
78
|
-
end
|
79
|
-
#:di-rep end
|
80
|
-
|
81
|
-
let (:xml) { %{<body><id>1</id></body>} }
|
82
|
-
it do
|
83
|
-
#:di-call
|
84
|
-
result = Create.(params: {},
|
85
|
-
document: '<body><id>1</id></body>',
|
86
|
-
"representer.default.class" => MyXMLRepresenter # injection
|
87
|
-
)
|
88
|
-
#:di-call end
|
89
|
-
result.inspect(:model).must_equal %{<Result:true [#<struct DocsRepresenterExplicitTest::Song id="1", title=nil>] >}
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
#---
|
94
|
-
# dependency injection
|
95
|
-
class DocsRepresenterDITest < Minitest::Spec
|
96
|
-
Song = Struct.new(:id, :title)
|
97
|
-
|
98
|
-
class MyRepresenter < Representable::Decorator
|
99
|
-
include Representable::JSON
|
100
|
-
property :id
|
101
|
-
end
|
102
|
-
|
103
|
-
class Create < Trailblazer::Operation
|
104
|
-
class MyContract < Reform::Form
|
105
|
-
property :id
|
106
|
-
end
|
107
|
-
|
108
|
-
step Model( Song, :new )
|
109
|
-
step Contract::Build( constant: MyContract )
|
110
|
-
step Contract::Validate()
|
111
|
-
step Contract::Persist( method: :sync )
|
112
|
-
end
|
113
|
-
|
114
|
-
let (:json) { MultiJson.dump(id: 1) }
|
115
|
-
it { Create.(params: {}, document: json,
|
116
|
-
"representer.default.class" => MyRepresenter).inspect(:model).must_equal %{<Result:true [#<struct DocsRepresenterDITest::Song id=1, title=nil>] >} }
|
117
|
-
end
|
118
|
-
|
119
|
-
#---
|
120
|
-
# inline
|
121
|
-
class DocsRepresenterInlineTest < Minitest::Spec
|
122
|
-
Song = Struct.new(:id, :title)
|
123
|
-
|
124
|
-
#:inline
|
125
|
-
class Create < Trailblazer::Operation
|
126
|
-
class MyContract < Reform::Form
|
127
|
-
property :id
|
128
|
-
end
|
129
|
-
|
130
|
-
extend Representer::DSL
|
131
|
-
|
132
|
-
representer do
|
133
|
-
property :id
|
134
|
-
end
|
135
|
-
|
136
|
-
step Model( Song, :new )
|
137
|
-
step Contract::Build( constant: MyContract )
|
138
|
-
step Contract::Validate( representer: self["representer.default.class"] )
|
139
|
-
step Contract::Persist( method: :sync )
|
140
|
-
end
|
141
|
-
#:inline end
|
142
|
-
|
143
|
-
let (:json) { MultiJson.dump(id: 1) }
|
144
|
-
it { Create.(params: {}, document: json).inspect(:model).must_equal %{<Result:true [#<struct DocsRepresenterInlineTest::Song id=1, title=nil>] >} }
|
145
|
-
end
|
146
|
-
|
147
|
-
#---
|
148
|
-
# rendering
|
149
|
-
class DocsRepresenterManualRenderTest < Minitest::Spec
|
150
|
-
Song = Struct.new(:id, :title) do
|
151
|
-
def self.find(id)
|
152
|
-
new(id)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
class Show < Trailblazer::Operation
|
157
|
-
extend Representer::DSL
|
158
|
-
representer do
|
159
|
-
property :id
|
160
|
-
end
|
161
|
-
|
162
|
-
step Model( Song, :find )
|
163
|
-
end
|
164
|
-
|
165
|
-
it do
|
166
|
-
result =Show.(params: { id: 1 })
|
167
|
-
json = result["representer.default.class"].new(result[:model]).to_json
|
168
|
-
json.must_equal %{{"id":1}}
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
#---
|
173
|
-
# naming
|
174
|
-
|
175
|
-
class DocsRepresenterNamingTest < Minitest::Spec
|
176
|
-
MyRepresenter = Object
|
177
|
-
|
178
|
-
#:naming
|
179
|
-
class Create < Trailblazer::Operation
|
180
|
-
extend Representer::DSL
|
181
|
-
representer MyRepresenter
|
182
|
-
end
|
183
|
-
|
184
|
-
Create["representer.default.class"] #=> MyRepresenter
|
185
|
-
#:naming end
|
186
|
-
it { Create["representer.default.class"].must_be_kind_of MyRepresenter }
|
187
|
-
end
|
188
|
-
|
189
|
-
#---
|
190
|
-
# rendering
|
191
|
-
require "roar/json/hal"
|
192
|
-
|
193
|
-
class DocsRepresenterFullExampleTest < Minitest::Spec
|
194
|
-
Song = Struct.new(:id, :title) do
|
195
|
-
def initialize(*)
|
196
|
-
self.id = 1
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
#:errors-rep
|
201
|
-
class ErrorsRepresenter < Representable::Decorator
|
202
|
-
include Representable::JSON
|
203
|
-
collection :errors
|
204
|
-
end
|
205
|
-
#:errors-rep end
|
206
|
-
|
207
|
-
#:full
|
208
|
-
class Create < Trailblazer::Operation
|
209
|
-
extend Contract::DSL
|
210
|
-
extend Representer::DSL
|
211
|
-
|
212
|
-
contract do
|
213
|
-
property :title
|
214
|
-
validates :title, presence: true
|
215
|
-
end
|
216
|
-
|
217
|
-
representer :parse do
|
218
|
-
property :title
|
219
|
-
end
|
220
|
-
|
221
|
-
representer :render do
|
222
|
-
include Roar::JSON::HAL
|
223
|
-
|
224
|
-
property :id
|
225
|
-
property :title
|
226
|
-
link(:self) { "/songs/#{represented.id}" }
|
227
|
-
end
|
228
|
-
|
229
|
-
representer :errors, ErrorsRepresenter # explicit reference.
|
230
|
-
|
231
|
-
step Model( Song, :new )
|
232
|
-
step Contract::Build()
|
233
|
-
step Contract::Validate( representer: self["representer.parse.class"] )
|
234
|
-
step Contract::Persist( method: :sync )
|
235
|
-
end
|
236
|
-
#:full end
|
237
|
-
|
238
|
-
it do
|
239
|
-
result =Create.(params: {}, document: '{"title": "Tested"}')
|
240
|
-
|
241
|
-
json = result["representer.render.class"].new(result[:model]).to_json
|
242
|
-
|
243
|
-
json.must_equal %{{"id":1,"title":"Tested","_links":{"self":{"href":"/songs/1"}}}}
|
244
|
-
|
245
|
-
|
246
|
-
#:full-call
|
247
|
-
def create
|
248
|
-
result = Create.(params, document: request.body.read)
|
249
|
-
|
250
|
-
if result.success?
|
251
|
-
result["representer.render.class"].new(result[:model]).to_json
|
252
|
-
else
|
253
|
-
result["representer.errors.class"].new(result["result.contract.default"]).to_json
|
254
|
-
end
|
255
|
-
end
|
256
|
-
#:full-call end
|
257
|
-
end
|
258
|
-
|
259
|
-
it do
|
260
|
-
result =Create.(params: {}, document: '{"title": ""}')
|
261
|
-
|
262
|
-
if result.failure?
|
263
|
-
json = result["representer.errors.class"].new(result["result.contract.default"]).to_json
|
264
|
-
end
|
265
|
-
|
266
|
-
json.must_equal %{{"errors":[["title","can't be blank"]]}}
|
267
|
-
end
|
268
|
-
end
|
data/test/docs/rescue_test.rb
DELETED
@@ -1,154 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class NestedRescueTest < Minitest::Spec
|
4
|
-
#---
|
5
|
-
# nested raise (i hope people won't use this but it works)
|
6
|
-
A = Class.new(RuntimeError)
|
7
|
-
Y = Class.new(RuntimeError)
|
8
|
-
|
9
|
-
class NestedInsanity < Trailblazer::Operation
|
10
|
-
step Rescue {
|
11
|
-
step ->(options, **) { options["a"] = true }
|
12
|
-
step Rescue {
|
13
|
-
step ->(options, **) { options["y"] = true }
|
14
|
-
success ->(options, **) { raise Y if options["raise-y"] }
|
15
|
-
step ->(options, **) { options["z"] = true }
|
16
|
-
}
|
17
|
-
step ->(options, **) { options["b"] = true }
|
18
|
-
success ->(options, **) { raise A if options["raise-a"] }
|
19
|
-
step ->(options, **) { options["c"] = true }
|
20
|
-
failure ->(options, **) { options["inner-err"] = true }
|
21
|
-
}
|
22
|
-
step ->(options, **) { options["e"] = true }, name: "nested/e"
|
23
|
-
failure ->(options, **) { options["outer-err"] = true }, name: "nested/failure"
|
24
|
-
end
|
25
|
-
|
26
|
-
it { Trailblazer::Operation::Inspect.(NestedInsanity).must_match /\[>Rescue\(\d+\),>nested/ } # FIXME: better introspect tests for all id-generating macros.
|
27
|
-
it { NestedInsanity.().inspect("a", "y", "z", "b", "c", "e", "inner-err", "outer-err").must_equal %{<Result:true [true, true, true, true, true, true, nil, nil] >} }
|
28
|
-
it { NestedInsanity.( "raise-y" => true).inspect("a", "y", "z", "b", "c", "e", "inner-err", "outer-err").must_equal %{<Result:false [true, true, nil, nil, nil, nil, true, true] >} }
|
29
|
-
it { NestedInsanity.( "raise-a" => true).inspect("a", "y", "z", "b", "c", "e", "inner-err", "outer-err").must_equal %{<Result:false [true, true, true, true, nil, nil, nil, true] >} }
|
30
|
-
|
31
|
-
#-
|
32
|
-
# inheritance
|
33
|
-
class UbernestedInsanity < NestedInsanity
|
34
|
-
end
|
35
|
-
|
36
|
-
it { UbernestedInsanity.().inspect("a", "y", "z", "b", "c", "e", "inner-err", "outer-err").must_equal %{<Result:true [true, true, true, true, true, true, nil, nil] >} }
|
37
|
-
it { UbernestedInsanity.( "raise-a" => true).inspect("a", "y", "z", "b", "c", "e", "inner-err", "outer-err").must_equal %{<Result:false [true, true, true, true, nil, nil, nil, true] >} }
|
38
|
-
end
|
39
|
-
|
40
|
-
class RescueTest < Minitest::Spec
|
41
|
-
RecordNotFound = Class.new(RuntimeError)
|
42
|
-
|
43
|
-
Song = Struct.new(:id, :title) do
|
44
|
-
def self.find(id)
|
45
|
-
raise if id == "RuntimeError!"
|
46
|
-
id.nil? ? raise(RecordNotFound) : new(id)
|
47
|
-
end
|
48
|
-
|
49
|
-
def lock!
|
50
|
-
true
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
#:simple
|
55
|
-
class Create < Trailblazer::Operation
|
56
|
-
class MyContract < Reform::Form
|
57
|
-
property :title
|
58
|
-
end
|
59
|
-
|
60
|
-
step Rescue {
|
61
|
-
step Model(Song, :find)
|
62
|
-
step Contract::Build( constant: MyContract )
|
63
|
-
}
|
64
|
-
step Contract::Validate()
|
65
|
-
step Contract::Persist( method: :sync )
|
66
|
-
end
|
67
|
-
#:simple end
|
68
|
-
|
69
|
-
it { Create.( params: {id: 1, title: "Prodigal Son"} )["contract.default"].model.inspect.must_equal %{#<struct RescueTest::Song id=1, title="Prodigal Son">} }
|
70
|
-
it { Create.( params: {id: nil} ).inspect(:model).must_equal %{<Result:false [nil] >} }
|
71
|
-
|
72
|
-
#-
|
73
|
-
# Rescue ExceptionClass, handler: ->(*) { }
|
74
|
-
class WithExceptionNameTest < Minitest::Spec
|
75
|
-
#
|
76
|
-
class MyContract < Reform::Form
|
77
|
-
property :title
|
78
|
-
end
|
79
|
-
#:name
|
80
|
-
class Create < Trailblazer::Operation
|
81
|
-
step Rescue( RecordNotFound, KeyError, handler: :rollback! ) {
|
82
|
-
step Model( Song, :find )
|
83
|
-
step Contract::Build( constant: MyContract )
|
84
|
-
}
|
85
|
-
step Contract::Validate()
|
86
|
-
step Contract::Persist( method: :sync )
|
87
|
-
|
88
|
-
def rollback!(exception, options)
|
89
|
-
options["x"] = exception.class
|
90
|
-
end
|
91
|
-
end
|
92
|
-
#:name end
|
93
|
-
|
94
|
-
it { Create.( params: {id: 1, title: "Prodigal Son"} )["contract.default"].model.inspect.must_equal %{#<struct RescueTest::Song id=1, title="Prodigal Son">} }
|
95
|
-
it { Create.( params: {id: 1, title: "Prodigal Son"} ).inspect("x").must_equal %{<Result:true [nil] >} }
|
96
|
-
it { Create.( params: {id: nil} ).inspect(:model, "x").must_equal %{<Result:false [nil, RescueTest::RecordNotFound] >} }
|
97
|
-
it { assert_raises(RuntimeError) { Create.( params: {id: "RuntimeError!"} ) } }
|
98
|
-
end
|
99
|
-
|
100
|
-
|
101
|
-
#-
|
102
|
-
# cdennl use-case
|
103
|
-
class CdennlRescueAndTransactionTest < Minitest::Spec
|
104
|
-
module Sequel
|
105
|
-
cattr_accessor :result
|
106
|
-
|
107
|
-
def self.transaction
|
108
|
-
yield.tap do |res|
|
109
|
-
self.result = res
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
#:example
|
115
|
-
class Create < Trailblazer::Operation
|
116
|
-
class MyContract < Reform::Form
|
117
|
-
property :title
|
118
|
-
end
|
119
|
-
|
120
|
-
step Rescue( RecordNotFound, handler: :rollback! ) {
|
121
|
-
step Wrap (->(*, &block) { Sequel.transaction do block.call end }) {
|
122
|
-
step Model( Song, :find )
|
123
|
-
step ->(options, *) { options[:model].lock! } # lock the model.
|
124
|
-
step Contract::Build( constant: MyContract )
|
125
|
-
step Contract::Validate( )
|
126
|
-
step Contract::Persist( method: :sync )
|
127
|
-
}
|
128
|
-
}
|
129
|
-
failure :error! # handle all kinds of errors.
|
130
|
-
|
131
|
-
def rollback!(exception, options)
|
132
|
-
#~ex
|
133
|
-
options["x"] = exception.class
|
134
|
-
#~ex end
|
135
|
-
end
|
136
|
-
|
137
|
-
def error!(options, *)
|
138
|
-
#~ex
|
139
|
-
options["err"] = true
|
140
|
-
#~ex end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
#:example end
|
144
|
-
|
145
|
-
it { Create.( params: {id: 1, title: "Pie"} ).inspect(:model, "x", "err").must_equal %{<Result:true [#<struct RescueTest::Song id=1, title=\"Pie\">, nil, nil] >} }
|
146
|
-
# raise exceptions in Model:
|
147
|
-
it { Create.( params: {id: nil} ).inspect(:model, "x").must_equal %{<Result:false [nil, RescueTest::RecordNotFound] >} }
|
148
|
-
it { assert_raises(RuntimeError) { Create.( params: {id: "RuntimeError!"} ) } }
|
149
|
-
it do
|
150
|
-
Create.( params: {id: 1, title: "Pie"} )
|
151
|
-
Sequel.result.first.must_be_kind_of Trailblazer::Operation::Railway::End::Success
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
data/test/docs/wrap_test.rb
DELETED
@@ -1,219 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
# TODO: consume End signal from wrapped
|
4
|
-
|
5
|
-
class WrapTest < Minitest::Spec
|
6
|
-
Song = Struct.new(:id, :title) do
|
7
|
-
def self.find(id)
|
8
|
-
id.nil? ? raise : new(id)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
class DirectWiringTest < Minitest::Spec
|
13
|
-
class Create < Trailblazer::Operation
|
14
|
-
class MyContract < Reform::Form
|
15
|
-
property :title
|
16
|
-
end
|
17
|
-
|
18
|
-
step( Wrap( ->(options, *args, &block) {
|
19
|
-
begin
|
20
|
-
block.call
|
21
|
-
rescue => exception
|
22
|
-
options["result.model.find"] = "argh! because #{exception.class}"
|
23
|
-
[ Railway.fail_fast!, options, *args ]
|
24
|
-
end }) {
|
25
|
-
step ->(options, **) { options["x"] = true }
|
26
|
-
step Model( Song, :find )
|
27
|
-
step Contract::Build( constant: MyContract )
|
28
|
-
}.merge(fast_track: true))
|
29
|
-
step Contract::Validate()
|
30
|
-
step Contract::Persist( method: :sync )
|
31
|
-
end
|
32
|
-
|
33
|
-
it { Create.( params: {id: 1, title: "Prodigal Son"} ).inspect("x", :model).must_equal %{<Result:true [true, #<struct WrapTest::Song id=1, title=\"Prodigal Son\">] >} }
|
34
|
-
|
35
|
-
it "goes directly from Wrap to End.fail_fast" do
|
36
|
-
Create.(params: {}).inspect("x", :model, "result.model.find").must_equal %{<Result:false [true, nil, "argh! because RuntimeError"] >}
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# it allows returning legacy true/false
|
41
|
-
class Create < Trailblazer::Operation
|
42
|
-
class MyContract < Reform::Form
|
43
|
-
property :title
|
44
|
-
end
|
45
|
-
|
46
|
-
step Wrap( ->(options, *, &block) {
|
47
|
-
begin
|
48
|
-
block.call
|
49
|
-
rescue => exception
|
50
|
-
options["result.model.find"] = "argh! because #{exception.class}"
|
51
|
-
return false
|
52
|
-
end
|
53
|
-
true
|
54
|
-
}) {
|
55
|
-
step Model( Song, :find )
|
56
|
-
step Contract::Build( constant: MyContract )
|
57
|
-
}
|
58
|
-
step Contract::Validate()
|
59
|
-
step Contract::Persist( method: :sync )
|
60
|
-
end
|
61
|
-
|
62
|
-
it { Create.( params: {id: 1, title: "Prodigal Son"} )["contract.default"].model.inspect.must_equal %{#<struct WrapTest::Song id=1, title="Prodigal Son">} }
|
63
|
-
it { Create.( params: {id: nil }).inspect("result.model.find").must_equal %{<Result:false [\"argh! because RuntimeError\"] >} }
|
64
|
-
|
65
|
-
#-
|
66
|
-
# Wrap return
|
67
|
-
class WrapReturnTest < Minitest::Spec
|
68
|
-
class Create < Trailblazer::Operation
|
69
|
-
step Wrap( ->(options, *, &block) { options["yield?"] ? block.call : false }) {
|
70
|
-
step ->(options, **) { options["x"] = true }
|
71
|
-
success :noop!
|
72
|
-
# ...
|
73
|
-
}
|
74
|
-
|
75
|
-
def noop!(options, **)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
it { Create.(params: {}).inspect("x").must_equal %{<Result:false [nil] >} }
|
80
|
-
# returns falsey means deviate to left.
|
81
|
-
it { Create.("yield?" => true).inspect("x").must_equal %{<Result:true [true] >} }
|
82
|
-
end
|
83
|
-
|
84
|
-
class WrapWithCallableTest < Minitest::Spec
|
85
|
-
class MyWrapper
|
86
|
-
extend Uber::Callable
|
87
|
-
|
88
|
-
def self.call(options, *, &block)
|
89
|
-
options["yield?"] ? yield : false
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
class Create < Trailblazer::Operation
|
94
|
-
step Wrap( MyWrapper ) {
|
95
|
-
step ->(options, **) { options["x"] = true }
|
96
|
-
# ...
|
97
|
-
}
|
98
|
-
end
|
99
|
-
|
100
|
-
it { Create.(params: {}).inspect("x").must_equal %{<Result:false [nil] >} }
|
101
|
-
# returns falsey means deviate to left.
|
102
|
-
it { Create.("yield?" => true).inspect("x").must_equal %{<Result:true [true] >} }
|
103
|
-
end
|
104
|
-
|
105
|
-
class WrapExampleProcTest < Minitest::Spec
|
106
|
-
module Sequel
|
107
|
-
def self.transaction
|
108
|
-
yield
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
module MyNotifier
|
113
|
-
def self.mail; true; end
|
114
|
-
end
|
115
|
-
|
116
|
-
#:sequel-transaction
|
117
|
-
class Create < Trailblazer::Operation
|
118
|
-
#~wrap-only
|
119
|
-
class MyContract < Reform::Form
|
120
|
-
property :title
|
121
|
-
end
|
122
|
-
|
123
|
-
#~wrap-only end
|
124
|
-
step Wrap( ->(*, &block) { Sequel.transaction do block.call end } ) {
|
125
|
-
step Model( Song, :new )
|
126
|
-
#~wrap-only
|
127
|
-
step Contract::Build( constant: MyContract )
|
128
|
-
step Contract::Validate( )
|
129
|
-
step Contract::Persist( method: :sync )
|
130
|
-
#~wrap-only end
|
131
|
-
}
|
132
|
-
failure :error! # handle all kinds of errors.
|
133
|
-
#~wrap-only
|
134
|
-
step :notify!
|
135
|
-
|
136
|
-
def error!(options)
|
137
|
-
# handle errors after the wrap
|
138
|
-
end
|
139
|
-
|
140
|
-
def notify!(options, **)
|
141
|
-
MyNotifier.mail
|
142
|
-
end
|
143
|
-
#~wrap-only end
|
144
|
-
end
|
145
|
-
#:sequel-transaction end
|
146
|
-
|
147
|
-
it { Create.( params: {title: "Pie"} ).inspect(:model, "x", "err").must_equal %{<Result:true [#<struct WrapTest::Song id=nil, title=\"Pie\">, nil, nil] >} }
|
148
|
-
end
|
149
|
-
|
150
|
-
class WrapExampleCallableTest < Minitest::Spec
|
151
|
-
module Sequel
|
152
|
-
def self.transaction
|
153
|
-
yield
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
module MyNotifier
|
158
|
-
def self.mail; true; end
|
159
|
-
end
|
160
|
-
|
161
|
-
#:callable-t
|
162
|
-
class MyTransaction
|
163
|
-
def self.call(options, *)
|
164
|
-
Sequel.transaction { yield } # yield runs the nested pipe.
|
165
|
-
# return value decides about left or right track!
|
166
|
-
end
|
167
|
-
end
|
168
|
-
#:callable-t end
|
169
|
-
#:sequel-transaction-callable
|
170
|
-
class Create < Trailblazer::Operation
|
171
|
-
#~wrap-onlyy
|
172
|
-
class MyContract < Reform::Form
|
173
|
-
property :title
|
174
|
-
end
|
175
|
-
|
176
|
-
#~wrap-onlyy end
|
177
|
-
step Wrap( MyTransaction ) {
|
178
|
-
step Model( Song, :new )
|
179
|
-
#~wrap-onlyy
|
180
|
-
step Contract::Build( constant: MyContract )
|
181
|
-
step Contract::Validate( )
|
182
|
-
step Contract::Persist( method: :sync )
|
183
|
-
#~wrap-onlyy end
|
184
|
-
}
|
185
|
-
failure :error! # handle all kinds of errors.
|
186
|
-
#~wrap-onlyy
|
187
|
-
step :notify!
|
188
|
-
|
189
|
-
def error!(options)
|
190
|
-
# handle errors after the wrap
|
191
|
-
end
|
192
|
-
|
193
|
-
def notify!(options, **)
|
194
|
-
MyNotifier.mail # send emails, because success...
|
195
|
-
end
|
196
|
-
#~wrap-onlyy end
|
197
|
-
end
|
198
|
-
#:sequel-transaction-callable end
|
199
|
-
|
200
|
-
it { Create.( params: {title: "Pie"} ).inspect(:model, "x", "err").must_equal %{<Result:true [#<struct WrapTest::Song id=nil, title=\"Pie\">, nil, nil] >} }
|
201
|
-
end
|
202
|
-
|
203
|
-
class WrapWithMethodTest < Minitest::Spec
|
204
|
-
class Create < Trailblazer::Operation
|
205
|
-
step Model( Song, :new )
|
206
|
-
step Wrap( ->(options, *, &block) { block.call } ) {
|
207
|
-
step :check_model!
|
208
|
-
|
209
|
-
}
|
210
|
-
|
211
|
-
def check_model!(options, model:, **)
|
212
|
-
options["x"] = model
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
it { Create.(params: {}) }
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|