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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +107 -43
  3. data/lib/mangrove/result.rb +50 -0
  4. data/lib/mangrove/version.rb +1 -1
  5. data/sorbet/config +1 -0
  6. data/sorbet/rbi/gems/benchmark@0.4.0.rbi +618 -0
  7. data/sorbet/rbi/gems/date@3.4.1.rbi +75 -0
  8. data/sorbet/rbi/gems/{docile@1.4.0.rbi → docile@1.4.1.rbi} +2 -1
  9. data/sorbet/rbi/gems/{erubi@1.12.0.rbi → erubi@1.13.1.rbi} +26 -17
  10. data/sorbet/rbi/gems/{json@2.7.2.rbi → json@2.9.1.rbi} +516 -134
  11. data/sorbet/rbi/gems/logger@1.6.5.rbi +940 -0
  12. data/sorbet/rbi/gems/{parallel@1.24.0.rbi → parallel@1.26.3.rbi} +31 -21
  13. data/sorbet/rbi/gems/{parser@3.3.2.0.rbi → parser@3.3.7.0.rbi} +23 -1736
  14. data/sorbet/rbi/gems/{prism@0.29.0.rbi → prism@1.3.0.rbi} +13817 -10401
  15. data/sorbet/rbi/gems/{psych@5.1.2.rbi → psych@5.2.3.rbi} +289 -236
  16. data/sorbet/rbi/gems/{racc@1.8.0.rbi → racc@1.8.1.rbi} +0 -4
  17. data/sorbet/rbi/gems/rbi@0.2.3.rbi +4542 -0
  18. data/sorbet/rbi/gems/rbs@3.8.1.rbi +6882 -0
  19. data/sorbet/rbi/gems/{rdoc@6.7.0.rbi → rdoc@6.11.0.rbi} +1115 -1058
  20. data/sorbet/rbi/gems/{regexp_parser@2.9.2.rbi → regexp_parser@2.10.0.rbi} +193 -170
  21. data/sorbet/rbi/gems/{rspec-core@3.13.0.rbi → rspec-core@3.13.2.rbi} +146 -280
  22. data/sorbet/rbi/gems/{rspec-expectations@3.13.0.rbi → rspec-expectations@3.13.3.rbi} +323 -294
  23. data/sorbet/rbi/gems/{rspec-mocks@3.13.1.rbi → rspec-mocks@3.13.2.rbi} +46 -46
  24. data/sorbet/rbi/gems/{rspec-support@3.13.1.rbi → rspec-support@3.13.2.rbi} +22 -22
  25. data/sorbet/rbi/gems/ruboclean@0.7.1.rbi +473 -0
  26. data/sorbet/rbi/gems/{rubocop-ast@1.31.3.rbi → rubocop-ast@1.37.0.rbi} +1293 -745
  27. data/sorbet/rbi/gems/{rubocop-rspec@2.30.0.rbi → rubocop-rspec@3.4.0.rbi} +341 -1073
  28. data/sorbet/rbi/gems/{rubocop@1.64.1.rbi → rubocop@1.70.0.rbi} +5693 -3796
  29. data/sorbet/rbi/gems/{simplecov-html@0.12.3.rbi → simplecov-html@0.13.1.rbi} +77 -68
  30. data/sorbet/rbi/gems/{spoom@1.3.2.rbi → spoom@1.5.1.rbi} +2306 -1701
  31. data/sorbet/rbi/gems/{stringio@3.1.0.rbi → stringio@3.1.2.rbi} +1 -0
  32. data/sorbet/rbi/gems/{tapioca@0.14.3.rbi → tapioca@0.16.8.rbi} +411 -332
  33. data/sorbet/rbi/gems/{thor@1.3.1.rbi → thor@1.3.2.rbi} +57 -31
  34. data/sorbet/rbi/gems/unicode-display_width@3.1.4.rbi +132 -0
  35. data/sorbet/rbi/gems/unicode-emoji@4.0.4.rbi +251 -0
  36. data/sorbet/rbi/gems/{webrick@1.8.1.rbi → webrick@1.9.1.rbi} +92 -72
  37. data/sorbet/rbi/gems/{yard-sorbet@0.8.1.rbi → yard-sorbet@0.9.0.rbi} +36 -29
  38. data/sorbet/rbi/gems/{yard@0.9.36.rbi → yard@0.9.37.rbi} +393 -235
  39. metadata +39 -42
  40. data/sorbet/rbi/gems/rbi@0.1.13.rbi +0 -3078
  41. data/sorbet/rbi/gems/rexml@3.2.8.rbi +0 -4794
  42. data/sorbet/rbi/gems/ruboclean@0.6.0.rbi +0 -315
  43. data/sorbet/rbi/gems/rubocop-capybara@2.20.0.rbi +0 -1208
  44. data/sorbet/rbi/gems/rubocop-factory_bot@2.25.1.rbi +0 -928
  45. data/sorbet/rbi/gems/rubocop-rspec_rails@2.28.3.rbi +0 -911
  46. data/sorbet/rbi/gems/strscan@3.1.0.rbi +0 -9
  47. data/sorbet/rbi/gems/unicode-display_width@2.5.0.rbi +0 -65
  48. /data/sorbet/rbi/gems/{io-console@0.7.2.rbi → io-console@0.8.0.rbi} +0 -0
  49. /data/sorbet/rbi/gems/{reline@0.5.8.rbi → reline@0.6.0.rbi} +0 -0
  50. /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: 5f834b6984567df445825c79b6027e0259d955c082aa68bbfbd7dc6ac1cf7e40
4
- data.tar.gz: 989be7ac4cd2fab0ccf154785ab19560dd0133b51b76880d2e1ce281e638ea83
3
+ metadata.gz: 1dfe08aeea0151d419caef995589fe18b98674aeb78817f651d58eef0b45e552
4
+ data.tar.gz: 070b2971e1f62072b6e26289fe7e04f0f5527c414db63664cb76ef82c19b9ffd
5
5
  SHA512:
6
- metadata.gz: 8b4fe3703902f7f2c566f3789c3d2cc2e8ee4d02d2591bcedfa3425319af3da86d215c63ab6dfd5ba79826ff07f7f4ab4c33f8d33560eb2378a14a9a132e7030
7
- data.tar.gz: fc2b7c8ad55cd4052b25837c64e20573b2ed0446871cb2f1c3a9d8dcd554224c44848256f0c2f9752161dfb54d7e6fcd5740d2a854aaff1117fa7e30fda80eeb
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 Gem designed to be the definitive toolkit for leveraging Sorbet's type system in Ruby applications. It's designed to offer a robust, statically-typed experience, focusing on solid types, a functional programming style, and an interface-driven approach.
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
- ## Features
8
+ ---
9
9
 
10
- - Option Type
11
- - Result Type
12
- - Enums with inner types (ADTs)
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
- ## Usage
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
- [Documentation is available here](https://kazzix14.github.io/mangrove/docs).
23
- For more concrete examples, see [`spec/**/**_spec.rb`](https://github.com/kazzix14/mangrove/tree/main/spec).
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
- Mangrove::Result[OkType, ErrType]
27
- Mangrove::Result::Ok[OkType]
28
- Mangrove::Result::Err[ErrType]
29
- Mangrove::Option[InnerType]
30
- Mangrove::Option::Some[InnerType]
31
- Mangrove::Option::None[InnerType]
32
-
33
- my_ok = Result::Ok.new("my value")
34
- my_err = Result::Err.new("my err")
35
- my_some = Option::Some.new(1234)
36
- my_none = Option::None.new
37
-
38
- ##############################
39
-
40
- response = MyClient
41
- .new
42
- .and_then { |client| client.get_response() }
43
- .and_then { |response| response.body }
44
-
45
- case response
46
- when Mangrove::Result::Ok
47
- puts response.ok_inner
48
- when Mangrove::Result::Err
49
- puts response.err_inner
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 VariantWithInteger, Integer
59
- variant VariantWithString, String
60
- variant VariantWithException, Exception
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.
@@ -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
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Mangrove
5
- VERSION = "0.31.0"
5
+ VERSION = "0.34.0"
6
6
  end
data/sorbet/config CHANGED
@@ -3,3 +3,4 @@
3
3
  --ignore=tmp/
4
4
  --ignore=vendor/
5
5
  --enable-experimental-requires-ancestor
6
+ --disable-watchman