trailblazer-operation 0.4.1 → 0.6.0

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/.rubocop_todo.yml +223 -0
  4. data/.travis.yml +6 -7
  5. data/CHANGES.md +16 -12
  6. data/Gemfile +5 -3
  7. data/README.md +13 -2
  8. data/Rakefile +2 -2
  9. data/lib/trailblazer/operation.rb +52 -67
  10. data/lib/trailblazer/operation/class_dependencies.rb +1 -1
  11. data/lib/trailblazer/operation/container.rb +14 -0
  12. data/lib/trailblazer/operation/deprecated_macro.rb +2 -2
  13. data/lib/trailblazer/operation/public_call.rb +23 -20
  14. data/lib/trailblazer/operation/railway.rb +2 -3
  15. data/lib/trailblazer/operation/railway/macaroni.rb +2 -2
  16. data/lib/trailblazer/operation/result.rb +14 -1
  17. data/lib/trailblazer/operation/trace.rb +9 -12
  18. data/lib/trailblazer/operation/version.rb +4 -2
  19. data/test/benchmark/skill_resolver_benchmark.rb +8 -9
  20. data/test/call_test.rb +57 -31
  21. data/test/callable_test.rb +147 -147
  22. data/test/class_dependencies_test.rb +6 -7
  23. data/test/docs/doormat_test.rb +13 -12
  24. data/test/docs/macaroni_test.rb +7 -9
  25. data/test/docs/operation_test.rb +69 -4
  26. data/test/docs/wiring_test.rb +85 -153
  27. data/test/dry_container_test.rb +4 -3
  28. data/test/fast_track_test.rb +24 -44
  29. data/test/inheritance_test.rb +13 -12
  30. data/test/introspect_test.rb +6 -6
  31. data/test/operation_test.rb +17 -25
  32. data/test/result_test.rb +4 -4
  33. data/test/ruby-2.0.0/operation_test.rb +9 -9
  34. data/test/ruby-2.0.0/step_test.rb +17 -16
  35. data/test/step_test.rb +55 -50
  36. data/test/test_helper.rb +7 -13
  37. data/test/trace_test.rb +27 -27
  38. data/test/wiring/defaults_test.rb +29 -33
  39. data/trailblazer-operation.gemspec +9 -7
  40. metadata +46 -27
  41. data/lib/trailblazer/operation/heritage.rb +0 -30
  42. data/lib/trailblazer/operation/inject.rb +0 -36
  43. data/lib/trailblazer/operation/inspect.rb +0 -79
  44. data/lib/trailblazer/operation/railway/fast_track.rb +0 -13
  45. data/lib/trailblazer/operation/railway/normalizer.rb +0 -58
  46. data/lib/trailblazer/operation/railway/task_builder.rb +0 -37
  47. data/test/inspect_test.rb +0 -43
  48. data/test/macro_test.rb +0 -60
  49. data/test/task_wrap_test.rb +0 -97
@@ -16,7 +16,7 @@ class Trailblazer::Operation
16
16
  # The use of this module is not encouraged and it is only here for backward-compatibility.
17
17
  # Instead, please pass dependencies via containers, locals, or macros into the respective steps.
18
18
  module ClassDependencies
19
- def call_with_circuit_interface( (ctx, flow_options), **circuit_options )
19
+ def call_with_circuit_interface((ctx, flow_options), **circuit_options)
20
20
  @skills.each { |name, value| ctx[name] ||= value } # this resembles the behavior in 2.0. we didn't say we liked it.
21
21
 
22
22
  super
@@ -0,0 +1,14 @@
1
+ module Trailblazer
2
+ module Operation::Container
3
+ def options_for_public_call(options={}, *containers)
4
+ # generate the skill hash that embraces runtime options plus potential containers, the so called Runtime options.
5
+ # This wrapping is supposed to happen once in the entire system.
6
+
7
+ hash_transformer = ->(containers) { containers[0].to_hash } # FIXME: don't transform any containers into kw args.
8
+
9
+ immutable_options = Trailblazer::Context::ContainerChain.new([options, *containers], to_hash: hash_transformer)
10
+
11
+ Trailblazer::Context(immutable_options)
12
+ end
13
+ end
14
+ end
@@ -5,7 +5,7 @@ module Trailblazer
5
5
  def self.call(proc, options)
6
6
  warn %{[Trailblazer] Macros with API (input, options) are deprecated. Please use the "Task API" signature (options, flow_options) or use a simpler Callable. (#{proc})}
7
7
 
8
- wrapped_proc = ->( (options, flow_options), **circuit_options ) do
8
+ wrapped_proc = ->((options, flow_options), **circuit_options) do
9
9
  result = proc.(circuit_options[:exec_context], options) # run the macro, with the deprecated signature.
10
10
 
11
11
  direction = Activity::TaskBuilder.binary_signal_for(result, Activity::Right, Activity::Left)
@@ -13,7 +13,7 @@ module Trailblazer
13
13
  return direction, [options, flow_options]
14
14
  end
15
15
 
16
- options.merge( task: wrapped_proc )
16
+ options.merge(task: wrapped_proc)
17
17
  end
18
18
  end
19
19
  end
@@ -13,43 +13,46 @@ module Trailblazer
13
13
  #
14
14
  # @note Do not override this method as it will be removed in future versions. Also, you will break tracing.
15
15
  # @return Operation::Railway::Result binary result object
16
- def call(*args)
17
- return call_with_circuit_interface(*args) if args.any? && args[0].is_a?(Array) # This is kind of a hack that could be well hidden if Ruby had method overloading. Goal is to simplify the call/__call__ thing as we're fading out Operation::call anyway.
18
- call_with_public_interface(*args)
16
+ def call(options = {}, *args)
17
+ return call_with_circuit_interface(options, *args) if options.is_a?(Array) # This is kind of a hack that could be well hidden if Ruby had method overloading. Goal is to simplify the call/__call__ thing as we're fading out Operation::call anyway.
18
+
19
+ call_with_public_interface(options, *args)
19
20
  end
20
21
 
21
22
  def call_with_public_interface(*args)
22
- ctx = Operation::PublicCall.options_for_public_call(*args)
23
+ ctx = options_for_public_call(*args, flow_options())
23
24
 
24
25
  # call the activity.
25
26
  # This will result in invoking {::call_with_circuit_interface}.
26
- last_signal, (options, flow_options) = Activity::TaskWrap.invoke(self, [ctx, {}], {})
27
+ # last_signal, (options, flow_options) = Activity::TaskWrap.invoke(self, [ctx, {}], {})
28
+ signal, (ctx, flow_options) = Activity::TaskWrap.invoke(
29
+ @activity,
30
+ [ctx, flow_options()],
31
+ exec_context: new
32
+ )
27
33
 
28
34
  # Result is successful if the activity ended with an End event derived from Railway::End::Success.
29
- Operation::Railway::Result(last_signal, options, flow_options)
35
+ Operation::Railway::Result(signal, ctx, flow_options)
30
36
  end
31
37
 
32
38
  # This interface is used for all nested OPs (and the outer-most, too).
33
39
  def call_with_circuit_interface(args, circuit_options)
34
- @activity.(
35
- args,
36
- circuit_options.merge(
37
- exec_context: new
38
- )
39
- )
40
+ strategy_call(args, circuit_options) # FastTrack#call
41
+ end
42
+
43
+ def options_for_public_call(*args)
44
+ Operation::PublicCall.options_for_public_call(*args)
40
45
  end
41
46
 
42
47
  # Compile a Context object to be passed into the Activity::call.
43
48
  # @private
44
- def self.options_for_public_call(options={}, *containers)
45
- # generate the skill hash that embraces runtime options plus potential containers, the so called Runtime options.
46
- # This wrapping is supposed to happen once in the entire system.
47
-
48
- hash_transformer = ->(containers) { containers[0].to_hash } # FIXME: don't transform any containers into kw args.
49
-
50
- immutable_options = Trailblazer::Context::ContainerChain.new( [options, *containers], to_hash: hash_transformer ) # Runtime options, immutable.
49
+ def self.options_for_public_call(options, **flow_options)
50
+ Trailblazer::Context.for_circuit(options, {}, [options, flow_options], {})
51
+ end
51
52
 
52
- ctx = Trailblazer::Context(immutable_options)
53
+ # @semi=public
54
+ def flow_options
55
+ {context_alias: {}}
53
56
  end
54
57
  end
55
58
  end
@@ -23,10 +23,9 @@ module Trailblazer
23
23
  end
24
24
 
25
25
  module End
26
- class Success < Activity::End; end
27
- class Failure < Activity::End; end
26
+ Success = Activity::Railway::End::Success
27
+ Failure = Activity::Railway::End::Failure
28
28
  end
29
-
30
29
  end # Railway
31
30
  end
32
31
  end
@@ -7,13 +7,13 @@ module Trailblazer
7
7
  # def my_step( params:, options:, ** )
8
8
  module Macaroni
9
9
  def self.call(user_proc)
10
- Activity::TaskBuilder::Task.new( Trailblazer::Option.build( Macaroni::Option, user_proc ), user_proc )
10
+ Activity::TaskBuilder::Task.new(Trailblazer::Option.build(Macaroni::Option, user_proc), user_proc)
11
11
  end
12
12
 
13
13
  class Option < Trailblazer::Option
14
14
  # The Option#call! method prepares the arguments.
15
15
  def self.call!(proc, options, *)
16
- proc.( **options.to_hash.merge( options: options ) )
16
+ proc.(**options.to_hash.merge(options: options))
17
17
  end
18
18
  end
19
19
  end
@@ -11,7 +11,15 @@ class Trailblazer::Operation
11
11
  end
12
12
 
13
13
  def failure?
14
- ! success?
14
+ !success?
15
+ end
16
+
17
+ def to_hash
18
+ data.to_hash
19
+ end
20
+
21
+ def keys
22
+ data.to_hash.keys
15
23
  end
16
24
 
17
25
  extend Forwardable
@@ -20,11 +28,16 @@ class Trailblazer::Operation
20
28
  # DISCUSS: the two methods below are more for testing.
21
29
  def inspect(*slices)
22
30
  return "<Result:#{success?} #{slice(*slices).inspect} >" if slices.any?
31
+
23
32
  "<Result:#{success?} #{@data.inspect} >"
24
33
  end
25
34
 
26
35
  def slice(*keys)
27
36
  keys.collect { |k| self[k] }
28
37
  end
38
+
39
+ private
40
+
41
+ attr_reader :data
29
42
  end
30
43
  end
@@ -2,17 +2,14 @@ module Trailblazer
2
2
  class Operation
3
3
  module Trace
4
4
  # @note The problem in this method is, we have redundancy with Operation::PublicCall
5
- def self.call(operation, *args)
6
- ctx = PublicCall.options_for_public_call(*args) # redundant with PublicCall::call.
5
+ def self.call(operation, options)
6
+ ctx = PublicCall.options_for_public_call(options) # redundant with PublicCall::call.
7
7
 
8
- # Prepare the tracing-specific arguments. This is only run once for the entire circuit!
9
- operation, *args = Trailblazer::Activity::Trace.arguments_for_call( operation, [ctx, {}], {} )
8
+ stack, signal, (ctx, _flow_options) = Developer::Trace.(operation, [ctx, {}])
10
9
 
11
- last_signal, (ctx, flow_options) = Activity::TaskWrap.invoke(operation, *args )
10
+ result = Railway::Result(signal, ctx) # redundant with PublicCall::call.
12
11
 
13
- result = Railway::Result(last_signal, ctx) # redundant with PublicCall::call.
14
-
15
- Result.new(result, flow_options[:stack].to_a)
12
+ Result.new(result, stack.to_a)
16
13
  end
17
14
 
18
15
  # `Operation::trace` is included for simple tracing of the flow.
@@ -20,9 +17,9 @@ module Trailblazer
20
17
  #
21
18
  # @public
22
19
  #
23
- # Operation.trace(params, "current_user" => current_user).wtf
24
- def trace(*args)
25
- Trace.(self, *args)
20
+ # Operation.trace(params, current_user: current_user).wtf
21
+ def trace(options)
22
+ Trace.(self, options)
26
23
  end
27
24
 
28
25
  # Presentation of the traced stack via the returned result object.
@@ -34,7 +31,7 @@ module Trailblazer
34
31
  end
35
32
 
36
33
  def wtf
37
- Trailblazer::Activity::Trace::Present.(@stack)
34
+ Trailblazer::Developer::Trace::Present.(@stack)
38
35
  end
39
36
 
40
37
  def wtf?
@@ -1,5 +1,7 @@
1
1
  module Trailblazer
2
- class Operation
3
- VERSION = "0.4.1"
2
+ module Version
3
+ module Operation
4
+ VERSION = "0.6.0"
5
+ end
4
6
  end
5
7
  end
@@ -11,28 +11,27 @@ normal_container = {}
11
11
  normal_container["xbla_#{i}"] = i
12
12
  end
13
13
 
14
-
15
14
  Benchmark.ips do |x|
16
- x.report(:merge) {
15
+ x.report(:merge) do
17
16
  attrs = normal_container.merge(initialize_hash)
18
- 10.times do |i|
17
+ 10.times do |_i|
19
18
  attrs["bla_8"]
20
19
  end
21
- 10.times do |i|
20
+ 10.times do |_i|
22
21
  attrs["xbla_1"]
23
22
  end
24
- }
23
+ end
25
24
 
26
- x.report(:resolver) {
25
+ x.report(:resolver) do
27
26
  attrs = Trailblazer::Skill::Resolver.new(initialize_hash, normal_container)
28
27
 
29
- 10.times do |i|
28
+ 10.times do |_i|
30
29
  attrs["bla_8"]
31
30
  end
32
- 10.times do |i|
31
+ 10.times do |_i|
33
32
  attrs["xbla_1"]
34
33
  end
35
- }
34
+ end
36
35
  end
37
36
 
38
37
  # Warming up --------------------------------------
@@ -1,47 +1,73 @@
1
- require "test_helper"
1
+ require "test_helper"
2
2
 
3
3
  class CallTest < Minitest::Spec
4
- describe "::call" do
5
- class Create < Trailblazer::Operation
6
- step ->(*) { true }
7
- def inspect
8
- "#{@skills.inspect}"
9
- end
4
+ class Create < Trailblazer::Operation
5
+ step ->(*) { true }
6
+ def inspect
7
+ @skills.inspect.to_s
10
8
  end
9
+ end
11
10
 
12
- it { Create.().must_be_instance_of Trailblazer::Operation::Railway::Result }
11
+ it { Create.().must_be_instance_of Trailblazer::Operation::Railway::Result }
13
12
 
14
- # it { Create.({}).inspect.must_equal %{<Result:true <Skill {} {\"params\"=>{}} {\"pipetree\"=>[>operation.new]}> >} }
15
- # it { Create.(name: "Jacob").inspect.must_equal %{<Result:true <Skill {} {\"params\"=>{:name=>\"Jacob\"}} {\"pipetree\"=>[>operation.new]}> >} }
16
- # it { Create.({ name: "Jacob" }, { policy: Object }).inspect.must_equal %{<Result:true <Skill {} {:policy=>Object, \"params\"=>{:name=>\"Jacob\"}} {\"pipetree\"=>[>operation.new]}> >} }
13
+ # it { Create.({}).inspect.must_equal %{<Result:true <Skill {} {\"params\"=>{}} {\"pipetree\"=>[>operation.new]}> >} }
14
+ # it { Create.(name: "Jacob").inspect.must_equal %{<Result:true <Skill {} {\"params\"=>{:name=>\"Jacob\"}} {\"pipetree\"=>[>operation.new]}> >} }
15
+ # it { Create.({ name: "Jacob" }, { policy: Object }).inspect.must_equal %{<Result:true <Skill {} {:policy=>Object, \"params\"=>{:name=>\"Jacob\"}} {\"pipetree\"=>[>operation.new]}> >} }
17
16
 
18
- #---
19
- # success?
20
- class Update < Trailblazer::Operation
21
- step ->(options, **) { options[:result] }
22
- end
17
+ #---
18
+ # success?
19
+ class Update < Trailblazer::Operation
20
+ step ->(ctx, **) { ctx[:result] }
21
+ end
23
22
 
24
- # operation success
25
- it do
26
- result = Update.(result: true)
23
+ # operation success
24
+ it do
25
+ result = Update.(result: true)
27
26
 
28
- result.success?.must_equal true
27
+ result.success?.must_equal true
29
28
 
30
- result.event.must_be_instance_of Trailblazer::Operation::Railway::End::Success
31
- result.event.must_equal Update.outputs[:success].signal
32
- end
29
+ result.event.must_be_instance_of Trailblazer::Operation::Railway::End::Success
30
+ result.event.must_equal Update.to_h[:outputs][0].signal
31
+ end
32
+
33
+ # operation failure
34
+ it do
35
+ result = Update.(result: false)
33
36
 
34
- # operation failure
35
- it do
36
- result = Update.(result: false)
37
+ result.success?.must_equal false
38
+ result.failure?.must_equal true
39
+
40
+ result.event.must_be_instance_of Trailblazer::Operation::Railway::End::Failure
41
+ result.event.must_equal Update.to_h[:outputs].find { |output| output.semantic == :failure }.signal
42
+ end
37
43
 
38
- result.success?.must_equal false
39
- result.failure?.must_equal true
44
+ it "invokes with the taskWrap" do
45
+ operation = Class.new(Trailblazer::Operation) do
46
+ include Trailblazer::Activity::Testing.def_steps(:a)
40
47
 
41
- result.event.must_be_instance_of Trailblazer::Operation::Railway::End::Failure
42
- result.event.must_equal Update.outputs[:failure].signal
48
+ def self.add_1(wrap_ctx, original_args)
49
+ ctx, = original_args[0]
50
+ ctx[:seq] << 1
51
+ return wrap_ctx, original_args # yay to mutable state. not.
52
+ end
53
+
54
+ merge = [
55
+ [Trailblazer::Activity::TaskWrap::Pipeline.method(:insert_before), "task_wrap.call_task", ["user.add_1", method(:add_1)]]
56
+ ]
57
+
58
+ step :a, extensions: [Trailblazer::Activity::TaskWrap::Extension(merge: merge)]
43
59
  end
44
60
 
61
+ # normal operation invocation
62
+ result = operation.(seq: [])
63
+
64
+ result.inspect(:seq).must_equal %{<Result:true [[1, :a]] >}
65
+
66
+ # with tracing
67
+ result = operation.trace(seq: [])
68
+
69
+ result.inspect(:seq).must_equal %{<Result:true [[1, :a]] >}
70
+
71
+ result.wtf?
45
72
  end
46
73
  end
47
-
@@ -1,147 +1,147 @@
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
+ # 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