trailblazer 1.1.2 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +10 -7
- data/CHANGES.md +108 -0
- data/COMM-LICENSE +91 -0
- data/Gemfile +18 -4
- data/LICENSE.txt +7 -20
- data/README.md +55 -15
- data/Rakefile +21 -2
- data/draft-1.2.rb +7 -0
- data/lib/trailblazer.rb +17 -4
- data/lib/trailblazer/dsl.rb +47 -0
- data/lib/trailblazer/operation/auto_inject.rb +47 -0
- data/lib/trailblazer/operation/builder.rb +18 -18
- data/lib/trailblazer/operation/callback.rb +31 -38
- data/lib/trailblazer/operation/contract.rb +46 -0
- data/lib/trailblazer/operation/controller.rb +45 -27
- data/lib/trailblazer/operation/guard.rb +24 -0
- data/lib/trailblazer/operation/model.rb +41 -33
- data/lib/trailblazer/operation/nested.rb +43 -0
- data/lib/trailblazer/operation/params.rb +13 -0
- data/lib/trailblazer/operation/persist.rb +13 -0
- data/lib/trailblazer/operation/policy.rb +26 -72
- data/lib/trailblazer/operation/present.rb +19 -0
- data/lib/trailblazer/operation/procedural/contract.rb +15 -0
- data/lib/trailblazer/operation/procedural/validate.rb +22 -0
- data/lib/trailblazer/operation/pundit.rb +42 -0
- data/lib/trailblazer/operation/representer.rb +25 -92
- data/lib/trailblazer/operation/rescue.rb +23 -0
- data/lib/trailblazer/operation/resolver.rb +18 -24
- data/lib/trailblazer/operation/validate.rb +50 -0
- data/lib/trailblazer/operation/wrap.rb +37 -0
- data/lib/trailblazer/version.rb +1 -1
- data/test/{operation/controller_test.rb → controller_test.rb} +8 -4
- data/test/docs/auto_inject_test.rb +30 -0
- data/test/docs/contract_test.rb +429 -0
- data/test/docs/dry_test.rb +31 -0
- data/test/docs/guard_test.rb +143 -0
- data/test/docs/nested_test.rb +117 -0
- data/test/docs/policy_test.rb +2 -0
- data/test/docs/pundit_test.rb +109 -0
- data/test/docs/representer_test.rb +268 -0
- data/test/docs/rescue_test.rb +153 -0
- data/test/docs/wrap_test.rb +174 -0
- data/test/gemfiles/Gemfile.ruby-1.9 +3 -0
- data/test/gemfiles/Gemfile.ruby-2.0 +12 -0
- data/test/gemfiles/Gemfile.ruby-2.3 +12 -0
- data/test/module_test.rb +22 -15
- data/test/operation/builder_test.rb +66 -18
- data/test/operation/callback_test.rb +70 -0
- data/test/operation/contract_test.rb +385 -15
- data/test/operation/dsl/callback_test.rb +18 -30
- data/test/operation/dsl/contract_test.rb +209 -19
- data/test/operation/dsl/representer_test.rb +42 -15
- data/test/operation/guard_test.rb +1 -147
- data/test/operation/model_test.rb +105 -0
- data/test/operation/params_test.rb +36 -0
- data/test/operation/persist_test.rb +44 -0
- data/test/operation/pipedream_test.rb +59 -0
- data/test/operation/pipetree_test.rb +104 -0
- data/test/operation/present_test.rb +24 -0
- data/test/operation/pundit_test.rb +104 -0
- data/test/{representer_test.rb → operation/representer_test.rb} +58 -42
- data/test/operation/resolver_test.rb +34 -70
- data/test/operation_test.rb +57 -189
- data/test/test_helper.rb +23 -3
- data/trailblazer.gemspec +8 -7
- metadata +91 -59
- data/gemfiles/Gemfile.rails.lock +0 -130
- data/gemfiles/Gemfile.reform-2.0 +0 -6
- data/gemfiles/Gemfile.reform-2.1 +0 -7
- data/lib/trailblazer/autoloading.rb +0 -15
- data/lib/trailblazer/endpoint.rb +0 -31
- data/lib/trailblazer/operation.rb +0 -175
- data/lib/trailblazer/operation/collection.rb +0 -6
- data/lib/trailblazer/operation/dispatch.rb +0 -3
- data/lib/trailblazer/operation/model/dsl.rb +0 -29
- data/lib/trailblazer/operation/model/external.rb +0 -34
- data/lib/trailblazer/operation/policy/guard.rb +0 -35
- data/lib/trailblazer/operation/uploaded_file.rb +0 -77
- data/test/callback_test.rb +0 -104
- data/test/collection_test.rb +0 -57
- data/test/model_test.rb +0 -148
- data/test/operation/external_model_test.rb +0 -71
- data/test/operation/policy_test.rb +0 -97
- data/test/operation/reject_test.rb +0 -34
- data/test/rollback_test.rb +0 -47
@@ -0,0 +1,153 @@
|
|
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
|
+
step ->(options) { raise Y if options["raise-y"] }
|
15
|
+
step ->(options) { options["z"] = true }
|
16
|
+
}
|
17
|
+
step ->(options) { options["b"] = true }
|
18
|
+
step ->(options) { raise A if options["raise-a"] }
|
19
|
+
step ->(options) { options["c"] = true }
|
20
|
+
self.< ->(options) { options["inner-err"] = true }
|
21
|
+
}
|
22
|
+
step ->(options) { options["e"] = true }
|
23
|
+
self.< ->(options) { options["outer-err"] = true }
|
24
|
+
end
|
25
|
+
|
26
|
+
it { NestedInsanity["pipetree"].inspect.must_equal %{[>>operation.new,&Rescue:10,>:22,<NestedRescueTest::NestedInsanity: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
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#:simple
|
54
|
+
class Create < Trailblazer::Operation
|
55
|
+
class MyContract < Reform::Form
|
56
|
+
property :title
|
57
|
+
end
|
58
|
+
|
59
|
+
step Rescue {
|
60
|
+
step Model(Song, :find)
|
61
|
+
step Contract::Build( constant: MyContract )
|
62
|
+
}
|
63
|
+
step Contract::Validate()
|
64
|
+
step Persist( method: :sync )
|
65
|
+
end
|
66
|
+
#:simple end
|
67
|
+
|
68
|
+
it { Create.( id: 1, title: "Prodigal Son" )["contract.default"].model.inspect.must_equal %{#<struct RescueTest::Song id=1, title="Prodigal Son">} }
|
69
|
+
it { Create.( id: nil ).inspect("model").must_equal %{<Result:false [nil] >} }
|
70
|
+
|
71
|
+
#-
|
72
|
+
# Rescue ExceptionClass, handler: ->(*) { }
|
73
|
+
class WithExceptionNameTest < Minitest::Spec
|
74
|
+
#
|
75
|
+
class MyContract < Reform::Form
|
76
|
+
property :title
|
77
|
+
end
|
78
|
+
#:name
|
79
|
+
class Create < Trailblazer::Operation
|
80
|
+
step Rescue( RecordNotFound, KeyError, handler: :rollback! ) {
|
81
|
+
step Model( Song, :find )
|
82
|
+
step Contract::Build( constant: MyContract )
|
83
|
+
}
|
84
|
+
step Contract::Validate()
|
85
|
+
step Persist( method: :sync )
|
86
|
+
|
87
|
+
def rollback!(exception, options)
|
88
|
+
options["x"] = exception.class
|
89
|
+
end
|
90
|
+
end
|
91
|
+
#:name end
|
92
|
+
|
93
|
+
it { Create.( id: 1, title: "Prodigal Son" )["contract.default"].model.inspect.must_equal %{#<struct RescueTest::Song id=1, title="Prodigal Son">} }
|
94
|
+
it { Create.( id: 1, title: "Prodigal Son" ).inspect("x").must_equal %{<Result:true [nil] >} }
|
95
|
+
it { Create.( id: nil ).inspect("model", "x").must_equal %{<Result:false [nil, RescueTest::RecordNotFound] >} }
|
96
|
+
it { assert_raises(RuntimeError) { Create.( id: "RuntimeError!" ) } }
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
#-
|
101
|
+
# cdennl use-case
|
102
|
+
class CdennlRescueAndTransactionTest < Minitest::Spec
|
103
|
+
module Sequel
|
104
|
+
cattr_accessor :result
|
105
|
+
|
106
|
+
def self.transaction
|
107
|
+
yield.tap do |res|
|
108
|
+
self.result = res
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
#:example
|
114
|
+
class Create < Trailblazer::Operation
|
115
|
+
class MyContract < Reform::Form
|
116
|
+
property :title
|
117
|
+
end
|
118
|
+
|
119
|
+
step Rescue( RecordNotFound, handler: :rollback! ) {
|
120
|
+
step Wrap ->(*, &block) { Sequel.transaction do block.call end } {
|
121
|
+
step Model( Song, :find )
|
122
|
+
step ->(options) { options["model"].lock! } # lock the model.
|
123
|
+
step Contract::Build( constant: MyContract )
|
124
|
+
step Contract::Validate( )
|
125
|
+
step Persist( method: :sync )
|
126
|
+
}
|
127
|
+
}
|
128
|
+
failure :error! # handle all kinds of errors.
|
129
|
+
|
130
|
+
def rollback!(exception, options)
|
131
|
+
#~ex
|
132
|
+
options["x"] = exception.class
|
133
|
+
#~ex end
|
134
|
+
end
|
135
|
+
|
136
|
+
def error!(options)
|
137
|
+
#~ex
|
138
|
+
options["err"] = true
|
139
|
+
#~ex end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
#:example end
|
143
|
+
|
144
|
+
it { Create.( id: 1, title: "Pie" ).inspect("model", "x", "err").must_equal %{<Result:true [#<struct RescueTest::Song id=1, title=\"Pie\">, nil, nil] >} }
|
145
|
+
# raise exceptions in Model:
|
146
|
+
it { Create.( id: nil ).inspect("model", "x").must_equal %{<Result:false [nil, RescueTest::RecordNotFound] >} }
|
147
|
+
it { assert_raises(RuntimeError) { Create.( id: "RuntimeError!" ) } }
|
148
|
+
it do
|
149
|
+
Create.( id: 1, title: "Pie" )
|
150
|
+
Sequel.result.first.must_equal Pipetree::Flow::Right
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class WrapTest < Minitest::Spec
|
4
|
+
Song = Struct.new(:id, :title) do
|
5
|
+
def self.find(id)
|
6
|
+
id.nil? ? raise : new(id)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class Create < Trailblazer::Operation
|
11
|
+
class MyContract < Reform::Form
|
12
|
+
property :title
|
13
|
+
end
|
14
|
+
|
15
|
+
step Wrap ->(options, *, &block) {
|
16
|
+
begin
|
17
|
+
block.call
|
18
|
+
rescue => exception
|
19
|
+
options["result.model.find"] = "argh! because #{exception.class}"
|
20
|
+
false
|
21
|
+
end } {
|
22
|
+
step Model( Song, :find )
|
23
|
+
step Contract::Build( constant: MyContract )
|
24
|
+
}
|
25
|
+
step Contract::Validate()
|
26
|
+
step Persist( method: :sync )
|
27
|
+
end
|
28
|
+
|
29
|
+
it { Create.( id: 1, title: "Prodigal Son" )["contract.default"].model.inspect.must_equal %{#<struct WrapTest::Song id=1, title="Prodigal Son">} }
|
30
|
+
it { Create.( id: nil ).inspect("result.model.find").must_equal %{<Result:false [\"argh! because RuntimeError\"] >} }
|
31
|
+
|
32
|
+
#-
|
33
|
+
# Wrap return
|
34
|
+
class WrapReturnTest < Minitest::Spec
|
35
|
+
class Create < Trailblazer::Operation
|
36
|
+
step Wrap ->(options, *, &block) { options["yield?"] ? block.call : false } {
|
37
|
+
step ->(options) { options["x"] = true }
|
38
|
+
step :noop!
|
39
|
+
# ...
|
40
|
+
}
|
41
|
+
|
42
|
+
def noop!(options)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it { Create.().inspect("x").must_equal %{<Result:false [nil] >} }
|
47
|
+
# returns falsey means deviate to left.
|
48
|
+
it { Create.({}, "yield?" => true).inspect("x").must_equal %{<Result:true [true] >} }
|
49
|
+
end
|
50
|
+
|
51
|
+
class WrapWithCallableTest < Minitest::Spec
|
52
|
+
class MyWrapper
|
53
|
+
extend Uber::Callable
|
54
|
+
|
55
|
+
def self.call(options, *, &block)
|
56
|
+
options["yield?"] ? yield : false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Create < Trailblazer::Operation
|
61
|
+
step Wrap( MyWrapper ) {
|
62
|
+
step ->(options) { options["x"] = true }
|
63
|
+
# ...
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
it { Create.().inspect("x").must_equal %{<Result:false [nil] >} }
|
68
|
+
# returns falsey means deviate to left.
|
69
|
+
it { Create.({}, "yield?" => true).inspect("x").must_equal %{<Result:true [true] >} }
|
70
|
+
end
|
71
|
+
|
72
|
+
#-
|
73
|
+
# arguments for Wrap
|
74
|
+
class Update < Trailblazer::Operation
|
75
|
+
step Wrap ->(options, operation, pipe, &block) { operation["yield?"] ? block.call : false } {
|
76
|
+
step ->(options) { options["x"] = true }
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
it { Update.().inspect("x").must_equal %{<Result:false [nil] >} }
|
81
|
+
it { Update.({}, "yield?" => true).inspect("x").must_equal %{<Result:true [true] >} }
|
82
|
+
|
83
|
+
class WrapExampleProcTest < Minitest::Spec
|
84
|
+
module Sequel
|
85
|
+
def self.transaction
|
86
|
+
yield
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
#:sequel-transaction
|
91
|
+
class Create < Trailblazer::Operation
|
92
|
+
#~wrap-only
|
93
|
+
class MyContract < Reform::Form
|
94
|
+
property :title
|
95
|
+
end
|
96
|
+
|
97
|
+
#~wrap-only end
|
98
|
+
step Wrap ->(*, &block) { Sequel.transaction do block.call end } {
|
99
|
+
step Model( Song, :new )
|
100
|
+
#~wrap-only
|
101
|
+
step Contract::Build( constant: MyContract )
|
102
|
+
step Contract::Validate( )
|
103
|
+
step Persist( method: :sync )
|
104
|
+
#~wrap-only end
|
105
|
+
}
|
106
|
+
failure :error! # handle all kinds of errors.
|
107
|
+
#~wrap-only
|
108
|
+
step :notify!
|
109
|
+
|
110
|
+
def error!(options)
|
111
|
+
# handle errors after the wrap
|
112
|
+
end
|
113
|
+
|
114
|
+
def notify!(options)
|
115
|
+
# send emails, because success...
|
116
|
+
end
|
117
|
+
#~wrap-only end
|
118
|
+
end
|
119
|
+
#:sequel-transaction end
|
120
|
+
|
121
|
+
it { Create.( title: "Pie" ).inspect("model", "x", "err").must_equal %{<Result:true [#<struct WrapTest::Song id=nil, title=\"Pie\">, nil, nil] >} }
|
122
|
+
end
|
123
|
+
|
124
|
+
class WrapExampleCallableTest < Minitest::Spec
|
125
|
+
module Sequel
|
126
|
+
def self.transaction
|
127
|
+
yield
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
#:callable-t
|
132
|
+
class MyTransaction
|
133
|
+
extend Uber::Callable
|
134
|
+
|
135
|
+
def self.call(options, *)
|
136
|
+
Sequel.transaction { yield } # yield runs the nested pipe.
|
137
|
+
end
|
138
|
+
end
|
139
|
+
#:callable-t end
|
140
|
+
#:sequel-transaction-callable
|
141
|
+
class Create < Trailblazer::Operation
|
142
|
+
#~wrap-onlyy
|
143
|
+
class MyContract < Reform::Form
|
144
|
+
property :title
|
145
|
+
end
|
146
|
+
|
147
|
+
#~wrap-onlyy end
|
148
|
+
step Wrap( MyTransaction ) {
|
149
|
+
step Model( Song, :new )
|
150
|
+
#~wrap-onlyy
|
151
|
+
step Contract::Build( constant: MyContract )
|
152
|
+
step Contract::Validate( )
|
153
|
+
step Persist( method: :sync )
|
154
|
+
#~wrap-onlyy end
|
155
|
+
}
|
156
|
+
failure :error! # handle all kinds of errors.
|
157
|
+
#~wrap-onlyy
|
158
|
+
step :notify!
|
159
|
+
|
160
|
+
def error!(options)
|
161
|
+
# handle errors after the wrap
|
162
|
+
end
|
163
|
+
|
164
|
+
def notify!(options)
|
165
|
+
# send emails, because success...
|
166
|
+
end
|
167
|
+
#~wrap-onlyy end
|
168
|
+
end
|
169
|
+
#:sequel-transaction-callable end
|
170
|
+
|
171
|
+
it { Create.( title: "Pie" ).inspect("model", "x", "err").must_equal %{<Result:true [#<struct WrapTest::Song id=nil, title=\"Pie\">, nil, nil] >} }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in trailblazer.gemspec
|
4
|
+
gemspec path: "../../"
|
5
|
+
|
6
|
+
gem "multi_json"
|
7
|
+
gem "trailblazer-operation"
|
8
|
+
gem "minitest-line"
|
9
|
+
gem "benchmark-ips"
|
10
|
+
gem "activesupport", "~> 4.2.0"
|
11
|
+
gem "reform-rails"
|
12
|
+
gem "dry-validation"
|
data/test/module_test.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
require "trailblazer/operation/module"
|
3
|
-
require "trailblazer/operation/
|
3
|
+
require "trailblazer/operation/callback"
|
4
|
+
require "trailblazer/operation/contract"
|
4
5
|
|
5
6
|
class OperationModuleTest < MiniTest::Spec
|
6
7
|
Song = Struct.new(:name, :artist)
|
7
8
|
Artist = Struct.new(:id, :full_name)
|
8
9
|
|
9
10
|
class Create < Trailblazer::Operation
|
10
|
-
include Trailblazer::Operation::
|
11
|
+
include Trailblazer::Operation::Callback
|
12
|
+
include Contract::Explicit
|
11
13
|
|
12
14
|
contract do
|
13
15
|
property :name
|
@@ -20,18 +22,21 @@ class OperationModuleTest < MiniTest::Spec
|
|
20
22
|
on_change :notify_me!
|
21
23
|
end
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
+
attr_reader :model
|
26
|
+
def call(params)
|
27
|
+
self["model"] = Song.new
|
25
28
|
|
26
|
-
validate(params,
|
29
|
+
validate(params, model: self["model"]) do
|
27
30
|
contract.sync
|
28
31
|
|
29
32
|
dispatch!
|
30
33
|
end
|
34
|
+
|
35
|
+
self
|
31
36
|
end
|
32
37
|
|
33
38
|
def dispatched
|
34
|
-
|
39
|
+
self["dispatched"] ||= []
|
35
40
|
end
|
36
41
|
|
37
42
|
private
|
@@ -47,6 +52,8 @@ class OperationModuleTest < MiniTest::Spec
|
|
47
52
|
contract do
|
48
53
|
property :artist, inherit: true do
|
49
54
|
property :full_name
|
55
|
+
|
56
|
+
puts definitions.inspect
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
@@ -76,18 +83,18 @@ class OperationModuleTest < MiniTest::Spec
|
|
76
83
|
it do
|
77
84
|
op = Create.({name: "Feelings", artist: {id: 1, full_name: "The Offspring"}})
|
78
85
|
|
79
|
-
op
|
80
|
-
op
|
81
|
-
op
|
82
|
-
op
|
86
|
+
op["dispatched"].must_equal [:notify_me!]
|
87
|
+
op["model"].name.must_equal "Feelings"
|
88
|
+
op["model"].artist.id.must_equal 1
|
89
|
+
op["model"].artist.full_name.must_equal nil # property not declared.
|
83
90
|
end
|
84
91
|
|
85
92
|
it do
|
86
93
|
op = Update.({name: "Feelings", artist: {id: 1, full_name: "The Offspring"}})
|
87
94
|
|
88
|
-
op
|
89
|
-
op
|
90
|
-
op
|
91
|
-
op
|
95
|
+
op["dispatched"].must_equal [:notify_me!, :notify_them!, :notify_you!]
|
96
|
+
op["model"].name.must_equal "Feelings"
|
97
|
+
op["model"].artist.id.must_equal 1
|
98
|
+
op["model"].artist.full_name.must_equal "The Offspring" # property declared via Module.
|
92
99
|
end
|
93
|
-
end
|
100
|
+
end
|
@@ -1,41 +1,89 @@
|
|
1
1
|
require "test_helper"
|
2
|
+
require "trailblazer/operation/builder"
|
2
3
|
|
3
|
-
class
|
4
|
-
|
5
|
-
|
4
|
+
class BuilderTest < MiniTest::Spec
|
5
|
+
#---
|
6
|
+
# pass proc to Builder[]
|
7
|
+
# this is the puristic way.
|
8
|
+
class A < Trailblazer::Operation
|
9
|
+
builds = ->(klass, options) do
|
10
|
+
return B if options["params"][:sub]
|
11
|
+
klass
|
12
|
+
end
|
13
|
+
|
14
|
+
self.| Builder( builds )
|
15
|
+
self.| :process
|
16
|
+
|
17
|
+
class B < A
|
6
18
|
end
|
7
19
|
|
20
|
+
def process(*); self["x"] = self.class end
|
21
|
+
end
|
22
|
+
|
23
|
+
it { A.()["x"].must_equal A }
|
24
|
+
it { A.({ sub: true })["x"].must_equal A::B }
|
25
|
+
it { A::B["builder"].must_equal nil }
|
26
|
+
|
27
|
+
#---
|
28
|
+
# use manual Builders object
|
29
|
+
MyBuilders = Uber::Builder::Builders.new
|
30
|
+
MyBuilders << ->(options) { return self::B if options["params"][:sub] }
|
31
|
+
|
32
|
+
class Create < Trailblazer::Operation
|
33
|
+
self.| Builder( MyBuilders )
|
34
|
+
self["pipetree"].> ->(input, options) { options["x"] = input.class }
|
35
|
+
end
|
36
|
+
|
37
|
+
it { Create.()["x"].must_equal Create }
|
38
|
+
|
39
|
+
#---
|
40
|
+
#- Builder inheritance
|
41
|
+
class B < A
|
42
|
+
end
|
43
|
+
|
44
|
+
it { B["pipetree"].inspect.must_equal %{[>>operation.new,>process]} }
|
45
|
+
|
46
|
+
#---
|
47
|
+
# use Builder DSL
|
48
|
+
# you don't need to include Builder in the pipetree
|
49
|
+
class ParentOperation < Trailblazer::Operation
|
8
50
|
class Sub < self
|
9
51
|
end
|
10
52
|
|
11
|
-
|
12
|
-
|
53
|
+
include Builder
|
54
|
+
builds -> (options) do
|
55
|
+
return Sub if options["params"][:sub]
|
13
56
|
end
|
57
|
+
|
58
|
+
def process(*); self["x"] = self.class end
|
59
|
+
self.| :process
|
14
60
|
end
|
15
61
|
|
16
|
-
it { ParentOperation.
|
17
|
-
it { ParentOperation.
|
18
|
-
it { ParentOperation.({}).class.must_equal ParentOperation }
|
19
|
-
it { ParentOperation.({sub: true}).class.must_equal ParentOperation::Sub }
|
62
|
+
it { ParentOperation.({})["x"].must_equal ParentOperation }
|
63
|
+
it { ParentOperation.({ sub: true })["x"].must_equal ParentOperation::Sub }
|
20
64
|
end
|
21
65
|
|
66
|
+
#---
|
67
|
+
# copying via Operation.builders
|
22
68
|
class OperationBuilderClassTest < MiniTest::Spec
|
23
69
|
class SuperOperation < Trailblazer::Operation
|
24
|
-
|
25
|
-
|
70
|
+
include Builder
|
71
|
+
|
72
|
+
builds do |options|
|
73
|
+
self::Sub if options["params"][:sub] # Sub is defined in ParentOperation.
|
26
74
|
end
|
27
75
|
end
|
28
76
|
|
29
77
|
class ParentOperation < Trailblazer::Operation
|
30
|
-
def process(params)
|
31
|
-
end
|
32
|
-
|
33
78
|
class Sub < self
|
34
79
|
end
|
35
80
|
|
36
|
-
self
|
81
|
+
self.| Builder( SuperOperation.builders )
|
82
|
+
|
83
|
+
def process(*); self["x"] = self.class end
|
84
|
+
self.| :process
|
37
85
|
end
|
38
86
|
|
39
|
-
it { ParentOperation.({}).
|
40
|
-
it { ParentOperation.({sub: true}).
|
41
|
-
end
|
87
|
+
it { ParentOperation.({})["x"].must_equal ParentOperation }
|
88
|
+
it { ParentOperation.({ sub: true })["x"].must_equal ParentOperation::Sub }
|
89
|
+
end
|