Skip to content

Commit f806ca1

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

5 files changed

Lines changed: 138 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: 33 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,50 @@ 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+
71+
private attr_reader :value
72+
73+
def initialize(value, type: nil)
6874
if value == nil
6975
raise(Rs::Option::ArgumentError, "Some value cannot be nil")
7076
end
7177

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

7797
class None
7898
include Rs::Option
7999

100+
attr_reader :type
101+
attr_reader :some
102+
103+
private attr_reader :value
104+
80105
def initialize
106+
@type = NilClass
81107
@some = false
108+
@value = nil
109+
end
110+
111+
def ==(other)
112+
other.is_a? None
82113
end
83114
end

lib/rs/result.rb

Lines changed: 45 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,60 @@ 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+
98+
private attr_reader :value
99+
100+
def initialize(value, type: nil)
94101
if value == nil
95102
raise(Rs::Result::ArgumentError, "Ok value cannot be nil")
96103
end
97104

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

103124
class Err
104125
include Rs::Result
105-
def initialize(error)
106-
@value = error
126+
127+
attr_reader :type
128+
attr_reader :ok
129+
130+
private attr_reader :value
131+
132+
def initialize(error, type: nil)
133+
if type
134+
if error.class != type
135+
raise(Rs::Result::TypeError, "Error type #{error.class} does not match #{type}")
136+
end
137+
138+
@type = type
139+
else
140+
@type = error.class
141+
end
142+
107143
@ok = false
144+
@value = error
145+
end
146+
147+
def ==(other)
148+
other.is_a?(Err) && @type == other.type && @value == other.unwrap_err
108149
end
109150
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)