Skip to content

Commit 231adb6

Browse files
committed
feat: add type, add == for comparison
1 parent ad3a798 commit 231adb6

5 files changed

Lines changed: 142 additions & 7 deletions

File tree

.rubocop.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ plugins:
77
Metrics/BlockLength:
88
Enabled: false
99

10+
Metrics/MethodLength:
11+
Enabled: false
12+
1013
RSpec/MultipleExpectations:
1114
Enabled: false
1215

@@ -15,4 +18,3 @@ RSpec/ExampleLength:
1518

1619
RSpec/MissingExpectationTargetMethod:
1720
Enabled: false
18-

lib/rs/option.rb

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Rs
88
module Option
99
class ArgumentError < StandardError; end
1010
class UnwrapNone < StandardError; end
11+
class TypeError < StandardError; end
1112

1213
def some?
1314
@some
@@ -64,20 +65,52 @@ def unwrap_or_else(&block)
6465
class Some
6566
include Rs::Option
6667

67-
def initialize(value)
68+
attr_reader :type
69+
attr_reader :some
70+
attr_reader :value
71+
72+
private :value
73+
74+
def initialize(value, type: nil)
6875
if value == nil
6976
raise(Rs::Option::ArgumentError, "Some value cannot be nil")
7077
end
7178

72-
@value = value
79+
if type
80+
if value.class != type
81+
raise(Rs::Option::TypeError, "Value type #{value.class} does not match #{type}")
82+
end
83+
84+
@type = type
85+
else
86+
@type = value.class
87+
end
88+
7389
@some = true
90+
@value = value
91+
end
92+
93+
def ==(other)
94+
other.is_a?(Some) && @type == other.type && @value == other.unwrap
7495
end
7596
end
7697

7798
class None
7899
include Rs::Option
79100

101+
attr_reader :type
102+
attr_reader :some
103+
attr_reader :value
104+
105+
private :value
106+
80107
def initialize
108+
@type = NilClass
81109
@some = false
110+
@value = nil
111+
end
112+
113+
def ==(other)
114+
other.is_a? None
82115
end
83116
end

lib/rs/result.rb

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Result
1111
class ArgumentError < StandardError; end
1212
class UnwrapOnErr < StandardError; end
1313
class UnwrapErrOnOk < StandardError; end
14+
class TypeError < StandardError; end
1415

1516
def ok?
1617
@ok
@@ -90,20 +91,62 @@ def unwrap_err
9091

9192
class Ok
9293
include Rs::Result
93-
def initialize(value)
94+
95+
attr_reader :type
96+
attr_reader :ok
97+
attr_reader :value
98+
99+
private :value
100+
101+
def initialize(value, type: nil)
94102
if value == nil
95103
raise(Rs::Result::ArgumentError, "Ok value cannot be nil")
96104
end
97105

98-
@value = value
106+
if type
107+
if value.class != type
108+
raise(Rs::Result::TypeError, "Value type #{value.class} does not match #{type}")
109+
end
110+
111+
@type = type
112+
else
113+
@type = value.class
114+
end
115+
99116
@ok = true
117+
@value = value
118+
end
119+
120+
def ==(other)
121+
other.is_a?(Ok) && @type == other.type && @value == other.unwrap
100122
end
101123
end
102124

103125
class Err
104126
include Rs::Result
105-
def initialize(error)
106-
@value = error
127+
128+
attr_reader :type
129+
attr_reader :ok
130+
attr_reader :value
131+
132+
private :value
133+
134+
def initialize(error, type: nil)
135+
if type
136+
if error.class != type
137+
raise(Rs::Result::TypeError, "Error type #{error.class} does not match #{type}")
138+
end
139+
140+
@type = type
141+
else
142+
@type = error.class
143+
end
144+
107145
@ok = false
146+
@value = error
147+
end
148+
149+
def ==(other)
150+
other.is_a?(Err) && @type == other.type && @value == other.unwrap_err
108151
end
109152
end

spec/rs/option_spec.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,37 @@
8585
expect(x.unwrap_or).to be_nil
8686
expect(y.unwrap_or).to eq 12
8787
end
88+
89+
it "pattern_matching" do
90+
def divide(numerator, denominator)
91+
if denominator == 0
92+
None.new
93+
else
94+
Some.new(numerator / denominator)
95+
end
96+
end
97+
98+
result = divide(3, 1)
99+
case result
100+
when Some
101+
x = result.unwrap
102+
else
103+
x = "Cannot divide by 0"
104+
end
105+
expect(x).to eq 3
106+
end
107+
108+
it "type ==" do
109+
a = Some.new(1)
110+
b = Some.new(1.0)
111+
c = Some.new(1.0, type: Float)
112+
d = Some.new("a")
113+
e = None.new
114+
115+
expect(a == b).to be false
116+
expect(a == c).to be false
117+
expect(b == c).to be true
118+
expect(a == d).to be false
119+
expect(a == e).to be false
120+
end
88121
end

spec/rs/result_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,28 @@ def parse_year(str)
133133
expect(Ok.new(2).unwrap_or_else { |x| x.size }).to eq 2
134134
expect(Err.new("foo").unwrap_or_else { |x| x.size }).to eq 3
135135
end
136+
137+
it "type ==" do
138+
a = Ok.new(1)
139+
b = Ok.new(1.0)
140+
c = Ok.new(1.0, type: Float)
141+
d = Ok.new("a")
142+
143+
e = Err.new(1)
144+
f = Err.new(1.0)
145+
g = Err.new(1.0, type: Float)
146+
h = Err.new("a")
147+
i = Err.new(nil)
148+
149+
expect(a == b).to be false
150+
expect(a == c).to be false
151+
expect(b == c).to be true
152+
expect(a == d).to be false
153+
154+
expect(e == f).to be false
155+
expect(e == g).to be false
156+
expect(f == g).to be true
157+
expect(e == h).to be false
158+
expect(e == i).to be false
159+
end
136160
end

0 commit comments

Comments
 (0)