lib/trailblazer/circuit/wrapped.rb in trailblazer-circuit-0.0.4 vs lib/trailblazer/circuit/wrapped.rb in trailblazer-circuit-0.0.5

- old
+ new

@@ -1,58 +1,72 @@ class Trailblazer::Circuit + # Lingo: task_wrap module Activity::Wrapped - # Input = ->(direction, options, flow_options) { [direction, options, flow_options] } + # The runner is passed into Circuit#call( runner: Runner ) and is called for every task in the circuit. + # Its primary job is to actually `call` the task. + # + # Here, we extend this, and wrap the task `call` into its own pipeline, so we can add external behavior per task. + class Runner + # private flow_options[ :task_wraps ] # DISCUSS: move to separate arg? + # @api private + def self.call(task, direction, options, task_wraps:raise, wrap_alterations:{}, **flow_options) + # TODO: test this decider! + task_wrap = task_wraps[task] || raise("test me!") + task_wrap = wrap_alterations.(task, task_wrap) + wrap_config = { task: task } + + # Call the task_wrap circuit: + # |-- Start + # |-- Trace.capture_args [optional] + # |-- Call (call actual task) + # |-- Trace.capture_return [optional] + # |-- End + # Pass empty flow_options to the task_wrap, so it doesn't infinite-loop. + task_wrap.( task_wrap[:Start], options, {}, wrap_config, flow_options.merge( task_wraps: task_wraps, wrap_alterations: wrap_alterations) ) + end + end # Runner + + class Wraps + def initialize(default, hash={}) + @default, @hash = default, hash + end + + def [](task) + @hash.fetch(task) { @default } + end + end + + class Alterations < Wraps + # Find alterations for `task` and apply them to `task_wrap`. + # This usually means that tracing steps/tasks are added, input/output contracts added, etc. + def call(task, task_wrap) + self[task]. + inject(task_wrap) { |circuit, alteration| alteration.(circuit) } + end + end + def self.call_activity(direction, options, flow_options, wrap_config, original_flow_options) - task = wrap_config[:step] + task = wrap_config[:task] # Call the actual task we're wrapping here. wrap_config[:result_direction], options, flow_options = task.( direction, options, original_flow_options ) [ direction, options, flow_options, wrap_config, original_flow_options ] end Call = method(:call_activity) - # Output = ->(direction, options, flow_options) { [direction, options, flow_options] } - class End < Trailblazer::Circuit::End def call(direction, options, flow_options, wrap_config, *args) - [ wrap_config[:result_direction], options, flow_options, wrap_config, *args ] + [ wrap_config[:result_direction], options, flow_options ] # note how we don't return the appended internal args. end end Activity = Trailblazer::Circuit::Activity({ id: "task.wrap" }, end: { default: End.new(:default) }) do |act| { - act[:Start] => { Right => Call }, # options from outside - # Input => { Circuit::Right => Trace::CaptureArgs }, - # MyInject => { Circuit::Right => Trace::CaptureArgs }, - # Trace::CaptureArgs => { Circuit::Right => Call }, - Call => { Right => act[:End] }, - # Trace::CaptureReturn => { Circuit::Right => Output }, - # Output => { Circuit::Right => act[:End] } + act[:Start] => { Right => Call }, # options from outside + Call => { Right => act[:End] }, } - end - - # Find the respective wrap per task, and run it. - class Runner - # private flow_options[ :step_runners ] - def self.call(task, direction, options, flow_options) - # TODO: test this decider! - task_wrap = flow_options[:step_runners][task] || flow_options[:step_runners][nil] # DISCUSS: default could be more explicit@ - - # we can't pass :runner in here since the Step::Pipeline would call itself again, then. - # However, we need the runner in nested activities. - wrap_config = { step: task } - - # Call the task_wrap circuit: - # |-- Start - # |-- Trace.capture_args [optional] - # |-- Call (call actual task) - # |-- Trace.capture_return [optional] - # |-- End - # Pass empty flow_options to the task_wrap, so it doesn't infinite-loop. - task_wrap.( task_wrap[:Start], options, {}, wrap_config, flow_options ) # all tasks in Wrap have to implement this signature. - end - end # Runner + end # Activity end end