mangrove 0.31.0 → 0.34.0
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/README.md +107 -43
- data/lib/mangrove/result.rb +50 -0
- data/lib/mangrove/version.rb +1 -1
- data/sorbet/config +1 -0
- data/sorbet/rbi/gems/benchmark@0.4.0.rbi +618 -0
- data/sorbet/rbi/gems/date@3.4.1.rbi +75 -0
- data/sorbet/rbi/gems/{docile@1.4.0.rbi → docile@1.4.1.rbi} +2 -1
- data/sorbet/rbi/gems/{erubi@1.12.0.rbi → erubi@1.13.1.rbi} +26 -17
- data/sorbet/rbi/gems/{json@2.7.2.rbi → json@2.9.1.rbi} +516 -134
- data/sorbet/rbi/gems/logger@1.6.5.rbi +940 -0
- data/sorbet/rbi/gems/{parallel@1.24.0.rbi → parallel@1.26.3.rbi} +31 -21
- data/sorbet/rbi/gems/{parser@3.3.2.0.rbi → parser@3.3.7.0.rbi} +23 -1736
- data/sorbet/rbi/gems/{prism@0.29.0.rbi → prism@1.3.0.rbi} +13817 -10401
- data/sorbet/rbi/gems/{psych@5.1.2.rbi → psych@5.2.3.rbi} +289 -236
- data/sorbet/rbi/gems/{racc@1.8.0.rbi → racc@1.8.1.rbi} +0 -4
- data/sorbet/rbi/gems/rbi@0.2.3.rbi +4542 -0
- data/sorbet/rbi/gems/rbs@3.8.1.rbi +6882 -0
- data/sorbet/rbi/gems/{rdoc@6.7.0.rbi → rdoc@6.11.0.rbi} +1115 -1058
- data/sorbet/rbi/gems/{regexp_parser@2.9.2.rbi → regexp_parser@2.10.0.rbi} +193 -170
- data/sorbet/rbi/gems/{rspec-core@3.13.0.rbi → rspec-core@3.13.2.rbi} +146 -280
- data/sorbet/rbi/gems/{rspec-expectations@3.13.0.rbi → rspec-expectations@3.13.3.rbi} +323 -294
- data/sorbet/rbi/gems/{rspec-mocks@3.13.1.rbi → rspec-mocks@3.13.2.rbi} +46 -46
- data/sorbet/rbi/gems/{rspec-support@3.13.1.rbi → rspec-support@3.13.2.rbi} +22 -22
- data/sorbet/rbi/gems/ruboclean@0.7.1.rbi +473 -0
- data/sorbet/rbi/gems/{rubocop-ast@1.31.3.rbi → rubocop-ast@1.37.0.rbi} +1293 -745
- data/sorbet/rbi/gems/{rubocop-rspec@2.30.0.rbi → rubocop-rspec@3.4.0.rbi} +341 -1073
- data/sorbet/rbi/gems/{rubocop@1.64.1.rbi → rubocop@1.70.0.rbi} +5693 -3796
- data/sorbet/rbi/gems/{simplecov-html@0.12.3.rbi → simplecov-html@0.13.1.rbi} +77 -68
- data/sorbet/rbi/gems/{spoom@1.3.2.rbi → spoom@1.5.1.rbi} +2306 -1701
- data/sorbet/rbi/gems/{stringio@3.1.0.rbi → stringio@3.1.2.rbi} +1 -0
- data/sorbet/rbi/gems/{tapioca@0.14.3.rbi → tapioca@0.16.8.rbi} +411 -332
- data/sorbet/rbi/gems/{thor@1.3.1.rbi → thor@1.3.2.rbi} +57 -31
- data/sorbet/rbi/gems/unicode-display_width@3.1.4.rbi +132 -0
- data/sorbet/rbi/gems/unicode-emoji@4.0.4.rbi +251 -0
- data/sorbet/rbi/gems/{webrick@1.8.1.rbi → webrick@1.9.1.rbi} +92 -72
- data/sorbet/rbi/gems/{yard-sorbet@0.8.1.rbi → yard-sorbet@0.9.0.rbi} +36 -29
- data/sorbet/rbi/gems/{yard@0.9.36.rbi → yard@0.9.37.rbi} +393 -235
- metadata +39 -42
- data/sorbet/rbi/gems/rbi@0.1.13.rbi +0 -3078
- data/sorbet/rbi/gems/rexml@3.2.8.rbi +0 -4794
- data/sorbet/rbi/gems/ruboclean@0.6.0.rbi +0 -315
- data/sorbet/rbi/gems/rubocop-capybara@2.20.0.rbi +0 -1208
- data/sorbet/rbi/gems/rubocop-factory_bot@2.25.1.rbi +0 -928
- data/sorbet/rbi/gems/rubocop-rspec_rails@2.28.3.rbi +0 -911
- data/sorbet/rbi/gems/strscan@3.1.0.rbi +0 -9
- data/sorbet/rbi/gems/unicode-display_width@2.5.0.rbi +0 -65
- /data/sorbet/rbi/gems/{io-console@0.7.2.rbi → io-console@0.8.0.rbi} +0 -0
- /data/sorbet/rbi/gems/{reline@0.5.8.rbi → reline@0.6.0.rbi} +0 -0
- /data/sorbet/rbi/gems/{ruby-lsp@0.17.2.rbi → ruby-lsp@0.23.6.rbi} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1dfe08aeea0151d419caef995589fe18b98674aeb78817f651d58eef0b45e552
|
4
|
+
data.tar.gz: 070b2971e1f62072b6e26289fe7e04f0f5527c414db63664cb76ef82c19b9ffd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 75bc64b315237e3e0c44ce8245a13e4562daf2ac2444cd3aff98151869f3c3f796259b9f62ab3d3b5fc2a58749033e3839e44d86785c20f0ec1a6b3a51e23474
|
7
|
+
data.tar.gz: 60204fffda1d393f5d1b6b0c893c29757d66c14c149685b0e138d2b1e86926da61784315f789c45dcec549dd564cc87f0c7166f9c5f259ce9de05081d41ddac2
|
data/README.md
CHANGED
@@ -1,79 +1,124 @@
|
|
1
1
|
# Mangrove
|
2
2
|
|
3
|
-
Mangrove is a Ruby
|
3
|
+
Mangrove is a Ruby toolkit that brings a functional, statically-typed flavor to your Sorbet-enabled projects. Inspired by concepts from languages like Rust and Haskell, Mangrove provides a robust set of tools—primarily `Result` and ADT-like Enums—to help you write safer, more expressive Ruby code.
|
4
4
|
|
5
|
-
- [Documentation](https://kazzix14.github.io/mangrove/docs/)
|
6
|
-
- [Coverage](https://kazzix14.github.io/mangrove/coverage/index.html#_AllFiles)
|
5
|
+
- **[Documentation](https://kazzix14.github.io/mangrove/docs/)**
|
6
|
+
- **[Coverage](https://kazzix14.github.io/mangrove/coverage/index.html#_AllFiles)**
|
7
7
|
|
8
|
-
|
8
|
+
---
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
-
|
10
|
+
## Highlights
|
11
|
+
|
12
|
+
- **Sorbet Integration**
|
13
|
+
Built from the ground up to work smoothly with Sorbet’s type system.
|
14
|
+
|
15
|
+
- **Result Type**
|
16
|
+
Model success/failure outcomes with explicit types—no more “return false or nil” for errors!
|
17
|
+
|
18
|
+
- **Enums (ADTs)**
|
19
|
+
Define your own sealed enums with typed variants. Each variant can hold distinct inner data.
|
20
|
+
|
21
|
+
- **Functional Patterns**
|
22
|
+
Chain transformations or short-circuit error handling with a clean monadic style.
|
23
|
+
|
24
|
+
---
|
13
25
|
|
14
26
|
## Installation
|
15
27
|
|
16
|
-
```
|
28
|
+
```bash
|
17
29
|
bundle add mangrove
|
18
30
|
```
|
19
31
|
|
20
|
-
|
32
|
+
---
|
33
|
+
|
34
|
+
## Usage Overview
|
35
|
+
|
36
|
+
Mangrove revolves around **`Result`** and a sealed “Enum” mechanism for ADTs.
|
37
|
+
|
38
|
+
### Result
|
39
|
+
|
40
|
+
A `Result` is either `Ok(T)` or `Err(E)`. You can compose them with monadic methods like `and_then` and `or_else`.
|
41
|
+
For “early returns” in a functional style, you have two main approaches:
|
21
42
|
|
22
|
-
|
23
|
-
|
43
|
+
1. **A context-based DSL (e.g., `ctx.try!`)**
|
44
|
+
2. **An instance method on `Result` itself, `unwrap_in(ctx)`**, which behaves similarly.
|
45
|
+
|
46
|
+
Here’s an example of chaining requests and short-circuiting on error:
|
24
47
|
|
25
48
|
```ruby
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
Mangrove::
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
class MyClient
|
50
|
+
extend T::Sig
|
51
|
+
|
52
|
+
sig { returns(Mangrove::Result[String, StandardError]) }
|
53
|
+
def connect
|
54
|
+
# ...
|
55
|
+
Mangrove::Result::Ok.new("Connected")
|
56
|
+
end
|
57
|
+
|
58
|
+
sig { params(data: String).returns(Mangrove::Result[String, StandardError]) }
|
59
|
+
def request(data)
|
60
|
+
# ...
|
61
|
+
Mangrove::Result::Ok.new("Response: #{data}")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Let's say we have a special DSL context for collecting short-circuits:
|
66
|
+
# (Hypothetical usage)
|
67
|
+
|
68
|
+
Result.collecting(String, StandardError) do |ctx|
|
69
|
+
final_result = MyClient.new
|
70
|
+
.connect
|
71
|
+
.and_then do |connection|
|
72
|
+
MyClient.new.request("Payload from #{connection}")
|
73
|
+
end
|
74
|
+
|
75
|
+
# Option 1: Call from the context
|
76
|
+
response_data = ctx.try!(final_result)
|
77
|
+
# => If 'final_result' is Err, short-circuits now;
|
78
|
+
# otherwise returns the Ok(T) value.
|
79
|
+
|
80
|
+
puts response_data # If no errors, prints "Response: Connected"
|
81
|
+
|
82
|
+
# Option 2: Call via 'unwrap_in(ctx)'
|
83
|
+
# This does the same short-circuit if 'Err', using the context:
|
84
|
+
response_data_alt = final_result.unwrap_in(ctx)
|
50
85
|
end
|
51
86
|
|
52
|
-
|
87
|
+
# More chaining, etc...
|
88
|
+
```
|
89
|
+
|
90
|
+
### Enums (ADTs)
|
91
|
+
|
92
|
+
Define an enum with typed variants:
|
53
93
|
|
94
|
+
```ruby
|
54
95
|
class MyEnum
|
55
96
|
extend Mangrove::Enum
|
56
97
|
|
57
98
|
variants do
|
58
|
-
variant
|
59
|
-
variant
|
60
|
-
variant
|
61
|
-
variant VariantWithTuple, [Integer, String]
|
62
|
-
variant VariantWithShape, { name: String, age: Integer }
|
99
|
+
variant IntVariant, Integer
|
100
|
+
variant StrVariant, String
|
101
|
+
variant ShapeVariant, { name: String, age: Integer }
|
63
102
|
end
|
64
103
|
end
|
104
|
+
|
105
|
+
int_v = MyEnum::IntVariant.new(123)
|
106
|
+
puts int_v.inner # => 123
|
65
107
|
```
|
66
108
|
|
109
|
+
For more details on monadic methods, short-circuit contexts, and advanced usage, please visit the [official documentation](https://kazzix14.github.io/mangrove/docs/) or see real-world usages in [`spec/`](https://github.com/kazzix14/mangrove/tree/main/spec).
|
110
|
+
|
111
|
+
---
|
112
|
+
|
67
113
|
## Commands for Development
|
68
114
|
|
69
|
-
```
|
115
|
+
```bash
|
70
116
|
git config core.hooksPath hooks
|
71
117
|
bundle install
|
72
118
|
bundle exec tapioca init
|
73
119
|
bundle exec tapioca gems -w `nproc`
|
74
120
|
bundle exec tapioca dsl -w `nproc`
|
75
121
|
bundle exec tapioca check-shims
|
76
|
-
bundle exec tapioca init
|
77
122
|
bundle exec rspec -f d
|
78
123
|
bundle exec rubocop -DESP
|
79
124
|
bundle exec srb typecheck
|
@@ -85,3 +130,22 @@ bundle exec yard server --reload --plugin yard-sorbet
|
|
85
130
|
rake build
|
86
131
|
rake release
|
87
132
|
```
|
133
|
+
|
134
|
+
Run these commands to maintain code quality, generate documentation, and verify type safety under Sorbet.
|
135
|
+
|
136
|
+
---
|
137
|
+
|
138
|
+
## Contributing
|
139
|
+
|
140
|
+
We welcome contributions! To get started:
|
141
|
+
|
142
|
+
1. Fork & clone the repo
|
143
|
+
2. Install dependencies: `bundle install`
|
144
|
+
3. Make your changes and add tests
|
145
|
+
4. Submit a PR
|
146
|
+
|
147
|
+
---
|
148
|
+
|
149
|
+
## License
|
150
|
+
|
151
|
+
Mangrove is available under the [MIT License](https://opensource.org/licenses/MIT). See the LICENSE file for details.
|
data/lib/mangrove/result.rb
CHANGED
@@ -42,6 +42,9 @@ module Mangrove
|
|
42
42
|
sig { abstract.returns(OkType) }
|
43
43
|
def unwrap_or_raise_inner!; end
|
44
44
|
|
45
|
+
sig { abstract.params(ctx: Result::CollectingContext[OkType, ErrType]).returns(OkType) }
|
46
|
+
def unwrap_in(ctx); end
|
47
|
+
|
45
48
|
sig { abstract.params(message: String).returns(OkType) }
|
46
49
|
def expect!(message); end
|
47
50
|
|
@@ -157,6 +160,43 @@ module Mangrove
|
|
157
160
|
def err_wt(_t_ok, inner)
|
158
161
|
Result::Err[T.type_parameter(:ErrType)].new(inner)
|
159
162
|
end
|
163
|
+
|
164
|
+
sig {
|
165
|
+
type_parameters(:O, :E)
|
166
|
+
.params(
|
167
|
+
_t_ok: T::Class[T.type_parameter(:O)],
|
168
|
+
_t_err: T::Class[T.type_parameter(:E)],
|
169
|
+
block: T.proc.params(
|
170
|
+
do_block: CollectingContext[T.type_parameter(:O), T.type_parameter(:E)]
|
171
|
+
).returns(Mangrove::Result[T.type_parameter(:O), T.type_parameter(:E)])
|
172
|
+
)
|
173
|
+
.returns(Mangrove::Result[T.type_parameter(:O), T.type_parameter(:E)])
|
174
|
+
}
|
175
|
+
def collecting(_t_ok, _t_err, &block)
|
176
|
+
catch(:__mangrove_result_collecting_context_return) {
|
177
|
+
block.call(CollectingContext[T.type_parameter(:O), T.type_parameter(:E)].new)
|
178
|
+
}
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
class CollectingContext
|
183
|
+
extend T::Sig
|
184
|
+
extend T::Generic
|
185
|
+
|
186
|
+
O = type_member
|
187
|
+
E = type_member
|
188
|
+
|
189
|
+
sig { params(result: Mangrove::Result[O, E]).returns(O) }
|
190
|
+
def try!(result)
|
191
|
+
case result
|
192
|
+
when Mangrove::Result::Ok
|
193
|
+
result.ok_inner
|
194
|
+
when Mangrove::Result::Err
|
195
|
+
throw :__mangrove_result_collecting_context_return, result
|
196
|
+
else
|
197
|
+
T.absurd(result)
|
198
|
+
end
|
199
|
+
end
|
160
200
|
end
|
161
201
|
|
162
202
|
class Ok
|
@@ -212,6 +252,11 @@ module Mangrove
|
|
212
252
|
@inner
|
213
253
|
end
|
214
254
|
|
255
|
+
sig { override.params(_ctx: Result::CollectingContext[OkType, ErrType]).returns(OkType) }
|
256
|
+
def unwrap_in(_ctx)
|
257
|
+
@inner
|
258
|
+
end
|
259
|
+
|
215
260
|
sig { override.params(_message: String).returns(OkType) }
|
216
261
|
def expect!(_message)
|
217
262
|
@inner
|
@@ -398,6 +443,11 @@ module Mangrove
|
|
398
443
|
raise T.unsafe(@inner)
|
399
444
|
end
|
400
445
|
|
446
|
+
sig { override.params(_ctx: Result::CollectingContext[OkType, ErrType]).returns(T.noreturn) }
|
447
|
+
def unwrap_in(_ctx)
|
448
|
+
throw :__mangrove_result_collecting_context_return, self
|
449
|
+
end
|
450
|
+
|
401
451
|
sig { override.params(message: String).returns(OkType) }
|
402
452
|
def expect!(message)
|
403
453
|
raise Result::ControlSignal, message
|
data/lib/mangrove/version.rb
CHANGED
data/sorbet/config
CHANGED