trailblazer-operation 0.0.13 → 0.1.1

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.
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