trailblazer 2.0.3 → 2.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +5 -1
- data/Gemfile +1 -1
- data/lib/trailblazer/operation/nested.rb +11 -5
- data/lib/trailblazer/operation/rescue.rb +1 -5
- data/lib/trailblazer/operation/test.rb +17 -0
- data/lib/trailblazer/version.rb +1 -1
- data/test/docs/contract_test.rb +140 -46
- data/test/docs/nested_test.rb +17 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c715d450be489fd1d47e0e9543044dbecc683db8
|
4
|
+
data.tar.gz: 3212afa6969b12ed86cab5b73cb43a84ffa56ac0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ff9d994e6c2176ed8dd418ed49fd9214edb7251c44251b6a1afaa93803063bf599f10f0f08b2e726ec69d979e550bee18567e73ffdb822210db93744d2689b4
|
7
|
+
data.tar.gz: 4f7a37983d925bd4e6c8722422aa97d067a1dec4ba11c3018c4887d9b5ec8e2fab57aed6ce6a062ad4a0ea2713dbfdd15fda98401343e0c7e5d934783e3abf24
|
data/CHANGES.md
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
# 2.0.4
|
2
|
+
|
3
|
+
* When using `Nested(X)`, the automatic `:name` option is now `"Nested(X)"` instead of the cryptic proc string.
|
4
|
+
|
1
5
|
# 2.0.3
|
2
6
|
|
3
7
|
* `Guard` now allows kw args for its option.
|
4
8
|
* Fix a bug where `Nested( ->{} )` wouldn't `_call` the nested operation and did too much work on re-nested the already nested params. Thanks to @eliranf for spotting this.
|
5
9
|
* Add `Nested(..., input: )` to dynamically decide the input to the nested operation. http://trailblazer.to/gems/operation/2.0/api.html#nested-input
|
6
|
-
* Add `Nested(..., output: )`: http://
|
10
|
+
* Add `Nested(..., output: )`: http://trailblazer.to/gems/operation/2.0/api.html#nested-output
|
7
11
|
|
8
12
|
# 2.0.2
|
9
13
|
|
data/Gemfile
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
class Trailblazer::Operation
|
2
|
-
def self.Nested(
|
3
|
-
step = Nested.for(
|
2
|
+
def self.Nested(callable, input:nil, output:nil)
|
3
|
+
step = Nested.for(callable, input, output)
|
4
4
|
|
5
|
-
[ step, { name: "Nested(#{
|
5
|
+
[ step, { name: "Nested(#{callable})" } ]
|
6
6
|
end
|
7
7
|
|
8
8
|
# WARNING: this is experimental API, but it will end up with something like that.
|
@@ -22,9 +22,10 @@ class Trailblazer::Operation
|
|
22
22
|
module Nested
|
23
23
|
# Please note that the instance_variable_get are here on purpose since the
|
24
24
|
# superinternal API is not entirely decided, yet.
|
25
|
-
|
25
|
+
# @api private
|
26
|
+
def self.for(step, input, output, is_nestable_object=method(:nestable_object?)) # DISCUSS: use builders here?
|
26
27
|
invoker = Caller::Dynamic.new(step)
|
27
|
-
invoker = Caller.new(step) if
|
28
|
+
invoker = Caller.new(step) if is_nestable_object.(step)
|
28
29
|
|
29
30
|
options_for_nested = Options.new
|
30
31
|
options_for_nested = Options::Dynamic.new(input) if input
|
@@ -42,6 +43,11 @@ class Trailblazer::Operation
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
46
|
+
def self.nestable_object?(object)
|
47
|
+
# interestingly, with < we get a weird nil exception. bug in Ruby?
|
48
|
+
object.is_a?(Class) && object <= Trailblazer::Operation
|
49
|
+
end
|
50
|
+
|
45
51
|
# Is executed at runtime and calls the nested operation.
|
46
52
|
class Caller
|
47
53
|
include Element
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Trailblazer::Operation
|
2
|
-
def self.Rescue(*exceptions, handler:
|
2
|
+
def self.Rescue(*exceptions, handler: lambda { |*| }, &block)
|
3
3
|
exceptions = [StandardError] unless exceptions.any?
|
4
4
|
handler = Option.(handler)
|
5
5
|
|
@@ -17,9 +17,5 @@ class Trailblazer::Operation
|
|
17
17
|
|
18
18
|
[ step, name: "Rescue:#{block.source_location.last}" ]
|
19
19
|
end
|
20
|
-
|
21
|
-
module Rescue
|
22
|
-
Noop = ->(*) {}
|
23
|
-
end
|
24
20
|
end
|
25
21
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Test
|
3
|
+
module Run
|
4
|
+
# DISCUSS: use Endpoint here?
|
5
|
+
# DISCUSS: use Controller code here?
|
6
|
+
module_function
|
7
|
+
def run(operation_class, *args)
|
8
|
+
result = operation_class.(*args)
|
9
|
+
|
10
|
+
raise "[Trailblazer] #{operation_class} wasn't run successfully. #{result.inspect}" if result.failure?
|
11
|
+
|
12
|
+
result
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/trailblazer/version.rb
CHANGED
data/test/docs/contract_test.rb
CHANGED
@@ -4,7 +4,7 @@ class DocsContractOverviewTest < Minitest::Spec
|
|
4
4
|
Song = Struct.new(:length, :title)
|
5
5
|
|
6
6
|
#:overv-reform
|
7
|
-
# app/concepts/
|
7
|
+
# app/concepts/song/create.rb
|
8
8
|
class Create < Trailblazer::Operation
|
9
9
|
#~bla
|
10
10
|
extend Contract::DSL
|
@@ -126,29 +126,6 @@ class DocsContractExplicitTest < Minitest::Spec
|
|
126
126
|
#:reform-inline-op end
|
127
127
|
end
|
128
128
|
|
129
|
-
#---
|
130
|
-
#- Validate[key: :song]
|
131
|
-
class DocsContractKeyTest < Minitest::Spec
|
132
|
-
Song = Struct.new(:id, :title)
|
133
|
-
#:key
|
134
|
-
class Create < Trailblazer::Operation
|
135
|
-
extend Contract::DSL
|
136
|
-
|
137
|
-
contract do
|
138
|
-
property :title
|
139
|
-
end
|
140
|
-
|
141
|
-
step Model( Song, :new )
|
142
|
-
step Contract::Build()
|
143
|
-
step Contract::Validate( key: "song" )
|
144
|
-
step Contract::Persist( method: :sync )
|
145
|
-
end
|
146
|
-
#:key end
|
147
|
-
|
148
|
-
it { Create.({}).inspect("model", "result.contract.default.extract").must_equal %{<Result:false [#<struct DocsContractKeyTest::Song id=nil, title=nil>, nil] >} }
|
149
|
-
it { Create.({"song" => { title: "SVG" }}).inspect("model").must_equal %{<Result:true [#<struct DocsContractKeyTest::Song id=nil, title="SVG">] >} }
|
150
|
-
end
|
151
|
-
|
152
129
|
#- Validate with manual key extraction
|
153
130
|
class DocsContractSeparateKeyTest < Minitest::Spec
|
154
131
|
Song = Struct.new(:id, :title)
|
@@ -181,48 +158,165 @@ class DocsContractSeparateKeyTest < Minitest::Spec
|
|
181
158
|
end
|
182
159
|
|
183
160
|
#---
|
184
|
-
#- Contract::Build
|
161
|
+
#- Contract::Build( constant: XXX )
|
185
162
|
class ContractConstantTest < Minitest::Spec
|
186
|
-
Song = Struct.new(:
|
187
|
-
|
188
|
-
|
189
|
-
class MyContract < Reform::Form
|
190
|
-
property :title
|
191
|
-
validates :title, length: 2..33
|
163
|
+
Song = Struct.new(:title, :length) do
|
164
|
+
def save
|
165
|
+
true
|
192
166
|
end
|
167
|
+
end
|
193
168
|
|
169
|
+
#:constant-contract
|
170
|
+
# app/concepts/song/contract/create.rb
|
171
|
+
module Song::Contract
|
172
|
+
class Create < Reform::Form
|
173
|
+
property :title
|
174
|
+
property :length
|
194
175
|
|
176
|
+
validates :title, length: 2..33
|
177
|
+
validates :length, numericality: true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
#:constant-contract end
|
195
181
|
|
182
|
+
#:constant
|
183
|
+
class Song::Create < Trailblazer::Operation
|
196
184
|
step Model( Song, :new )
|
197
|
-
step Contract::Build( constant:
|
185
|
+
step Contract::Build( constant: Song::Contract::Create )
|
198
186
|
step Contract::Validate()
|
199
|
-
step Contract::Persist(
|
187
|
+
step Contract::Persist()
|
200
188
|
end
|
201
189
|
#:constant end
|
202
190
|
|
203
|
-
it { Create.({ title: "A" }).inspect("model").must_equal %{<Result:false [#<struct ContractConstantTest::Song
|
204
|
-
it { Create.({ title: "Anthony's Song" }).inspect("model").must_equal %{<Result:true [#<struct ContractConstantTest::Song
|
191
|
+
it { Song::Create.({ title: "A" }).inspect("model").must_equal %{<Result:false [#<struct ContractConstantTest::Song title=nil, length=nil>] >} }
|
192
|
+
it { Song::Create.({ title: "Anthony's Song", length: 12 }).inspect("model").must_equal %{<Result:true [#<struct ContractConstantTest::Song title="Anthony's Song", length=12>] >} }
|
193
|
+
it do
|
194
|
+
#:constant-result
|
195
|
+
result = Song::Create.( title: "A" )
|
196
|
+
result.success? #=> false
|
197
|
+
result["contract.default"].errors.messages
|
198
|
+
#=> {:title=>["is too short (minimum is 2 characters)"], :length=>["is not a number"]}
|
199
|
+
#:constant-result end
|
200
|
+
|
201
|
+
#:constant-result-true
|
202
|
+
result = Song::Create.( title: "Rising Force", length: 13 )
|
203
|
+
result.success? #=> true
|
204
|
+
result["model"] #=> #<Song title="Rising Force", length=13>
|
205
|
+
#:constant-result-true end
|
206
|
+
end
|
207
|
+
|
208
|
+
#---
|
209
|
+
# Song::New
|
210
|
+
#:constant-new
|
211
|
+
class Song::New < Trailblazer::Operation
|
212
|
+
step Model( Song, :new )
|
213
|
+
step Contract::Build( constant: Song::Contract::Create )
|
214
|
+
end
|
215
|
+
#:constant-new end
|
216
|
+
|
217
|
+
it { Song::New.().inspect("model").must_equal %{<Result:true [#<struct ContractConstantTest::Song title=nil, length=nil>] >} }
|
218
|
+
it { Song::New.()["contract.default"].model.inspect.must_equal %{#<struct ContractConstantTest::Song title=nil, length=nil>} }
|
219
|
+
it do
|
220
|
+
#:constant-new-result
|
221
|
+
result = Song::New.()
|
222
|
+
result["model"] #=> #<struct Song title=nil, length=nil>
|
223
|
+
result["contract.default"]
|
224
|
+
#=> #<Song::Contract::Create model=#<struct Song title=nil, length=nil>>
|
225
|
+
#:constant-new-result end
|
226
|
+
end
|
227
|
+
|
228
|
+
#---
|
229
|
+
#:validate-only
|
230
|
+
class Song::ValidateOnly < Trailblazer::Operation
|
231
|
+
step Model( Song, :new )
|
232
|
+
step Contract::Build( constant: Song::Contract::Create )
|
233
|
+
step Contract::Validate()
|
234
|
+
end
|
235
|
+
#:validate-only end
|
236
|
+
|
237
|
+
it { Song::ValidateOnly.().inspect("model").must_equal %{<Result:false [#<struct ContractConstantTest::Song title=nil, length=nil>] >} }
|
238
|
+
it do
|
239
|
+
result = Song::ValidateOnly.({ title: "Rising Forse", length: 13 })
|
240
|
+
result.inspect("model").must_equal %{<Result:true [#<struct ContractConstantTest::Song title=nil, length=nil>] >}
|
241
|
+
end
|
242
|
+
|
243
|
+
it do
|
244
|
+
#:validate-only-result-false
|
245
|
+
result = Song::ValidateOnly.({}) # empty params
|
246
|
+
result.success? #=> false
|
247
|
+
#:validate-only-result-false end
|
248
|
+
end
|
249
|
+
|
250
|
+
it do
|
251
|
+
#:validate-only-result
|
252
|
+
result = Song::ValidateOnly.({ title: "Rising Force", length: 13 })
|
253
|
+
|
254
|
+
result.success? #=> true
|
255
|
+
result["model"] #=> #<struct Song title=nil, length=nil>
|
256
|
+
result["contract.default"].title #=> "Rising Force"
|
257
|
+
#:validate-only-result end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
#---
|
262
|
+
#- Validate( key: :song )
|
263
|
+
class DocsContractKeyTest < Minitest::Spec
|
264
|
+
Song = Class.new(ContractConstantTest::Song)
|
265
|
+
|
266
|
+
module Song::Contract
|
267
|
+
Create = ContractConstantTest::Song::Contract::Create
|
268
|
+
end
|
269
|
+
|
270
|
+
#:key
|
271
|
+
class Song::Create < Trailblazer::Operation
|
272
|
+
step Model( Song, :new )
|
273
|
+
step Contract::Build( constant: Song::Contract::Create )
|
274
|
+
step Contract::Validate( key: "song" )
|
275
|
+
step Contract::Persist( )
|
276
|
+
end
|
277
|
+
#:key end
|
278
|
+
|
279
|
+
it { Song::Create.({}).inspect("model", "result.contract.default.extract").must_equal %{<Result:false [#<struct DocsContractKeyTest::Song title=nil, length=nil>, nil] >} }
|
280
|
+
it { Song::Create.({"song" => { title: "SVG", length: 13 }}).inspect("model").must_equal %{<Result:true [#<struct DocsContractKeyTest::Song title=\"SVG\", length=13>] >} }
|
281
|
+
it do
|
282
|
+
#:key-res
|
283
|
+
result = Song::Create.({ "song" => { title: "Rising Force", length: 13 } })
|
284
|
+
result.success? #=> true
|
285
|
+
#:key-res end
|
286
|
+
|
287
|
+
#:key-res-false
|
288
|
+
result = Song::Create.({ title: "Rising Force", length: 13 })
|
289
|
+
result.success? #=> false
|
290
|
+
#:key-res-false end
|
291
|
+
end
|
205
292
|
end
|
206
293
|
|
207
294
|
#- Contract::Build[ constant: XXX, name: AAA ]
|
208
295
|
class ContractNamedConstantTest < Minitest::Spec
|
209
|
-
Song =
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
validates :title, length: 2..33
|
215
|
-
end
|
296
|
+
Song = Class.new(ContractConstantTest::Song)
|
297
|
+
|
298
|
+
module Song::Contract
|
299
|
+
Create = ContractConstantTest::Song::Contract::Create
|
300
|
+
end
|
216
301
|
|
302
|
+
#:constant-name
|
303
|
+
class Song::Create < Trailblazer::Operation
|
217
304
|
step Model( Song, :new )
|
218
|
-
step Contract::Build(
|
305
|
+
step Contract::Build( name: "form", constant: Song::Contract::Create )
|
219
306
|
step Contract::Validate( name: "form" )
|
220
|
-
step Contract::Persist(
|
307
|
+
step Contract::Persist( name: "form" )
|
221
308
|
end
|
222
309
|
#:constant-name end
|
223
310
|
|
224
|
-
it { Create.({ title: "A" }).inspect("model").must_equal %{<Result:false [#<struct ContractNamedConstantTest::Song
|
225
|
-
it { Create.({ title: "Anthony's Song" }).inspect("model").must_equal %{<Result:true [#<struct ContractNamedConstantTest::Song
|
311
|
+
it { Song::Create.({ title: "A" }).inspect("model").must_equal %{<Result:false [#<struct ContractNamedConstantTest::Song title=nil, length=nil>] >} }
|
312
|
+
it { Song::Create.({ title: "Anthony's Song", length: 13 }).inspect("model").must_equal %{<Result:true [#<struct ContractNamedConstantTest::Song title="Anthony's Song", length=13>] >} }
|
313
|
+
|
314
|
+
it do
|
315
|
+
#:name-res
|
316
|
+
result = Song::Create.({ title: "A" })
|
317
|
+
result["contract.form"].errors.messages #=> {:title=>["is too short (minimum is 2 ch...
|
318
|
+
#:name-res end
|
319
|
+
end
|
226
320
|
end
|
227
321
|
|
228
322
|
#---
|
data/test/docs/nested_test.rb
CHANGED
@@ -76,6 +76,7 @@ class DocsNestedOperationTest < Minitest::Spec
|
|
76
76
|
class B < Trailblazer::Operation
|
77
77
|
success ->(options) { options["can.B.see.it?"] = options["this.should.not.be.visible.in.B"] }
|
78
78
|
success ->(options) { options["can.B.see.current_user?"] = options["current_user"] }
|
79
|
+
success ->(options) { options["can.B.see.params?"] = options["params"] }
|
79
80
|
success ->(options) { options["can.B.see.A.class.data?"] = options["A.class.data"] }
|
80
81
|
end
|
81
82
|
|
@@ -91,6 +92,7 @@ class DocsNestedOperationTest < Minitest::Spec
|
|
91
92
|
it { A.()["this.should.not.be.visible.in.B"].must_equal true }
|
92
93
|
# runtime dependencies are visible in B.
|
93
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 }) }
|
94
96
|
# class data from A doesn't bleed into B.
|
95
97
|
it { A.()["can.B.see.A.class.data?"].must_equal nil }
|
96
98
|
|
@@ -315,3 +317,18 @@ class NestedWithCallableTest < Minitest::Spec
|
|
315
317
|
end
|
316
318
|
|
317
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
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trailblazer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: trailblazer-operation
|
@@ -184,6 +184,7 @@ files:
|
|
184
184
|
- lib/trailblazer/operation/pundit.rb
|
185
185
|
- lib/trailblazer/operation/representer.rb
|
186
186
|
- lib/trailblazer/operation/rescue.rb
|
187
|
+
- lib/trailblazer/operation/test.rb
|
187
188
|
- lib/trailblazer/operation/validate.rb
|
188
189
|
- lib/trailblazer/operation/wrap.rb
|
189
190
|
- lib/trailblazer/version.rb
|
@@ -242,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
242
243
|
version: '0'
|
243
244
|
requirements: []
|
244
245
|
rubyforge_project:
|
245
|
-
rubygems_version: 2.
|
246
|
+
rubygems_version: 2.5.2
|
246
247
|
signing_key:
|
247
248
|
specification_version: 4
|
248
249
|
summary: A high-level architecture for Ruby and Rails.
|