unsound 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/unsound/data.rb +2 -101
- data/lib/unsound/data/either.rb +101 -0
- data/lib/unsound/data/maybe.rb +87 -0
- data/lib/unsound/version.rb +1 -1
- data/spec/unit/unsound/data/maybe_spec.rb +92 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3c645e777dc983c390c247a59c5f2de02727346b
|
4
|
+
data.tar.gz: a316ea5ccba27d63f3a823344e7c256f36056f1c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0c2101d6baca2654803b9edcca62d5f2e7967a29114f252a7e1c7dbef763ffaa98c0bcaa00e042cf524014a04f13c46de7a7962f43e1857792a24f5921f221c0
|
7
|
+
data.tar.gz: 59979f8819eff54c06cab5d71eb3a8e27e2e555b1185a6721df4235d1512bd443affd17ed3a0a1adea2b6ae7609442ae0bf9e6feddd12c88e69cdc29e40477de
|
data/lib/unsound/data.rb
CHANGED
@@ -1,101 +1,2 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
module Unsound
|
5
|
-
module Data
|
6
|
-
# @abstract
|
7
|
-
class Either
|
8
|
-
include AbstractType
|
9
|
-
include Concord::Public.new(:value)
|
10
|
-
|
11
|
-
# Wraps a raw value in a {Data::Right}
|
12
|
-
#
|
13
|
-
# @param value [Any] the value to wrap
|
14
|
-
# @return [Data::Right]
|
15
|
-
def self.of(value)
|
16
|
-
Right.new(value)
|
17
|
-
end
|
18
|
-
|
19
|
-
abstract_method :fmap
|
20
|
-
abstract_method :>>
|
21
|
-
|
22
|
-
abstract_method :either
|
23
|
-
abstract_method :and_then
|
24
|
-
abstract_method :or_else
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def of(value)
|
29
|
-
self.class.of(value)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class Left < Either
|
34
|
-
# A Noop
|
35
|
-
#
|
36
|
-
# @return [Data::Left]
|
37
|
-
def fmap(*)
|
38
|
-
self
|
39
|
-
end
|
40
|
-
|
41
|
-
# A Noop
|
42
|
-
#
|
43
|
-
# @return [Data::Left]
|
44
|
-
def >>(*)
|
45
|
-
self
|
46
|
-
end
|
47
|
-
alias :and_then :>>
|
48
|
-
|
49
|
-
# Chain another operation which can result in a {Data::Either}
|
50
|
-
#
|
51
|
-
# @param f[#call] the next operation
|
52
|
-
# @return [Data::Left, Data::Right]
|
53
|
-
def or_else(f = nil, &blk)
|
54
|
-
(f || blk)[value]
|
55
|
-
end
|
56
|
-
|
57
|
-
# Call a function on the value in the {Data::Left}
|
58
|
-
#
|
59
|
-
# @param f [#call] a function capable of processing the value
|
60
|
-
# @param _ [#call] a function that will never be called
|
61
|
-
def either(f, _)
|
62
|
-
f[value]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
class Right < Either
|
67
|
-
# Apply a function to a value contained in a {Data::Right}
|
68
|
-
#
|
69
|
-
# @param f [#call] the function to apply
|
70
|
-
# @return [Data::Right] the result of applying the function
|
71
|
-
# wrapped in a {Data::Right}
|
72
|
-
def fmap(f = nil, &blk)
|
73
|
-
self >> Composition.compose(method(:of), (f || blk))
|
74
|
-
end
|
75
|
-
|
76
|
-
# Chain another operation which can result in a {Data::Either}
|
77
|
-
#
|
78
|
-
# @param f[#call] the next operation
|
79
|
-
# @return [Data::Left, Data::Right]
|
80
|
-
def >>(f = nil, &blk)
|
81
|
-
(f || blk)[value]
|
82
|
-
end
|
83
|
-
alias :and_then :>>
|
84
|
-
|
85
|
-
# A Noop
|
86
|
-
#
|
87
|
-
# @return [Data::Right]
|
88
|
-
def or_else(*)
|
89
|
-
self
|
90
|
-
end
|
91
|
-
|
92
|
-
# Call a function on the value in the {Data::Right}
|
93
|
-
#
|
94
|
-
# @param _ [#call] a function that will never be called
|
95
|
-
# @param f [#call] a function capable of processing the value
|
96
|
-
def either(_, f)
|
97
|
-
f[value]
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
1
|
+
require_relative "data/either"
|
2
|
+
require_relative "data/maybe"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "abstract_type"
|
2
|
+
require "concord"
|
3
|
+
|
4
|
+
module Unsound
|
5
|
+
module Data
|
6
|
+
# @abstract
|
7
|
+
class Either
|
8
|
+
include AbstractType
|
9
|
+
include Concord::Public.new(:value)
|
10
|
+
|
11
|
+
# Wraps a raw value in a {Data::Right}
|
12
|
+
#
|
13
|
+
# @param value [Any] the value to wrap
|
14
|
+
# @return [Data::Right]
|
15
|
+
def self.of(value)
|
16
|
+
Right.new(value)
|
17
|
+
end
|
18
|
+
|
19
|
+
abstract_method :fmap
|
20
|
+
abstract_method :>>
|
21
|
+
|
22
|
+
abstract_method :either
|
23
|
+
abstract_method :and_then
|
24
|
+
abstract_method :or_else
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def of(value)
|
29
|
+
self.class.of(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Left < Either
|
34
|
+
# A Noop
|
35
|
+
#
|
36
|
+
# @return [Data::Left]
|
37
|
+
def fmap(*)
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# A Noop
|
42
|
+
#
|
43
|
+
# @return [Data::Left]
|
44
|
+
def >>(*)
|
45
|
+
self
|
46
|
+
end
|
47
|
+
alias :and_then :>>
|
48
|
+
|
49
|
+
# Chain another operation which can result in a {Data::Either}
|
50
|
+
#
|
51
|
+
# @param f[#call] the next operation
|
52
|
+
# @return [Data::Left, Data::Right]
|
53
|
+
def or_else(f = nil, &blk)
|
54
|
+
(f || blk)[value]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Call a function on the value in the {Data::Left}
|
58
|
+
#
|
59
|
+
# @param f [#call] a function capable of processing the value
|
60
|
+
# @param _ [#call] a function that will never be called
|
61
|
+
def either(f, _)
|
62
|
+
f[value]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Right < Either
|
67
|
+
# Apply a function to a value contained in a {Data::Right}
|
68
|
+
#
|
69
|
+
# @param f [#call] the function to apply
|
70
|
+
# @return [Data::Right] the result of applying the function
|
71
|
+
# wrapped in a {Data::Right}
|
72
|
+
def fmap(f = nil, &blk)
|
73
|
+
self >> Composition.compose(method(:of), (f || blk))
|
74
|
+
end
|
75
|
+
|
76
|
+
# Chain another operation which can result in a {Data::Either}
|
77
|
+
#
|
78
|
+
# @param f[#call] the next operation
|
79
|
+
# @return [Data::Left, Data::Right]
|
80
|
+
def >>(f = nil, &blk)
|
81
|
+
(f || blk)[value]
|
82
|
+
end
|
83
|
+
alias :and_then :>>
|
84
|
+
|
85
|
+
# A Noop
|
86
|
+
#
|
87
|
+
# @return [Data::Right]
|
88
|
+
def or_else(*)
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
# Call a function on the value in the {Data::Right}
|
93
|
+
#
|
94
|
+
# @param _ [#call] a function that will never be called
|
95
|
+
# @param f [#call] a function capable of processing the value
|
96
|
+
def either(_, f)
|
97
|
+
f[value]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require "abstract_type"
|
2
|
+
require "equalizer"
|
3
|
+
|
4
|
+
module Unsound
|
5
|
+
module Data
|
6
|
+
# @abstract
|
7
|
+
class Maybe
|
8
|
+
include AbstractType
|
9
|
+
|
10
|
+
# Wraps a raw value in a {Data::Just}
|
11
|
+
#
|
12
|
+
# @param value [Any] the value to wrap
|
13
|
+
# @return [Data::Just]
|
14
|
+
def self.of(value)
|
15
|
+
Just.new(value)
|
16
|
+
end
|
17
|
+
|
18
|
+
abstract_method :fmap
|
19
|
+
abstract_method :>>
|
20
|
+
|
21
|
+
abstract_method :and_then
|
22
|
+
abstract_method :or_else
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def of(value)
|
27
|
+
self.class.of(value)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class Nothing < Maybe
|
32
|
+
include Equalizer.new
|
33
|
+
|
34
|
+
# A Noop
|
35
|
+
#
|
36
|
+
# @return [Data::Nothing]
|
37
|
+
def fmap(*)
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
# A Noop
|
42
|
+
#
|
43
|
+
# @return [Data::Nothing]
|
44
|
+
def >>(*)
|
45
|
+
self
|
46
|
+
end
|
47
|
+
alias :and_then :>>
|
48
|
+
|
49
|
+
# Chain another operation which can result in a {Data::Maybe}
|
50
|
+
#
|
51
|
+
# @param f[#call] the next operation
|
52
|
+
# @return [Data::Nothing, Data::Just]
|
53
|
+
def or_else(f = nil, &blk)
|
54
|
+
(f || blk).call
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Just < Maybe
|
59
|
+
include Concord::Public.new(:value)
|
60
|
+
|
61
|
+
# Apply a function to a value contained in a {Data::Just}
|
62
|
+
#
|
63
|
+
# @param f [#call] the function to apply
|
64
|
+
# @return [Data::Just] the result of applying the function
|
65
|
+
# wrapped in a {Data::Just}
|
66
|
+
def fmap(f = nil, &blk)
|
67
|
+
self >> Composition.compose(method(:of), (f || blk))
|
68
|
+
end
|
69
|
+
|
70
|
+
# Chain another operation which can result in a {Data::Maybe}
|
71
|
+
#
|
72
|
+
# @param f[#call] the next operation
|
73
|
+
# @return [Data::Nothing, Data::Just]
|
74
|
+
def >>(f = nil, &blk)
|
75
|
+
(f || blk)[value]
|
76
|
+
end
|
77
|
+
alias :and_then :>>
|
78
|
+
|
79
|
+
# A Noop
|
80
|
+
#
|
81
|
+
# @return [Data::Just]
|
82
|
+
def or_else(*)
|
83
|
+
self
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/unsound/version.rb
CHANGED
@@ -0,0 +1,92 @@
|
|
1
|
+
require "shared/functor_examples"
|
2
|
+
require "shared/monad_examples"
|
3
|
+
|
4
|
+
require "unsound"
|
5
|
+
|
6
|
+
RSpec.describe Unsound::Data::Maybe do
|
7
|
+
let(:value) { double(:value) }
|
8
|
+
|
9
|
+
let(:instances) do
|
10
|
+
[
|
11
|
+
Unsound::Data::Nothing.new,
|
12
|
+
Unsound::Data::Just.new(value)
|
13
|
+
]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "has an abstract base class" do
|
17
|
+
expect {
|
18
|
+
Unsound::Data::Maybe.new
|
19
|
+
}.to raise_error(NotImplementedError)
|
20
|
+
end
|
21
|
+
|
22
|
+
it_behaves_like "a Functor"
|
23
|
+
|
24
|
+
it_behaves_like "a Monad" do
|
25
|
+
let(:type) { Unsound::Data::Maybe }
|
26
|
+
|
27
|
+
specify { expect(type.of(value)).to eq(Unsound::Data::Just.new(value)) }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#and_then" do
|
31
|
+
let(:and_then) do
|
32
|
+
->(value) { Unsound::Data::Just.new([value, value]) }
|
33
|
+
end
|
34
|
+
|
35
|
+
context "a just" do
|
36
|
+
let(:just) { Unsound::Data::Just.new(value) }
|
37
|
+
let(:value) { double(:value) }
|
38
|
+
|
39
|
+
context "a function" do
|
40
|
+
it "applies the function over the value" do
|
41
|
+
expect(just.and_then(and_then)).to eq(and_then.call(value))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "a block" do
|
46
|
+
it "applies the block over the value" do
|
47
|
+
expect(just.and_then(&and_then)).to eq(and_then.call(value))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "a nothing" do
|
53
|
+
let(:nothing) { Unsound::Data::Nothing.new }
|
54
|
+
let(:error) { double(:error) }
|
55
|
+
|
56
|
+
it "is a noop returning self" do
|
57
|
+
expect(nothing.and_then(and_then)).to eq(nothing)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#or_else" do
|
63
|
+
let(:or_else) do
|
64
|
+
-> { Unsound::Data::Nothing.new }
|
65
|
+
end
|
66
|
+
|
67
|
+
context "a just" do
|
68
|
+
let(:just) { Unsound::Data::Right.new(value) }
|
69
|
+
let(:value) { double(:value) }
|
70
|
+
|
71
|
+
it "is a noop returning self" do
|
72
|
+
expect(just.or_else(or_else)).to eq(just)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context "a nothing" do
|
77
|
+
let(:nothing) { Unsound::Data::Nothing.new }
|
78
|
+
|
79
|
+
context "a function" do
|
80
|
+
it "calls the function" do
|
81
|
+
expect(nothing.or_else(or_else)).to eq(or_else.call)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context "a block" do
|
86
|
+
it "yields to the block" do
|
87
|
+
expect(nothing.or_else(&or_else)).to eq(or_else.call)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: unsound
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Swan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concord
|
@@ -86,6 +86,8 @@ files:
|
|
86
86
|
- lib/unsound/composition.rb
|
87
87
|
- lib/unsound/control.rb
|
88
88
|
- lib/unsound/data.rb
|
89
|
+
- lib/unsound/data/either.rb
|
90
|
+
- lib/unsound/data/maybe.rb
|
89
91
|
- lib/unsound/version.rb
|
90
92
|
- spec/integration/try_spec.rb
|
91
93
|
- spec/shared/functor_examples.rb
|
@@ -93,6 +95,7 @@ files:
|
|
93
95
|
- spec/spec_helper.rb
|
94
96
|
- spec/unit/unsound/control_spec.rb
|
95
97
|
- spec/unit/unsound/data/either_spec.rb
|
98
|
+
- spec/unit/unsound/data/maybe_spec.rb
|
96
99
|
- unsound.gemspec
|
97
100
|
homepage: https://github.com/pdswan/unsound
|
98
101
|
licenses:
|
@@ -125,3 +128,4 @@ test_files:
|
|
125
128
|
- spec/spec_helper.rb
|
126
129
|
- spec/unit/unsound/control_spec.rb
|
127
130
|
- spec/unit/unsound/data/either_spec.rb
|
131
|
+
- spec/unit/unsound/data/maybe_spec.rb
|