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/policy_test.rb
DELETED
data/test/docs/pundit_test.rb
DELETED
@@ -1,133 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
#:policy
|
4
|
-
class MyPolicy
|
5
|
-
def initialize(user, model)
|
6
|
-
@user, @model = user, model
|
7
|
-
end
|
8
|
-
|
9
|
-
def create?
|
10
|
-
@user == Module && @model.id.nil?
|
11
|
-
end
|
12
|
-
|
13
|
-
def new?
|
14
|
-
@user == Class
|
15
|
-
end
|
16
|
-
end
|
17
|
-
#:policy end
|
18
|
-
|
19
|
-
#--
|
20
|
-
# with policy
|
21
|
-
class DocsPunditProcTest < Minitest::Spec
|
22
|
-
Song = Struct.new(:id)
|
23
|
-
|
24
|
-
#:pundit
|
25
|
-
class Create < Trailblazer::Operation
|
26
|
-
step Model( Song, :new )
|
27
|
-
step Policy::Pundit( MyPolicy, :create? )
|
28
|
-
# ...
|
29
|
-
end
|
30
|
-
#:pundit end
|
31
|
-
|
32
|
-
it { Create["pipetree"].inspect.must_equal %{[>operation.new,>model.build,>policy.default.eval]} }
|
33
|
-
it { Create.({}, "current_user" => Module).inspect("model").must_equal %{<Result:true [#<struct DocsPunditProcTest::Song id=nil>] >} }
|
34
|
-
it { Create.({} ).inspect("model").must_equal %{<Result:false [#<struct DocsPunditProcTest::Song id=nil>] >} }
|
35
|
-
|
36
|
-
it do
|
37
|
-
#:pundit-result
|
38
|
-
result = Create.({}, "current_user" => Module)
|
39
|
-
result["result.policy.default"].success? #=> true
|
40
|
-
result["result.policy.default"]["policy"] #=> #<MyPolicy ...>
|
41
|
-
#:pundit-result end
|
42
|
-
result["result.policy.default"].success?.must_equal true
|
43
|
-
result["result.policy.default"]["policy"].is_a?(MyPolicy).must_equal true
|
44
|
-
end
|
45
|
-
|
46
|
-
#---
|
47
|
-
#- override
|
48
|
-
class New < Create
|
49
|
-
step Policy::Pundit( MyPolicy, :new? ), override: true
|
50
|
-
end
|
51
|
-
|
52
|
-
it { New["pipetree"].inspect.must_equal %{[>operation.new,>model.build,>policy.default.eval]} }
|
53
|
-
it { New.({}, "current_user" => Class ).inspect("model").must_equal %{<Result:true [#<struct DocsPunditProcTest::Song id=nil>] >} }
|
54
|
-
it { New.({}, "current_user" => nil ).inspect("model").must_equal %{<Result:false [#<struct DocsPunditProcTest::Song id=nil>] >} }
|
55
|
-
|
56
|
-
#---
|
57
|
-
#- override with :name
|
58
|
-
class Edit < Trailblazer::Operation
|
59
|
-
step Policy::Pundit( MyPolicy, :create?, name: "first" )
|
60
|
-
step Policy::Pundit( MyPolicy, :new?, name: "second" )
|
61
|
-
end
|
62
|
-
|
63
|
-
class Update < Edit
|
64
|
-
step Policy::Pundit( MyPolicy, :new?, name: "first" ), override: true
|
65
|
-
end
|
66
|
-
|
67
|
-
it { Edit["pipetree"].inspect.must_equal %{[>operation.new,>policy.first.eval,>policy.second.eval]} }
|
68
|
-
it { Edit.({}, "current_user" => Class).inspect("model").must_equal %{<Result:false [nil] >} }
|
69
|
-
it { Update["pipetree"].inspect.must_equal %{[>operation.new,>policy.first.eval,>policy.second.eval]} }
|
70
|
-
it { Update.({}, "current_user" => Class).inspect("model").must_equal %{<Result:true [nil] >} }
|
71
|
-
|
72
|
-
#---
|
73
|
-
# dependency injection
|
74
|
-
class AnotherPolicy < MyPolicy
|
75
|
-
def create?
|
76
|
-
true
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
it {
|
81
|
-
result =
|
82
|
-
#:di-call
|
83
|
-
Create.({},
|
84
|
-
"current_user" => Module,
|
85
|
-
"policy.default.eval" => Trailblazer::Operation::Policy::Pundit.build(AnotherPolicy, :create?)
|
86
|
-
)
|
87
|
-
#:di-call end
|
88
|
-
result.inspect("").must_equal %{<Result:true [nil] >} }
|
89
|
-
end
|
90
|
-
|
91
|
-
#-
|
92
|
-
# with name:
|
93
|
-
class PunditWithNameTest < Minitest::Spec
|
94
|
-
Song = Struct.new(:id)
|
95
|
-
|
96
|
-
#:name
|
97
|
-
class Create < Trailblazer::Operation
|
98
|
-
step Model( Song, :new )
|
99
|
-
step Policy::Pundit( MyPolicy, :create?, name: "after_model" )
|
100
|
-
# ...
|
101
|
-
end
|
102
|
-
#:name end
|
103
|
-
|
104
|
-
it {
|
105
|
-
#:name-call
|
106
|
-
result = Create.({}, "current_user" => Module)
|
107
|
-
result["result.policy.after_model"].success? #=> true
|
108
|
-
#:name-call end
|
109
|
-
result["result.policy.after_model"].success?.must_equal true }
|
110
|
-
end
|
111
|
-
|
112
|
-
#---
|
113
|
-
# class-level guard
|
114
|
-
# class DocsGuardClassLevelTest < Minitest::Spec
|
115
|
-
# #:class-level
|
116
|
-
# class Create < Trailblazer::Operation
|
117
|
-
# step Policy::Guard[ ->(options) { options["current_user"] == Module } ],
|
118
|
-
# before: "operation.new"
|
119
|
-
# #~pipe--only
|
120
|
-
# step ->(options) { options["x"] = true }
|
121
|
-
# #~pipe--only end
|
122
|
-
# end
|
123
|
-
# #:class-level end
|
124
|
-
|
125
|
-
# it { Create.(); Create["result.policy"].must_equal nil }
|
126
|
-
# it { Create.({}, "current_user" => Module)["x"].must_equal true }
|
127
|
-
# it { Create.({} )["x"].must_equal nil }
|
128
|
-
# end
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
# TODO:
|
133
|
-
#policy.default
|
@@ -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.({}, "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.({}, "document" => json).inspect("model").must_equal %{<Result:true [#<struct DocsRepresenterExplicitTest::Song id=1, title=nil>] >} }
|
53
|
-
it do
|
54
|
-
#:explicit-call
|
55
|
-
Create.({}, "document" => '{"id": 1}')
|
56
|
-
#:explicit-call end
|
57
|
-
end
|
58
|
-
|
59
|
-
#- render
|
60
|
-
it do
|
61
|
-
#:render
|
62
|
-
result = Create.({}, "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.({},
|
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.({}, "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.({}, "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.({ 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.({}, "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.({}, "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 }
|
23
|
-
failure ->(options) { options["outer-err"] = true }
|
24
|
-
end
|
25
|
-
|
26
|
-
it { NestedInsanity["pipetree"].inspect.must_equal %{[>operation.new,>Rescue:10,>rescue_test.rb:22,<rescue_test.rb:23]} }
|
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.( id: 1, title: "Prodigal Son" )["contract.default"].model.inspect.must_equal %{#<struct RescueTest::Song id=1, title="Prodigal Son">} }
|
70
|
-
it { Create.( 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.( id: 1, title: "Prodigal Son" )["contract.default"].model.inspect.must_equal %{#<struct RescueTest::Song id=1, title="Prodigal Son">} }
|
95
|
-
it { Create.( id: 1, title: "Prodigal Son" ).inspect("x").must_equal %{<Result:true [nil] >} }
|
96
|
-
it { Create.( id: nil ).inspect("model", "x").must_equal %{<Result:false [nil, RescueTest::RecordNotFound] >} }
|
97
|
-
it { assert_raises(RuntimeError) { Create.( 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.( 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.( id: nil ).inspect("model", "x").must_equal %{<Result:false [nil, RescueTest::RecordNotFound] >} }
|
148
|
-
it { assert_raises(RuntimeError) { Create.( id: "RuntimeError!" ) } }
|
149
|
-
it do
|
150
|
-
Create.( id: 1, title: "Pie" )
|
151
|
-
Sequel.result.first.must_equal Pipetree::Railway::Right
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|