loading
Generated 2026-01-22T08:41:54+00:00

All Files ( 96.13% covered at 27.5 hits/line )

13 files in total.
620 relevant lines, 596 lines covered and 24 lines missed. ( 96.13% )
117 total branches, 30 branches covered and 87 branches missed. ( 25.64% )
File % covered Lines Relevant Lines Lines covered Lines missed Avg. Hits / Line Branch Coverage Branches Covered branches Missed branches
lib/mangrove.rb 100.00 % 14 8 8 0 1.00 100.00 % 0 0 0
lib/mangrove/control_flow/control_signal.rb 100.00 % 16 8 8 0 1.13 100.00 % 0 0 0
lib/mangrove/enum.rb 100.00 % 142 4 4 0 1.00 6.94 % 72 5 67
lib/mangrove/option.rb 95.87 % 210 121 116 5 1.64 50.00 % 8 4 4
lib/mangrove/option/control_signal.rb 94.12 % 33 17 16 1 1.71 50.00 % 2 1 1
lib/mangrove/result.rb 98.74 % 603 318 314 4 3.38 73.33 % 15 11 4
lib/mangrove/result/collector.rb 100.00 % 22 12 12 0 1.08 100.00 % 0 0 0
lib/mangrove/result/control_signal.rb 94.12 % 33 17 16 1 1.82 50.00 % 2 1 1
lib/mangrove/result/ext.rb 100.00 % 18 8 8 0 2.00 100.00 % 0 0 0
lib/mangrove/try_from_ext.rb 100.00 % 41 18 18 0 5.33 100.00 % 2 2 0
lib/tapioca/dsl/compilers/mangrove_enum.rb 82.00 % 92 50 41 9 54.06 40.00 % 10 4 6
lib/tapioca/dsl/compilers/mangrove_result_ext.rb 100.00 % 40 21 21 0 216.90 50.00 % 2 1 1
lib/tapioca/dsl/compilers/mangrove_try_from_ext.rb 77.78 % 33 18 14 4 461.83 25.00 % 4 1 3

lib/mangrove.rb

100.0% lines covered

100.0% branches covered

8 relevant lines. 8 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. 1 require "sorbet-runtime"
  4. 1 require_relative "mangrove/version"
  5. 1 require_relative "mangrove/option"
  6. 1 require_relative "mangrove/result"
  7. 1 require_relative "mangrove/enum"
  8. 1 require_relative "mangrove/control_flow/control_signal"
  9. 1 require_relative "mangrove/try_from_ext"
  10. # Mangrove
  11. 1 module Mangrove; end

lib/mangrove/control_flow/control_signal.rb

100.0% lines covered

100.0% branches covered

8 relevant lines. 8 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. 1 module Mangrove
  4. 1 module ControlFlow
  5. 1 module ControlSignal
  6. 1 extend T::Sig
  7. 1 extend T::Helpers
  8. 1 interface!
  9. 2 sig { abstract.returns(T.untyped) }
  10. 1 def inner_value; end
  11. end
  12. end
  13. end

lib/mangrove/enum.rb

100.0% lines covered

6.94% branches covered

4 relevant lines. 4 lines covered and 0 lines missed.
72 total branches, 5 branches covered and 67 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. require "sorbet-runtime"
  4. module Mangrove
  5. class EnumVariantsScope
  6. extend ::T::Sig
  7. extend ::T::Helpers
  8. sig { params(parent: T::Class[T.anything]).void }
  9. def initialize(parent)
  10. @parent = parent
  11. end
  12. sig { params(block: T.proc.void).void }
  13. def call(&block)
  14. instance_eval(&block)
  15. end
  16. sig { params(variant: T::Class[T.anything], inner_type: T.untyped).void }
  17. def variant(variant, inner_type)
  18. variant.instance_variable_set(:@__mangrove__enum_inner_type, inner_type)
  19. end
  20. end
  21. private_constant :EnumVariantsScope
  22. module Enum
  23. extend ::T::Sig
  24. extend ::T::Helpers
  25. requires_ancestor { Module }
  26. sig { params(block: T.proc.bind(EnumVariantsScope).void).void }
  27. def variants(&block)
  28. receiver = block.send(:binding).receiver
  29. outer_code = <<~RUBY
  30. def self.const_missing(id)
  31. code = <<~NESTED_RUBY
  32. class \#{id} < \#{caller.send(:binding).receiver.name}
  33. def initialize(inner)
  34. @inner = T.let(inner, self.class.instance_variable_get(:@__mangrove__enum_inner_type))
  35. end
  36. def inner
  37. @inner
  38. end
  39. def as_super
  40. T.cast(self, \#{caller.send(:binding).receiver.name})
  41. end
  42. def serialize(inner_serialization_methods: [:serialize, :to_h])
  43. serialized_inner = begin
  44. serialized_klass = [
  45. Hash,
  46. String,
  47. Numeric,
  48. TrueClass,
  49. FalseClass,
  50. NilClass,
  51. Array
  52. ]
  53. if serialized_klass.any? { |klass| @inner.is_a?(klass) }
  54. @inner
  55. else
  56. inner_serialization_methods.find do |method_name|
  57. if @inner.respond_to?(method_name, true)
  58. maybe_hash = @inner.send(method_name)
  59. if maybe_hash.is_a?(Hash)
  60. break maybe_hash
  61. end
  62. end
  63. end
  64. end
  65. end
  66. { type: self.class.name, value: serialized_inner }
  67. end
  68. def ==(other)
  69. other.is_a?(self.class) && other.inner == @inner
  70. end
  71. end
  72. NESTED_RUBY
  73. class_eval(code, __FILE__, __LINE__ + 1)
  74. class_eval(id.to_s, __FILE__, __LINE__ + 1)
  75. end
  76. RUBY
  77. original_const_missing = receiver.method(:const_missing)
  78. receiver.class_eval(outer_code, __FILE__, __LINE__ + 1)
  79. 1 EnumVariantsScope.new(receiver).call(&block)
  80. 1
  81. # Mark as sealed hear because we can not define classes in const_missing after marking as sealed
  82. 1 receiver.send(:eval, "sealed!", nil, __FILE__, __LINE__)
  83. variants = constants.filter_map { |variant_name|
  84. maybe_variant = receiver.const_get(variant_name, false)
  85. if maybe_variant.instance_variable_defined?(:@__mangrove__enum_inner_type)
  86. maybe_variant
  87. end
  88. }
  89. receiver.class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
  90. 1 @sorbet_sealed_module_all_subclasses = #{variants} # @sorbet_sealed_module_all_subclasses = #{variants}
  91. RUBY
  92. # Bring back the original const_missing
  93. receiver.define_singleton_method(:const_missing, original_const_missing)
  94. end
  95. sig { params(receiver: T::Class[T.anything]).void }
  96. def self.extended(receiver)
  97. code = <<~RUBY
  98. extend T::Sig
  99. extend T::Helpers
  100. abstract!
  101. def self.deserialize(hash)
  102. klass = const_get(hash[:type] || hash["type"])
  103. value = hash[:value] || hash["value"]
  104. begin
  105. klass.new(value)
  106. rescue TypeError
  107. klass.new(klass.deserialize(value))
  108. end
  109. end
  110. RUBY
  111. receiver.class_eval(code)
  112. end
  113. end
  114. end

lib/mangrove/option.rb

95.87% lines covered

50.0% branches covered

121 relevant lines. 116 lines covered and 5 lines missed.
8 total branches, 4 branches covered and 4 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. 1 require_relative "option/control_signal"
  4. 1 require_relative "result"
  5. 1 module Mangrove
  6. # Option is a type that represents either some value (`Some`) or no value (`None`).
  7. 1 module Option
  8. 1 extend T::Sig
  9. 1 extend T::Generic
  10. 1 extend T::Helpers
  11. 1 include Kernel
  12. 1 sealed!
  13. 1 interface!
  14. 1 InnerType = type_member
  15. 1 class << self
  16. 1 extend ::T::Sig
  17. 2 sig { type_parameters(:InnerType).params(nilable: T.nilable(T.type_parameter(:InnerType))).returns(Mangrove::Option[T.type_parameter(:InnerType)]) }
  18. 1 def from_nilable(nilable)
  19. 2 case nilable
  20. when: 1 when NilClass
  21. 1 Mangrove::Option::None.new
  22. else: 1 else
  23. 1 Mangrove::Option::Some.new(nilable)
  24. end
  25. end
  26. end
  27. # Option::Some
  28. 1 class Some
  29. 1 extend T::Sig
  30. 1 extend T::Generic
  31. 1 extend T::Helpers
  32. 1 include Option
  33. 1 InnerType = type_member
  34. 2 sig { params(inner: InnerType).void }
  35. 1 def initialize(inner)
  36. 28 @inner = T.let(inner, InnerType)
  37. end
  38. 2 sig { override.params(other: BasicObject).returns(T::Boolean) }
  39. 1 def ==(other)
  40. 7 case other
  41. when: 7 when Option::Some
  42. 7 other.instance_variable_get(:@inner) == @inner
  43. when: 0 when Option::None
  44. false
  45. else # rubocop:disable Lint/DuplicateBranch
  46. else: 0 # Because == is defined on BasicObject, we can't be sure that `other` is an Option
  47. false
  48. end
  49. end
  50. 1 sig { returns(InnerType) }
  51. 1 def unwrap
  52. @inner
  53. end
  54. 2 sig { override.params(_default: InnerType).returns(InnerType) }
  55. 1 def unwrap_or(_default)
  56. 1 @inner
  57. end
  58. 2 sig { override.returns(InnerType) }
  59. 1 def unwrap!
  60. 2 @inner
  61. end
  62. 2 sig { override.params(_message: String).returns(InnerType) }
  63. 1 def expect!(_message)
  64. 2 @inner
  65. end
  66. 2 sig { override.params(_block: T.proc.returns(T.untyped)).returns(InnerType) }
  67. 1 def expect_with!(&_block)
  68. 2 @inner
  69. end
  70. 2 sig { override.returns(T::Boolean) }
  71. 1 def some? = true
  72. 2 sig { override.returns(T::Boolean) }
  73. 1 def none? = false
  74. 2 sig { override.type_parameters(:NewInnerType).params(block: T.proc.params(inner: InnerType).returns(Option[T.type_parameter(:NewInnerType)])).returns(::Mangrove::Option[T.type_parameter(:NewInnerType)]) }
  75. 1 def map(&block)
  76. 2 block.call(@inner)
  77. end
  78. 2 sig { override.params(_default: Option[InnerType]).returns(Option[InnerType]) }
  79. 1 def or(_default)
  80. 2 self
  81. end
  82. 2 sig { override.type_parameters(:ErrType).params(_err: T.type_parameter(:ErrType)).returns(Mangrove::Result[InnerType, T.type_parameter(:ErrType)]) }
  83. 1 def transpose(_err)
  84. 1 Result::Ok.new(@inner)
  85. end
  86. 1 private
  87. 1 sig { returns(InnerType) }
  88. 1 attr_reader :inner
  89. end
  90. # Option::None
  91. 1 class None
  92. 1 extend T::Sig
  93. 1 extend T::Generic
  94. 1 extend T::Helpers
  95. 1 include Option
  96. 1 InnerType = type_member
  97. 2 sig { override.params(other: BasicObject).returns(T::Boolean) }
  98. 1 def ==(other)
  99. 3 case other
  100. when: 0 when Option::Some
  101. false
  102. when: 3 when Option::None
  103. 3 true
  104. else # rubocop:disable Lint/DuplicateBranch
  105. else: 0 # Because == is defined on BasicObject, we can't be sure that `other` is an Option
  106. false
  107. end
  108. end
  109. 2 sig { override.params(default: InnerType).returns(InnerType) }
  110. 1 def unwrap_or(default)
  111. 1 default
  112. end
  113. 2 sig { override.returns(InnerType) }
  114. 1 def unwrap!
  115. 1 raise Option::ControlSignal, "called `Option#unwrap!` on an `None` value: #{self}"
  116. end
  117. 2 sig { override.params(message: String).returns(InnerType) }
  118. 1 def expect!(message)
  119. 1 raise Option::ControlSignal, message
  120. end
  121. 2 sig { override.params(block: T.proc.returns(T.untyped)).returns(InnerType) }
  122. 1 def expect_with!(&block)
  123. 1 raise Option::ControlSignal, block.call
  124. end
  125. 2 sig { override.returns(T::Boolean) }
  126. 1 def some? = false
  127. 2 sig { override.returns(T::Boolean) }
  128. 1 def none? = true
  129. 2 sig { override.type_parameters(:NewInnerType).params(_block: T.proc.params(inner: InnerType).returns(Option[T.type_parameter(:NewInnerType)])).returns(Option[T.type_parameter(:NewInnerType)]) }
  130. 1 def map(&_block)
  131. 2 T.cast(self, Option[T.type_parameter(:NewInnerType)])
  132. end
  133. 2 sig { override.params(default: Option[InnerType]).returns(Option[InnerType]) }
  134. 1 def or(default)
  135. 2 default
  136. end
  137. 2 sig { override.type_parameters(:ErrType).params(err: T.type_parameter(:ErrType)).returns(Mangrove::Result[InnerType, T.type_parameter(:ErrType)]) }
  138. 1 def transpose(err)
  139. 1 Result::Err.new(err)
  140. end
  141. end
  142. 2 sig { abstract.params(other: BasicObject).returns(T::Boolean) }
  143. 1 def ==(other); end
  144. 2 sig { abstract.params(default: InnerType).returns(InnerType) }
  145. 1 def unwrap_or(default); end
  146. 2 sig { abstract.returns(InnerType) }
  147. 1 def unwrap!; end
  148. 2 sig { abstract.params(message: String).returns(InnerType) }
  149. 1 def expect!(message); end
  150. 2 sig { abstract.params(block: T.proc.returns(T.untyped)).returns(InnerType) }
  151. 1 def expect_with!(&block); end
  152. 2 sig { abstract.returns(T::Boolean) }
  153. 1 def some?; end
  154. 2 sig { abstract.returns(T::Boolean) }
  155. 1 def none?; end
  156. 2 sig { abstract.type_parameters(:NewInnerType).params(block: T.proc.params(inner: InnerType).returns(Option[T.type_parameter(:NewInnerType)])).returns(::Mangrove::Option[T.type_parameter(:NewInnerType)]) }
  157. 1 def map(&block); end
  158. 2 sig { abstract.params(default: Option[InnerType]).returns(Option[InnerType]) }
  159. 1 def or(default); end
  160. 2 sig { abstract.type_parameters(:ErrType).params(err: T.type_parameter(:ErrType)).returns(Mangrove::Result[InnerType, T.type_parameter(:ErrType)]) }
  161. 1 def transpose(err); end
  162. end
  163. end

lib/mangrove/option/control_signal.rb

94.12% lines covered

50.0% branches covered

17 relevant lines. 16 lines covered and 1 lines missed.
2 total branches, 1 branches covered and 1 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. 1 require "mangrove/control_flow/control_signal"
  4. 1 module Mangrove
  5. 1 module Option
  6. 1 class ControlSignal < StandardError
  7. 1 extend T::Sig
  8. 1 include Mangrove::ControlFlow::ControlSignal
  9. 2 sig { params(inner_value: T.untyped).void }
  10. 1 def initialize(inner_value)
  11. 5 @inner_value = inner_value
  12. 5 super
  13. end
  14. 2 sig { override.params(other: BasicObject).returns(T::Boolean) }
  15. 1 def ==(other)
  16. 2 case other
  17. when: 2 when ControlSignal
  18. 2 other.inner_value == inner_value
  19. else: 0 else
  20. false
  21. end
  22. end
  23. 2 sig { override.returns(T.untyped) }
  24. 1 attr_reader :inner_value
  25. end
  26. end
  27. end

lib/mangrove/result.rb

98.74% lines covered

73.33% branches covered

318 relevant lines. 314 lines covered and 4 lines missed.
15 total branches, 11 branches covered and 4 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. 1 require_relative "result/control_signal"
  4. 1 require_relative "result/ext"
  5. 1 require_relative "result/collector"
  6. 1 module Mangrove
  7. # Result is a type that represents either success (`Ok`) or failure (`Err`).
  8. 1 module Result
  9. 1 extend T::Sig
  10. 1 extend T::Generic
  11. 1 extend T::Helpers
  12. 1 include Kernel
  13. 1 sealed!
  14. 1 interface!
  15. 1 OkType = type_member(:out)
  16. 1 ErrType = type_member(:out)
  17. 2 sig { abstract.params(other: BasicObject).returns(T::Boolean) }
  18. 1 def ==(other); end
  19. # @deprecated Use #is_a?(Result::Ok) instead to enable Sorbet to define types statically.
  20. # This method will be removed in future versions.
  21. 2 sig { abstract.returns(T::Boolean) }
  22. 1 def ok?; end
  23. # @deprecated Use #is_a?(Result::Err) instead to enable Sorbet to define types statically.
  24. 2 sig { abstract.returns(T::Boolean) }
  25. 1 def err?; end
  26. 2 sig { abstract.returns(OkType) }
  27. 1 def unwrap!; end
  28. 2 sig { abstract.params(block: T.proc.params(err: ErrType).returns(Exception)).returns(OkType) }
  29. 1 def unwrap_or_raise_with!(&block); end
  30. 2 sig { abstract.params(exception: Exception).returns(OkType) }
  31. 1 def unwrap_or_raise!(exception); end
  32. 2 sig { abstract.returns(OkType) }
  33. 1 def unwrap_or_raise_inner!; end
  34. 2 sig { abstract.params(ctx: Result::CollectingContext[T.untyped, ErrType]).returns(OkType) }
  35. 1 def unwrap_in(ctx); end
  36. 2 sig { abstract.params(message: String).returns(OkType) }
  37. 1 def expect!(message); end
  38. 2 sig { abstract.type_parameters(:E).params(block: T.proc.params(err: ErrType).returns(T.type_parameter(:E))).returns(OkType) }
  39. 1 def expect_with!(&block); end
  40. 2 sig { abstract.type_parameters(:NewOkType, :NewErrType).params(block: T.proc.params(this: Result[OkType, ErrType]).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  41. 1 def map(&block); end
  42. 2 sig { abstract.type_parameters(:NewOkType, :NewErrType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], _t_new_err: T::Class[T.type_parameter(:NewErrType)], block: T.proc.params(this: Result[OkType, ErrType]).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  43. 1 def map_wt(_t_new_ok, _t_new_err, &block); end
  44. 2 sig { abstract.type_parameters(:NewOkType).params(block: T.proc.params(this: OkType).returns(T.type_parameter(:NewOkType))).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  45. 1 def map_ok(&block); end
  46. 2 sig { abstract.type_parameters(:NewOkType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], block: T.proc.params(this: OkType).returns(T.type_parameter(:NewOkType))).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  47. 1 def map_ok_wt(_t_new_ok, &block); end
  48. 2 sig { abstract.type_parameters(:NewErrType).params(block: T.proc.params(this: ErrType).returns(T.type_parameter(:NewErrType))).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  49. 1 def map_err(&block); end
  50. 2 sig { abstract.type_parameters(:NewErrType).params(_t_new_err: T::Class[T.type_parameter(:NewErrType)], block: T.proc.params(this: ErrType).returns(T.type_parameter(:NewErrType))).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  51. 1 def map_err_wt(_t_new_err, &block); end
  52. 2 sig { abstract.params(block: T.proc.params(this: OkType).void).returns(Result[OkType, ErrType]) }
  53. 1 def tap_ok(&block); end
  54. 2 sig { abstract.params(block: T.proc.params(this: ErrType).void).returns(Result[OkType, ErrType]) }
  55. 1 def tap_err(&block); end
  56. 2 sig { abstract.type_parameters(:NewOkType, :NewErrType).params(other: Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]).returns(T.any(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)], Result[T.type_parameter(:NewOkType), ErrType])) }
  57. 1 def and(other); end
  58. 2 sig { abstract.type_parameters(:NewOkType, :NewErrType).params(block: T.proc.params(this: OkType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(T.any(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)], Result[T.type_parameter(:NewOkType), ErrType])) }
  59. 1 def and_then(&block); end
  60. 2 sig { abstract.type_parameters(:NewOkType, :NewErrType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], block: T.proc.params(this: OkType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(T.any(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)], Result[T.type_parameter(:NewOkType), ErrType])) }
  61. 1 def and_then_wt(_t_new_ok, &block); end
  62. 1 sig {
  63. 1 abstract
  64. .type_parameters(:NewErrType)
  65. .params(
  66. new_err_inner: T.type_parameter(:NewErrType),
  67. condition: T.proc.params(inner: OkType).returns(T::Boolean)
  68. )
  69. .returns(
  70. T.any(Result[OkType, T.type_parameter(:NewErrType)], Result[OkType, ErrType])
  71. )
  72. }
  73. 1 def and_err_if(new_err_inner, &condition); end
  74. 2 sig { abstract.type_parameters(:NewOkType, :NewErrType).params(other: Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]).returns(T.any(Result[OkType, T.type_parameter(:NewErrType)], Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])) }
  75. 1 def or(other); end
  76. 2 sig { abstract.type_parameters(:NewOkType, :NewErrType).params(block: T.proc.params(this: ErrType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(T.any(Result[OkType, T.type_parameter(:NewErrType)], Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])) }
  77. 1 def or_else(&block); end
  78. 2 sig { abstract.type_parameters(:NewOkType, :NewErrType).params(_t_new_err: T::Class[T.type_parameter(:NewErrType)], block: T.proc.params(this: ErrType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(T.any(Result[OkType, T.type_parameter(:NewErrType)], Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])) }
  79. 1 def or_else_wt(_t_new_err, &block); end
  80. 1 sig {
  81. 1 abstract
  82. .type_parameters(:NewOkType)
  83. .params(
  84. new_ok_inner: T.type_parameter(:NewOkType),
  85. condition: T.proc.params(inner: ErrType).returns(T::Boolean)
  86. )
  87. .returns(
  88. T.any(Result[T.type_parameter(:NewOkType), ErrType], Result[OkType, ErrType])
  89. )
  90. }
  91. 1 def or_ok_if(new_ok_inner, &condition); end
  92. 1 class << self
  93. 1 extend T::Sig
  94. 1 extend T::Generic
  95. 1 OkType = type_member
  96. 1 ErrType = type_member
  97. 2 sig { type_parameters(:T, :E).params(results: T::Enumerable[Result[T.type_parameter(:T), T.type_parameter(:E)]]).returns(Result[T::Enumerable[T.type_parameter(:T)], T::Enumerable[T.type_parameter(:E)]]) }
  98. 1 def from_results(results)
  99. 4 errs = results.filter(&:err?)
  100. 4 if errs.empty?
  101. then: 2 # This is safe as errs is empty.
  102. 8 Result::Ok[T::Enumerable[T.type_parameter(:T)]].new(results.map { |r| T.cast(r, Result::Ok[T.type_parameter(:T)]).ok_inner })
  103. else
  104. else: 2 # This is safe as errs is results where err? is true
  105. 6 Result::Err[T::Enumerable[T.type_parameter(:E)]].new(errs.map { |r| T.cast(r, Result::Err[T.type_parameter(:E)]).err_inner })
  106. end
  107. end
  108. 2 sig { type_parameters(:OkType).params(inner: T.type_parameter(:OkType)).returns(Result::Ok[T.type_parameter(:OkType)]) }
  109. 1 def ok(inner)
  110. 4 Result::Ok[T.type_parameter(:OkType)].new(inner)
  111. end
  112. # @deprecated
  113. 2 sig { type_parameters(:OkType, :ErrType).params(inner: T.type_parameter(:OkType), _t_err: T::Class[T.type_parameter(:ErrType)]).returns(Result::Ok[T.type_parameter(:OkType)]) }
  114. 1 def ok_wt(inner, _t_err)
  115. 13 Result::Ok[T.type_parameter(:OkType)].new(inner)
  116. end
  117. 2 sig { type_parameters(:ErrType).params(inner: T.type_parameter(:ErrType)).returns(Result::Err[T.type_parameter(:ErrType)]) }
  118. 1 def err(inner)
  119. 1 Result::Err[T.type_parameter(:ErrType)].new(inner)
  120. end
  121. # @deprecated
  122. 2 sig { type_parameters(:OkType, :ErrType).params(_t_ok: T::Class[T.type_parameter(:OkType)], inner: T.type_parameter(:ErrType)).returns(Result::Err[T.type_parameter(:ErrType)]) }
  123. 1 def err_wt(_t_ok, inner)
  124. 10 Result::Err[T.type_parameter(:ErrType)].new(inner)
  125. end
  126. 1 sig {
  127. 1 type_parameters(:O, :E)
  128. .params(
  129. _t_ok: T::Class[T.type_parameter(:O)],
  130. _t_err: T::Class[T.type_parameter(:E)],
  131. block: T.proc.params(
  132. do_block: CollectingContext[T.type_parameter(:O), T.type_parameter(:E)]
  133. ).returns(Mangrove::Result[T.type_parameter(:O), T.type_parameter(:E)])
  134. )
  135. .returns(Mangrove::Result[T.type_parameter(:O), T.type_parameter(:E)])
  136. }
  137. 1 def collecting(_t_ok, _t_err, &block)
  138. 5 catch(:__mangrove_result_collecting_context_return) {
  139. 5 block.call(CollectingContext[T.type_parameter(:O), T.type_parameter(:E)].new)
  140. }
  141. end
  142. end
  143. 1 class CollectingContext
  144. 1 extend T::Sig
  145. 1 extend T::Generic
  146. 1 O = type_member
  147. 1 E = type_member
  148. 2 sig { type_parameters(:T).params(result: Mangrove::Result[T.type_parameter(:T), E]).returns(T.type_parameter(:T)) }
  149. 1 def try!(result)
  150. 10 case result
  151. when: 7 when Mangrove::Result::Ok
  152. 7 result.ok_inner
  153. when: 3 when Mangrove::Result::Err
  154. 3 throw :__mangrove_result_collecting_context_return, result
  155. else: 0 else
  156. T.absurd(result)
  157. end
  158. end
  159. end
  160. 1 class Ok
  161. 1 extend T::Sig
  162. 1 extend T::Generic
  163. 1 extend T::Helpers
  164. 1 include Result
  165. 1 OkType = type_member
  166. 1 ErrType = type_member { { fixed: T.noreturn } }
  167. 2 sig { params(inner: OkType).void }
  168. 1 def initialize(inner)
  169. 165 @inner = inner
  170. end
  171. 2 sig { override.params(other: BasicObject).returns(T::Boolean) }
  172. 1 def ==(other)
  173. 50 case other
  174. when: 50 when Result::Ok
  175. 50 other.instance_variable_get(:@inner) == @inner
  176. when: 0 when Result::Err
  177. false
  178. else # rubocop:disable Lint/DuplicateBranch
  179. else: 0 # Because == is defined on BasicObject, we can't be sure that `other` is an Option
  180. false
  181. end
  182. end
  183. 2 sig { returns(OkType) }
  184. 1 def ok_inner
  185. 20 @inner
  186. end
  187. 2 sig { override.returns(OkType) }
  188. 1 def unwrap!
  189. 6 @inner
  190. end
  191. 2 sig { override.params(_exception: Exception).returns(OkType) }
  192. 1 def unwrap_or_raise!(_exception)
  193. 2 @inner
  194. end
  195. 2 sig { override.params(_block: T.proc.params(err: ErrType).returns(Exception)).returns(OkType) }
  196. 1 def unwrap_or_raise_with!(&_block)
  197. 2 @inner
  198. end
  199. 2 sig { override.returns(OkType) }
  200. 1 def unwrap_or_raise_inner!
  201. 2 @inner
  202. end
  203. 2 sig { override.params(_ctx: Result::CollectingContext[T.untyped, ErrType]).returns(OkType) }
  204. 1 def unwrap_in(_ctx)
  205. 5 @inner
  206. end
  207. 2 sig { override.params(_message: String).returns(OkType) }
  208. 1 def expect!(_message)
  209. 2 @inner
  210. end
  211. 2 sig { override.type_parameters(:E).params(_block: T.proc.params(err: ErrType).returns(T.type_parameter(:E))).returns(OkType) }
  212. 1 def expect_with!(&_block)
  213. 2 @inner
  214. end
  215. # @deprecated Use #is_a?(Result::Ok) instead to enable Sorbet to define types statically.
  216. 2 sig { override.returns(T::Boolean) }
  217. 1 def ok? = true
  218. # @deprecated Use #is_a?(Result::Err) instead to enable Sorbet to define types statically.
  219. 2 sig { override.returns(T::Boolean) }
  220. 1 def err? = false
  221. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(block: T.proc.params(this: Result[OkType, ErrType]).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  222. 1 def map(&block)
  223. 2 block.call(self)
  224. end
  225. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], _t_new_err: T::Class[T.type_parameter(:NewErrType)], block: T.proc.params(this: Result[OkType, ErrType]).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  226. 1 def map_wt(_t_new_ok, _t_new_err, &block)
  227. 2 block.call(self)
  228. end
  229. 2 sig { override.type_parameters(:NewOkType).params(block: T.proc.params(this: OkType).returns(T.type_parameter(:NewOkType))).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  230. 1 def map_ok(&block)
  231. 4 Result::Ok[T.type_parameter(:NewOkType)].new(block.call(@inner))
  232. end
  233. # Because sorbet does not deduct types from return values well. This method takes a type of new inner values.
  234. 2 sig { override.type_parameters(:NewOkType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], block: T.proc.params(this: OkType).returns(T.type_parameter(:NewOkType))).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  235. 1 def map_ok_wt(_t_new_ok, &block)
  236. 2 Result::Ok[T.type_parameter(:NewOkType)].new(block.call(@inner))
  237. end
  238. 2 sig { override.type_parameters(:NewErrType).params(_block: T.proc.params(this: ErrType).returns(T.type_parameter(:NewErrType))).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  239. 1 def map_err(&_block)
  240. 2 self
  241. end
  242. # Because sorbet does not deduct types from return values well. This method takes a type of new inner values.
  243. 2 sig { override.type_parameters(:NewErrType).params(_t_new_err: T::Class[T.type_parameter(:NewErrType)], _block: T.proc.params(this: ErrType).returns(T.type_parameter(:NewErrType))).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  244. 1 def map_err_wt(_t_new_err, &_block)
  245. 7 self
  246. end
  247. 2 sig { override.params(block: T.proc.params(this: OkType).void).returns(Result[OkType, ErrType]) }
  248. 1 def tap_ok(&block)
  249. 2 block.call(@inner)
  250. 2 self
  251. end
  252. 2 sig { override.params(_block: T.proc.params(this: ErrType).void).returns(Result[OkType, ErrType]) }
  253. 1 def tap_err(&_block)
  254. 2 self
  255. end
  256. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(other: Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  257. 1 def and(other)
  258. 2 other
  259. end
  260. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(block: T.proc.params(this: OkType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  261. 1 def and_then(&block)
  262. 2 block.call(@inner)
  263. end
  264. # @deprecated
  265. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], block: T.proc.params(this: OkType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  266. 1 def and_then_wt(_t_new_ok, &block)
  267. 8 block.call(@inner)
  268. end
  269. 1 sig {
  270. 1 override
  271. .type_parameters(:NewErrType)
  272. .params(
  273. new_err_inner: T.type_parameter(:NewErrType),
  274. condition: T.proc.params(inner: OkType).returns(T::Boolean)
  275. )
  276. .returns(
  277. Result[OkType, T.type_parameter(:NewErrType)]
  278. )
  279. }
  280. 1 def and_err_if(new_err_inner, &condition)
  281. 4 then: 2 if condition.call(@inner)
  282. 2 Result::Err[T.type_parameter(:NewErrType)].new(new_err_inner)
  283. else: 2 else
  284. 2 self
  285. end
  286. end
  287. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_other: Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  288. 1 def or(_other)
  289. 2 self
  290. end
  291. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_block: T.proc.params(this: ErrType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  292. 1 def or_else(&_block)
  293. 2 self
  294. end
  295. # @deprecated
  296. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_t_new_err: T::Class[T.type_parameter(:NewErrType)], _block: T.proc.params(this: ErrType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  297. 1 def or_else_wt(_t_new_err, &_block)
  298. 2 self
  299. end
  300. 1 sig {
  301. 1 override
  302. .type_parameters(:NewOkType)
  303. .params(
  304. _new_ok_inner: T.type_parameter(:NewOkType),
  305. _condition: T.proc.params(inner: ErrType).returns(T::Boolean)
  306. )
  307. .returns(
  308. Result[OkType, ErrType]
  309. )
  310. }
  311. 1 def or_ok_if(_new_ok_inner, &_condition)
  312. 4 self
  313. end
  314. 2 sig { returns(T::Array[OkType]) }
  315. 1 def deconstruct
  316. 2 [@inner]
  317. end
  318. 2 sig { params(_keys: T.nilable(T::Array[Symbol])).returns(T::Hash[Symbol, OkType]) }
  319. 1 def deconstruct_keys(_keys)
  320. 3 { inner: @inner }
  321. end
  322. 2 sig { returns(String) }
  323. 1 def to_s
  324. 1 "#{super}: inner=`#{@inner}`"
  325. end
  326. end
  327. 1 class Err
  328. 1 extend T::Sig
  329. 1 extend T::Generic
  330. 1 extend T::Helpers
  331. 1 include Result
  332. 1 OkType = type_member { { fixed: T.noreturn } }
  333. 1 ErrType = type_member
  334. 2 sig { params(inner: ErrType).void }
  335. 1 def initialize(inner)
  336. 134 @inner = inner
  337. end
  338. 2 sig { override.params(other: BasicObject).returns(T::Boolean) }
  339. 1 def ==(other)
  340. 50 case other
  341. when: 0 when Result::Ok
  342. false
  343. when: 49 when Result::Err
  344. 49 other.instance_variable_get(:@inner) == @inner
  345. else # rubocop:disable Lint/DuplicateBranch
  346. else: 1 # Because == is defined on BasicObject, we can't be sure that `other` is an Option
  347. 1 false
  348. end
  349. end
  350. 2 sig { returns(ErrType) }
  351. 1 def err_inner
  352. 10 @inner
  353. end
  354. 2 sig { override.returns(OkType) }
  355. 1 def unwrap!
  356. 2 raise Result::ControlSignal, @inner
  357. end
  358. 2 sig { override.params(exception: Exception).returns(OkType) }
  359. 1 def unwrap_or_raise!(exception)
  360. 1 raise exception
  361. end
  362. 2 sig { override.params(block: T.proc.params(err: ErrType).returns(Exception)).returns(OkType) }
  363. 1 def unwrap_or_raise_with!(&block)
  364. 1 raise block.call(@inner)
  365. end
  366. 2 sig { override.returns(OkType) }
  367. 1 def unwrap_or_raise_inner!
  368. 1 raise T.unsafe(@inner)
  369. end
  370. 2 sig { override.params(_ctx: Result::CollectingContext[T.untyped, ErrType]).returns(T.noreturn) }
  371. 1 def unwrap_in(_ctx)
  372. 2 throw :__mangrove_result_collecting_context_return, self
  373. end
  374. 2 sig { override.params(message: String).returns(OkType) }
  375. 1 def expect!(message)
  376. 1 raise Result::ControlSignal, message
  377. end
  378. 2 sig { override.type_parameters(:E).params(block: T.proc.params(err: ErrType).returns(T.type_parameter(:E))).returns(OkType) }
  379. 1 def expect_with!(&block)
  380. 1 raise Result::ControlSignal, block.call(@inner)
  381. end
  382. # @deprecated Use #is_a?(Result::Ok) instead to enable Sorbet to define types statically.
  383. 2 sig { override.returns(T::Boolean) }
  384. 1 def ok? = false
  385. # @deprecated Use #is_a?(Result::Err) instead to enable Sorbet to define types statically.
  386. 2 sig { override.returns(T::Boolean) }
  387. 1 def err? = true
  388. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(block: T.proc.params(this: Result[OkType, ErrType]).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  389. 1 def map(&block)
  390. 2 block.call(self)
  391. end
  392. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], _t_new_err: T::Class[T.type_parameter(:NewErrType)], block: T.proc.params(this: Result[OkType, ErrType]).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  393. 1 def map_wt(_t_new_ok, _t_new_err, &block)
  394. 2 block.call(self)
  395. end
  396. 2 sig { override.type_parameters(:NewOkType).params(_block: T.proc.params(this: OkType).returns(T.type_parameter(:NewOkType))).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  397. 1 def map_ok(&_block)
  398. 4 self
  399. end
  400. 2 sig { override.type_parameters(:NewOkType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], _block: T.proc.params(this: OkType).returns(T.type_parameter(:NewOkType))).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  401. 1 def map_ok_wt(_t_new_ok, &_block)
  402. 2 self
  403. end
  404. 2 sig { override.type_parameters(:NewErrType).params(block: T.proc.params(this: ErrType).returns(T.type_parameter(:NewErrType))).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  405. 1 def map_err(&block)
  406. 2 Result::Err[T.type_parameter(:NewErrType)].new(block.call(@inner))
  407. end
  408. 2 sig { override.type_parameters(:NewErrType).params(_t_new_err: T::Class[T.type_parameter(:NewErrType)], block: T.proc.params(this: ErrType).returns(T.type_parameter(:NewErrType))).returns(Result[OkType, T.type_parameter(:NewErrType)]) }
  409. 1 def map_err_wt(_t_new_err, &block)
  410. 4 Result::Err[T.type_parameter(:NewErrType)].new(block.call(@inner))
  411. end
  412. 2 sig { override.params(_block: T.proc.params(this: OkType).void).returns(Result[OkType, ErrType]) }
  413. 1 def tap_ok(&_block)
  414. 2 self
  415. end
  416. 2 sig { override.params(block: T.proc.params(this: ErrType).void).returns(Result[OkType, ErrType]) }
  417. 1 def tap_err(&block)
  418. 2 block.call(@inner)
  419. 2 self
  420. end
  421. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_other: Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  422. 1 def and(_other)
  423. 1 self
  424. end
  425. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_block: T.proc.params(this: OkType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  426. 1 def and_then(&_block)
  427. 2 self
  428. end
  429. # @deprecated
  430. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_t_new_ok: T::Class[T.type_parameter(:NewOkType)], _block: T.proc.params(this: OkType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), ErrType]) }
  431. 1 def and_then_wt(_t_new_ok, &_block)
  432. 3 self
  433. end
  434. 1 sig {
  435. 1 override
  436. .type_parameters(:NewErrType)
  437. .params(
  438. _new_err_inner: T.type_parameter(:NewErrType),
  439. _condition: T.proc.params(inner: OkType).returns(T::Boolean)
  440. )
  441. .returns(
  442. Result[OkType, ErrType]
  443. )
  444. }
  445. 1 def and_err_if(_new_err_inner, &_condition)
  446. 4 self
  447. end
  448. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(other: Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  449. 1 def or(other)
  450. 2 other
  451. end
  452. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(block: T.proc.params(this: ErrType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  453. 1 def or_else(&block)
  454. 2 block.call(@inner)
  455. end
  456. 2 sig { override.type_parameters(:NewOkType, :NewErrType).params(_t_new_err: T::Class[T.type_parameter(:NewErrType)], block: T.proc.params(this: ErrType).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)])).returns(Result[T.type_parameter(:NewOkType), T.type_parameter(:NewErrType)]) }
  457. 1 def or_else_wt(_t_new_err, &block)
  458. 2 block.call(@inner)
  459. end
  460. 1 sig {
  461. 1 override
  462. .type_parameters(:NewOkType)
  463. .params(
  464. new_ok_inner: T.type_parameter(:NewOkType),
  465. condition: T.proc.params(inner: ErrType).returns(T::Boolean)
  466. )
  467. .returns(
  468. Result[T.type_parameter(:NewOkType), ErrType]
  469. )
  470. }
  471. 1 def or_ok_if(new_ok_inner, &condition)
  472. 4 then: 2 if condition.call(@inner)
  473. 2 Result::Ok[T.type_parameter(:NewOkType)].new(new_ok_inner)
  474. else: 2 else
  475. 2 self
  476. end
  477. end
  478. 2 sig { returns(T::Array[ErrType]) }
  479. 1 def deconstruct
  480. 2 [@inner]
  481. end
  482. 2 sig { params(_keys: T.nilable(T::Array[Symbol])).returns(T::Hash[Symbol, ErrType]) }
  483. 1 def deconstruct_keys(_keys)
  484. 3 { inner: @inner }
  485. end
  486. 2 sig { returns(String) }
  487. 1 def to_s
  488. 1 "#{super}: inner=`#{@inner}`"
  489. end
  490. end
  491. end
  492. end

lib/mangrove/result/collector.rb

100.0% lines covered

100.0% branches covered

12 relevant lines. 12 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # typed: true
  2. # frozen_string_literal: true
  3. 1 module Mangrove
  4. 1 module Result
  5. 1 class Collector
  6. 1 extend T::Sig
  7. 1 extend T::Generic
  8. 1 extend T::Helpers
  9. 1 OkType = type_member
  10. 1 ErrType = type_member
  11. 2 sig { params(block: T.proc.params(ctx: CollectingContext[OkType, ErrType]).returns(Result[OkType, ErrType])).returns(Result[OkType, ErrType]) }
  12. 1 def collecting(&block)
  13. 1 catch(:__mangrove_result_collecting_context_return) {
  14. 1 block.call(CollectingContext[OkType, ErrType].new)
  15. }
  16. end
  17. end
  18. end
  19. end

lib/mangrove/result/control_signal.rb

94.12% lines covered

50.0% branches covered

17 relevant lines. 16 lines covered and 1 lines missed.
2 total branches, 1 branches covered and 1 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. 1 require "mangrove/control_flow/control_signal"
  4. 1 module Mangrove
  5. 1 module Result
  6. 1 class ControlSignal < StandardError
  7. 1 extend T::Sig
  8. 1 include Mangrove::ControlFlow::ControlSignal
  9. 2 sig { params(inner_value: T.untyped).void }
  10. 1 def initialize(inner_value)
  11. 6 @inner_value = inner_value
  12. 6 super
  13. end
  14. 2 sig { override.params(other: BasicObject).returns(T::Boolean) }
  15. 1 def ==(other)
  16. 2 case other
  17. when: 2 when ControlSignal
  18. 2 other.inner_value == inner_value
  19. else: 0 else
  20. false
  21. end
  22. end
  23. 2 sig { override.returns(T.untyped) }
  24. 1 attr_reader :inner_value
  25. end
  26. end
  27. end

lib/mangrove/result/ext.rb

100.0% lines covered

100.0% branches covered

8 relevant lines. 8 lines covered and 0 lines missed.
0 total branches, 0 branches covered and 0 branches missed.
    
  1. # typed: true
  2. # frozen_string_literal: true
  3. 1 module Mangrove
  4. 1 module Result
  5. 1 module Ext
  6. 1 extend T::Sig
  7. 1 def in_ok
  8. 5 Mangrove::Result::Ok.new(self)
  9. end
  10. 1 def in_err
  11. 5 Mangrove::Result::Err.new(self)
  12. end
  13. end
  14. end
  15. end

lib/mangrove/try_from_ext.rb

100.0% lines covered

100.0% branches covered

18 relevant lines. 18 lines covered and 0 lines missed.
2 total branches, 2 branches covered and 0 branches missed.
    
  1. # typed: true
  2. # frozen_string_literal: true
  3. 1 module Mangrove
  4. 1 module TryFromExt
  5. 1 extend T::Sig
  6. 1 extend T::Helpers
  7. 1 include Kernel
  8. 1 sig {
  9. 1 type_parameters(:I, :O, :E)
  10. .params(
  11. from: T::Class[T.type_parameter(:I)],
  12. to: T::Class[T.type_parameter(:O)],
  13. err: T::Class[T.type_parameter(:E)],
  14. block: T.proc.params(arg: T.type_parameter(:I)).returns(Mangrove::Result[T.type_parameter(:O), T.type_parameter(:E)])
  15. ).void
  16. }
  17. # rubocop:disable Lint/UnusedMethodArgument
  18. 1 def try_convert_from(from:, to:, err:, &block)
  19. 9 T.bind(self, T::Class[T.type_parameter(:O)])
  20. 9 vars = from.instance_variable_get(:@convertable_to) || {}
  21. 9 vars[self] = block
  22. 9 from.instance_variable_set(:@convertable_to, vars)
  23. 9 @convertable_from ||= {}
  24. 9 @convertable_from[from] = [err, block]
  25. 9 into_t = T.cast(self, Class)
  26. 9 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
  27. 11 then: 5 else: 1 proc = T.unsafe(self).class.ancestors.lazy.map { |klass| klass.instance_variable_get(:@convertable_to)&.[](into_t) }.find(&:itself)
  28. 5 proc.call(self)
  29. end
  30. end
  31. # rubocop:enable Lint/UnusedMethodArgument
  32. end
  33. end

lib/tapioca/dsl/compilers/mangrove_enum.rb

82.0% lines covered

40.0% branches covered

50 relevant lines. 41 lines covered and 9 lines missed.
10 total branches, 4 branches covered and 6 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. 1 require "mangrove"
  4. 1 require "tapioca/dsl"
  5. # @api private
  6. 1 module Tapioca
  7. 1 module Compilers
  8. 1 class MangroveEnum < Tapioca::Dsl::Compiler
  9. 1 extend T::Sig
  10. 1 ConstantType = type_member { { fixed: T.class_of(::Mangrove::Enum) } }
  11. 2 sig { override.returns(T::Enumerable[Module]) }
  12. 1 def self.gather_constants
  13. 2660 all_classes.select { |c| c.singleton_class < ::Mangrove::Enum && T::AbstractUtils.abstract_module?(c) }
  14. end
  15. 2 sig { override.void }
  16. 1 def decorate
  17. 1 root.create_path(constant) { |constant_type|
  18. 1 constant_type.nodes.append(
  19. RBI::Helper.new("abstract"),
  20. RBI::Helper.new("sealed")
  21. )
  22. 1 variants = constant
  23. .constants
  24. .filter_map { |variant_name|
  25. 1 maybe_variant = constant.const_get(variant_name, false)
  26. 1 then: 1 else: 0 if maybe_variant.instance_variable_defined?(:@__mangrove__enum_inner_type)
  27. 1 maybe_variant
  28. end
  29. }
  30. 1 .sort_by { |variant| variant.name.to_s }
  31. 1 inner_types = variants.map { |variant|
  32. 1 inner_type = runtime_type_to_type_name(variant.instance_variable_get(:@__mangrove__enum_inner_type))
  33. 1 constant_type.create_class(variant.name.gsub(/.*::/, ""), superclass_name: constant_type.fully_qualified_name) { |variant_type|
  34. 1 variant_type.create_method("initialize", parameters: [create_param("inner", type: inner_type)], return_type: "void")
  35. 1 variant_type.create_method("serialize", parameters: [create_kw_opt_param("inner_serialization_methods", type: "T.nilable(T::Array[Symbol])", default: "[:serialize, :to_h]")], return_type: "T::Hash[Symbol, T.untyped]")
  36. 1 variant_type.create_method("inner", return_type: inner_type)
  37. 1 variant_type.create_method("as_super", return_type: constant.name.to_s)
  38. 1 variant_type.sort_nodes!
  39. }
  40. 1 inner_type
  41. }
  42. 1 then: 1 return_type = if inner_types.size == 1
  43. 1 T.must(inner_types.first)
  44. else: 0 else
  45. "T.any(#{inner_types.join(", ")})"
  46. end
  47. 1 constant_type.create_method("inner", return_type:)
  48. 1 constant_type.create_method("serialize", parameters: [create_kw_opt_param("inner_serialization_methods", type: "T.nilable(T::Array[Symbol])", default: "[:serialize, :to_h]")], return_type: "T::Hash[Symbol, T.untyped]")
  49. 1 constant_type.create_method("deserialize", parameters: [create_param("hash", type: "T::Hash[T.any(Symbol, String), T.untyped]")], return_type: constant.name, class_method: true)
  50. 1 constant_type.create_method("as_super", return_type: constant.name.to_s)
  51. 1 constant_type.sort_nodes!
  52. }
  53. end
  54. 1 private
  55. 2 sig { params(runtime_type: T.untyped).returns(String) }
  56. 1 def runtime_type_to_type_name(runtime_type)
  57. 1 then: 0 if runtime_type.is_a?(Array)
  58. content = runtime_type.map { |inner|
  59. runtime_type_to_type_name(inner)
  60. }.join(", ")
  61. else: 1 "[#{content}]"
  62. 1 then: 0 elsif runtime_type.is_a?(Hash)
  63. content = runtime_type.map { |k, v|
  64. else: 0 then: 0 unless k.is_a?(Symbol) || k.is_a?(String)
  65. raise "shape key must be Symbol or String"
  66. end
  67. "#{k}: #{runtime_type_to_type_name(v)}"
  68. }.join(", ")
  69. "{ #{content} }"
  70. else: 1 else
  71. 1 runtime_type.to_s
  72. end
  73. end
  74. end
  75. end
  76. end

lib/tapioca/dsl/compilers/mangrove_result_ext.rb

100.0% lines covered

50.0% branches covered

21 relevant lines. 21 lines covered and 0 lines missed.
2 total branches, 1 branches covered and 1 branches missed.
    
  1. # typed: strict
  2. # frozen_string_literal: true
  3. 1 require "mangrove/result/ext"
  4. 1 require "tapioca/dsl"
  5. 1 require "sorbet-runtime"
  6. 1 module Tapioca
  7. 1 module Compilers
  8. 1 class MangroveResultExt < Tapioca::Dsl::Compiler
  9. 1 extend T::Sig
  10. 1 ConstantType = type_member { { fixed: T.class_of(Mangrove::Result::Ext) } }
  11. 2 sig { override.returns(T::Enumerable[Module]) }
  12. 1 def self.gather_constants
  13. 4527 all_classes.select { |c| c < ::Mangrove::Result::Ext }
  14. end
  15. 2 sig { override.void }
  16. 1 def decorate
  17. 2 else: 2 then: 0 return unless valid_constant_name?(constant.to_s)
  18. 2 root.create_path(constant) do |klass|
  19. 2 klass.create_method("in_ok", return_type: "Mangrove::Result::Ok[#{constant}]")
  20. 2 klass.create_method("in_err", return_type: "Mangrove::Result::Err[#{constant}]")
  21. end
  22. rescue NameError
  23. # 握りつぶす
  24. end
  25. 1 private
  26. 2 sig { params(string: String).returns(T::Boolean) }
  27. 1 def valid_constant_name?(string)
  28. 2 Object.const_defined?(string) && !!(string =~ /\A[A-Z][a-zA-Z0-9_]*\z/)
  29. end
  30. end
  31. end
  32. end

lib/tapioca/dsl/compilers/mangrove_try_from_ext.rb

77.78% lines covered

25.0% branches covered

18 relevant lines. 14 lines covered and 4 lines missed.
4 total branches, 1 branches covered and 3 branches missed.
    
  1. # typed: true
  2. # frozen_string_literal: true
  3. 1 require "mangrove/try_from_ext"
  4. 1 require "tapioca/dsl"
  5. 1 require "sorbet-runtime"
  6. 1 module Tapioca
  7. 1 module Compilers
  8. 1 class TryFromExt < Tapioca::Dsl::Compiler
  9. 1 extend T::Sig
  10. 1 ConstantType = type_member { { fixed: T.class_of(Mangrove::TryFromExt) } }
  11. 2 sig { override.returns(T::Enumerable[Module]) }
  12. 1 def self.gather_constants
  13. 8298 all_classes.select { |c| c.singleton_class < ::Mangrove::TryFromExt }
  14. end
  15. 2 sig { override.void }
  16. 1 def decorate
  17. 1 then: 1 else: 0 return if constant.instance_variable_get(:@convertable_from).nil? || constant.instance_variable_get(:@convertable_from).empty?
  18. then: 0 else: 0 constant.instance_variable_get(:@convertable_from)&.each do |convertable_from, values|
  19. err_constant, _block = values
  20. root.create_path(convertable_from) do |klass|
  21. 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}]")
  22. end
  23. end
  24. end
  25. end
  26. end
  27. end