Releases: dry-rb/dry-monads
v1.6.0
v1.5.0
Changed
- Use zeitwerk for auto-loading dry-monads classes (@flash-gordon)
Task#then
is deprecated in favor ofTask#bind
(@flash-gordon)- Minimal Ruby version is now 2.7 (@flash-gordon)
- Either (old name of Result) was removed (@flash-gordon)
v1.4.0
Added
Unit
destructures to an empty array (flash-gordon)- When
.value!
called on aFailure
value the error references to the value (rewritten + flash-gordon)begin Failure("oops").value! rescue => error error.receiver # => Failure("oops") end
Result#alt_map
for mapping failure values (flash-gordon)Failure("oops").alt_map(&:upcase) # => Failure("OOPS")
Try#recover
recovers from errors (flash-gordon)error = Try { Hash.new.fetch(:missing) } error.recover(KeyError) { 'default' } # => Try::Value("default")
Maybe#filter
runs a predicate against the wrapped value. ReturnsNone
if the result is false (flash-gordon)Some(3).filter(&:odd?) # => Some(3) Some(3).filter(&:even?) # => None # no block given Some(3 == 5).filter # => None
RightBiased#|
is an alias for#or
(flash-gordon)None() | Some(6) | Some(7) # => Some(6) Failure() | Success("one") | Success("two") # => Success("one")
Fixed
- Do notation preserves method visibility (anicholson + flash-gordon)
Changed
- Coercing
nil
values toNone
withSome#fmap
is officially deprecated. (flash-gordon)
Switch toSome#maybe
when you expectnil
.
This behavior will be dropped in 2.0 but you can opt-out of warnings for the time beingDry::Monads::Maybe.warn_on_implicit_nil_coercion false
- Minimal Ruby version is 2.6
v1.3.5
v1.3.4
v1.3.4 2019-12-28
Fixed
- One more delegation warning happenning in do notation (flash-gordon)
v1.3.3
v1.3.3 2019-12-11
Fixed
- Incompatibility with Rails. Internal (!) halt exceptions now use mutable backtraces because spring mutates (!) them. For the record, this a bug in Rails (johnmaxwell)
v1.3.2
v1.3.2 2019-11-30
Fixed
- Warnings about keywords from Ruby 2.7 (flash-gordon)
Added
- Pattern matching syntax was improved by implementing
#deconstruct_keys
. Now curly braces aren't necessary when the wrapped value is a Hash (flash-gordon)case result in Success(code: 200...300) then :ok end
Internal
- Performance of do notation was improved for failing cases (1.2x to 1.3x on synthetic benchmarks) (flash-gordon)
v1.3.1
v1.3.0
v1.3.0 2019-08-03
BREAKING CHANGES
- Support for Ruby 2.3 was dropped.
Added
-
Result#either
(waiting-for-dev)Success(1).either(-> x { x + 1 }, -> x { x + 2 }) # => 2 Failure(1).either(-> x { x + 1 }, -> x { x + 2 }) # => 3
-
Maybe#to_result
(SpyMachine + flash-gordon)Some(3).to_result(:no_value) # => Success(3) None().to_result { :no_value } # => Failure(:no_value) None().to_result # => Failure()
-
Do notation can be used with
extend
. This simplifies usage in class methods and in other "complicated" cases (gogiel + flash-gordon)class CreateUser extend Dry::Monads::Do::Mixin extend Dry::Monads[:result] def self.run(params) self.call do values = bind Validator.validate(params) user = bind UserRepository.create(values) Success(user) end end end
Or you can bind values directly:
ma = Dry::Monads.Success(1) mb = Dry::Monads.Success(2) Dry::Monads::Do.() do a = Dry::Monads::Do.bind(ma) b = Dry::Monads::Do.bind(mb) Dry::Monads.Success(a + b) end
-
{Some,Success,Failure}#[]
shortcuts for building arrays wrapped within monadic value (flash-gordon)Success[1, 2] # => Success([1, 2])
-
List.unfold
yields a block returningMaybe<Any>
. If the block returnsSome(a)
a
is appended to the output list. ReturningNone
halts the unfloding (flash-gordon)List.unfold(0) do |x| if x > 5 None() else Some[x + 1, 2**x] end end # => List[1, 2, 3, 4, 5]
-
Experimental support for pattern matching! 🎉 (flash-gordon)
case value in Failure(_) then :failure in Success(10) then :ten in Success(100..500 => code) then code in Success() then :empty in Success(:code, x) then x in Success[:status, x] then x in Success({ status: x }) then x in Success({ code: 200..300 => x }) then x end
Read more about pattern matching in Ruby:
- https://medium.com/@baweaver/ruby-2-7-pattern-matching-destructuring-on-point-90f56aaf7b4e
- https://bugs.ruby-lang.org/issues/14912
Keep in mind this feature is experimental and can be changed by 2.7 release. But it rocks already!
v1.2.0
v1.2.0 2019-01-12
BREAKING CHANGES
- Support for Ruby 2.2 was dropped. Ruby 2.2 reached its EOL on March 31, 2018.
Added
-
Most of the constructors now have
call
alias so you can compose them with Procs nicely if you've switched to Ruby 2.6 (flash-gordon)pipe = -> x { x.upcase } >> Success pipe.('foo') # => Success('FOO')
-
List#collect
gathersSome
values from the list (flash-gordon)include Dry::Monads::List::Mixin include Dry::Monads::Maybe::Mixin # ... List[10, 5, 0].collect do |divisor| if divisor.zero? None() else Some(n / divisor) end end # => List[4, 2]
Without block:
List[Some(5), None(), Some(3)].collect.map { |x| x * 2 } # => [10, 6]
-
Right-biased monads got
#flatten
and#and
(falsh-gordon)#flatten
removes one level of monadic structure, it's useful when you're dealing with things likeMaybe
ofMaybe
of something:include Dry::Monads::Maybe::Mixin Some(Some(1)).flatten # => Some(1) Some(None()).flatten # => None None().flatten # => None
In contrast to
Array#flatten
, dry-monads' version removes only 1 level of nesting, that is always acts asArray#flatten(1)
:Some(Some(Some(1))).flatten # => Some(Some(1))
#and
is handy for combining two monadic values and working with them at once:include Dry::Monads::Maybe::Mixin # using block Some(5).and(Some(3)) { |x, y| x + y } # => Some(8) # without block Some(5).and(Some(3)) # => Some([5, 3]) # other cases Some(5).and(None()) # => None() None().and(Some(5)) # => None()
-
Concise imports with
Dry::Monads.[]
. You're no longer required to require all desired monads and include them one-by-one, the[]
method handles it for you (flash-gordon)require 'dry/monads' class CreateUser include Dry::Monads[:result, :do] def initialize(repo, send_email) @repo = repo @send_email = send_email end def call(name) if @repo.user_exist?(name) Failure(:user_exists) else user = yield @repo.add_user(name) yield @send_email.(user) Success(user) end end end
-
Task.failed
is a counterpart ofTask.pure
, accepts an exception and returns a failed task immediately (flash-gordon)