mangrove 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +42 -0
  3. data/LICENSE +21 -0
  4. data/README.md +54 -0
  5. data/Rakefile +14 -0
  6. data/lib/mangrove/control_flow/control_signal.rb +16 -0
  7. data/lib/mangrove/control_flow/rewriter.rb +152 -0
  8. data/lib/mangrove/control_flow.rb +84 -0
  9. data/lib/mangrove/interfaces.rb +8 -0
  10. data/lib/mangrove/mangrove.rb +35 -0
  11. data/lib/mangrove/option/control_signal.rb +33 -0
  12. data/lib/mangrove/option.rb +134 -0
  13. data/lib/mangrove/result/control_signal.rb +33 -0
  14. data/lib/mangrove/result.rb +167 -0
  15. data/lib/mangrove/version.rb +6 -0
  16. data/lib/mangrove.rb +8 -0
  17. data/sig/mangrove.rbs +4 -0
  18. data/sorbet/config +4 -0
  19. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  20. data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
  21. data/sorbet/rbi/gems/base64@0.1.1.rbi +172 -0
  22. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1083 -0
  23. data/sorbet/rbi/gems/erubi@1.12.0.rbi +145 -0
  24. data/sorbet/rbi/gems/json@2.6.3.rbi +1533 -0
  25. data/sorbet/rbi/gems/language_server-protocol@3.17.0.3.rbi +14237 -0
  26. data/sorbet/rbi/gems/method_source@1.0.0.rbi +272 -0
  27. data/sorbet/rbi/gems/netrc@0.11.0.rbi +158 -0
  28. data/sorbet/rbi/gems/ordinare@0.4.0.rbi +77 -0
  29. data/sorbet/rbi/gems/parallel@1.23.0.rbi +273 -0
  30. data/sorbet/rbi/gems/parser@3.2.2.3.rbi +7253 -0
  31. data/sorbet/rbi/gems/prettier_print@1.2.1.rbi +951 -0
  32. data/sorbet/rbi/gems/racc@1.7.1.rbi +161 -0
  33. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +402 -0
  34. data/sorbet/rbi/gems/rake@13.0.6.rbi +3024 -0
  35. data/sorbet/rbi/gems/rbi@0.0.17.rbi +2972 -0
  36. data/sorbet/rbi/gems/regexp_parser@2.8.1.rbi +3749 -0
  37. data/sorbet/rbi/gems/rexml@3.2.6.rbi +4781 -0
  38. data/sorbet/rbi/gems/rspec-core@3.12.2.rbi +10805 -0
  39. data/sorbet/rbi/gems/rspec-expectations@3.12.3.rbi +8100 -0
  40. data/sorbet/rbi/gems/rspec-mocks@3.12.6.rbi +5310 -0
  41. data/sorbet/rbi/gems/rspec-sorbet@1.9.2.rbi +163 -0
  42. data/sorbet/rbi/gems/rspec-support@3.12.1.rbi +1609 -0
  43. data/sorbet/rbi/gems/rspec@3.12.0.rbi +82 -0
  44. data/sorbet/rbi/gems/ruboclean@0.4.0.rbi +189 -0
  45. data/sorbet/rbi/gems/rubocop-ast@1.29.0.rbi +6985 -0
  46. data/sorbet/rbi/gems/rubocop@1.56.0.rbi +56491 -0
  47. data/sorbet/rbi/gems/ruby-lsp@0.8.0.rbi +11 -0
  48. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1317 -0
  49. data/sorbet/rbi/gems/spoom@1.2.3.rbi +3203 -0
  50. data/sorbet/rbi/gems/syntax_tree@6.1.1.rbi +22855 -0
  51. data/sorbet/rbi/gems/tapioca@0.11.8.rbi +3349 -0
  52. data/sorbet/rbi/gems/thor@1.2.2.rbi +3965 -0
  53. data/sorbet/rbi/gems/unicode-display_width@2.4.2.rbi +65 -0
  54. data/sorbet/rbi/gems/unparser@0.6.8.rbi +4525 -0
  55. data/sorbet/rbi/gems/yard-sorbet@0.8.1.rbi +428 -0
  56. data/sorbet/rbi/gems/yard@0.9.34.rbi +18219 -0
  57. data/sorbet/rbi/shims/gems/rspec-core.rbi +12 -0
  58. data/sorbet/rbi/shims/gems/rspec-expectations.rbi +8 -0
  59. data/sorbet/rbi/shims/mangrove/option.rbi +15 -0
  60. data/sorbet/rbi/shims/mangrove/result.rbi +15 -0
  61. data/sorbet/tapioca/config.yml +13 -0
  62. data/sorbet/tapioca/require.rb +4 -0
  63. metadata +161 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b5d153e07f630102b67bf06ae910d39fd063ec6d29237ad555f33b5068837a54
4
+ data.tar.gz: 002d2fbd0168c3b0fcac8effea4455918a6a8845d124d8303e480accb2f5d634
5
+ SHA512:
6
+ metadata.gz: 26c16d1c8e83204252284f47381e6e9d9a517ba8a4b0b84ccbf65f645b0cc42f7fb3331e90a216b2490549bb409e0dc08e7942b15897bb9e9f1020f75a4ec130
7
+ data.tar.gz: 2f52b60822834d12e1c669b34088223f57bcc575b5bf2a9adf9bc25286a91e8e2e456d71415e1ee0e947455cebc1beacd8f079e296148cf13fbfa09b7aa20f25
data/.rubocop.yml ADDED
@@ -0,0 +1,42 @@
1
+ ---
2
+
3
+ AllCops:
4
+ TargetRubyVersion: 3.2
5
+
6
+ Layout/FirstArrayElementIndentation:
7
+ EnforcedStyle: consistent
8
+
9
+ Layout/LineLength:
10
+ Enabled: false
11
+
12
+ Metrics/AbcSize:
13
+ Enabled: false
14
+
15
+ Metrics/ClassLength:
16
+ Enabled: false
17
+
18
+ Metrics/MethodLength:
19
+ Enabled: false
20
+
21
+ Metrics/ModuleLength:
22
+ Enabled: false
23
+
24
+ Naming/VariableNumber:
25
+ EnforcedStyle: snake_case
26
+
27
+ Style/Documentation:
28
+ Enabled: false
29
+
30
+ Style/GuardClause:
31
+ Enabled: false
32
+
33
+ Style/IfUnlessModifier:
34
+ Enabled: false
35
+
36
+ Style/StringLiterals:
37
+ Enabled: true
38
+ EnforcedStyle: double_quotes
39
+
40
+ Style/StringLiteralsInInterpolation:
41
+ Enabled: true
42
+ EnforcedStyle: double_quotes
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Kazzix
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # Mangrove
2
+ Mangrove provides utility types to use with Sorbet
3
+
4
+ ## Features
5
+ Most features are not implemented.
6
+
7
+ - [x] Option Type (Partially Implemented)
8
+ - [x] Auto propagation like Rust's `?` (formerly `try!`)
9
+ - [x] Result Type (Partially Implemented)
10
+ - [x] Auto propagation like Rust's `?` (formerly `try!`)
11
+ - [ ] Builder type (Not implemented)
12
+ - [ ] Auto Implementation
13
+
14
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/mangrove`. To experiment with that code, run `bin/console` for an interactive prompt.
15
+
16
+ ## Installation
17
+
18
+ TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with instructions to install your gem from git if you don't plan to release to RubyGems.org.
19
+
20
+ Install the gem and add to the application's Gemfile by executing:
21
+
22
+ $ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
23
+
24
+ If bundler is not being used to manage dependencies, install the gem by executing:
25
+
26
+ $ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
27
+
28
+ ## Usage
29
+
30
+ TODO: Write usage instructions here
31
+
32
+ ## Commands
33
+ ```
34
+ bundle exec tapioca init
35
+ bundle exec tapioca gems
36
+ bundle exec tapioca dsl
37
+ bundle exec tapioca check-shims
38
+ bundle exec tapioca init
39
+ bundle exec rspec -f d
40
+ bundle exec rubocop -DESP
41
+ bundle exec srb typecheck
42
+ bundle exec ordinare --check
43
+ bundle exec ruboclean
44
+ ```
45
+
46
+ ## Development
47
+
48
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
49
+
50
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
51
+
52
+ ## Contributing
53
+
54
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/mangrove.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ task :check do
7
+ system("bundle exec ordinare --check") &&
8
+ system("bundle exec rubocop -DESP") &&
9
+ system("bundle exec tapioca check-shims") &&
10
+ system("bundle exec srb typecheck") &&
11
+ system("bundle exec rspec -f d")
12
+ end
13
+
14
+ task default: :check
@@ -0,0 +1,16 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Mangrove
5
+ module ControlFlow
6
+ module ControlSignal
7
+ extend T::Sig
8
+ extend T::Helpers
9
+
10
+ interface!
11
+
12
+ sig { abstract.returns(T.untyped) }
13
+ def inner_value; end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,152 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "parser"
5
+ require "parser/current"
6
+ require "unparser"
7
+ require "method_source"
8
+ require "sorbet-runtime"
9
+
10
+ module Mangrove
11
+ module ControlFlow
12
+ class << self
13
+ extend T::Sig
14
+
15
+ sig { params(method_to_be_rewritten: T.any(Method, UnboundMethod)).returns(String) }
16
+ def impl!(method_to_be_rewritten)
17
+ filename, line_number = method_to_be_rewritten.source_location
18
+
19
+ source = method_to_be_rewritten.source
20
+ ast = Parser::CurrentRuby.parse(source)
21
+ source_buffer = Parser::Source::Buffer.new("#{filename}:#{line_number}", source:)
22
+ rewriter = Rewriter.new
23
+ rewriter.rewrite(source_buffer, ast)
24
+ end
25
+ end
26
+
27
+ class Rewriter < Parser::TreeRewriter
28
+ CONTROL_SIGNAL = Mangrove::ControlFlow::ControlSignal
29
+
30
+ def on_def(node)
31
+ indent = node.location.expression.begin.column
32
+ code = Unparser.unparse(with_rescue(node))
33
+ indented_code = code.lines.map.with_index { |line, index| index.zero? ? line : (" " * indent) + line }
34
+ replace(node.location.expression, indented_code)
35
+ end
36
+
37
+ def on_defs(node)
38
+ indent = node.location.expression.begin.column
39
+ code = Unparser.unparse(with_rescue(node))
40
+ indented_code = code.lines.map.with_index { |line, index| index.zero? ? line : (" " * indent) + line }
41
+ replace(node.location.expression, indented_code)
42
+ end
43
+
44
+ def on_block(node)
45
+ indent = node.location.expression.begin.column
46
+ code = Unparser.unparse(with_rescue(node))
47
+ indented_code = code.lines.map.with_index { |line, index| index.zero? ? line : (" " * indent) + line }
48
+ replace(node.location.expression, indented_code)
49
+ end
50
+
51
+ private
52
+
53
+ def rescue_node(body)
54
+ ::Parser::AST::Node.new(:rescue, [
55
+ body,
56
+ nil
57
+ ])
58
+ end
59
+
60
+ def add_rescue_node(parent)
61
+ children = parent.children.dup
62
+ # nilの場合はblockをこちらで包む必要がある
63
+ # nilではない場合はすでに包まれているのでこちらで包む必要はない
64
+ method_body_index = children.length - 1
65
+ method_body = children[method_body_index]
66
+
67
+ children[method_body_index] = rescue_node(method_body)
68
+ parent.updated(nil, children)
69
+ end
70
+
71
+ def use_rescue_node(parent)
72
+ children = parent.children.dup
73
+
74
+ rescue_index = children.find_index { _1.respond_to?(:type) && _1.type == :rescue }
75
+
76
+ rescue_node_on_ast = children[rescue_index]
77
+ updated_rescue_node_on_ast = insert_rescue_body_node(rescue_node_on_ast)
78
+ children[rescue_index] = updated_rescue_node_on_ast
79
+
80
+ parent.updated(nil, children)
81
+ end
82
+
83
+ def insert_rescue_body_node(rescue_node)
84
+ rescue_node_children = rescue_node.children.dup
85
+ rescue_body_node_index = rescue_node_children.find_index { _1.respond_to?(:type) && _1.type == :resbody }
86
+
87
+ # when rescue is newly inserted
88
+ if rescue_body_node_index.nil?
89
+ rescue_body_node_index = rescue_node_children.length - 1
90
+ end
91
+
92
+ rescue_node_children.insert(rescue_body_node_index, rescue_body_node)
93
+ rescue_node.updated(nil, rescue_node_children)
94
+ end
95
+
96
+ def use_ensure_node(ensure_node)
97
+ # ensureのchildrenの最後から2番目(最後のrescue)に追加する
98
+
99
+ ensure_node_children = ensure_node.children.dup
100
+
101
+ rescue_index = ensure_node_children.find_index { _1.respond_to?(:type) && _1.type == :rescue }
102
+
103
+ if rescue_index.nil?
104
+ ensure_node = add_rescue_node(ensure_node)
105
+ end
106
+
107
+ use_rescue_node(ensure_node)
108
+ end
109
+
110
+ def with_rescue(parent)
111
+ children = parent.children.dup
112
+ ensure_index = children.find_index { _1.respond_to?(:type) && _1.type == :ensure }
113
+
114
+ if ensure_index.nil?
115
+ rescue_index = children.find_index { _1.respond_to?(:type) && _1.type == :rescue }
116
+
117
+ if rescue_index.nil?
118
+ parent = add_rescue_node(parent)
119
+ end
120
+
121
+ use_rescue_node(parent)
122
+ else
123
+ updated_ensure_node = use_ensure_node(children[ensure_index])
124
+ children[ensure_index] = updated_ensure_node
125
+ parent.updated(nil, children)
126
+ end
127
+ end
128
+
129
+ def rescue_body_node
130
+ control_flow = StandardError
131
+
132
+ ::Parser::AST::Node.new(:resbody, [
133
+ ::Parser::AST::Node.new(:array, [
134
+ ::Parser::AST::Node.new(:const, [nil, control_flow.to_s])
135
+ ]),
136
+ ::Parser::AST::Node.new(:lvasgn, [:exception]),
137
+ ::Parser::AST::Node.new(:send, [
138
+ ::Parser::AST::Node.new(:const, [
139
+ ::Parser::AST::Node.new(:const, [
140
+ nil,
141
+ :Result
142
+ ]),
143
+ :Err
144
+ ]),
145
+ :new,
146
+ ::Parser::AST::Node.new(:lvar, [:exception])
147
+ ])
148
+ ])
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,84 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "control_flow/control_signal"
5
+ require_relative "control_flow/rewriter"
6
+
7
+ module Mangrove
8
+ # Mangrove::ControlFlow
9
+ module ControlFlow
10
+ # Mangrove::ControlFlow::Handler
11
+ module Handler
12
+ extend T::Sig
13
+ extend T::Helpers
14
+
15
+ interface!
16
+
17
+ # Mangrove::ControlFlow::ClassMethods
18
+ module ClassMethods
19
+ extend T::Sig
20
+ extend T::Helpers
21
+
22
+ abstract!
23
+
24
+ def singleton_method_added(method_name)
25
+ T.bind(self, T.all(ClassMethods, Module))
26
+
27
+ super
28
+
29
+ unless @__inside_mangrove_control_flow
30
+ original_method = method(method_name)
31
+
32
+ wrap_original_method_to_handle_flow_control_exception(original_method)
33
+ end
34
+ end
35
+
36
+ def method_added(method_name)
37
+ T.bind(self, T.all(ClassMethods, Module))
38
+
39
+ super
40
+
41
+ unless @__inside_mangrove_control_flow
42
+ original_method = instance_method(method_name)
43
+
44
+ wrap_original_method_to_handle_flow_control_exception(original_method)
45
+ end
46
+ end
47
+
48
+ sig { params(signal: ControlFlow::ControlSignal).void }
49
+ def handle_flow_control_exception(signal)
50
+ signal.inner_value
51
+ end
52
+
53
+ sig { params(original_method: T.any(Method, UnboundMethod)).void }
54
+ def wrap_original_method_to_handle_flow_control_exception(original_method)
55
+ T.bind(self, T.class_of(Kernel))
56
+
57
+ @__mangrove_flow_controlled_method_names ||= T.let(
58
+ {},
59
+ T.nilable(T::Hash[Symbol, T::Set[Symbol]])
60
+ )
61
+
62
+ @__mangrove_flow_controlled_method_names[name.to_s.intern] ||= T.let(Set.new, T::Set[Symbol])
63
+
64
+ return if T.cast(@__mangrove_flow_controlled_method_names[name.to_s.intern], T::Set[Symbol]).include?(original_method.name)
65
+
66
+ begin
67
+ @__inside_mangrove_control_flow = T.let(true, T.nilable(T::Boolean))
68
+
69
+ class_eval(Mangrove::ControlFlow.impl!(original_method))
70
+ ensure
71
+ @__inside_mangrove_control_flow = false
72
+ end
73
+
74
+ T.cast(@__mangrove_flow_controlled_method_names[name.to_s.intern], T::Set[Symbol]) << original_method.name
75
+ end
76
+
77
+ sig { returns(T.nilable(T::Hash[Symbol, T::Set[Symbol]])) }
78
+ attr_reader :__mangrove_flow_controlled_method_names
79
+ end
80
+
81
+ mixes_in_class_methods(ClassMethods)
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,8 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Mangrove
5
+ module Interfaces
6
+ require_relative "interfaces/control_signal"
7
+ end
8
+ end
@@ -0,0 +1,35 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # ==============================================================================
5
+ # sorbet - tapioca - compilers - enumerize
6
+ # ==============================================================================
7
+ require "tapioca/dsl"
8
+ require "sorbet-runtime"
9
+ require "mangrove/control_flow"
10
+
11
+ ::Method.prepend(T::CompatibilityPatches::MethodExtensions)
12
+
13
+ module Tapioca
14
+ module Compilers
15
+ class Enumerize < Tapioca::Dsl::Compiler
16
+ extend T::Sig
17
+
18
+ ConstantType = type_member { { fixed: T.class_of(::Mangrove::ControlFlow::Handler) } }
19
+
20
+ sig { override.returns(T::Enumerable[Module]) }
21
+ def self.gather_constants
22
+ all_classes.find_all { |c| c < ::Mangrove::ControlFlow::Handler }
23
+ end
24
+
25
+ sig { override.void }
26
+ def decorate
27
+ root.create_path(constant) do |klass|
28
+ # constant.instance_variable_get(:@__mangrove_flow_controlled_method_names).each do |method_name|
29
+ # klass.create_method(method_name, parameters: [create_rest_param("args", type: "T.untyped")], return_type: "T.untyped")
30
+ # end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,33 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "mangrove/control_flow/control_signal"
5
+
6
+ module Mangrove
7
+ module Option
8
+ class ControlSignal < StandardError
9
+ extend T::Sig
10
+
11
+ include Mangrove::ControlFlow::ControlSignal
12
+
13
+ sig { params(inner_value: T.untyped).void }
14
+ def initialize(inner_value)
15
+ @inner_value = inner_value
16
+ super
17
+ end
18
+
19
+ sig { override.params(other: BasicObject).returns(T::Boolean) }
20
+ def ==(other)
21
+ case other
22
+ when ControlSignal
23
+ other.inner_value == inner_value
24
+ else
25
+ false
26
+ end
27
+ end
28
+
29
+ sig { override.returns(T.untyped) }
30
+ attr_reader :inner_value
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,134 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "option/control_signal"
5
+ require_relative "result"
6
+
7
+ module Mangrove
8
+ # Option is a type that represents either some value (`Some`) or no value (`None`).
9
+ module Option
10
+ extend T::Sig
11
+ extend T::Generic
12
+ extend T::Helpers
13
+
14
+ include Kernel
15
+
16
+ sealed!
17
+ interface!
18
+
19
+ InnerType = type_member
20
+
21
+ # Option::Some
22
+ class Some
23
+ extend T::Sig
24
+ extend T::Generic
25
+ extend T::Helpers
26
+
27
+ include Option
28
+
29
+ InnerType = type_member
30
+
31
+ sig { params(inner: InnerType).void }
32
+ def initialize(inner)
33
+ @inner = T.let(inner, InnerType)
34
+ end
35
+
36
+ sig { override.params(other: BasicObject).returns(T::Boolean) }
37
+ def ==(other)
38
+ case other
39
+ when Option::Some
40
+ other.instance_variable_get(:@inner) == @inner
41
+ when Option::None
42
+ false
43
+ else
44
+ # T.absurd(other)
45
+ false
46
+ end
47
+ end
48
+
49
+ sig { override.returns(InnerType) }
50
+ def unwrap!
51
+ @inner
52
+ end
53
+
54
+ sig { override.params(_message: String).returns(InnerType) }
55
+ def expect!(_message)
56
+ @inner
57
+ end
58
+
59
+ sig { override.params(block: T.proc.params(inner: InnerType).returns(Option[InnerType])).returns(Option[InnerType]) }
60
+ def map_some(&block)
61
+ block.call(@inner)
62
+ end
63
+
64
+ sig { override.params(_block: T.proc.returns(Option[InnerType])).returns(Option::Some[InnerType]) }
65
+ def map_none(&_block)
66
+ self
67
+ end
68
+
69
+ private
70
+
71
+ sig { returns(InnerType) }
72
+ attr_reader :inner
73
+ end
74
+
75
+ # Option::None
76
+ class None
77
+ extend T::Sig
78
+ extend T::Generic
79
+ extend T::Helpers
80
+
81
+ include Option
82
+
83
+ InnerType = type_member
84
+
85
+ sig { override.params(other: BasicObject).returns(T::Boolean) }
86
+ def ==(other)
87
+ case other
88
+ when Option::Some
89
+ false
90
+ when Option::None
91
+ true
92
+ else
93
+ false
94
+ # T.absurd(other)
95
+ end
96
+ end
97
+
98
+ sig { override.returns(InnerType) }
99
+ def unwrap!
100
+ raise Option::ControlSignal, Result::Err.new("called `Option#unwrap!` on an `None` value: #{self}")
101
+ end
102
+
103
+ sig { override.params(message: String).returns(InnerType) }
104
+ def expect!(message)
105
+ raise Option::ControlSignal, Result::Err.new(message)
106
+ end
107
+
108
+ sig { override.params(_block: T.proc.params(inner: InnerType).returns(Option[InnerType])).returns(Option::None[InnerType]) }
109
+ def map_some(&_block)
110
+ self
111
+ end
112
+
113
+ sig { override.params(block: T.proc.returns(Option[InnerType])).returns(Option[InnerType]) }
114
+ def map_none(&block)
115
+ block.call
116
+ end
117
+ end
118
+
119
+ sig { abstract.params(other: BasicObject).returns(T::Boolean) }
120
+ def ==(other); end
121
+
122
+ sig { abstract.returns(InnerType) }
123
+ def unwrap!; end
124
+
125
+ sig { abstract.params(message: String).returns(InnerType) }
126
+ def expect!(message); end
127
+
128
+ sig { abstract.params(block: T.proc.params(inner: InnerType).returns(Option[InnerType])).returns(Option[InnerType]) }
129
+ def map_some(&block); end
130
+
131
+ sig { abstract.params(block: T.proc.returns(Option[InnerType])).returns(Option[InnerType]) }
132
+ def map_none(&block); end
133
+ end
134
+ end
@@ -0,0 +1,33 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "mangrove/control_flow/control_signal"
5
+
6
+ module Mangrove
7
+ module Result
8
+ class ControlSignal < StandardError
9
+ extend T::Sig
10
+
11
+ include Mangrove::ControlFlow::ControlSignal
12
+
13
+ sig { params(inner_value: T.untyped).void }
14
+ def initialize(inner_value)
15
+ @inner_value = inner_value
16
+ super
17
+ end
18
+
19
+ sig { override.params(other: BasicObject).returns(T::Boolean) }
20
+ def ==(other)
21
+ case other
22
+ when ControlSignal
23
+ other.inner_value == inner_value
24
+ else
25
+ false
26
+ end
27
+ end
28
+
29
+ sig { override.returns(T.untyped) }
30
+ attr_reader :inner_value
31
+ end
32
+ end
33
+ end