Skip to content

Commit e0c0958

Browse files
committed
feat: add missing methods, add untyped sig
Add Steepfile Update rubocop config
1 parent e5b0a8a commit e0c0958

9 files changed

Lines changed: 715 additions & 16 deletions

File tree

.rubocop.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,11 @@ Naming/PredicatePrefix:
3131
Metrics/AbcSize:
3232
Enabled: false
3333

34+
Metrics/ClassLength:
35+
Enabled: false
36+
3437
Layout/LineLength:
3538
Enabled: false
39+
40+
Lint/UnusedBlockArgument:
41+
Enabled: false

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ RuboCop::RakeTask.new do |task|
1010
task.plugins << "rubocop-rspec"
1111
end
1212

13-
task default: [:spec, :rubocop]
13+
task default: [:spec]

Steepfile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# frozen_string_literal: true
2+
3+
# D = Steep::Diagnostic
4+
5+
target :lib do
6+
signature "sig"
7+
8+
# Directory name
9+
check "lib"
10+
# ignore "lib/templates/*.rb"
11+
12+
# library "pathname" # Standard libraries
13+
# library "strong_json" # Gems
14+
15+
# configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
16+
# configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
17+
# configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
18+
# configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
19+
# configure_code_diagnostics do |hash| # You can setup everything yourself
20+
# hash[D::Ruby::NoMethod] = :information
21+
# end
22+
end
23+
24+
# target :test do
25+
# unreferenced! # Skip type checking the `lib` code when types in `test` target is changed
26+
# signature "sig/test" # Put RBS files for tests under `sig/test`
27+
# check "test" # Type check Ruby scripts under `test`
28+
#
29+
# configure_code_diagnostics(D::Ruby.lenient) # Weak type checking for test code
30+
#
31+
# # library "pathname" # Standard libraries
32+
# end

lib/rs/option.rb

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,109 @@ def unwrap_or(default)
4848
def unwrap_or_else(&block)
4949
is_some ? @value : block.call
5050
end
51+
52+
def map(value_type, &block)
53+
if is_some
54+
Some[value_type] { block.call(@value) }
55+
else
56+
None[value_type]
57+
end
58+
end
59+
60+
def tap(&block)
61+
if is_some
62+
value = @value
63+
block.call(value)
64+
end
65+
self
66+
end
67+
68+
def map_or(default, &block)
69+
is_some ? block.call(@value) : default
70+
end
71+
72+
def map_or_else(default, &block)
73+
is_some ? block.call(@value) : default.call
74+
end
75+
76+
def ok_or(error)
77+
if is_some
78+
Ok[@value_type, error.class] { @value }
79+
else
80+
Err[@value_type, error.class] { error }
81+
end
82+
end
83+
84+
def ok_or_else(&block)
85+
error = block.call
86+
if is_some
87+
Ok[@value_type, error.class] { @value }
88+
else
89+
Err[@value_type, error.class] { error }
90+
end
91+
end
92+
93+
def and(other)
94+
is_some ? other : None[other.value_type]
95+
end
96+
97+
def and_then(value_type, &block)
98+
is_some ? block.call(@value) : None[value_type]
99+
end
100+
101+
def select(&block)
102+
if is_some
103+
value = @value
104+
block.call(value) ? self : None[@value_type]
105+
else
106+
None[@value_type]
107+
end
108+
end
109+
110+
def or(other)
111+
if is_some
112+
self
113+
else
114+
other
115+
end
116+
end
117+
118+
def or_else(&block)
119+
is_some ? self : block.call
120+
end
121+
122+
def xor(other)
123+
case [is_some, other.is_some]
124+
when [true, false]
125+
self
126+
when [false, true]
127+
other
128+
when [true, true]
129+
None[@value_type]
130+
else
131+
None[@value_type]
132+
end
133+
end
134+
135+
def self.from(value_type, &block)
136+
Some[value_type, &block]
137+
end
138+
139+
def self.from?(value_type, &block)
140+
value = block.call
141+
if value == nil
142+
None[value_type]
143+
else
144+
Some[value_type] { value }
145+
end
146+
end
147+
148+
def self.from!(value_type, &block)
149+
value = block.call
150+
Some[value_type] { value }
151+
rescue StandardError
152+
None[value_type]
153+
end
51154
end
52155
end
53156

lib/rs/result.rb

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,59 @@ def is_err_and(&block)
3636
end
3737

3838
def ok
39-
is_ok ? Some[@value_type] { @value } : None[@value_type]
39+
if is_ok
40+
Some[@value_type] { @value }
41+
else
42+
None[@value_type]
43+
end
4044
end
4145

4246
def err
43-
is_err ? Some[@error_type] { @error } : None[@error_type]
47+
if is_err
48+
Some[@error_type] { @error }
49+
else
50+
None[@error_type]
51+
end
52+
end
53+
54+
def map(value_type, &block)
55+
if is_ok
56+
Ok[value_type, @error_type] { block.call(@value) }
57+
else
58+
Err[value_type, @error_type] { @error }
59+
end
60+
end
61+
62+
def map_or(default, &block)
63+
is_ok ? block.call(@value) : default
64+
end
65+
66+
def map_or_else(default, &block)
67+
is_ok ? block.call(@value) : default.call(@error)
68+
end
69+
70+
def map_err(error_type, &block)
71+
if is_ok
72+
Ok[@value_type, error_type] { @value }
73+
else
74+
Err[@value_type, error_type] { block.call(@error) }
75+
end
76+
end
77+
78+
def tap(&block)
79+
if is_ok
80+
value = @value
81+
block.call(value)
82+
end
83+
self
84+
end
85+
86+
def tap_err(&block)
87+
if is_err
88+
error = @error
89+
block.call(error)
90+
end
91+
self
4492
end
4593

4694
def expect(msg)
@@ -51,6 +99,46 @@ def unwrap
5199
is_ok ? @value : raise(UnwrapOnErr.new("called unwrap on an Err value: #{@error}"))
52100
end
53101

102+
def expect_err(msg)
103+
is_ok ? raise(UnwrapErrOnOk.new("#{msg}: #{@value}")) : @error
104+
end
105+
106+
def unwrap_err
107+
is_ok ? raise(UnwrapErrOnOk.new("called unwrap_err() on an Ok value: #{@value}")) : @error
108+
end
109+
110+
def and(other)
111+
if is_ok
112+
other
113+
else
114+
Err[other.value_type, @error_type] { @error }
115+
end
116+
end
117+
118+
def and_then(value_type, &block)
119+
if is_ok
120+
block.call(@value)
121+
else
122+
Err[value_type, @error_type] { @error }
123+
end
124+
end
125+
126+
def or(other)
127+
if is_ok
128+
Ok[@value_type, other.error_type] { @value }
129+
else
130+
other
131+
end
132+
end
133+
134+
def or_else(error_type, &block)
135+
if is_ok
136+
Ok[@value_type, error_type] { @value }
137+
else
138+
block.call(@error)
139+
end
140+
end
141+
54142
def unwrap_or(default)
55143
is_ok ? @value : default
56144
end
@@ -59,12 +147,24 @@ def unwrap_or_else(&block)
59147
is_ok ? @value : block.call(@error)
60148
end
61149

62-
def expect_err(msg)
63-
is_ok ? raise(UnwrapErrOnOk.new("#{msg}: #{@value}")) : @error
150+
def self.from_or(value_type, error, &block)
151+
Ok[value_type, error.class] { block.call }
64152
end
65153

66-
def unwrap_err
67-
is_ok ? raise(UnwrapErrOnOk.new("called unwrap_err() on an Ok value: #{@value}")) : @error
154+
def self.from_or?(value_type, error, &block)
155+
value = block.call
156+
if value == nil
157+
Err[value_type, error.class] { error }
158+
else
159+
Ok[value_type, error.class] { value }
160+
end
161+
end
162+
163+
def self.from_or!(value_type, error, &block)
164+
value = block.call
165+
Ok[value_type, error.class] { value }
166+
rescue StandardError
167+
Err[value_type, error.class] { error }
68168
end
69169
end
70170
end

sig/rs/option.rbs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
module Rs
2+
# https://doc.rust-lang.org/std/option/index.html
3+
# https://doc.rust-lang.org/std/option/enum.Option.html
4+
# https://doc.rust-lang.org/src/core/option.rs.html
5+
class Option
6+
class TypeError < StandardError
7+
def initialize: (untyped value_type) -> void
8+
end
9+
10+
class TypeNilClass < StandardError
11+
end
12+
13+
class TypeMismatch < StandardError
14+
end
15+
16+
class WrapNil < StandardError
17+
end
18+
19+
class UnwrapNone < StandardError
20+
end
21+
22+
def is_some: () -> untyped
23+
24+
def is_some_and: () { (?) -> untyped } -> (untyped | false)
25+
26+
def is_none: () -> untyped
27+
28+
def is_none_or: () { (?) -> untyped } -> (true | untyped)
29+
30+
def expect: (untyped msg) -> untyped
31+
32+
def unwrap: () -> untyped
33+
34+
def unwrap_or: (untyped default) -> untyped
35+
36+
def unwrap_or_else: () { (?) -> untyped } -> untyped
37+
38+
def map: (untyped value_type) { (?) -> untyped } -> untyped
39+
40+
def map_or: (untyped default) { (?) -> untyped } -> untyped
41+
42+
def map_or_else: (untyped default) { (?) -> untyped } -> untyped
43+
44+
def ok_or: (untyped error) -> untyped
45+
46+
def ok_or_else: () { (?) -> untyped } -> untyped
47+
48+
def and: (untyped other) -> untyped
49+
50+
def and_then: (untyped value_type) { (?) -> untyped } -> untyped
51+
52+
def select: () { (?) -> untyped } -> (self | untyped | untyped)
53+
54+
def or: (untyped other) -> (self | untyped)
55+
56+
def or_else: () { (?) -> untyped } -> (self | untyped)
57+
58+
def xor: (untyped other) -> untyped
59+
60+
def tap: () { (?) -> untyped } -> self
61+
62+
def self.from: (untyped value_type) { (?) -> untyped } -> untyped
63+
64+
def self.from?: (untyped value_type) { (?) -> untyped } -> untyped
65+
66+
def self.from!: (untyped value_type) { (?) -> untyped } -> untyped
67+
end
68+
end
69+
70+
class Some < Rs::Option
71+
@value: untyped
72+
73+
@value_type: untyped
74+
75+
attr_reader value_type: untyped
76+
77+
def self.[]: (untyped value_type) { (?) -> untyped } -> untyped
78+
79+
def inspect: () -> ::String
80+
81+
def ==: (untyped other) -> untyped
82+
83+
def initialize: (untyped value) -> void
84+
end
85+
86+
class None < Rs::Option
87+
@value_type: untyped
88+
89+
attr_reader value_type: untyped
90+
91+
def self.[]: (untyped value_type) -> untyped
92+
93+
def inspect: () -> ::String
94+
95+
def ==: (untyped other) -> untyped
96+
97+
def initialize: (?untyped value_type) -> void
98+
end

0 commit comments

Comments
 (0)