mangrove 0.34.0 → 0.36.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1dfe08aeea0151d419caef995589fe18b98674aeb78817f651d58eef0b45e552
4
- data.tar.gz: 070b2971e1f62072b6e26289fe7e04f0f5527c414db63664cb76ef82c19b9ffd
3
+ metadata.gz: 371d0e77c422e441bc8798ca1aacf77cf11126fcea3bec2aba243c1a4970300f
4
+ data.tar.gz: 1cc24f3c80fe6c2fdca11c75193df51f7d77be047ecb40f98700b30a6eb5df4a
5
5
  SHA512:
6
- metadata.gz: 75bc64b315237e3e0c44ce8245a13e4562daf2ac2444cd3aff98151869f3c3f796259b9f62ab3d3b5fc2a58749033e3839e44d86785c20f0ec1a6b3a51e23474
7
- data.tar.gz: 60204fffda1d393f5d1b6b0c893c29757d66c14c149685b0e138d2b1e86926da61784315f789c45dcec549dd564cc87f0c7166f9c5f259ce9de05081d41ddac2
6
+ metadata.gz: 2aa303b678e5a045c0f1b13acd24cbbed698ea69e278b94fb7df2015924f5627cc86841c5769e30434ca613fef2adf489c6b555875dafff8733b593358321ea1
7
+ data.tar.gz: 62c17b4a366a86ec193b09196af476e58f921edebf1118ac875af70e6a61ca5eaa58e5a764f28f82372a266149be5b02a0af3276e2c8857e1d0699019366073a
data/.rubocop.yml CHANGED
@@ -31,10 +31,14 @@ Metrics/ModuleLength:
31
31
  Naming/BlockForwarding:
32
32
  EnforcedStyle: explicit
33
33
 
34
+ Naming/MethodParameterName:
35
+ Enabled: false
36
+
34
37
  Naming/VariableNumber:
35
38
  EnforcedStyle: snake_case
36
39
 
37
40
  Style/BlockDelimiters:
41
+ Enabled: false
38
42
  EnforcedStyle: always_braces
39
43
  AllowedMethods:
40
44
  - describe
@@ -63,3 +67,4 @@ Style/StringLiterals:
63
67
  Style/StringLiteralsInInterpolation:
64
68
  Enabled: true
65
69
  EnforcedStyle: double_quotes
70
+
data/README.md CHANGED
@@ -2,22 +2,21 @@
2
2
 
3
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
10
  ## Highlights
11
11
 
12
12
  - **Sorbet Integration**
13
- Built from the ground up to work smoothly with Sorbets type system.
13
+ Built from the ground up to work smoothly with Sorbet's type system.
14
14
 
15
15
  - **Result Type**
16
- Model success/failure outcomes with explicit types—no more return false or nil for errors!
16
+ Model success/failure outcomes with explicit types—no more "return false or nil" for errors!
17
17
 
18
18
  - **Enums (ADTs)**
19
19
  Define your own sealed enums with typed variants. Each variant can hold distinct inner data.
20
-
21
20
  - **Functional Patterns**
22
21
  Chain transformations or short-circuit error handling with a clean monadic style.
23
22
 
@@ -33,17 +32,17 @@ bundle add mangrove
33
32
 
34
33
  ## Usage Overview
35
34
 
36
- Mangrove revolves around **`Result`** and a sealed Enum mechanism for ADTs.
35
+ Mangrove revolves around **`Result`** and a sealed "Enum" mechanism for ADTs.
37
36
 
38
37
  ### Result
39
38
 
40
39
  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:
40
+ For "early returns" in a functional style, you have two main approaches:
42
41
 
43
42
  1. **A context-based DSL (e.g., `ctx.try!`)**
44
43
  2. **An instance method on `Result` itself, `unwrap_in(ctx)`**, which behaves similarly.
45
44
 
46
- Heres an example of chaining requests and short-circuiting on error:
45
+ Here's an example of chaining requests and short-circuiting on error:
47
46
 
48
47
  ```ruby
49
48
  class MyClient
@@ -87,6 +86,32 @@ end
87
86
  # More chaining, etc...
88
87
  ```
89
88
 
89
+ ### Extension Methods
90
+
91
+ Mangrove provides convenient extension methods through `Mangrove::Result::Ext`. These methods allow you to easily wrap any value in a `Result`:
92
+
93
+ ```ruby
94
+ # Include the extension in your classes
95
+ class Object
96
+ include Mangrove::Result::Ext
97
+ end
98
+
99
+ # Now you can use in_ok and in_err on any object
100
+ "success".in_ok # => Result::Ok("success")
101
+ "error".in_err # => Result::Err("error")
102
+
103
+ # Useful in method chains
104
+ "hello"
105
+ .upcase
106
+ .in_ok
107
+ .map_ok { |s| "#{s}!" } # => Result::Ok("HELLO!")
108
+
109
+ # Error case
110
+ "error message"
111
+ .in_err
112
+ .map_err { |e| "#{e}!" } # => Result::Err("error message!")
113
+ ```
114
+
90
115
  ### Enums (ADTs)
91
116
 
92
117
  Define an enum with typed variants:
@@ -0,0 +1,18 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Mangrove
5
+ module Result
6
+ module Ext
7
+ extend T::Sig
8
+
9
+ def in_ok
10
+ Mangrove::Result::Ok.new(self)
11
+ end
12
+
13
+ def in_err
14
+ Mangrove::Result::Err.new(self)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative "result/control_signal"
5
+ require_relative "result/ext"
5
6
 
6
7
  module Mangrove
7
8
  # Result is a type that represents either success (`Ok`) or failure (`Err`).
@@ -0,0 +1,41 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Mangrove
5
+ module TryFromExt
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ include Kernel
10
+
11
+ sig {
12
+ type_parameters(:I, :O, :E)
13
+ .params(
14
+ from: T::Class[T.type_parameter(:I)],
15
+ to: T::Class[T.type_parameter(:O)],
16
+ err: T::Class[T.type_parameter(:E)],
17
+ block: T.proc.params(arg: T.type_parameter(:I)).returns(Mangrove::Result[T.type_parameter(:O), T.type_parameter(:E)])
18
+ ).void
19
+ }
20
+ # rubocop:disable Lint/UnusedMethodArgument
21
+ def try_convert_from(from:, to:, err:, &block)
22
+ T.bind(self, T::Class[T.type_parameter(:O)])
23
+
24
+ vars = from.instance_variable_get(:@convertable_to) || {}
25
+ vars[self] = block
26
+ from.instance_variable_set(:@convertable_to, vars)
27
+
28
+ @convertable_from ||= {}
29
+ @convertable_from[from] = [err, block]
30
+
31
+ into_t = T.cast(self, Class)
32
+
33
+ from.define_method("try_into_#{T.must_because(into_t.name) { "name is required" }.gsub(/::|([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase}") do
34
+ proc = T.unsafe(self).class.ancestors.lazy.map { |klass| klass.instance_variable_get(:@convertable_to)&.[](into_t) }.find(&:itself)
35
+
36
+ proc.call(self)
37
+ end
38
+ end
39
+ # rubocop:enable Lint/UnusedMethodArgument
40
+ end
41
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Mangrove
5
- VERSION = "0.34.0"
5
+ VERSION = "0.36.0"
6
6
  end
data/lib/mangrove.rb CHANGED
@@ -8,6 +8,7 @@ require_relative "mangrove/option"
8
8
  require_relative "mangrove/result"
9
9
  require_relative "mangrove/enum"
10
10
  require_relative "mangrove/control_flow/control_signal"
11
+ require_relative "mangrove/try_from_ext"
11
12
 
12
13
  # Mangrove
13
14
  module Mangrove; end
@@ -0,0 +1,40 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "mangrove/result/ext"
5
+ require "tapioca/dsl"
6
+ require "sorbet-runtime"
7
+
8
+ module Tapioca
9
+ module Compilers
10
+ class MangroveResultExt < Tapioca::Dsl::Compiler
11
+ extend T::Sig
12
+
13
+ ConstantType = type_member { { fixed: T.class_of(Mangrove::Result::Ext) } }
14
+
15
+ sig { override.returns(T::Enumerable[Module]) }
16
+ def self.gather_constants
17
+ all_classes.select { |c| c < ::Mangrove::Result::Ext }
18
+ end
19
+
20
+ sig { override.void }
21
+ def decorate
22
+ return unless valid_constant_name?(constant.to_s)
23
+
24
+ root.create_path(constant) do |klass|
25
+ klass.create_method("in_ok", return_type: "Mangrove::Result::Ok[#{constant}]")
26
+ klass.create_method("in_err", return_type: "Mangrove::Result::Err[#{constant}]")
27
+ end
28
+ rescue NameError
29
+ # 握りつぶす
30
+ end
31
+
32
+ private
33
+
34
+ sig { params(string: String).returns(T::Boolean) }
35
+ def valid_constant_name?(string)
36
+ Object.const_defined?(string) && !!(string =~ /\A[A-Z][a-zA-Z0-9_]*\z/)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "mangrove/try_from_ext"
5
+ require "tapioca/dsl"
6
+ require "sorbet-runtime"
7
+
8
+ module Tapioca
9
+ module Compilers
10
+ class TryFromExt < Tapioca::Dsl::Compiler
11
+ extend T::Sig
12
+
13
+ ConstantType = type_member { { fixed: T.class_of(Mangrove::TryFromExt) } }
14
+
15
+ sig { override.returns(T::Enumerable[Module]) }
16
+ def self.gather_constants
17
+ all_classes.select { |c| c.singleton_class < ::Mangrove::TryFromExt }
18
+ end
19
+
20
+ sig { override.void }
21
+ def decorate
22
+ return if constant.instance_variable_get(:@convertable_from).nil? || constant.instance_variable_get(:@convertable_from).empty?
23
+
24
+ constant.instance_variable_get(:@convertable_from)&.each do |convertable_from, values|
25
+ err_constant, _block = values
26
+ root.create_path(convertable_from) do |klass|
27
+ klass.create_method("try_into_#{constant.to_s.gsub(/::|([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase}", return_type: "Mangrove::Result[#{constant}, #{err_constant}]")
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1 @@
1
+ **/*.rbi linguist-generated=true
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mangrove
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.34.0
4
+ version: 0.36.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kazuma Murata
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-21 00:00:00.000000000 Z
10
+ date: 2025-03-28 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: sorbet-runtime
@@ -46,13 +46,18 @@ files:
46
46
  - lib/mangrove/option/control_signal.rb
47
47
  - lib/mangrove/result.rb
48
48
  - lib/mangrove/result/control_signal.rb
49
+ - lib/mangrove/result/ext.rb
50
+ - lib/mangrove/try_from_ext.rb
49
51
  - lib/mangrove/version.rb
50
52
  - lib/tapioca/dsl/compilers/mangrove_enum.rb
53
+ - lib/tapioca/dsl/compilers/mangrove_result_ext.rb
54
+ - lib/tapioca/dsl/compilers/mangrove_try_from_ext.rb
51
55
  - rbi/mangrove.rbi
52
56
  - sig/mangrove.rbs
53
57
  - sorbet/config
54
58
  - sorbet/rbi/annotations/.gitattributes
55
59
  - sorbet/rbi/annotations/rainbow.rbi
60
+ - sorbet/rbi/dsl/.gitattributes
56
61
  - sorbet/rbi/gems/.gitattributes
57
62
  - sorbet/rbi/gems/ast@2.4.2.rbi
58
63
  - sorbet/rbi/gems/benchmark@0.4.0.rbi