So there is this dry-rb/dry-monads library that has lots of goodies. One that is really useful for mutations is the Result monad, which has two subclasses Success and Failure.
I propose (and I can actually provide the PR) to replace Outcome with subclasses of Success and Failure, provided that:
[x] They already respond to #success?.
[ ] Mutations::Success should alias success to result (with no arguments)
[ ] Mutations::Failure should alias failure to errors
[ ] Both Mutations::Success and Mutations::Failure should include a phony module Mutations::Outcome - so .is_a? and === will still work.
With the previous additions, they are completely backwards-compatible, and it would be some 50 LOC.
Having Outcomes based on monads adds this optional behavior (the first one was asked in #102):
# result method with two args, provided by Dry::Monads::Result
outcome.result(
->(error) { puts "Error: #{error.inspect}" },
->(result) { puts "Result: #{result.inspect}" }
)
# `bind`, `fmap` and `or` chain other code or return the receiver, depending on success:
# bind returns the result of the block - for instance another outcome, or something else
successful_outcome.bind { |result| 1 }
# => 1
failed_outcome.bind { |result| 1 }
# => failed_outcome
# fmap wraps the result inside the same type
successful_outcome.fmap { |result| 1 }
# => Outcome::Success<value=1>
failed_outcome.fmap { |result| 1 }
# => failed_outcome
# `or` chain other code provided it's a failure:
successful_outcome.or { |result| 1 }
# => successful_outcome
failed_outcome.or { |result| 1 }
# => 1
# `or_fmap` chain other code provided it's a failure, and wraps in a success:
successful_outcome.or_fmap { |result| 1 }
# => successful_outcome
failed_outcome.or_fmap { |result| 1 }
# => Outcome::Success<value=1>
plus many more:
value_or returns the result on success, executes the block on failure
flip flips between success and failure
All these methods accept any object responding to call instead of a block, plus any number of additional arguments that would be appended to the block/callable.
If Mutation::Command subclasses could additionally respond to call (by aliasing it to run), they would allow constructs like:
So there is this dry-rb/dry-monads library that has lots of goodies. One that is really useful for mutations is the Result monad, which has two subclasses
Success
andFailure
.I propose (and I can actually provide the PR) to replace Outcome with subclasses of Success and Failure, provided that:
#success?
.success
toresult
(with no arguments)failure
toerrors
.is_a?
and===
will still work.With the previous additions, they are completely backwards-compatible, and it would be some 50 LOC.
Having Outcomes based on monads adds this optional behavior (the first one was asked in #102):
plus many more:
value_or
returns the result on success, executes the block on failureflip
flips between success and failurecall
instead of a block, plus any number of additional arguments that would be appended to the block/callable.If Mutation::Command subclasses could additionally respond to
call
(by aliasing it torun
), they would allow constructs like:All without breaking current code depending on
run
,run!
andOutcome
.