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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -3
- data/CHANGES.md +44 -0
- data/Gemfile +13 -2
- data/Rakefile +8 -6
- data/lib/trailblazer/operation.rb +86 -12
- data/lib/trailblazer/operation/deprecated_macro.rb +19 -0
- data/lib/trailblazer/operation/inject.rb +34 -0
- data/lib/trailblazer/operation/inspect.rb +80 -0
- data/lib/trailblazer/operation/public_call.rb +62 -0
- data/lib/trailblazer/operation/railway.rb +32 -0
- data/lib/trailblazer/operation/railway/fast_track.rb +13 -0
- data/lib/trailblazer/operation/railway/normalizer.rb +73 -0
- data/lib/trailblazer/operation/railway/task_builder.rb +44 -0
- data/lib/trailblazer/operation/result.rb +6 -4
- data/lib/trailblazer/operation/skill.rb +8 -24
- data/lib/trailblazer/operation/task_wrap.rb +68 -0
- data/lib/trailblazer/operation/trace.rb +49 -0
- data/lib/trailblazer/operation/variable_mapping.rb +91 -0
- data/lib/trailblazer/operation/version.rb +1 -1
- data/test/call_test.rb +27 -8
- data/test/class_dependencies_test.rb +16 -0
- data/test/docs/doormat_test.rb +189 -0
- data/test/docs/wiring_test.rb +421 -0
- data/test/dry_container_test.rb +4 -0
- data/test/fast_track_test.rb +197 -0
- data/test/gemfiles/Gemfile.ruby-2.0 +1 -2
- data/test/gemfiles/Gemfile.ruby-2.0.lock +40 -0
- data/test/inheritance_test.rb +1 -1
- data/test/inspect_test.rb +43 -0
- data/test/introspect_test.rb +50 -0
- data/test/macro_test.rb +61 -0
- data/test/operation_test.rb +94 -0
- data/test/result_test.rb +14 -8
- data/test/ruby-2.0.0/operation_test.rb +73 -0
- data/test/ruby-2.0.0/step_test.rb +136 -0
- data/test/skill_test.rb +66 -48
- data/test/step_test.rb +228 -0
- data/test/task_wrap_test.rb +91 -0
- data/test/test_helper.rb +37 -0
- data/test/trace_test.rb +62 -0
- data/test/variable_mapping_test.rb +66 -0
- data/test/wire_test.rb +113 -0
- data/test/wiring/defaults_test.rb +197 -0
- data/test/wiring/subprocess_test.rb +70 -0
- data/trailblazer-operation.gemspec +3 -5
- metadata +62 -36
- data/lib/trailblazer/operation/1.9.3/option.rb +0 -36
- data/lib/trailblazer/operation/generic.rb +0 -12
- data/lib/trailblazer/operation/option.rb +0 -54
- data/lib/trailblazer/operation/pipetree.rb +0 -142
- data/lib/trailblazer/skill.rb +0 -70
- data/test/2.0.0-pipetree_test.rb +0 -100
- data/test/2.1.0-pipetree_test.rb +0 -100
- data/test/operation_skill_test.rb +0 -89
- data/test/pipetree_test.rb +0 -185
@@ -0,0 +1,13 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Operation::Railway
|
3
|
+
def self.fail! ; Activity::Left end
|
4
|
+
def self.pass! ; Activity::Right end
|
5
|
+
def self.fail_fast!; Activity::Magnetic::Builder::FastTrack::FailFast end
|
6
|
+
def self.pass_fast!; Activity::Magnetic::Builder::FastTrack::PassFast end
|
7
|
+
|
8
|
+
module End
|
9
|
+
FailFast = Class.new(Operation::Railway::End::Failure)
|
10
|
+
PassFast = Class.new(Operation::Railway::End::Success)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Operation::Railway
|
3
|
+
# The {Normalizer} is called for every DSL call (step/pass/fail etc.) and normalizes/defaults
|
4
|
+
# the user options, such as setting `:id`, connecting the task's outputs or wrapping the user's
|
5
|
+
# task via {TaskBuilder} in order to translate true/false to `Right` or `Left`.
|
6
|
+
#
|
7
|
+
# The Normalizer sits in the `@builder`, which receives all DSL calls from the Operation subclass.
|
8
|
+
module Normalizer
|
9
|
+
def self.call(task, options, unknown_options, sequence_options)
|
10
|
+
wrapped_task, options =
|
11
|
+
if task.is_a?(::Hash) # macro.
|
12
|
+
[
|
13
|
+
task[:task],
|
14
|
+
task.merge(options) # Note that the user options are merged over the macro options.
|
15
|
+
]
|
16
|
+
elsif task.is_a?(Array) # TODO remove in 2.2
|
17
|
+
Operation::DeprecatedMacro.( *task )
|
18
|
+
else # user step
|
19
|
+
[
|
20
|
+
TaskBuilder.(task),
|
21
|
+
{ id: task }.merge(options) # default :id
|
22
|
+
]
|
23
|
+
end
|
24
|
+
|
25
|
+
options, unknown_options = deprecate_name(options, unknown_options) # TODO remove in 2.2
|
26
|
+
|
27
|
+
raise "No :id given for #{wrapped_task}" unless options[:id]
|
28
|
+
|
29
|
+
options = defaultize(task, options) # :plus_poles
|
30
|
+
|
31
|
+
|
32
|
+
options, locals, sequence_options = override(task, options, sequence_options) # :override
|
33
|
+
|
34
|
+
return wrapped_task, options, unknown_options, sequence_options
|
35
|
+
end
|
36
|
+
|
37
|
+
# Merge user options over defaults.
|
38
|
+
def self.defaultize(task, options)
|
39
|
+
{
|
40
|
+
plus_poles: InitialPlusPoles(),
|
41
|
+
}.merge(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Handle the :override option which is specific to Operation.
|
45
|
+
def self.override(task, options, sequence_options)
|
46
|
+
options, locals = Activity::Magnetic::Builder.normalize(options, [:override])
|
47
|
+
sequence_options = sequence_options.merge( replace: options[:id] ) if locals[:override]
|
48
|
+
|
49
|
+
return options, locals, sequence_options
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.InitialPlusPoles
|
53
|
+
Activity::Magnetic::DSL::PlusPoles.new.merge(
|
54
|
+
Activity.Output(Activity::Right, :success) => nil,
|
55
|
+
Activity.Output(Activity::Left, :failure) => nil,
|
56
|
+
)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.deprecate_name(options, unknown_options) # TODO remove in 2.2
|
60
|
+
unknown_options, deprecated_options = Activity::Magnetic::Builder.normalize(unknown_options, [:name])
|
61
|
+
|
62
|
+
options = options.merge( name: deprecated_options[:name] ) if deprecated_options[:name]
|
63
|
+
|
64
|
+
options, locals = Activity::Magnetic::Builder.normalize(options, [:name])
|
65
|
+
if locals[:name]
|
66
|
+
warn "[Trailblazer] The :name option for #step, #success and #failure has been renamed to :id."
|
67
|
+
options = options.merge(id: locals[:name])
|
68
|
+
end
|
69
|
+
return options, unknown_options
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Operation::Railway
|
3
|
+
# every step is wrapped by this proc/decider. this is executed in the circuit as the actual task.
|
4
|
+
# Step calls step.(options, **options, flow_options)
|
5
|
+
# Output direction binary: true=>Right, false=>Left.
|
6
|
+
# Passes through all subclasses of Direction.~~~~~~~~~~~~~~~~~
|
7
|
+
module TaskBuilder
|
8
|
+
class Task < Proc
|
9
|
+
def initialize(source_location, &block)
|
10
|
+
@source_location = source_location
|
11
|
+
super &block
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
"<Railway::Task{#{@source_location}}>"
|
16
|
+
end
|
17
|
+
|
18
|
+
def inspect
|
19
|
+
to_s
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: make this class replaceable so @Mensfeld gets his own call style. :trollface:
|
24
|
+
|
25
|
+
def self.call(step, on_true=Activity::Right, on_false=Activity::Left)
|
26
|
+
Task.new step, &->( (options, *args), **circuit_args ) do
|
27
|
+
# Execute the user step with TRB's kw args.
|
28
|
+
result = Trailblazer::Option::KW(step).(options, **circuit_args) # circuit_args contains :exec_context.
|
29
|
+
|
30
|
+
# Return an appropriate signal which direction to go next.
|
31
|
+
direction = binary_direction_for(result, on_true, on_false)
|
32
|
+
|
33
|
+
[ direction, [ options, *args ], **circuit_args ]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Translates the return value of the user step into a valid signal.
|
38
|
+
# Note that it passes through subclasses of {Signal}.
|
39
|
+
def self.binary_direction_for(result, on_true, on_false)
|
40
|
+
result.is_a?(Class) && result < Activity::Signal ? result : (result ? on_true : on_false)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
class Trailblazer::Operation
|
2
2
|
class Result
|
3
|
+
# @param success Boolean validity of the result object
|
4
|
+
# @param data Context
|
3
5
|
def initialize(success, data)
|
4
|
-
@success, @data = success, data
|
6
|
+
@success, @data = success, data
|
5
7
|
end
|
6
8
|
|
7
|
-
extend Forwardable
|
8
|
-
def_delegators :@data, :[] # DISCUSS: make it a real delegator? see Nested.
|
9
|
-
|
10
9
|
def success?
|
11
10
|
@success
|
12
11
|
end
|
@@ -15,6 +14,9 @@ class Trailblazer::Operation
|
|
15
14
|
! success?
|
16
15
|
end
|
17
16
|
|
17
|
+
extend Forwardable
|
18
|
+
def_delegators :@data, :[] # DISCUSS: make it a real delegator? see Nested.
|
19
|
+
|
18
20
|
# DISCUSS: the two methods below are more for testing.
|
19
21
|
def inspect(*slices)
|
20
22
|
return "<Result:#{success?} #{slice(*slices).inspect} >" if slices.any?
|
@@ -1,11 +1,4 @@
|
|
1
|
-
|
2
|
-
# Dependency ("skill") management for Operation.
|
3
|
-
# Op::[]
|
4
|
-
# Op::[]=
|
5
|
-
# Writing, even with an existing name, will never mutate a container.
|
6
|
-
# Op#[]
|
7
|
-
# Op#[]=
|
8
|
-
# Op.(params, { "constructor" => competences })
|
1
|
+
# Dependencies can be defined on the operation. class level
|
9
2
|
class Trailblazer::Operation
|
10
3
|
module Skill
|
11
4
|
# The class-level skill container: Operation::[], ::[]=.
|
@@ -18,24 +11,15 @@ class Trailblazer::Operation
|
|
18
11
|
extend Forwardable
|
19
12
|
def_delegators :skills, :[], :[]=
|
20
13
|
end
|
14
|
+
end
|
21
15
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
alias :_call :call
|
16
|
+
# The use of this module is not encouraged and it is only here for backward-compatibility.
|
17
|
+
# Instead, please pass dependencies via containers, locals, or macros into the respective steps.
|
18
|
+
module ClassDependencies
|
19
|
+
def __call__( (ctx, flow_options), **circuit_options )
|
20
|
+
@skills.each { |name, value| ctx[name] ||= value } # this resembles the behavior in 2.0. we didn't say we liked it.
|
29
21
|
|
30
|
-
|
31
|
-
# two different implementations of ::call.
|
32
|
-
# FIXME: that shouldn't be here in this namespace.
|
33
|
-
module Positional
|
34
|
-
def call(params={}, options={}, *dependencies)
|
35
|
-
super(options.merge("params" => params), *dependencies)
|
36
|
-
end
|
37
|
-
end
|
22
|
+
super
|
38
23
|
end
|
39
|
-
|
40
24
|
end
|
41
25
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Operation::Railway
|
3
|
+
module TaskWrap
|
4
|
+
def self.included(includer)
|
5
|
+
includer.extend ClassMethods # ::__call__, ::inititalize_task_wraps!
|
6
|
+
includer.extend DSL
|
7
|
+
|
8
|
+
includer.initialize_task_wraps!
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def initialize_task_wraps!
|
13
|
+
heritage.record :initialize_task_wraps!
|
14
|
+
|
15
|
+
# The map of task_wrap per step/task. Note that it defaults to Wrap.initial_activity.
|
16
|
+
# This gets extended at compile-time for particular tasks as the steps are created via the DSL.
|
17
|
+
self["__static_task_wraps__"] = ::Hash.new(Activity::Wrap.initial_activity)
|
18
|
+
end
|
19
|
+
|
20
|
+
# __call__ prepares `flow_options` and `static_wraps` for {TaskWrap::Runner}.
|
21
|
+
def __call__(args, **circuit_args)
|
22
|
+
args, _circuit_args = TaskWrap.arguments_for_call(self, args, **circuit_args)
|
23
|
+
|
24
|
+
super( args, circuit_args.merge(_circuit_args) ) # Railway::__call__
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.arguments_for_call(operation, (options, flow_options), **circuit_args)
|
29
|
+
wrap_static = operation["__static_task_wraps__"]
|
30
|
+
|
31
|
+
circuit_args = {
|
32
|
+
runner: Activity::Wrap::Runner,
|
33
|
+
# FIXME: this sucks, why do we even need to pass an empty runtime there?
|
34
|
+
wrap_runtime: circuit_args[:wrap_runtime] || ::Hash.new([]), # FIXME:this sucks. (was:) this overwrites wrap_runtime from outside.
|
35
|
+
wrap_static: wrap_static,
|
36
|
+
}
|
37
|
+
|
38
|
+
return [ options, flow_options ], circuit_args
|
39
|
+
end
|
40
|
+
|
41
|
+
module DSL
|
42
|
+
# TODO: this override is hard to follow, we should have a pipeline circuit in DSL to add behavior.
|
43
|
+
# @private
|
44
|
+
def _task(*args)
|
45
|
+
returned = super # TODO: do this with a circuit :)
|
46
|
+
adds, (task, local_options) = returned
|
47
|
+
|
48
|
+
runner_options = local_options[:runner_options]
|
49
|
+
|
50
|
+
runner_options and apply_adds_from_runner_options!( task, runner_options )
|
51
|
+
|
52
|
+
returned
|
53
|
+
end
|
54
|
+
|
55
|
+
# Extend the static wrap for a specific task, at compile time.
|
56
|
+
def apply_adds_from_runner_options!(task, merge:raise, **ignored)
|
57
|
+
static_wrap = self["__static_task_wraps__"][task]
|
58
|
+
|
59
|
+
# macro might want to apply changes to the static task_wrap (e.g. Inject)
|
60
|
+
self["__static_task_wraps__"][task] = Activity::Magnetic::Builder.merge( static_wrap, merge )
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end # TaskWrap
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# |-- Railway::Call "insert.exec_context"
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
class Operation
|
3
|
+
module Trace
|
4
|
+
def self.call(operation, *args)
|
5
|
+
ctx = PublicCall.send(:options_for_public_call, *args)
|
6
|
+
|
7
|
+
# let Activity::Trace::call handle all parameters, just make sure it calls Operation.__call__
|
8
|
+
call_block = ->(operation, *args) { operation.__call__(*args) }
|
9
|
+
|
10
|
+
stack, direction, options, flow_options = Activity::Trace.(
|
11
|
+
operation,
|
12
|
+
ctx,
|
13
|
+
&call_block # instructs Trace to use __call__.
|
14
|
+
)
|
15
|
+
|
16
|
+
result = Railway::Result(direction, options)
|
17
|
+
|
18
|
+
Result.new(result, stack)
|
19
|
+
end
|
20
|
+
|
21
|
+
# `Operation::trace` is included for simple tracing of the flow.
|
22
|
+
# It simply forwards all arguments to `Trace.call`.
|
23
|
+
#
|
24
|
+
# @public
|
25
|
+
#
|
26
|
+
# Operation.trace(params, "current_user" => current_user).wtf
|
27
|
+
def trace(*args)
|
28
|
+
Trace.(self, *args)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Presentation of the traced stack via the returned result object.
|
32
|
+
# This object is wrapped around the original result in {Trace.call}.
|
33
|
+
class Result < SimpleDelegator
|
34
|
+
def initialize(result, stack)
|
35
|
+
super(result)
|
36
|
+
@stack = stack
|
37
|
+
end
|
38
|
+
|
39
|
+
def wtf
|
40
|
+
Activity::Trace::Present.tree(@stack)
|
41
|
+
end
|
42
|
+
|
43
|
+
def wtf?
|
44
|
+
puts wtf
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
class Trailblazer::Activity
|
2
|
+
module Wrap
|
3
|
+
# TaskWrap step to compute the incoming {Context} for the wrapped task.
|
4
|
+
# This allows renaming, filtering, hiding, of the options passed into the wrapped task.
|
5
|
+
#
|
6
|
+
# Both Input and Output are typically to be added before and after task_wrap.call_task.
|
7
|
+
#
|
8
|
+
# @note Assumption: we always have :input _and_ :output, where :input produces a Context and :output decomposes it.
|
9
|
+
class Input
|
10
|
+
def initialize(filter)
|
11
|
+
@filter = Trailblazer::Option(filter)
|
12
|
+
end
|
13
|
+
|
14
|
+
# `original_args` are the actual args passed to the wrapped task: [ [options, ..], circuit_options ]
|
15
|
+
#
|
16
|
+
def call( (wrap_ctx, original_args), **circuit_options )
|
17
|
+
# let user compute new ctx for the wrapped task.
|
18
|
+
input_ctx = apply_filter(*original_args) # FIXME: THIS SHOULD ALWAYS BE A _NEW_ Context.
|
19
|
+
# TODO: make this unnecessary.
|
20
|
+
# wrap user's hash in Context if it's not one, already (in case user used options.merge).
|
21
|
+
# DISCUSS: should we restrict user to .merge and options.Context?
|
22
|
+
input_ctx = Trailblazer.Context(input_ctx) if !input_ctx.instance_of?(Trailblazer::Context) || input_ctx==original_args[0][0]
|
23
|
+
|
24
|
+
wrap_ctx = wrap_ctx.merge( vm_original_args: original_args )
|
25
|
+
|
26
|
+
# decompose the original_args since we want to modify them.
|
27
|
+
(original_ctx, original_flow_options), original_circuit_options = original_args
|
28
|
+
|
29
|
+
# instead of the original Context, pass on the filtered `input_ctx` in the wrap.
|
30
|
+
return Trailblazer::Activity::Right, [ wrap_ctx, [[input_ctx, original_flow_options], original_circuit_options] ]
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def apply_filter((original_ctx, original_flow_options), original_circuit_options)
|
36
|
+
@filter.( original_ctx, **original_circuit_options )
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# TaskWrap step to compute the outgoing {Context} from the wrapped task.
|
41
|
+
# This allows renaming, filtering, hiding, of the options returned from the wrapped task.
|
42
|
+
class Output
|
43
|
+
def initialize(filter, strategy=CopyMutableToOriginal)
|
44
|
+
@filter = Trailblazer::Option(filter)
|
45
|
+
@strategy = strategy
|
46
|
+
end
|
47
|
+
|
48
|
+
# Runs the user filter and replaces the ctx in `wrap_ctx[:result_args]` with the filtered one.
|
49
|
+
def call( (wrap_ctx, original_args), **circuit_options )
|
50
|
+
(original_ctx, original_flow_options), original_circuit_options = original_args
|
51
|
+
|
52
|
+
returned_ctx, _ = wrap_ctx[:result_args] # this is the Context returned from `call`ing the task.
|
53
|
+
|
54
|
+
# returned_ctx is the Context object from the nested operation. In <=2.1, this might be a completely different one
|
55
|
+
# than "ours" we created in Input. We now need to compile a list of all added values. This is time-intensive and should
|
56
|
+
# be optimized by removing as many Context creations as possible (e.g. the one adding self[] stuff in Operation.__call__).
|
57
|
+
_, mutable_data = returned_ctx.decompose # DISCUSS: this is a weak assumption. What if the task returns a deeply nested Context?
|
58
|
+
|
59
|
+
# let user compute the output.
|
60
|
+
output = apply_filter(mutable_data, original_flow_options, original_circuit_options)
|
61
|
+
|
62
|
+
original_ctx = wrap_ctx[:vm_original_args][0][0]
|
63
|
+
|
64
|
+
new_ctx = @strategy.( original_ctx, output ) # here, we compute the "new" options {Context}.
|
65
|
+
|
66
|
+
wrap_ctx = wrap_ctx.merge( result_args: [new_ctx, original_flow_options] )
|
67
|
+
|
68
|
+
# and then pass on the "new" context.
|
69
|
+
return Trailblazer::Activity::Right, [ wrap_ctx, original_args ]
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# @note API not stable
|
75
|
+
def apply_filter(mutable_data, original_flow_options, original_circuit_options)
|
76
|
+
@filter.(mutable_data, **original_circuit_options)
|
77
|
+
end
|
78
|
+
|
79
|
+
# "merge" Strategy
|
80
|
+
module CopyMutableToOriginal
|
81
|
+
# @param original Context
|
82
|
+
# @param options Context The object returned from a (nested) {Activity}.
|
83
|
+
def self.call(original, mutable)
|
84
|
+
mutable.each { |k,v| original[k] = v }
|
85
|
+
|
86
|
+
original
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end # Wrap
|
91
|
+
end
|
data/test/call_test.rb
CHANGED
@@ -1,28 +1,47 @@
|
|
1
1
|
require "test_helper"
|
2
2
|
|
3
|
-
# DISCUSS: do we need this test?
|
4
3
|
class CallTest < Minitest::Spec
|
5
4
|
describe "::call" do
|
6
5
|
class Create < Trailblazer::Operation
|
6
|
+
step ->(*) { true }
|
7
7
|
def inspect
|
8
8
|
"#{@skills.inspect}"
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
it { Create.().must_be_instance_of Trailblazer::Operation::Result }
|
12
|
+
it { Create.().must_be_instance_of Trailblazer::Operation::Railway::Result }
|
13
13
|
|
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]}> >} }
|
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]}> >} }
|
17
17
|
|
18
18
|
#---
|
19
19
|
# success?
|
20
20
|
class Update < Trailblazer::Operation
|
21
|
-
step ->(options) { options[
|
21
|
+
step ->(options, **) { options[:result] }
|
22
|
+
end
|
23
|
+
|
24
|
+
# operation success
|
25
|
+
it do
|
26
|
+
result = Update.(result: true)
|
27
|
+
|
28
|
+
result.success?.must_equal true
|
29
|
+
|
30
|
+
result.event.must_be_instance_of Trailblazer::Operation::Railway::End::Success
|
31
|
+
result.event.must_equal Update.outputs[:success].signal
|
32
|
+
end
|
33
|
+
|
34
|
+
# operation failure
|
35
|
+
it do
|
36
|
+
result = Update.(result: false)
|
37
|
+
|
38
|
+
result.success?.must_equal false
|
39
|
+
result.failure?.must_equal true
|
40
|
+
|
41
|
+
result.event.must_be_instance_of Trailblazer::Operation::Railway::End::Failure
|
42
|
+
result.event.must_equal Update.outputs[:failure].signal
|
22
43
|
end
|
23
44
|
|
24
|
-
it { Update.(true).success?.must_equal true }
|
25
|
-
it { Update.(false).success?.must_equal false }
|
26
45
|
end
|
27
46
|
end
|
28
47
|
|