trailblazer-operation 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -2
  3. data/CHANGES.md +10 -0
  4. data/lib/trailblazer/operation/class_dependencies.rb +1 -1
  5. data/lib/trailblazer/operation/public_call.rb +24 -14
  6. data/lib/trailblazer/operation/railway.rb +13 -7
  7. data/lib/trailblazer/operation/version.rb +1 -1
  8. data/lib/trailblazer/operation/wtf.rb +11 -0
  9. data/lib/trailblazer/operation.rb +2 -2
  10. data/test/call_test.rb +32 -10
  11. data/test/class_dependencies_test.rb +8 -4
  12. data/test/docs/autogenerated/activity_basics_test.rb +72 -0
  13. data/test/docs/autogenerated/composable_variable_mapping_test.rb +880 -0
  14. data/test/docs/autogenerated/fast_track_layout_test.rb +76 -0
  15. data/test/docs/autogenerated/mechanics_test.rb +382 -0
  16. data/test/docs/autogenerated/sequence_options_test.rb +202 -0
  17. data/test/docs/autogenerated/subprocess_test.rb +257 -0
  18. data/test/docs/autogenerated/wiring_api_test.rb +435 -0
  19. data/test/docs/developer_test.rb +27 -0
  20. data/test/docs/public_call_monkeypatching_test.rb +96 -0
  21. data/test/docs/result_test.rb +38 -0
  22. data/test/docs/step_dsl_test.rb +93 -0
  23. data/test/operation_test.rb +53 -13
  24. data/test/result_test.rb +1 -1
  25. data/test/test_helper.rb +17 -5
  26. data/test/trace_test.rb +3 -43
  27. data/trailblazer-operation.gemspec +2 -1
  28. metadata +42 -23
  29. data/lib/trailblazer/operation/trace.rb +0 -67
  30. data/test/callable_test.rb +0 -147
  31. data/test/docs/doormat_test.rb +0 -190
  32. data/test/docs/macaroni_test.rb +0 -31
  33. data/test/skill_test.rb +0 -66
  34. data/test/wire_test.rb +0 -113
  35. data/test/wiring/defaults_test.rb +0 -193
  36. data/test/wiring/subprocess_test.rb +0 -70
@@ -1,67 +0,0 @@
1
- require "delegate"
2
- require "trailblazer/developer"
3
-
4
- module Trailblazer
5
- class Operation
6
- module Trace
7
- # @note The problem in this method is, we have redundancy with Operation::PublicCall
8
- def self.call(operation, options)
9
- # warn %{Trailblazer: `Operation.trace` is deprecated. Please use `Operation.wtf?`.} # DISCUSS: should this be deprecated?
10
- ctx = PublicCall.options_for_public_call(options) # redundant with PublicCall::call.
11
-
12
- stack, signal, (ctx, _flow_options) = Developer::Trace.(operation, [ctx, {}])
13
-
14
- result = Railway::Result(signal, ctx) # redundant with PublicCall::call.
15
-
16
- Result.new(result, stack)
17
- end
18
-
19
- # `Operation::trace` is included for simple tracing of the flow.
20
- # It simply forwards all arguments to `Trace.call`.
21
- #
22
- # @public
23
- #
24
- # Operation.trace(params, current_user: current_user).wtf
25
- # TODO: remove in 0.11.0.
26
- def trace(options)
27
- Activity::Deprecate.warn Trace.find_caller_location_for_deprecated, %(Using `Operation.trace` is deprecated and will be removed in {trailblazer-operation-0.11.0}.
28
- Please use `#{self}.wtf?` as documented here: https://trailblazer.to/2.1/docs/trailblazer#trailblazer-developer-wtf-)
29
-
30
- Trace.(self, options)
31
- end
32
-
33
- def wtf?(options)
34
- call_with_public_interface(options, {}, invoke_class: Developer::Wtf)
35
- end
36
-
37
- # TODO: remove in 0.11.0.
38
- def self.find_caller_location_for_deprecated
39
- our_caller_locations = caller_locations.to_a
40
- caller_location = our_caller_locations.reverse.find { |line| line.to_s =~ /operation\/trace/ }
41
-
42
- _caller_location = our_caller_locations[our_caller_locations.index(caller_location)+1]
43
- end
44
-
45
- # Presentation of the traced stack via the returned result object.
46
- # This object is wrapped around the original result in {Trace.call}.
47
- class Result < ::SimpleDelegator
48
- def initialize(result, stack)
49
- super(result)
50
- @stack = stack
51
- end
52
-
53
- # TODO: remove in 0.11.0.
54
- def wtf
55
- Activity::Deprecate.warn Trace.find_caller_location_for_deprecated, %(Using `result.wtf?` is deprecated. Please use `#{@stack.to_a[0].task}.wtf?` and have a nice day.)
56
-
57
- Developer::Trace::Present.(@stack)
58
- end
59
-
60
- # TODO: remove in 0.11.0.
61
- def wtf?
62
- puts wtf
63
- end
64
- end
65
- end
66
- end
67
- end
@@ -1,147 +0,0 @@
1
- # require "test_helper"
2
-
3
- # class CallableHelper < Minitest::Spec
4
- # Operation = Trailblazer::Operation
5
- # Activity = Trailblazer::Activity
6
-
7
- # module Blog
8
- # Read = ->((options, *args), *) { options["Read"] = 1; [ Activity::Right, [options, *args] ] }
9
- # Next = ->((options, *args), *) { options["NextPage"] = []; [ options["return"], [options, *args] ] }
10
- # Comment = ->((options, *args), *) { options["Comment"] = 2; [ Activity::Right, [options, *args] ] }
11
- # end
12
-
13
- # module User
14
- # Relax = ->((options, *args), *) { options["Relax"]=true; [ Activity::Right, [options, *args] ] }
15
- # end
16
-
17
- # ### Callable( )
18
- # ###
19
- # describe "circuit with 1 level of nesting" do # TODO: test this kind of configuration in dsl_tests somewhere.
20
- # let(:blog) do
21
- # Module.new do
22
- # extend Activity::Path()
23
-
24
- # task task: Blog::Read
25
- # task task: Blog::Next, Output(Activity::Right, :done) => "End.success", Output(Activity::Left, :success) => Track(:success)
26
- # task task: Blog::Comment
27
- # end
28
- # end
29
-
30
- # let(:user) do
31
- # _blog = blog
32
-
33
- # Module.new do
34
- # extend Activity::Path()
35
-
36
- # task task: _blog, _blog.outputs[:success] => Track(:success)
37
- # task task: User::Relax
38
- # end
39
- # end
40
-
41
- # it "ends before comment, on next_page" do
42
- # user.( [options = { "return" => Activity::Right }] ).must_equal(
43
- # [user.outputs[:success].signal, [{"return"=>Trailblazer::Activity::Right, "Read"=>1, "NextPage"=>[], "Relax"=>true}]]
44
- # )
45
-
46
- # options.must_equal({"return"=>Trailblazer::Activity::Right, "Read"=>1, "NextPage"=>[], "Relax"=>true})
47
- # end
48
- # end
49
-
50
- # ### Callable( End1, End2 )
51
- # ###
52
- # describe "circuit with 2 end events in the nested process" do
53
- # let(:blog) do
54
- # Module.new do
55
- # extend Activity::Path()
56
-
57
- # task task: Blog::Read
58
- # task task: Blog::Next, Output(Activity::Right, :success___) => :__success, Output(Activity::Left, :retry___) => _retry=End(:retry)
59
- # end
60
- # end
61
-
62
- # let(:user) do
63
- # _blog = blog
64
-
65
- # Module.new do
66
- # extend Activity::Path()
67
-
68
- # task task: _blog, _blog.outputs[:success] => Track(:success), _blog.outputs[:retry] => "End.success"
69
- # task task: User::Relax
70
- # end
71
- # end
72
-
73
- # it "runs from Callable->default to Relax" do
74
- # user.( [ options = { "return" => Activity::Right } ] ).must_equal [
75
- # user.outputs[:success].signal,
76
- # [ {"return"=>Activity::Right, "Read"=>1, "NextPage"=>[], "Relax"=>true} ]
77
- # ]
78
-
79
- # options.must_equal({"return"=>Activity::Right, "Read"=>1, "NextPage"=>[], "Relax"=>true})
80
- # end
81
-
82
- # it "runs from other Callable end" do
83
- # user.( [ options = { "return" => Activity::Left } ] ).must_equal [
84
- # user.outputs[:success].signal,
85
- # [ {"return"=>Activity::Left, "Read"=>1, "NextPage"=>[]} ]
86
- # ]
87
-
88
- # options.must_equal({"return"=>Activity::Left, "Read"=>1, "NextPage"=>[]})
89
- # end
90
-
91
- # #---
92
- # #- Callable( activity, start_at )
93
- # let(:with_nested_and_start_at) do
94
- # _blog = blog
95
-
96
- # Module.new do
97
- # extend Activity::Path()
98
-
99
- # task task: Operation::Callable( _blog, start_task: Blog::Next ), _blog.outputs[:success] => Track(:success)
100
- # task task: User::Relax
101
- # end
102
- # end
103
-
104
- # it "runs Callable from alternative start" do
105
- # with_nested_and_start_at.( [options = { "return" => Activity::Right }] ).
106
- # must_equal [
107
- # with_nested_and_start_at.outputs[:success].signal,
108
- # [ {"return"=>Activity::Right, "NextPage"=>[], "Relax"=>true} ]
109
- # ]
110
-
111
- # options.must_equal({"return"=>Activity::Right, "NextPage"=>[], "Relax"=>true})
112
- # end
113
-
114
- # #---
115
- # #- Callable( activity, call: :__call__ ) { ... }
116
- # describe "Callable with :call option" do
117
- # let(:process) do
118
- # class Workout
119
- # def self.__call__((options, *args), *)
120
- # options[:workout] = 9
121
-
122
- # return Activity::Right, [options, *args]
123
- # end
124
- # end
125
-
126
- # subprocess = Operation::Callable( Workout, call: :__call__ )
127
-
128
- # Module.new do
129
- # extend Activity::Path()
130
-
131
- # task task: subprocess
132
- # task task: User::Relax
133
- # end
134
- # end
135
-
136
- # it "runs Callable process with __call__" do
137
- # process.( [options = { "return" => Activity::Right }] ).
138
- # must_equal [
139
- # process.outputs[:success].signal,
140
- # [{"return"=>Activity::Right, :workout=>9, "Relax"=>true}]
141
- # ]
142
-
143
- # options.must_equal({"return"=>Activity::Right, :workout=>9, "Relax"=>true})
144
- # end
145
- # end
146
- # end
147
- # end
@@ -1,190 +0,0 @@
1
- require "test_helper"
2
-
3
- class TemplateWithGroupTest < Minitest::Spec
4
- module Memo; end
5
-
6
- #:template
7
- class Memo::Operation < Trailblazer::Operation
8
- step :log_call, group: :start
9
- step :log_success, group: :end, before: "End.success"
10
- fail :log_errors, group: :end, before: "End.failure"
11
- #~tmethods
12
-
13
- # our success "end":
14
- def log_call(options, **)
15
- options["row"] = [:a]
16
- end
17
-
18
- # our success "end":
19
- def log_success(options, **)
20
- options["row"] << :z
21
- end
22
-
23
- def log_errors(options, **)
24
- options["row"] << :f
25
- end
26
- #~tmethods end
27
- end
28
- #:template end
29
-
30
- #:template-user
31
- class Memo::Create < Memo::Operation
32
- step :create_model
33
- step :validate
34
- step :save
35
- #~meths
36
- def create_model(options, **)
37
- options["row"] << :l
38
- end
39
-
40
- def validate(options, **)
41
- options["row"] << :b
42
- end
43
-
44
- def save(options, **)
45
- options["row"] << :c
46
- end
47
- #~meths end
48
- end
49
- #:template-user end
50
-
51
- # it { pp F['__sequence__'].to_a }
52
- it {
53
- skip
54
- Memo::Create.(params: {}, "b_return" => false).inspect("row").must_equal %{<Result:true [[:a, :l, :b, :c, :z]] >}
55
- }
56
- end
57
-
58
- class DoormatWithGroupTest < Minitest::Spec
59
- module Memo; end
60
-
61
- #:doormat-group
62
- class Memo::Create < Trailblazer::Operation
63
- step :create_model
64
- step :log_success, group: :end, before: "End.success"
65
-
66
- step :validate
67
- step :save
68
-
69
- fail :log_errors, group: :end, before: "End.failure"
70
- #~methods
71
- def create_model(options, **)
72
- options["row"] = [:a]
73
- end
74
-
75
- # our success "end":
76
- def log_success(options, **)
77
- options["row"] << :z
78
- end
79
-
80
- # 2
81
- def validate(options, **)
82
- options["row"] << :b
83
- end
84
-
85
- # 3
86
- def save(options, **)
87
- options["row"] << :c
88
- end
89
-
90
- def log_errors(options, **)
91
- options["row"] << :f
92
- end
93
- #~methods end
94
- end
95
- #:doormat-group end
96
-
97
- # it { pp F['__sequence__'].to_a }
98
- it {
99
- skip
100
- Memo::Create.(params: {}, "b_return" => false).inspect("row").must_equal %{<Result:true [[:a, :b, :c, :z]] >}
101
- }
102
- end
103
-
104
- class DoormatStepDocsTest < Minitest::Spec
105
- module Memo; end
106
-
107
- #:doormat-before
108
- class Memo::Create < Trailblazer::Operation
109
- step :create_model
110
- step :log_success
111
-
112
- step :validate, before: :log_success
113
- step :save, before: :log_success
114
-
115
- fail :log_errors
116
- #~im
117
- def create_model(options, **)
118
- options["row"] = [:a]
119
- end
120
-
121
- # our success "end":
122
- def log_success(options, **)
123
- options["row"] << :z
124
- end
125
-
126
- # 2
127
- def validate(options, **)
128
- options["row"] << :b
129
- end
130
-
131
- # 3
132
- def save(options, **)
133
- options["row"] << :c
134
- end
135
-
136
- def log_errors(options, **)
137
- options["row"] << :f
138
- end
139
- #~im end
140
- end
141
- #:doormat-before end
142
-
143
- # it { pp F['__sequence__'].to_a }
144
- it { Memo::Create.(params: {}, "b_return" => false).inspect("row").must_equal %{<Result:true [[:a, :b, :c, :z]] >} }
145
- end
146
-
147
- class DoormatInheritanceTest < Minitest::Spec
148
- #:doormatx-before-inheritance
149
- class Base < Trailblazer::Operation
150
- step :log_success!
151
- fail :log_errors!
152
- #~ignored
153
- # our success "end":
154
- def log_success!(options, **)
155
- options["row"] << :z
156
- end
157
-
158
- def log_errors!(options, **)
159
- options["row"] << :f
160
- end
161
- #~ignored end
162
- end
163
- #:doormatx-before-inheritance end
164
-
165
- #:doormat-before-inheritance-sub
166
- class Create < Base
167
- step :first, before: :log_success!
168
- step :second, before: :log_success!
169
- step :third, before: :log_success!
170
- #~ignoredd
171
- def first(options, **)
172
- options["row"] = [:a]
173
- end
174
-
175
- # 2
176
- def second(options, **)
177
- options["row"] << :b
178
- end
179
-
180
- # 3
181
- def third(options, **)
182
- options["row"] << :c
183
- end
184
- #~ignoredd end
185
- end
186
- #:doormat-before-inheritance-sub end
187
-
188
- # it { pp F['__sequence__'].to_a }
189
- it { Create.("b_return" => false).inspect("row").must_equal %{<Result:true [[:a, :b, :c, :z]] >} }
190
- end
@@ -1,31 +0,0 @@
1
- # require "test_helper"
2
-
3
- # class MacaroniTaskBuilderTest < Minitest::Spec
4
- # Memo = Struct.new(:title) do
5
- # def save
6
- # self.title = title[:title].reverse
7
- # end
8
- # end
9
-
10
- # #:create
11
- # class Memo::Create < Trailblazer::Operation(step_interface_builder: Trailblazer::Operation::Railway::KwSignature)
12
- # #~ign
13
- # step :create_model
14
- # step :save
15
- # #~ign end
16
- # #~methods
17
- # def create_model(params:, options:, **)
18
- # options[:model] = Memo.new(title: params[:title])
19
- # end
20
-
21
- # def save(model:, **)
22
- # model.save
23
- # end
24
- # #~methods end
25
- # end
26
- # #:create end
27
-
28
- # it "allows optional macaroni call style" do
29
- # Memo::Create.(params: {title: "Wow!"}).inspect(:model).must_equal %{<Result:true [#<struct MacaroniTaskBuilderTest::Memo title=\"!woW\">] >}
30
- # end
31
- # end
data/test/skill_test.rb DELETED
@@ -1,66 +0,0 @@
1
- # require "test_helper"
2
- # require "trailblazer/skill"
3
-
4
- # class SkillTest < Minitest::Spec
5
- # it "wraps one" do
6
- # options = { params: "Hello!" }
7
-
8
- # skill = Trailblazer::Skill.new(options)
9
-
10
- # skill[:params].must_equal "Hello!"
11
-
12
- # skill.to_hash.must_equal( {params: "Hello!"} )
13
-
14
- # options.inspect.must_equal %{{:params=>"Hello!"}}
15
- # end
16
- # # FIXME: do we actually want key?
17
- # it "what" do
18
- # skills = Trailblazer::Skill.new({ "a" => false, "b" => nil })
19
- # (!!skills.key?("a")).must_equal true
20
- # (!!skills.key?("b")).must_equal true
21
- # end
22
-
23
- # describe "Skill" do
24
- # it do
25
- # class_level_container = {
26
- # "contract.class" => Object,
27
- # "model.class" => String
28
- # }
29
-
30
- # runtime_skills = {
31
- # "contract" => MyContract=Class.new,
32
- # "model.class" => Integer
33
- # }
34
-
35
- # skill = Trailblazer::Skill.new(runtime_skills, class_level_container)
36
-
37
- # # non-existent key.
38
- # skill[:nope].must_be_nil
39
-
40
- # # from runtime.
41
- # skill["contract"].must_equal MyContract
42
- # # from compile-time.
43
- # skill["contract.class"].must_equal Object
44
- # # runtime supersedes compile-time.
45
- # skill["model.class"].must_equal Integer
46
-
47
- # skill["model.class"] = Fixnum
48
- # skill["model.class"].must_equal Fixnum
49
-
50
- # # add new tuple.
51
- # skill["user.current"] = "Todd"
52
-
53
- # # original container don't get changed
54
- # class_level_container.inspect.must_equal %{{"contract.class"=>Object, "model.class"=>String}}
55
- # runtime_skills.inspect.must_equal %{{"contract"=>SkillTest::MyContract, "model.class"=>Integer}}
56
-
57
- # # setting false.
58
- # skill[:valid] = false
59
- # skill[:valid].must_equal false
60
-
61
- # # setting nil.
62
- # skill[:valid] = nil
63
- # skill[:valid].must_be_nil
64
- # end
65
- # end
66
- # end
data/test/wire_test.rb DELETED
@@ -1,113 +0,0 @@
1
- # require "test_helper"
2
- # # require "trailblazer/developer"
3
-
4
- # class WireTest < Minitest::Spec
5
- # Circuit = Trailblazer::Circuit
6
- # ExceptionFromD = Class.new # custom signal
7
-
8
- # D = ->((options, *args), *) do
9
- # options["D"] = [ options["a"], options["b"], options["c"] ]
10
-
11
- # signal = options["D_return"]
12
- # [ signal, [ options, *args ] ]
13
- # end
14
-
15
- # #---
16
- # #- step providing all :outputs manually.
17
- # class Create < Trailblazer::Operation
18
- # step ->(options, **) { options["a"] = 1 }
19
- # step ->(options, **) { options["b"] = 2 }, name: "b"
20
-
21
- # step( { task: D,
22
- # outputs: { Circuit::Right => :success, Circuit::Left => :failure, ExceptionFromD => :exception }, # any outputs and their polarization, generic.
23
- # id: :d,
24
- # },
25
- # :exception => MyEnd = End("End.ExceptionFromD_happened")
26
- # )
27
-
28
- # fail ->(options, **) { options["f"] = 4 }, id: "f"
29
- # step ->(options, **) { options["c"] = 3 }, id: "c"
30
- # end
31
-
32
- # # myend ==> d
33
- # it { Trailblazer::Operation::Inspect.(Create).gsub(/0x.+?wire_test.rb/, "").must_equal %{[>#<Proc::18 (lambda)>,>b,>d,<<f,>c]} }
34
-
35
- # # normal flow as D sits on the Right track.
36
- # it do
37
- # result = Create.({}, "D_return" => Circuit::Right)
38
-
39
- # result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:true [1, 2, 3, [1, 2, nil], nil] >}
40
- # result.event.must_equal Create.outputs.keys[1]
41
- # end
42
-
43
- # # ends on MyEnd, without hitting fail.
44
- # it do
45
- # result = Create.({}, "D_return" => ExceptionFromD)
46
-
47
- # result.event.must_equal Create::MyEnd
48
- # result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], nil] >}
49
- # end
50
-
51
- # # normal flow to left track.
52
- # it do
53
- # result = Create.({}, "D_return" => Circuit::Left)
54
-
55
- # result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], 4] >}
56
- # result.event.must_equal Create.outputs.keys[0]
57
- # end
58
-
59
- # #---
60
- # #- step with Merge
61
- # class CreateWithDefaults < Trailblazer::Operation
62
- # step ->(options, **) { options["a"] = 1 }
63
- # step ->(options, **) { options["b"] = 2 }, name: "b"
64
-
65
- # step( { task: D,
66
- # outputs: Merge( ExceptionFromD => { role: :exception } ), # any outputs and their polarization, generic.
67
- # id: :d,
68
- # },
69
- # :exception => MyEnd = End("End.ExceptionFromD_happened")
70
- # )
71
-
72
- # fail ->(options, **) { options["f"] = 4 }, id: "f"
73
- # step ->(options, **) { options["c"] = 3 }, id: "c"
74
- # end
75
-
76
- # # normal flow as D sits on the Right track.
77
- # it do
78
- # result = CreateWithDefaults.({}, "D_return" => Circuit::Right)
79
-
80
- # result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:true [1, 2, 3, [1, 2, nil], nil] >}
81
- # result.event.must_equal CreateWithDefaults.outputs.keys[1]
82
- # end
83
-
84
- # # ends on MyEnd, without hitting fail.
85
- # it do
86
- # result = CreateWithDefaults.({}, "D_return" => ExceptionFromD)
87
-
88
- # result.event.must_equal CreateWithDefaults::MyEnd
89
- # result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], nil] >}
90
- # end
91
-
92
- # # normal flow to left track.
93
- # it do
94
- # result = CreateWithDefaults.({}, "D_return" => Circuit::Left)
95
-
96
- # result.inspect("a", "b", "c", "D", "f").must_equal %{<Result:false [1, 2, nil, [1, 2, nil], 4] >}
97
- # result.event.must_equal CreateWithDefaults.outputs.keys[0]
98
- # end
99
-
100
- # end
101
-
102
- # class WireExceptionTest < Minitest::Spec
103
- # # role in :outputs can't be connected because not in :connect_to.
104
- # it do
105
- # exception = assert_raises do
106
- # class Create < Trailblazer::Operation
107
- # step :a, outputs: { "some" => { role: :success } }, connect_to: { :not_existent => "End.success" }
108
- # end
109
- # end
110
-
111
- # exception.message.must_equal %{Couldn't map output role :success for {:not_existent=>"End.success"}}
112
- # end
113
- # end