It's an object with very simple API based on its state like SimpleCommand:
.success?
.failure?
o = MyCommand.call(:a)
o.success? # => true
o.failure? # => false
o.result # => :a
Using Result::Command as an atomiq object. We can easily implement Monad Result with Result::Command and used it like a container:
Success[:a]
# => #<Success @content=:a, @called=true, @result=:a>
Success[:a].success? # => true
Success[:a].failure? # => false
Success[:a].result # => :a
Failure[:b]
# => #<Failure @content=:b, @called=true, @result=nil>
Failure[:b].success? # => false
Failure[:b].failure? # => true
Failure[:b].result # => :b
Result::Failure[42].with_errors(
Result::Errors.build(
source: 'test',
details: { base: ['something went wrong'] }
)
)
# => #<Result::Failure
# @content=42,
# @called=true,
# @errors=#<Result::Errors @source="test", @errors={ base: ['something went wrong'] }>,
# @result=42>
Chainable add some chainable methods;
then
(or alias|
)
Result::Params[:h] | MyCommande | MySecondCommande
=> #<MaSecondCommande @params="h", @called=true, @result="hello">
Result::Params[:h] | MyCommande | MyFaildCommand | MySecondCommande
=> #<MyFaildCommand @content="h", @called=true, @result="h">
with lambda
Result::Params[:hello].
then(->(input) { Result::Success[input.to_s] }).
then(->(input) { Result::Success[input + ' world'] })
=> #<Result::Success @content="hello world", @called=true, @result="hello world">
Result::Params[{ user: { first_name: 'John', last_name: 'Dow' } }]
.then(
lambda { |input|
response = MyClientApi.post('/users', payload: input)
if response.status == :ok
Result::Success[response.body]
else
Result::Failure[input].with_errors(
Result::Errors.build(source: self, errors: response.body)
)
end
}
)
.then(CreateUserLocaly)
wrap result after running call method
cmd = MyCommand.call(args)
cmd.success? # => true | false
cmd.failure? # => true | false
use block and callback
on_success
yield Errors instanceon_failure
yieldresult
MyCommand.call(args) do |cmd|
cmd.on_success do |result|
# do something
end
cmd.on_failure do |errors|
# or do something else
end
end
because chain of commands return Command instance, we can use callback :)
when_succeed = ->(result) { # do something with result }
when_fail = ->(errors) { # do something with error }
(Result::Params[:h] | MyCommande | MyFaildCommand | MySecondCommande).
on_failure(&when_fail).
on_success(&when_succeed)
or wrap by an other command
class WrapCommands
prepend Result::Command
def initialize(input)
@input = input
end
def call
Params[@input].
then(MyCommande).
then(MyFaildCommand).
then(MySecondCommande).
on_failure(&when_failed).
on_success(&when_succeed)
end
def when_succeed(result)
# do something with result
end
def when_failed(errors)
# do something with error
errors.merge(errors)
end
end