Last active
February 8, 2019 21:32
-
-
Save tylerjohnst/43b6592ab26c2fdb4a76f1ddbfc19a39 to your computer and use it in GitHub Desktop.
Don't do this in production, or do. I'm not your parent.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Maybe | |
attr_reader :value | |
# @returns [Maybe] | |
def self.empty | |
@empty ||= new(nil) | |
end | |
def initialize(value, &block) | |
@value = value.is_a?(Maybe) ? value.value : value | |
@value = MaybeBlock.maybe(self, &block) if block_given? | |
end | |
# Returns the inner value or a fallback. | |
def value_or(fallback) | |
value || fallback | |
end | |
def ==(other_value) | |
if other_value.is_a?(Maybe) | |
value == other_value.value | |
else | |
value == other_value | |
end | |
end | |
# @returns [Maybe] | |
def call(method_name, *args) | |
if value && value.respond_to?(method_name) | |
Maybe.new value.public_send(method_name, *args) | |
else | |
Maybe.empty | |
end | |
end | |
end | |
class MaybeBlock < BasicObject | |
def self.maybe(value, &block) | |
new(value).instance_exec(&block).instance_variable_get('@value') | |
end | |
def initialize(value) | |
@value = value | |
end | |
def method_missing(*args) | |
@value = @value.call(*args) | |
end | |
end | |
if $0 == __FILE__ | |
require 'minitest/autorun' | |
require 'minitest/spec' | |
Class.new(Minitest::Spec) do | |
it 'gracefully handles a nil object' do | |
assert_nil Maybe.new(nil).(:to_s).(:reverse).(:upcase).value | |
end | |
it 'returns nil if the resulting expression would throw an exception' do | |
assert_nil Maybe.new(:hello).(:rand).value | |
end | |
it 'is accepts other maybes' do | |
assert_equal 'Hello', Maybe.new(Maybe.new('Hello')).value | |
end | |
it 'returns a value or a another value if the monad is empty' do | |
assert_equal 'Yes', Maybe.empty.value_or('Yes') | |
end | |
it 'chains along the calls if they are correct' do | |
assert_equal "OLLEH", Maybe.new(:hello).(:to_s).(:split, '').(:reverse).(:join, '').(:upcase).value | |
end | |
it 'allows for checking equality' do | |
assert Maybe.empty == nil | |
assert Maybe.new('A') == Maybe.new('A') | |
end | |
it 'allows for hilarious block syntaxes' do | |
result = Maybe.new(:hello) do | |
to_s | |
split '' | |
reverse | |
join '' | |
upcase | |
end | |
assert_equal 'OLLEH', result.value | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment