Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
185 lines (115 sloc) 6.02 KB



Nothing.to_json yields nil


Nothing works with ===


Add #__fetch__ to Maybe().proxy to get the wrapped value.



Rename Either#else to Either#or to be consistent with Maybe Using Either#else will give you a deprecation warning for now, it will be removed in v1.0

New Validation#fill method for validating filling Structs.

ExampleStruct =, :b)
module ExampleValidator
  extend self
  def a(params); Try { params[0] }.or 'a cannot be empty'; end
  def b(params); Try { params[1] }.or 'b cannot be empty'; end

result = Validation.fill(ExampleStruct, [1, 2], ExampleValidator)         == Sucess
example = result.fetch
example.a  == 1
example.b  == 2


Extend Try to also support lambdas.

The first parameter of Try can be used as a predicate and the block as formatter

Try(true)                              == Success(true)
Try(false) { "string" }                == Failure("string")
Try(false) { "success" }.else("fail")  == Failure("fail")

Maybe supports #proxy to avoid naming clashes between the underlying value and Maybe itself.

Maybe({a: 1}).proxy.fetch(:a)          == Maybe(1)
# this is in effect syntactic sugar for
Maybe({a: 1}).map {|e| e.fetch(:a) }

Nothing#or coerces the or value into a Maybe, thus

Maybe(nil).or(1)          == Just(1)
Maybe(nil).or(nil)        == Nothing

Either coerces now Just and Nothing into Success and Failure

Either(       == Success(1)
Either(Nothing)           == Failure(Nothing)


Add the Try helper which works similar to Either, but takes a block

Try { Date.parse('2012-02-30') }       == Failure
Try { Date.parse('2012-02-28') }       == Success

Either else now supports also a block

Failure(1).else {|other| 1 + 2 }       == Failure(3)


#or returns for Nothing an alternative

Maybe(nil).or(1)          == 1
Maybe(1).or(2)            == 1


BREAKING CHANGES #to_s returns the inner value converted to string


Nothing has no method #name ... will need to use BasicObject



Monad#map does not recognize Enumerables automatically anymore. It just maps, as a Functor.
Instead the new Monad#flat_map function operates on the underlying value as on Enumerable.

Either#else allows to exchange the inner value of Nothing to an alternative value.

Either(false == true).else('false was not true')          == Failure(false was not true)
Success('truth needs no sugar coating').or('all lies')  == Success('truth needs no sugar coating')


Either() coerces only StandardError to Failure, other exceptions higher in the hierarchy are will break the flow.
Thanks to @pithyless for the suggestion.

Monad is now a Module instead of a Class as previously. This fits the Monad metaphor better. Each monad must now implement the unit method itself, which is the correct way to do anyway.


You can now chain Eithers with + without providing a block or a proc:

Success(1) + Failure(2)     == Failure(2)
Failure(1) + Failure(2)     == Failure(1)

All monads now have the #to_ary and #to_a method, which coerces the inner value into an Array.

I am considering the Api now almost stable, the only thing I am not so sure about, is whether to apply the magic coercion or not.

Validation() now returns the successfully validated values. See examples/validation.rb and examples/validation_module


Implements the #map method for all Monads. It works on value types and on Enumerable collections.
Provide a proc or a block and it will return a transformed value or collection boxed back in the monad.

Monad.unit('FOO').map(&:capitalize).map {|v| "Hello #{v}"}    == Monad(Hello Foo)

Add the Elvis operator _? - ruby does not allow ?: as operator and use it like the excellent andand

nil._?           == Nothing
"foo"._?         == 'foo'
{}._?.a.b        == Nothing
{}._?[:foo]      == Nothing


Contains Breaking Changes

Refactoring to use internal Monad class, from which all monads inherit.

Reimplemented Maybe as inherited class from Monad. The old Option implementation has been removed, maybe does the same though, but the code is much cleaner and obeys the 3 monadic laws.

Removed Maybe#fetch call with block`

Either and Validation are now in the Monadic namespace.

Added Travis-Ci integration, Build Status


Removed the #chain method alias for bind in Either.

Moar examples with instance variables in an Either.chain.

Add monadic Validation, which is a special application (an applicative functor) of the Either Monad e.g.

Validation() do
  check { check_age.(person.age);          }
  check { check_sobriety.(person.sobriety) }

It returns a Success([]) with an empty list, or a Failure([..]) with a list of all Failures.


To be more idiomatic rubyuesque, rename #value to #fetch, which throws now an NoValueError.
Thanks to @pithyless for the suggestion.

It now supports the Either monad, e.g.

either = Success(0).
  bind { Success(1) }.
  bind { Failure(2) }.
  bind { Success(3) }

either == Failure(2)      # the third bind is NOT executed  


Some#map and Some#select accept proc and block, you can now use:

Option("FOO").map(&:downcase)           # NEW
Option("FOO").map { |e| e.downcase }    # old
Option("FOO").downcase                  # old

Removed #none?, please use #empty? instead.

Some and None are now in the Monadic namespace, however they are aliased when requiring monadic

Jump to Line
Something went wrong with that request. Please try again.