Skip to content

Commit

Permalink
Feature/block call (#58)
Browse files Browse the repository at this point in the history
Allow using block on manipulation methods.
  • Loading branch information
alex-lairan authored Apr 15, 2020
1 parent ef9ea26 commit f7cb2b2
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .crystal-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.32.1
0.34.0
4 changes: 2 additions & 2 deletions shard.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
name: monads
version: 0.5.0
version: 0.6.0

authors:
- Alexandre Lairan <[email protected]>

crystal: 0.29.0
crystal: 0.34.0

license: MIT

Expand Down
37 changes: 31 additions & 6 deletions spec/monads/either/left_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,25 @@ describe Monads::Left do
monad.value_or(5).should eq(5)
end

it "export value (unit)" do
it "export value (unit) (proc)" do
monad = Monads::Left.new(1)
monad.value_or(->(x : Int32) { x + 1 }).should eq(2)
end

it "export value (unit) (block)" do
monad = Monads::Left.new(1)
monad.value_or { |x| x + 1 }.should eq(2)
end
end

describe "#fmap" do
it "not increase by one" do
monad = Monads::Left.new(1).fmap(->(value : String) { value + "a" })
it "not increase by one (proc)" do
monad = Monads::Left.new(1).fmap(->(value : Int32) { value.to_s + "a" })
monad.should eq(Monads::Left.new(1))
end

it "not increase by one (block)" do
monad = Monads::Left.new(1).fmap { |value| value.to_s + "a" }
monad.should eq(Monads::Left.new(1))
end
end
Expand Down Expand Up @@ -175,23 +185,38 @@ describe Monads::Left do
monad.should eq(Monads::Right.new('a'))
end

it "#or return argument with block" do
it "#or return argument (proc)" do
monad = Monads::Left.new(1).or(->(_value : Int32) { Monads::Right.new('a') })
monad.should eq(Monads::Right.new('a'))
end

it "#or return argument (block)" do
monad = Monads::Left.new(1).or { Monads::Right.new('a') }
monad.should eq(Monads::Right.new('a'))
end
end

describe "#bind" do
it "#bind return self" do
it "#bind return self (proc)" do
monad = Monads::Left.new(1).bind(->(x : Int32) { Monads::Right.new(x.to_s) })
monad.should eq(Monads::Left.new(1))
end

it "#bind return self (block)" do
monad = Monads::Left.new(1).bind { |x| Monads::Right.new(x.to_s) }
monad.should eq(Monads::Left.new(1))
end
end

describe "#map_or" do
it "#map_or return argument" do
it "#map_or return argument (proc)" do
value = Monads::Left.new("123").map_or('a', ->(x : String) { x[0] })
value.should eq('a')
end

it "#map_or return argument (block)" do
value = Monads::Left.new("123").map_or('a') { |x| x[0] }
value.should eq('a')
end
end
end
35 changes: 30 additions & 5 deletions spec/monads/either/right_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,27 @@ describe Monads::Right do
monad.value_or(5).should eq(1)
end

it "export value (unit) with proc" do
monad = Monads::Right.new(1)
monad.value_or( ->{ 5 }).should eq(1)
end

it "export value (unit) with block" do
monad = Monads::Right.new(1)
monad.value_or(-> { 5 }).should eq(1)
monad.value_or { 5 }.should eq(1)
end
end

describe "#fmap" do
it "increase by one" do
it "increase by one (proc)" do
monad = Monads::Right.new(1).fmap(->(value : Int32) { value + 1 })
monad.should eq(Monads::Right.new(2))
end

it "increase by one (block)" do
monad = Monads::Right.new(1).fmap { |value| value + 1 }
monad.should eq(Monads::Right.new(2))
end
end

describe "#<" do
Expand Down Expand Up @@ -176,17 +186,27 @@ describe Monads::Right do
monad.should eq(Monads::Right.new(1))
end

it "#or return self with block" do
it "#or return self with proc" do
monad = Monads::Right.new(1).or(->(_value : Int32) { Monads::Right.new('a') })
monad.should eq(Monads::Right.new(1))
end

it "#or return self with block" do
monad = Monads::Right.new(1).or { Monads::Right.new('a') }
monad.should eq(Monads::Right.new(1))
end
end

describe "#bind" do
it "#bind apply block" do
it "#bind apply proc" do
monad = Monads::Right.new(1).bind(->(x : Int32) { Monads::Right.new(x.to_s) })
monad.should eq(Monads::Right.new("1"))
end

it "#bind apply block" do
monad = Monads::Right.new(1).bind { |x| Monads::Right.new(x.to_s) }
monad.should eq(Monads::Right.new("1"))
end
end

describe "self.return" do
Expand All @@ -197,9 +217,14 @@ describe Monads::Right do
end

describe "#map_or" do
it "#map_or applies lambda to self.value! and return" do
it "#map_or applies proc to self.value! and return" do
value = Monads::Right.new("abc").map_or('b', ->(x : String) { x[0] })
value.should eq('a')
end

it "#map_or applies block to self.value! and return" do
value = Monads::Right.new("abc").map_or('b') { |x| x[0] }
value.should eq('a')
end
end
end
27 changes: 24 additions & 3 deletions spec/monads/maybe/just_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -48,32 +48,53 @@ describe Monads::Just do
monad.or(exclude).should eq(monad)
end

it "result himself with lambda" do
it "result himself with lambda (proc)" do
monad = Monads::Just.new(1)
exclude = Monads::Just.new(3)
monad.or(-> { exclude }).should eq(monad)
end

it "result himself with lambda (block)" do
monad = Monads::Just.new(1)
exclude = Monads::Just.new(3)
monad.or { exclude }.should eq(monad)
end
end

describe "#bind" do
it "export value (proc)" do
monad = Monads::Just.new(1).bind(->(value : Int32) { Monads::Just.new(value + 1) })
monad.should eq(Monads::Just.new(2))
end

it "export value (block)" do
monad = Monads::Just.new(1).bind { |value| Monads::Just.new(value + 1) }
monad.should eq(Monads::Just.new(2))
end
end

describe "#fmap" do
it "increase by one" do
it "increase by one (proc)" do
monad = Monads::Just.new(1).fmap(->(value : Int32) { value + 1 })
monad.should eq(Monads::Just.new(2))
end

it "increase by one (block)" do
monad = Monads::Just.new(1).fmap { |value| value + 1 }
monad.should eq(Monads::Just.new(2))
end
end

describe "#map_or" do
it "apply function in the case of Just" do
it "apply function in the case of Just (proc)" do
monad = Monads::Just.new(2).map_or(-1, ->(value : Int32) { value + 1 })
monad.should eq(3)
end

it "apply function in the case of Just (block)" do
monad = Monads::Just.new(2).map_or(-1) { |value| value + 1 }
monad.should eq(3)
end
end

describe "#to_s" do
Expand Down
29 changes: 25 additions & 4 deletions spec/monads/maybe/nothing_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,53 @@ describe Monads::Nothing do
monad.or(exclude).should eq(exclude)
end

it "result exclude result" do
it "result exclude result (proc)" do
monad = Monads::Nothing(Int32).new
exclude = Monads::Just.new(3)
monad.or(-> { exclude }).should eq(exclude)
end

it "result exclude result (proc)" do
monad = Monads::Nothing(Int32).new
exclude = Monads::Just.new(3)
monad.or { exclude }.should eq(exclude)
end
end

describe "#bind" do
it "export value (proc)" do
monad = Monads::Nothing(Int32).new.bind(->(value : Int32) { Monads::Maybe.return(value + 1) })
monad.should eq(monad)
end

it "export value (block)" do
monad = Monads::Nothing(Int32).new.bind { |value| Monads::Maybe.return(value + 1) }
monad.should eq(monad)
end
end

describe "#fmap" do
it "not increase by one" do
monad = Monads::Nothing(String).new.fmap(->(value : Int32) { value + 1 })
it "not increase by one (proc)" do
monad = Monads::Nothing(String).new.fmap(->(value : String) { value + "1" })
monad.should eq(Monads::Nothing(String).new)
end

it "not increase by one (block)" do
monad = Monads::Nothing(String).new.fmap { |value| value + "1" }
monad.should eq(Monads::Nothing(String).new)
end
end

describe "#map_or" do
it "return default value in the case of Nothign" do
it "return default value in the case of Nothing (proc)" do
monad = Monads::Nothing(Int32).new.map_or(-1, ->(value : Int32) { value + 1 })
monad.should eq(-1)
end

it "return default value in the case of Nothing (block)" do
monad = Monads::Nothing(Int32).new.map_or(-1) { |value| value + 1 }
monad.should eq(-1)
end
end

describe "#to_s" do
Expand Down
24 changes: 21 additions & 3 deletions src/monads/either.cr
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,20 @@ module Monads
end

abstract def value_or(element : U) forall U
abstract def value_or(lambda : E -> U) forall U
abstract def or(monad : Either)
abstract def or(lambda : E -> U) forall U
abstract def <=>(other : Right)
abstract def <=>(other : Left)
abstract def map_or(default : U, lambda : T -> U) forall U

def value_or(&block : E -> U) forall U
value_or(block)
end

def or(&block : E -> U) forall U
or(block)
end
end

struct Right(T) < Either(Nil, T)
Expand Down Expand Up @@ -74,6 +84,10 @@ module Monads
def map_or(default : U, lambda : T -> U) forall U
lambda.call(value!)
end

def map_or(default : U, &block : T -> U) forall U
map_or(default, block)
end
end

module Leftable(E)
Expand Down Expand Up @@ -107,7 +121,7 @@ module Monads
end

struct Left(E) < Either(E, Nil)
# include Leftable(E)
include Leftable(E)

def initialize(@data : E)
end
Expand All @@ -128,7 +142,7 @@ module Monads
-1
end

def fmap(lambda : _ -> _) : Left(E)
def fmap(lambda : _ -> U) : Left(E) forall U
self
end

Expand All @@ -155,10 +169,14 @@ module Monads
def map_or(default : U, lambda : _ -> _) forall U
default
end

def map_or(default : U, &block : E -> U) forall U
map_or(default, block)
end
end

struct LeftException < Either(Exception, Nil)
# include Leftable(Exception)
include Leftable(Exception)

def initialize(@data : E)
end
Expand Down
4 changes: 4 additions & 0 deletions src/monads/functor.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
module Monads
abstract struct Functor(T)
abstract def fmap(lambda : T -> U)

def fmap(&block : T -> U) forall U
fmap(block)
end
end
end
14 changes: 13 additions & 1 deletion src/monads/maybe.cr
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,21 @@ module Monads
abstract def <=>(other : Just)
abstract def to_s
abstract def or(default : Maybe)
abstract def or(lambda : -> _)
abstract def value_or(default : U) forall U
abstract def map_or(default : U, lambda : T -> U) forall U

def map_or(default : U, &block : T -> U) forall U
map_or(default, block)
end

def value_or(&block : E -> U) forall U
value_or(block)
end

def or(&block : -> U) forall U
or(block)
end
end

struct Just(T) < Maybe(T)
Expand Down Expand Up @@ -103,7 +116,6 @@ module Monads
end

def value_or(default : U) forall U
print(default)
default
end

Expand Down
Loading

0 comments on commit f7cb2b2

Please sign in to comment.