-
Notifications
You must be signed in to change notification settings - Fork 0
Step logical types
Logic flow is based on different step logic types regardless of invocable type. All logic types share the same set of reserved logic options. And some of the logic types have their own set of technical options (e. g. Switch).
Each of logic types has those options:
faston_successon_failurename
This option defines when flow execution should be finished immediately and return execution results. By default this options is unset but you can set it for any step to one of those values: true, :success, :failure
If option is set to true regardless of step result flow execution will be finished. Result of the step will be used to determine service is succeeded or failed
Example:
class Service < Yaso::Service
step :one
step :two, fast: true
# Flow execution will be finished on step "two" and never reaches steps "three" and "four"
step :three
failure :four
endIf option is set to :success flow execution will be finished only if step succeeds so service will succeed too.
Example:
class Service < Yaso::Service
step :one
step :two, fast: :success
# Flow execution will be finished on step "two" if "two" succeeds
# otherwise execution will be directed to failure "four"
# so step "three" is unreachable in this case
step :three
failure :four
endIf option is set to :failure flow execution will be finished only if step fails so service will fail too.
Example:
class Service < Yaso::Service
step :one
step :two, fast: :failure
# Flow execution will be finished on step "two" if "two" fails
# otherwise execution will be directed to step "three"
# but note that if step "one" fails execution will be directed to failure "four"
step :three
failure :four
endThis option defines to which step flow execution should be directed if step succeeds. By default this options is unset and next step will be set by the flow automatically but you can set it for any step to any step name that your service have. Note that you can't direct execution to Wrap logic type inner step outside of Wrap instance and vice versa, more information in the Wrap section. If you want to direct flow execution to the step with callable or yaso invocable type then you could use logical name option
Example:
class Service < Yaso::Service
step :one
pass :two, on_success: :four
# If step "two" succeeds flow execution will jump to step "four" skipping step "three"
# but if step "two" fails flow execution will go by the default way (steps "three" -> "four")
step :three
step :four
endThis option defines to which step flow execution should be directed if step fails. By default this options is unset and next failure step will be set by the flow automatically but you can set it for any step to any step name that your service have. Note that you can't direct execution to Wrap logic type inner step outside of Wrap instance and vice versa, more information in the Wrap section. If you want to direct flow execution to the step with callable or yaso invocable type then you could use logical name option
Example:
class Service < Yaso::Service
step :one
step :two, on_failure: :four
# If step "two" fails flow execution will jump to step "four" skipping step "three"
# but if step "two" succeeds flow execution will go by the default way (steps "three" -> "four")
step :three
step :four
endThis option defines step name that could be referenced in other steps on_success and on_failure options. Note that this option could be applied only to callable and yaso invocable step types because for inline and method invocable types name is already defined in the step definition and custom name will be simply ignored.
class Service < Yaso::Service
step :one
step :two, on_failure: :four
# If step "two" fails flow execution will be directed to the step with name "four"
step :three
step CallableStep, name: :four
# so it will be directed to this step
endStep is a basic step logical type that invokes business logic and resolves step result by it. If invocable succeeds flow execution will be directed to next step and flow execution will be resolved as successful otherwise to the next failure and flow execution will be resolved as failed. Note that custom on_success and on_failure steps could point to any step logic type so if step fails and directs flow execution to the logic type Step context status will be reset to success.
Example:
class Service < Yaso::Service
step :one
step :two, on_failure: :four
# If step "two" fails flow execution will be directed to the step with name "four"
# bypassing step "three" and flow execution will be successful
step :three
step :four
endFailure is a logical type that invokes business logic and sets flow execution status to failure. Regardless of invokable result flow execution will be directed to the next failure step. Note that custom on_success and on_failure steps could point to any step logic type so if step directs flow execution to the logic type Failure context status will be reset to failure regardless of previous status.
Examples:
class Service < Yaso::Service
step :one
failure :two
# If step "one" fails flow execution will be directed to the failure with name "two"
# and will skip steps "three" and "four"
step :three
step :four
endWhen on_success points to failure
class Service < Yaso::Service
pass :one, on_success: :two
failure :two
# If step "one" succeeds flow execution will be directed to the failure with name "two",
# fail and skip steps "three" and "four" otherwise will skip failure "two" and go by default flow
step :three
step :four
endPass is a logical type that invokes business logic and sets flow execution status to success. Regardless of invokable result flow execution will be directed to the next step. Note that custom on_success and on_failure steps could point to any step logic type so if step directs flow execution to the logic type Pass context status will be reset to success regardless of previous status.
class Service < Yaso::Service
pass :one
step :two
# If step "one" fails flow execution will be directed to the step "two"
# regardless of invocable result
failure :three
step :four
endWrap is a logical type that invokes nested business logic by wrapping it into a block. Block returns true if steps succeed and false otherwise. Wrap result is resolved in the same way as for Step type. Consider Wrap as a nested service, steps inside the wrap doesn't know about steps outside of it and vice versa. Wrap could be either a method or a callable.
Examples:
Wrap can be a method:
class Service < Yaso::Service
wrap :one do
step :two
end
def one(ctx, **, &block)
# your code goes here...
block.call
# and here...
end
# or
def one(ctx, **)
# your code goes here...
yield
# and here...
end
endOr a callable:
class WrapHandler
def self.call(ctx, **options, &block)
# your code goes here...
block.call
# and here...
end
end
class Service < Yaso::Service
wrap WrapHandler do
step :two
end
endSwitch is a logical type that invokes one of the steps based on the provided cases. Consider it as a case/when statement or a Strategy pattern or any other smart name you identify it. Switch should return an invocable (callable class, yaso service class or method name as a symbol). Switch could be either a method, a callable or hidden. Note that error will be raised if switch returns non-invocable value.
Examples:
Switch as a hidden:
class Service < Yaso::Service
# It means that switch will do the job for you
# if you don't need additional logic and
# simply want to retrieve invocable from the cases
switch :one, key: :key_from_ctx, cases: {foo: :bar, bar: Foo}
def bar(ctx, **)
# your code goes here...
end
endSwitch as a method:
class Service < Yaso::Service
CASES = {foo_1: :foo_1, foo_2: FooTwo, bar_1: BarOne, bar_2: YasoBar}
switch :one
def one(ctx, **)
# The use-case is when you need additional logic
# to resolve which case to invoke
key = "#{ctx[:key_from_ctx]}-#{rand(1..2}" # just an example
CASES[key]
end
def foo_1(ctx, **)
# your code goes here...
end
endSwitch as a callable:
class SwitchHandler
CASES = {foo_1: :foo_1, foo_2: FooTwo, bar_1: BarOne, bar_2: YasoBar}
def self.call(ctx, **options)
# The use-case is when you need additional logic
# to resolve which case to invoke
key = "#{ctx[:key_from_ctx]}-#{rand(1..2}" # just an example
CASES[key]
end
end
class Service < Yaso::Service
switch SwitchHandler
def foo_1(ctx, **)
# your code goes here...
end
endPlease, if you find a mistake or have a suggestion according documentation feel free to open an issue and describe your thoughts there.