trailblazer-operation 0.0.13 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -3
  3. data/CHANGES.md +44 -0
  4. data/Gemfile +13 -2
  5. data/Rakefile +8 -6
  6. data/lib/trailblazer/operation.rb +86 -12
  7. data/lib/trailblazer/operation/deprecated_macro.rb +19 -0
  8. data/lib/trailblazer/operation/inject.rb +34 -0
  9. data/lib/trailblazer/operation/inspect.rb +80 -0
  10. data/lib/trailblazer/operation/public_call.rb +62 -0
  11. data/lib/trailblazer/operation/railway.rb +32 -0
  12. data/lib/trailblazer/operation/railway/fast_track.rb +13 -0
  13. data/lib/trailblazer/operation/railway/normalizer.rb +73 -0
  14. data/lib/trailblazer/operation/railway/task_builder.rb +44 -0
  15. data/lib/trailblazer/operation/result.rb +6 -4
  16. data/lib/trailblazer/operation/skill.rb +8 -24
  17. data/lib/trailblazer/operation/task_wrap.rb +68 -0
  18. data/lib/trailblazer/operation/trace.rb +49 -0
  19. data/lib/trailblazer/operation/variable_mapping.rb +91 -0
  20. data/lib/trailblazer/operation/version.rb +1 -1
  21. data/test/call_test.rb +27 -8
  22. data/test/class_dependencies_test.rb +16 -0
  23. data/test/docs/doormat_test.rb +189 -0
  24. data/test/docs/wiring_test.rb +421 -0
  25. data/test/dry_container_test.rb +4 -0
  26. data/test/fast_track_test.rb +197 -0
  27. data/test/gemfiles/Gemfile.ruby-2.0 +1 -2
  28. data/test/gemfiles/Gemfile.ruby-2.0.lock +40 -0
  29. data/test/inheritance_test.rb +1 -1
  30. data/test/inspect_test.rb +43 -0
  31. data/test/introspect_test.rb +50 -0
  32. data/test/macro_test.rb +61 -0
  33. data/test/operation_test.rb +94 -0
  34. data/test/result_test.rb +14 -8
  35. data/test/ruby-2.0.0/operation_test.rb +73 -0
  36. data/test/ruby-2.0.0/step_test.rb +136 -0
  37. data/test/skill_test.rb +66 -48
  38. data/test/step_test.rb +228 -0
  39. data/test/task_wrap_test.rb +91 -0
  40. data/test/test_helper.rb +37 -0
  41. data/test/trace_test.rb +62 -0
  42. data/test/variable_mapping_test.rb +66 -0
  43. data/test/wire_test.rb +113 -0
  44. data/test/wiring/defaults_test.rb +197 -0
  45. data/test/wiring/subprocess_test.rb +70 -0
  46. data/trailblazer-operation.gemspec +3 -5
  47. metadata +62 -36
  48. data/lib/trailblazer/operation/1.9.3/option.rb +0 -36
  49. data/lib/trailblazer/operation/generic.rb +0 -12
  50. data/lib/trailblazer/operation/option.rb +0 -54
  51. data/lib/trailblazer/operation/pipetree.rb +0 -142
  52. data/lib/trailblazer/skill.rb +0 -70
  53. data/test/2.0.0-pipetree_test.rb +0 -100
  54. data/test/2.1.0-pipetree_test.rb +0 -100
  55. data/test/operation_skill_test.rb +0 -89
  56. data/test/pipetree_test.rb +0 -185
@@ -11,6 +11,10 @@ class DryContainerTest < Minitest::Spec
11
11
  class Create < Trailblazer::Operation
12
12
  end
13
13
 
14
+ it "allows 2.2 call style" do
15
+ Create.({}, my_container)["user_repository"].must_equal Object
16
+ end
17
+
14
18
  it { Create.({}, {}, my_container)["user_repository"].must_equal Object }
15
19
  it { Create.({}, {}, my_container)["contract.create"].must_equal Array }
16
20
  # also allows our own options PLUS containers.
@@ -0,0 +1,197 @@
1
+ require "test_helper"
2
+
3
+ class FastTrackTest < Minitest::Spec
4
+ # #failure fails fast.
5
+ # class Create < Trailblazer::Operation
6
+ # step ->(options, *) { options["x"] = options["dont_fail"] }
7
+ # failure ->(options, *) { options["a"] = true; options["fail_fast"] }, fail_fast: true
8
+ # failure ->(options, *) { options["b"] = true }
9
+ # step ->(options, *) { options["y"] = true }
10
+ # end
11
+
12
+ # puts Create["pipetree"].inspect
13
+
14
+ # require "trailblazer/diagram/bpmn"
15
+ # puts Trailblazer::Diagram::BPMN.to_xml(Create["pipetree"])
16
+
17
+ # it { Create.("fail_fast" => true, "dont_fail" => true ).inspect("x", "a", "b", "y").must_equal %{<Result:true [true, nil, nil, true] >} }
18
+ # it { Create.("fail_fast" => true ).inspect("x", "a", "b", "y").must_equal %{<Result:false [nil, true, nil, nil] >} }
19
+ # it { Create.("fail_fast" => false ).inspect("x", "a", "b", "y").must_equal %{<Result:false [nil, true, nil, nil] >} }
20
+
21
+ # #success passes fast.
22
+ class Retrieve < Trailblazer::Operation
23
+ pass ->(options, **) { options["x"] = options["dont_fail"] }, pass_fast: true
24
+ fail ->(options, **) { options["b"] = true }
25
+ step ->(options, **) { options["y"] = true }
26
+ end
27
+ it { Retrieve.("dont_fail" => true ).inspect("x", "b", "y").must_equal %{<Result:true [true, nil, nil] >} }
28
+ it { Retrieve.("dont_fail" => false ).inspect("x", "b", "y").must_equal %{<Result:true [false, nil, nil] >} }
29
+
30
+ # #step fails fast if option set and returns false.
31
+ class Update < Trailblazer::Operation
32
+ step ->(options, *) { options["x"] = true }
33
+ step ->(options, *) { options["a"] = options["dont_fail"] }, fail_fast: true # only on false.
34
+ failure ->(options, *) { options["b"] = true }
35
+ step ->(options, *) { options["y"] = true }
36
+ end
37
+
38
+ it { Update.("dont_fail" => true).inspect("x", "a", "b", "y").must_equal %{<Result:true [true, true, nil, true] >} }
39
+ it { Update.({} ).inspect("x", "a", "b", "y").must_equal %{<Result:false [true, nil, nil, nil] >} }
40
+
41
+ # #step passes fast if option set and returns true.
42
+ class Delete < Trailblazer::Operation
43
+ step ->(options, *) { options["x"] = true }
44
+ step ->(options, *) { options["a"] = options["dont_fail"] }, pass_fast: true # only on true.
45
+ fail ->(options, *) { options["b"] = true }
46
+ step ->(options, *) { options["y"] = true }
47
+ end
48
+
49
+ it { Delete.("dont_fail" => true).inspect("x", "a", "b", "y").must_equal %{<Result:true [true, true, nil, nil] >} }
50
+ it { Delete.({} ).inspect("x", "a", "b", "y").must_equal %{<Result:false [true, nil, true, nil] >} }
51
+ end
52
+
53
+ class FailBangTest < Minitest::Spec
54
+ class Create < Trailblazer::Operation
55
+ step ->(options, *) { options["x"] = true; Railway.fail! }
56
+ step ->(options, *) { options["y"] = true }
57
+ failure ->(options, *) { options["a"] = true }
58
+ end
59
+
60
+ it { Create.().inspect("x", "y", "a").must_equal %{<Result:false [true, nil, true] >} }
61
+ end
62
+
63
+ class PassBangTest < Minitest::Spec
64
+ class Create < Trailblazer::Operation
65
+ step ->(options, *) { options["x"] = true; Railway.pass! }
66
+ step ->(options, *) { options["y"] = true }
67
+ failure ->(options, *) { options["a"] = true }
68
+ end
69
+
70
+ it { Create.().inspect("x", "y", "a").must_equal %{<Result:true [true, true, nil] >} }
71
+ end
72
+
73
+ class FailFastBangTest < Minitest::Spec
74
+ class Create < Trailblazer::Operation
75
+ step ->(options, *) { options["x"] = true; Railway.fail_fast! }
76
+ step ->(options, *) { options["y"] = true }
77
+ failure ->(options, *) { options["a"] = true }
78
+ end
79
+
80
+ # without proper configuration, emitting a FastTrack signal is illegal.
81
+ it { assert_raises(Trailblazer::Circuit::IllegalOutputSignalError) { Create.().inspect("x", "y", "a").must_equal %{<Result:false [true, nil, nil] >} } }
82
+
83
+ class Update < Trailblazer::Operation
84
+ step ->(options, *) { options["x"] = true; Railway.fail_fast! }, fast_track: true
85
+ step ->(options, *) { options["y"] = true }
86
+ failure ->(options, *) { options["a"] = true }
87
+ end
88
+
89
+ it { Update.().inspect("x", "y", "a").must_equal %{<Result:false [true, nil, nil] >} }
90
+ end
91
+
92
+ class PassFastBangTest < Minitest::Spec
93
+ class Create < Trailblazer::Operation
94
+ step ->(options, *) { options["x"] = true; Railway.pass_fast! }, fast_track: true
95
+ step ->(options, *) { options["y"] = true }
96
+ failure ->(options, *) { options["a"] = true }
97
+ end
98
+
99
+ it { Create.().inspect("x", "y", "a").must_equal %{<Result:true [true, nil, nil] >} }
100
+ end
101
+
102
+ #-
103
+ class NestedFastTrackTest < Minitest::Spec
104
+ #- The ::step DSL method automatically connects the nested's End.fail_fast/End.pass_fast to Update's End.fail_fast/End.pass_fast.
105
+ #
106
+ # Edit has fast-tracked steps, so it has outputs :success/:failure/:pass_fast/:fail_fast.
107
+ class Edit < Trailblazer::Operation
108
+ step :a, fast_track: true # task is connected to End.pass_fast and End.fail_fast.
109
+
110
+ def a(options, edit_return:, **)
111
+ options["a"] = 1
112
+ edit_return # End.success, End.pass_fast, etc.
113
+ end
114
+ end
115
+
116
+ module Steps
117
+ def b(options, a:, **)
118
+ options["b"] = a+1
119
+ end
120
+
121
+ def f(options, **)
122
+ options["f"] = 3
123
+ end
124
+ end
125
+
126
+ describe "Nested, fast_track: true and all its outputs given" do
127
+ let(:update) do
128
+ Class.new(Trailblazer::Operation) do
129
+ step task: Trailblazer::Activity::Subprocess( Edit, call: :__call__ ), id: "Subprocess/",
130
+ plus_poles: Trailblazer::Activity::Magnetic::DSL::PlusPoles::from_outputs( Edit.outputs ),
131
+ fast_track: true
132
+ step :b
133
+ fail :f
134
+
135
+ include Steps
136
+ end
137
+ end
138
+
139
+ # Edit returns End.success
140
+ it { update.(edit_return: true).inspect("a", "b", "f").must_equal %{<Result:true [1, 2, nil] >} }
141
+ # Edit returns End.failure
142
+ it { update.(edit_return: false).inspect("a", "b", "f").must_equal %{<Result:false [1, nil, 3] >} }
143
+ # Edit returns End.pass_fast
144
+ it { update.(edit_return: Trailblazer::Operation::Railway.pass_fast!).inspect("a", "b", "f").must_equal %{<Result:true [1, nil, nil] >} }
145
+ # Edit returns End.fail_fast
146
+ it { update.(edit_return: Trailblazer::Operation::Railway.fail_fast!).inspect("a", "b", "f").must_equal %{<Result:false [1, nil, nil] >} }
147
+ end
148
+
149
+ describe "Nested, no :fast_track option but all its outputs given" do
150
+ let(:update) do
151
+ Class.new(Trailblazer::Operation) do
152
+ include Steps
153
+
154
+ step task: Trailblazer::Activity::Subprocess( Edit, call: :__call__ ), id: "Subprocess/",
155
+ plus_poles: Trailblazer::Activity::Magnetic::DSL::PlusPoles::from_outputs( Edit.outputs ) # all outputs given means it "works"
156
+ step :b
157
+ fail :f
158
+ end
159
+ end
160
+
161
+ # Edit returns End.success
162
+ it { update.(edit_return: true).inspect("a", "b", "f").must_equal %{<Result:true [1, 2, nil] >} }
163
+ # Edit returns End.failure
164
+ it { update.(edit_return: false).inspect("a", "b", "f").must_equal %{<Result:false [1, nil, 3] >} }
165
+ # Edit returns End.pass_fast
166
+ it { update.(edit_return: Trailblazer::Operation::Railway.pass_fast!).inspect("a", "b", "f").must_equal %{<Result:true [1, nil, nil] >} }
167
+ # Edit returns End.fail_fast
168
+ it { update.(edit_return: Trailblazer::Operation::Railway.fail_fast!).inspect("a", "b", "f").must_equal %{<Result:false [1, nil, nil] >} }
169
+ end
170
+
171
+ describe "2.0 behavior: no :fast_track option, all outputs given, but we rewire fast_track" do
172
+ let(:update) do
173
+ Class.new(Trailblazer::Operation) do
174
+ include Steps
175
+
176
+ step({task: Trailblazer::Activity::Subprocess( Edit, call: :__call__ ), id: "Subprocess/",
177
+ plus_poles: Trailblazer::Activity::Magnetic::DSL::PlusPoles::from_outputs( Edit.outputs )},
178
+ {Output(:pass_fast) => :success, Output(:fail_fast) => :failure} )# manually rewire the fast-track outputs to "conventional" railway ends.
179
+
180
+ step :b
181
+ fail :f
182
+ end
183
+ end
184
+
185
+ # it { puts Trailblazer::Activity::Introspect.Cct(update.instance_variable_get(:@process)) }
186
+ it { puts Trailblazer::Activity::Magnetic::Introspect.seq( update ) }
187
+ # Edit returns End.success
188
+ it { update.(edit_return: true).inspect("a", "b", "f").must_equal %{<Result:true [1, 2, nil] >} }
189
+ # Edit returns End.failure
190
+ it { update.(edit_return: false).inspect("a", "b", "f").must_equal %{<Result:false [1, nil, 3] >} }
191
+ # Edit returns End.pass_fast, but behaves like :success.
192
+ it { update.(edit_return: Trailblazer::Operation::Railway.pass_fast!).inspect("a", "b", "f").must_equal %{<Result:true [1, 2, nil] >} }
193
+ # Edit returns End.fail_fast, but behaves like :failure.
194
+ it { update.(edit_return: Trailblazer::Operation::Railway.fail_fast!).inspect("a", "b", "f").must_equal %{<Result:false [1, nil, 3] >} }
195
+ end
196
+ end
197
+
@@ -1,6 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
  gemspec path: "../../"
3
3
 
4
- gem "declarative"
5
- gem "pipetree"
6
4
  gem "dry-container"
5
+ gem "minitest-line"
@@ -0,0 +1,40 @@
1
+ PATH
2
+ remote: ../..
3
+ specs:
4
+ trailblazer-operation (0.1.0)
5
+ declarative
6
+ trailblazer-activity (>= 0.1.3, < 0.2.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ concurrent-ruby (1.0.2)
12
+ declarative (0.0.9)
13
+ dry-configurable (0.4.0)
14
+ concurrent-ruby (~> 1.0)
15
+ dry-container (0.6.0)
16
+ concurrent-ruby (~> 1.0)
17
+ dry-configurable (~> 0.1, >= 0.1.3)
18
+ hirb (0.7.3)
19
+ minitest (5.10.2)
20
+ minitest-line (0.6.3)
21
+ minitest (~> 5.0)
22
+ raise (0.0.2)
23
+ rake (12.0.0)
24
+ trailblazer-activity (0.1.3)
25
+ hirb
26
+
27
+ PLATFORMS
28
+ ruby
29
+
30
+ DEPENDENCIES
31
+ bundler
32
+ dry-container
33
+ minitest
34
+ minitest-line
35
+ raise
36
+ rake
37
+ trailblazer-operation!
38
+
39
+ BUNDLED WITH
40
+ 1.15.3
@@ -23,6 +23,6 @@ class InheritanceTest < Minitest::Spec
23
23
  it do
24
24
  Update["a"].must_equal "A"
25
25
  Update["b"].must_equal "B"
26
- Update["c"].must_equal nil
26
+ Update["c"].must_be_nil
27
27
  end
28
28
  end
@@ -0,0 +1,43 @@
1
+ require "test_helper"
2
+
3
+
4
+ class InspectTest < Minitest::Spec
5
+ # Test: #to_table
6
+ class Create < Trailblazer::Operation
7
+ step :decide!
8
+ pass :wasnt_ok!
9
+ pass :was_ok!
10
+ fail :return_true!
11
+ fail :return_false!
12
+ step :finalize!
13
+ end
14
+
15
+ #---
16
+ #- to_table
17
+
18
+ # pp Create.instance_variable_get(:@builder)
19
+
20
+ it do
21
+ Trailblazer::Operation.introspect(Create).must_equal %{[>decide!,>>wasnt_ok!,>>was_ok!,<<return_true!,<<return_false!,>finalize!]}
22
+ end
23
+
24
+ it do
25
+ Trailblazer::Operation::Inspect.call(Create, style: :rows).must_equal %{
26
+ 0 ==============================>decide!
27
+ 1 ===========================>>wasnt_ok!
28
+ 2 =============================>>was_ok!
29
+ 3 <<return_true!========================
30
+ 4 <<return_false!=======================
31
+ 5 ============================>finalize!}
32
+ end
33
+
34
+ describe "step with only one plus pole (happens with Nested)" do
35
+ class Present < Trailblazer::Operation
36
+ pass :ok!, plus_poles: Trailblazer::Activity::Magnetic::DSL::PlusPoles::from_outputs( :success => Trailblazer::Activity.Output("signal", :success) )
37
+ end
38
+
39
+ it do
40
+ Trailblazer::Operation.introspect(Present).must_equal %{[>>ok!]}
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,50 @@
1
+ require "test_helper"
2
+
3
+ class IntrospectTest < Minitest::Spec
4
+ A = ->(*args) { [ Activity::Right, *args ] }
5
+ B = ->(*args) { [ Activity::Right, *args ] }
6
+ C = ->(*args) { [ Activity::Right, *args ] }
7
+ D = ->(*args) { [ Activity::Right, *args ] }
8
+
9
+ let(:activity) do
10
+ nested = bc
11
+
12
+ Class.new(Trailblazer::Operation) do
13
+ step A
14
+ step nested, Output(nested.outputs.keys.first, :success) => :success
15
+ step D, id: "D"
16
+ end
17
+ end
18
+
19
+ let(:bc) do
20
+ Class.new(Trailblazer::Operation) do
21
+ step B
22
+ step C
23
+ end
24
+ end
25
+
26
+ describe "#collect" do
27
+ it "iterates over each task element in the top activity" do
28
+ all_tasks = Activity::Introspect.collect(activity) do |task, connections|
29
+ task
30
+ end
31
+
32
+ # pp all_tasks
33
+
34
+ all_tasks.size.must_equal 8
35
+ # all_tasks[1..3].must_equal [A, bc, D]
36
+ # TODO: test start and end!
37
+ end
38
+
39
+ it "iterates over all task elements recursively" do
40
+ skip
41
+ all_tasks = Activity::Introspect.collect(activity, recursive: true) do |task, connections|
42
+ task
43
+ end
44
+
45
+ all_tasks.size.must_equal 9
46
+ all_tasks[1..2].must_equal [A, bc]
47
+ all_tasks[4..5].must_equal [B, C]
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,61 @@
1
+ require "test_helper"
2
+ #- test
3
+ # macro [ task, {name} ]
4
+ # macro [ task, {name}, { alteration: } ] # see task_wrap_test.rb
5
+ # macro [ task, {name}, { alteration: }, {task_outputs} ] # for eg. nested
6
+
7
+ class MacroTest < Minitest::Spec
8
+ PlusPoles = Trailblazer::Activity::Magnetic::DSL::PlusPoles
9
+
10
+ MacroB = ->(( options, *args ), **) do
11
+ options[:B] = true # we were here!
12
+
13
+ [ options[:MacroB_return], [ options, *args ] ]
14
+ end
15
+
16
+ it "raises exception when macro doesn't provide :id" do
17
+ assert_raises do
18
+
19
+ Class.new(Trailblazer::Operation) do
20
+ step( task: "<some macro>" )
21
+ end
22
+
23
+ end.message.must_equal %{No :id given for <some macro>}
24
+ end
25
+
26
+
27
+ class Create < Trailblazer::Operation
28
+ step :a
29
+ step( task: MacroB, id: :MacroB, plus_poles: Test.plus_poles_for("Allgood" => :success, "Fail!" => :failure, "Winning" => :pass_fast) )
30
+ step :c
31
+
32
+ def a(options, **); options[:a] = true end
33
+ def c(options, **); options[:c] = true end
34
+ end
35
+
36
+ # MacroB returns Allgood and is wired to the :success edge (right track).
37
+ it { Create.( {}, MacroB_return: "Allgood" ).inspect(:a, :B, :c).must_equal %{<Result:true [true, true, true] >} }
38
+ # MacroB returns Fail! and is wired to the :failure edge (left track).
39
+ it { Create.( {}, MacroB_return: "Fail!" ).inspect(:a, :B, :c).must_equal %{<Result:false [true, true, nil] >} }
40
+ # MacroB returns Winning and is wired to the :pass_fast edge.
41
+ it { Create.( {}, MacroB_return: "Winning" ).inspect(:a, :B, :c).must_equal %{<Result:true [true, true, nil] >} }
42
+
43
+ #- user overrides :plus_poles
44
+ class Update < Trailblazer::Operation
45
+ macro = { task: MacroB, id: :MacroB, plus_poles: Test.plus_poles_for("Allgood" => :success, "Fail!" => :failure, "Winning" => :pass_fast) }
46
+
47
+ step :a
48
+ step macro, plus_poles: Test.plus_poles_for("Allgood" => :failure, "Fail!" => :success, "Winning" => :fail_fast)
49
+ step :c
50
+
51
+ def a(options, **); options[:a] = true end
52
+ def c(options, **); options[:c] = true end
53
+ end
54
+
55
+ # MacroB returns Allgood and is wired to the :failure edge.
56
+ it { Update.( {}, MacroB_return: "Allgood" ).inspect(:a, :B, :c).must_equal %{<Result:false [true, true, nil] >} }
57
+ # MacroB returns Fail! and is wired to the :success edge.
58
+ it { Update.( {}, MacroB_return: "Fail!" ).inspect(:a, :B, :c).must_equal %{<Result:true [true, true, true] >} }
59
+ # MacroB returns Winning and is wired to the :fail_fast edge.
60
+ it { Update.( {}, MacroB_return: "Winning" ).inspect(:a, :B, :c).must_equal %{<Result:false [true, true, nil] >} }
61
+ end
@@ -0,0 +1,94 @@
1
+ require "test_helper"
2
+
3
+ class DeclarativeApiTest < Minitest::Spec
4
+ #---
5
+ #- step, pass, fail
6
+
7
+ # Test: step/pass/fail
8
+ # * do they deviate properly?
9
+ class Create < Trailblazer::Operation
10
+ step :decide!
11
+ pass :wasnt_ok!
12
+ pass :was_ok!
13
+ fail :return_true!
14
+ fail :return_false!
15
+
16
+ def decide!(options, decide:raise, **)
17
+ options["a"] = true
18
+ decide
19
+ end
20
+
21
+ def wasnt_ok!(options, **)
22
+ options["y"] = false
23
+ end
24
+
25
+ def was_ok!(options, **)
26
+ options["x"] = true
27
+ end
28
+
29
+ def return_true! (options, **); options["b"] = true end
30
+ def return_false!(options, **); options["c"] = false end
31
+ end
32
+
33
+ it { Create.(decide: true).inspect("a", "x", "y", "b", "c").must_equal %{<Result:true [true, true, false, nil, nil] >} }
34
+ it { Create.(decide: false).inspect("a", "x", "y", "b", "c").must_equal %{<Result:false [true, nil, nil, true, false] >} }
35
+
36
+ #---
37
+ #- trace
38
+
39
+ it do
40
+
41
+ end
42
+
43
+ #---
44
+ #- empty class
45
+ class Noop < Trailblazer::Operation
46
+ end
47
+
48
+ it { Noop.().inspect("params").must_equal %{<Result:true [nil] >} }
49
+
50
+ #---
51
+ #- pass
52
+ #- fail
53
+ class Update < Trailblazer::Operation
54
+ pass ->(options, **) { options["a"] = false }
55
+ step ->(options, params:raise, **) { options["b"] = params[:decide] }
56
+ fail ->(options, **) { options["c"] = true }
57
+ end
58
+
59
+ it { Update.("params" => {decide: true}).inspect("a", "b", "c").must_equal %{<Result:true [false, true, nil] >} }
60
+ it { Update.("params" => {decide: false}).inspect("a", "b", "c").must_equal %{<Result:false [false, false, true] >} }
61
+
62
+ #---
63
+ #- inheritance
64
+ class Upsert < Update
65
+ step ->(options, **) { options["d"] = 1 }
66
+ end
67
+
68
+ class Unset < Upsert
69
+ step ->(options, **) { options["e"] = 2 }
70
+ end
71
+
72
+ it "allows to inherit" do
73
+ Upsert.("params" => {decide: true}).inspect("a", "b", "c", "d", "e").must_equal %{<Result:true [false, true, nil, 1, nil] >}
74
+ Unset. ("params" => {decide: true}).inspect("a", "b", "c", "d", "e").must_equal %{<Result:true [false, true, nil, 1, 2] >}
75
+ end
76
+
77
+ describe "Activity::Interface" do
78
+ class Edit < Trailblazer::Operation
79
+ step :a
80
+ step :b, fast_track: true
81
+ end
82
+
83
+ it "provides #outputs" do
84
+ Activity::Introspect.Outputs(Edit.outputs).must_equal %{success=> (#<Trailblazer::Operation::Railway::End::Success:>, success)
85
+ failure=> (#<Trailblazer::Operation::Railway::End::Failure:>, failure)
86
+ pass_fast=> (#<Trailblazer::Operation::Railway::End::PassFast:>, pass_fast)
87
+ fail_fast=> (#<Trailblazer::Operation::Railway::End::FailFast:>, fail_fast)}
88
+ end
89
+
90
+ it "is an Interface" do
91
+ Edit.is_a?( Activity::Interface ).must_equal true
92
+ end
93
+ end
94
+ end