Skip to content

Instantly share code, notes, and snippets.

@stefanoc
Last active May 17, 2016 00:53
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stefanoc/b4a9ab4c9516123d6bd7 to your computer and use it in GitHub Desktop.
Save stefanoc/b4a9ab4c9516123d6bd7 to your computer and use it in GitHub Desktop.
class Option
private def initialize(value)
@value = value
end
def self.Some(value)
new(value)
end
None = new(nil)
def to_s
case @value
when nil then "None"
else "Some(#{@value})"
end
end
def some?
@value != nil
end
def none?
@value == nil
end
def unwrap
some? ? @value : fail("Panic")
end
def map
some? ? Maybe(yield @value) : None
end
def map_or(default)
some? ? yield(@value) : default
end
def unwrap_or(default)
some? ? @value : default
end
def unwrap_or_else
some? ? @value : yield
end
def ok_or(err)
some? ? Result::Ok(@value) : Result::Err(err)
end
def ok_or_else
some? ? Result::Ok(@value) : Capture { yield }
end
def and(optb)
some? ? Maybe(optb) : None
end
def and_then
some? ? Maybe(yield @value) : None
end
def or(optb)
some? ? self : Maybe(optb)
end
def or_else
some? ? self : Maybe(yield @value)
end
end
class Result
private def initialize(value, err)
@value = value
@err = err
end
def self.Ok(value)
new(value, nil)
end
def self.Err(err)
new(nil, err)
end
def to_s
if @err
"Err(#{@err})"
else
"Ok(#{@value})"
end
end
def ok?
!!@value
end
def err?
!!@err
end
def ok
ok? ? Option::Some(@value) : Option::None
end
def err
ok? ? Option::None : Option::Some(@err)
end
def map
ok? ? Capture { yield(@value) } : self
end
alias and_then map
def map_err
ok? ? self : capture_err { yield(@err) }
end
alias or_else map_err
def and(res)
ok? ? Capture { res } : self
end
alias & and
def or(res)
ok? ? self : Capture { res }
end
alias | or
def unwrap
ok? ? @value : fail("Panic")
end
def unwrap_or(optb)
ok? ? @value : optb
end
def unwrap_or_else
ok? ? @value : yield(@err)
end
def expect(msg)
ok? ? @value : fail(msg)
end
def unwrap_err
ok? ? fail("Panic") : @err
end
private
def capture_err(&block)
Err(block.call)
rescue => e
Err(e)
end
end
def Maybe(value)
case value
when Option then value
when nil then Option::None
else Option::Some(value)
end
end
def Result(value)
case value
when Result then value
when StandardError then Result::Err(value)
else Result::Ok(value)
end
end
def Capture
Result(yield)
rescue => e
Result::Err(e)
end
def Ok(_); Result::Ok(_) end
def Err(_); Result::Err(_) end
def Some(_); Option::Some(_) end
None = Option::None
# Examples
def read_line #-> Result<Option<String>, _>
Capture { Maybe(STDIN.gets) }
end
# @value Option<String>
def strip_line(value) #-> Option<String>
value.and_then { |line| line.chomp }
end
# @str Option<String>
def reverse_it(str) #-> Result<String, _>
Capture { str.and_then(&:reverse) }
end
# @str Option<String>
def capitalize_it(str) #-> Option<String, _>
str.and_then(&:capitalize)
end
puts read_line
.map { |v| strip_line(v) }
.map { |v| reverse_it(v) }
.map { |v| capitalize_it(v) }
#=> Ok(C)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment