option.rb is an attempt to duplicate the functionality of Scala's Option class in Ruby
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Because nil stinks and I'm tired of NoMethodError: undefined method '[]' for nil:NilClass


An Option is either the singleton None or an instance of Some:

s = Some(1)
s == Some(1) # true
s != None    # true

Both None and instances of Some have the standard collection methods (including filter, for those of you who agree with me that select is a stupid name):

s.each {|i| i + 1}   # 2
s.map {|i| i + 1}    # Some(2)
s.filter {|i| i > 1} # None

To get the raw values:

s.get # 1
s.each {|i| i} # 1
None.get # RuntimeError: None has no value

Because of this, it's best to give a default:

s.getOrElse(2)    # 1
None.getOrElse(2) # 2

Blocks are supported for lazy loading the default:

s.getOrElse {|| slow_calculation} # 1, slow_calculation is never done
None.getOrElse {|| slow_calculation} # result of slow_calculation

The Option() method is a good way to get an Option. Any value is converted to Some(value), while nil is converted to None:

result      = Option(some_method_that_might_return_nil("something"))
transformed = result.filter{|i| i > 2}.map{|i| i.to_s}
puts filtered.getOrElse("default")

If nil is bad, so are exceptions. Eat them with tryo:

result      = tryo {|| raise "silly error" }
transformed = result.filter{|i| i > 2}.map{|i| i.to_s}
puts filtered.getOrElse("default") # will be "default"

If you start using lots of Options you might want to flatten them with flatMap:

s.map {|id| get_user_from_db(id) }      # Some(Some(User #1 ...))
s.flatMap {|id| get_user_from_db(id) }  # Some(User #1 ...)

The block passed to flatMap must return an Option:

id = Some("unknown id")
id.flatMap {|id| get_user_from_db(id) } # None
id.flatMap {|id| id}                    # RuntimeError: Did not return an Option