data-option 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c482aa6857657bf2abcfbd51ef9bf19f485c2096645301a61a1b3391573f0bd4
4
+ data.tar.gz: 950af8e9f4b3fceec8c1dad184597a821e3e6094961bf352d31730eb627250ce
5
+ SHA512:
6
+ metadata.gz: 972535d4f3b0c310ef247a680c6cd47b7e7041285b1a8a46d3af46f91022e4c42e9d3773ef814478db32ae6e0d4c4bc43a1f64283eb7a4e3b6ba76ba9f647a87
7
+ data.tar.gz: 93fb7a298300733845dbfec34099bfde13dd6f084cceccd281fad62fc204438f903c25a1868171e3db0836503125f133e0b989ea0fa17d95af736f894f606397
data/.rubocop.yml ADDED
@@ -0,0 +1,58 @@
1
+ plugins:
2
+ - rubocop-minitest
3
+ - rubocop-rake
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 3.4
7
+ NewCops: enable
8
+
9
+ Bundler/GemFilename:
10
+ Enabled: false
11
+
12
+ Layout/SpaceInsideHashLiteralBraces:
13
+ EnforcedStyle: no_space
14
+
15
+ Lint/AmbiguousOperatorPrecedence:
16
+ Enabled: false
17
+
18
+ Lint/BinaryOperatorWithIdenticalOperands:
19
+ Enabled: false
20
+
21
+ Lint/SuppressedException:
22
+ Enabled: false
23
+
24
+ Metrics/AbcSize:
25
+ Max: 25
26
+
27
+ Metrics/ClassLength:
28
+ Max: 200
29
+
30
+ Metrics/MethodLength:
31
+ Max: 42
32
+
33
+ Minitest/MultipleAssertions:
34
+ Max: 6
35
+
36
+ Naming/FileName:
37
+ Enabled: false
38
+
39
+ Naming/MethodName:
40
+ Enabled: false
41
+
42
+ Naming/RescuedExceptionsVariableName:
43
+ Enabled: false
44
+
45
+ Style/Alias:
46
+ Enabled: false
47
+
48
+ Style/Documentation:
49
+ Enabled: false
50
+
51
+ Style/MixinUsage:
52
+ Enabled: false
53
+
54
+ Style/NumberedParametersLimit:
55
+ Max: 9
56
+
57
+ Style/RescueStandardError:
58
+ Enabled: false
data/LICENSE.txt ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) Shannon Skipper
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,291 @@
1
+ # Data::Option
2
+
3
+ This gem provides a `None` and `Some` with methods for creating, matching, and transforming optional values with Rust-like semantics.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ bundle add data-option
9
+ ```
10
+
11
+ If you're not using Bundler, install the gem with:
12
+
13
+ ```bash
14
+ gem install data-option
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ### Basic Example
20
+
21
+ To use `Some[value]` and `None[]`, first `include Data::Option`.
22
+
23
+ ```ruby
24
+ require 'data/option'
25
+
26
+ include Data::Option
27
+
28
+ def checked_division(dividend, divisor)
29
+ if divisor.zero?
30
+ None[]
31
+ else
32
+ Some[dividend / divisor]
33
+ end
34
+ end
35
+
36
+ def try_division(dividend, divisor)
37
+ case checked_division(dividend, divisor)
38
+ in None
39
+ puts "#{dividend} / #{divisor} failed!"
40
+ in Some(quotient)
41
+ puts "#{dividend} / #{divisor} = #{quotient}"
42
+ end
43
+ end
44
+
45
+ try_division(4, 2)
46
+ # >> 4 / 2 = 2
47
+ try_division(1, 0)
48
+ # >> 1 / 0 failed!
49
+ ```
50
+
51
+ ### Creating an Option Value
52
+
53
+ A `Some` or `None` can be created with multiple syntaxes:
54
+
55
+ ```ruby
56
+ require 'data/option'
57
+
58
+ include Data::Option
59
+
60
+ Some[42] # => Some[42]
61
+ None[] # => None
62
+
63
+ Some.new(42) # => Some[42]
64
+ None.instance # => None
65
+ ```
66
+
67
+ Kernel#Option creates an Option from any value:
68
+
69
+ ```ruby
70
+ require 'data/option'
71
+
72
+ Option(42) # => Some[42]
73
+ Option(false) # => Some[false]
74
+ Option(nil) # => None
75
+ ```
76
+
77
+ The equivalent class method `Option.from`:
78
+
79
+ ```ruby
80
+ require 'data/option'
81
+
82
+ # Same behavior as the Kernel method
83
+ Option.from(42) # => Some[42]
84
+ Option.from(false) # => Some[false]
85
+ Option.from(nil) # => None
86
+ ```
87
+
88
+ Enable Object#to_option via refinements:
89
+
90
+ ```ruby
91
+ require 'data/option'
92
+
93
+ using Data::Option::Refinement
94
+
95
+ 42.to_option # => Some[42]
96
+ false.to_option # => Some[false]
97
+ nil.to_option # => None
98
+
99
+ 42.to_option.map(&:succ) # => Some[43]
100
+ nil.to_option.map(&:succ) # => None
101
+ ```
102
+
103
+ ### Predicates
104
+
105
+ Check the state of your Option values with predicate methods:
106
+
107
+ ```ruby
108
+ require 'data/option'
109
+
110
+ include Data::Option
111
+
112
+ some = Some[42]
113
+ none = None[]
114
+
115
+ some.some? # => true
116
+ some.none? # => false
117
+ none.some? # => false
118
+ none.none? # => true
119
+
120
+ Some[42].some_and?(&:even?) # => true (value exists and is even)
121
+ Some[41].some_and?(&:even?) # => false (value exists but isn't even)
122
+ None[].some_and?(&:even?) # => false (no value to check)
123
+
124
+ Some[42].none_or?(&:even?) # => true (either None or predicate is true)
125
+ Some[41].none_or?(&:even?) # => false (has value but predicate is false)
126
+ None[].none_or? { false } # => true (None satisfies this predicate)
127
+ ```
128
+
129
+ ### Unwrapping
130
+
131
+ Extract values from an Option safely:
132
+
133
+ ```ruby
134
+ require 'data/option'
135
+
136
+ include Data::Option
137
+
138
+ some = Some[42]
139
+ none = None[]
140
+
141
+ some.unwrap # => 42
142
+ none.unwrap #!> None::UnwrapError
143
+
144
+ some.unwrap_or(0) # => 42
145
+ none.unwrap_or(0) # => 0
146
+
147
+ some.unwrap_or_else { rand(100) } # => 42
148
+ none.unwrap_or_else { rand(100) } # => some random number
149
+
150
+ some.expect('Should contain value') # => 42
151
+ none.expect('Missing expected value') #!> None::UnwrapError
152
+ ```
153
+
154
+ ### Enumeration and Transformation
155
+
156
+ Map, filter, and transform Option values:
157
+
158
+ ```ruby
159
+ require 'data/option'
160
+
161
+ include Data::Option
162
+
163
+ Some[42].each { |value| puts value } # prints 42
164
+ None[].each { |value| puts value } # no output
165
+
166
+ Some[42].map { |n| n + 1 } # => Some[43]
167
+ None[].map { |n| n + 1 } # => None
168
+
169
+ Some[42].filter(&:even?) # => Some[42]
170
+ Some[41].filter(&:even?) # => None
171
+ None[].filter { true } # => None
172
+
173
+ Some[42].flat_map { |n| Some[n + 1] } # => Some[43]
174
+ Some[42].flat_map { |_| None[] } # => None
175
+ None[].flat_map { |n| Some[n + 1] } # => None
176
+
177
+ Some[Some[42]].flatten # => Some[42]
178
+ Some[None[]].flatten # => None
179
+ Some[42].flatten # => Some[42]
180
+ None[].flatten # => None
181
+
182
+ Some[42].map_or(0) { |n| n + 1 } # => 43
183
+ None[].map_or(0) { |n| n + 1 } # => 0
184
+
185
+ Some[42].map_or_else(-> { rand(100) }) { |n| n + 1 } # => 43
186
+ None[].map_or_else(-> { rand(100) }) { |n| n + 1 } # => random number
187
+ ```
188
+
189
+ ### Logical Operations
190
+
191
+ Combine Option values with logical operations:
192
+
193
+ ```ruby
194
+ require 'data/option'
195
+
196
+ include Data::Option
197
+
198
+ Some[1].and(Some[2]) # => Some[2]
199
+ Some[1].and(None[]) # => None
200
+ None[].and(Some[1]) # => None
201
+ None[].and(None[]) # => None
202
+
203
+ Some[1].and_then { |n| Some[n + 1] } # => Some[2]
204
+ Some[1].and_then { |_| None[] } # => None
205
+ None[].and_then { |n| Some[n + 1] } # => None
206
+
207
+ Some[1].or(Some[2]) # => Some[1]
208
+ Some[1].or(None[]) # => Some[1]
209
+ None[].or(Some[2]) # => Some[2]
210
+ None[].or(None[]) # => None
211
+
212
+ Some[1].or_else { Some[2] } # => Some[1]
213
+ None[].or_else { Some[2] } # => Some[2]
214
+ None[].or_else { None[] } # => None
215
+
216
+ Some[1].xor(Some[2]) # => None
217
+ Some[1].xor(None[]) # => Some[1]
218
+ None[].xor(Some[2]) # => Some[2]
219
+ None[].xor(None[]) # => None
220
+ ```
221
+
222
+ ### String Representation and Formatting
223
+
224
+ Options provide clear string representations:
225
+
226
+ ```ruby
227
+ require 'data/option'
228
+
229
+ include Data::Option
230
+
231
+ Some[42].to_s # => "Some[42]"
232
+ Some[42].inspect # => "Some[42]"
233
+ None[].to_s # => "None"
234
+ None[].inspect # => "None"
235
+
236
+ Some[[1, 2, 3]].inspect # => "Some[[1, 2, 3]]"
237
+ Some[Some["hello"]].inspect # => "Some[Some[\"hello\"]]"
238
+
239
+ require 'pp'
240
+ PP.pp(Some[42]) # Some[ 42 ]
241
+ PP.pp(Some[Some[None[]]]) # Some[ Some[ None ] ]
242
+ ```
243
+
244
+ ### Comparison and Sorting
245
+
246
+ `Some` and `None` are comparable and sortable. `None` is considered lower than all `Some` values, and `Some` values are ordered by their contained values:
247
+
248
+ ```ruby
249
+ require 'data/option'
250
+
251
+ include Data::Option
252
+
253
+ Some[1] < Some[2] # => true
254
+ Some[2] > Some[1] # => true
255
+ Some[1] == Some[1] # => true
256
+
257
+ Some[1] > None[] # => true
258
+ None[] < Some[1] # => true
259
+
260
+ [Some[3], None[], Some[1], Some[2]].sort # => [None[], Some[1], Some[2], Some[3]]
261
+ ```
262
+
263
+ ### Method Chaining
264
+
265
+ Chain operations for elegant functional transformations:
266
+
267
+ ```ruby
268
+ require 'data/option'
269
+
270
+ include Data::Option
271
+
272
+ Option(42)
273
+ .map { |it| it * 10 } # => Some[420]
274
+ .flat_map { |it| Option(it - 440) } # => Some[-20]
275
+ .filter(&:positive?) # => None
276
+ .map { |it| it * 10 } # => None
277
+ .unwrap_or(99) # => 99
278
+ ```
279
+
280
+ ### Method Overview
281
+
282
+ `Some` and `None` both respond to a wide range of utility methods that cover common functional programming patterns:
283
+
284
+ - Checking: `some?`, `none?`, `some_and?`, `none_or?`
285
+ - Unwrapping: `unwrap`, `unwrap_or`, `unwrap_or_else`, `expect`
286
+ - Transforming: `map`, `flat_map`, `filter`, `flatten`, `map_or`, `map_or_else`, `each`
287
+ - Combining: `and`, `and_then`, `or`, `or_else`, `xor`
288
+ - Formatting: `to_s`, `inspect`
289
+ - Comparison: `<=>`, `==`, `<`, `>`, etc.
290
+
291
+ See Rust's Option [Method overview](https://doc.rust-lang.org/std/option/#method-overview) for background and inspiration for these methods.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rake/testtask'
5
+ require 'rubocop/rake_task'
6
+
7
+ task default: %i[test rubocop]
8
+
9
+ Rake::TestTask.new do |test|
10
+ test.pattern = 'test/**/*_test.rb'
11
+ test.warning = false
12
+ end
13
+
14
+ RuboCop::RakeTask.new do |task|
15
+ task.plugins << 'rubocop-minitest'
16
+ end
data/Steepfile ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ target :lib do
4
+ signature 'sig'
5
+ check 'lib'
6
+ library 'singleton'
7
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'data/option'
4
+
5
+ include Data::Option
6
+
7
+ # An integer division that doesn't `raise ZeroDivisionError`
8
+ def checked_division(dividend, divisor)
9
+ if divisor.zero?
10
+ # Failure is represented as the `None` variant
11
+ None[]
12
+ else
13
+ # Result is wrapped in a `Some` variant
14
+ Some[dividend / divisor]
15
+ end
16
+ end
17
+
18
+ # This function handles a division that may not succeed
19
+ def try_division(dividend, divisor)
20
+ # `Option` values can be pattern matched, just like other enums
21
+ case checked_division(dividend, divisor)
22
+ in None
23
+ puts "#{dividend} / #{divisor} failed!"
24
+ in Some(quotient)
25
+ puts "#{dividend} / #{divisor} = #{quotient}"
26
+ end
27
+ end
28
+
29
+ try_division(4, 2)
30
+ # >> 4 / 2 = 2
31
+ try_division(1, 0)
32
+ # >> 1 / 0 failed!
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kernel
4
+ private
5
+
6
+ def Option(value) = Data::Option.from(value)
7
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ class Data
6
+ module Option
7
+ None = Data.define
8
+ class None
9
+ class UnwrapError < StandardError
10
+ def initialize(message = 'cannot unwrap a `None` value') = super
11
+ end
12
+
13
+ include Comparable
14
+ include Singleton
15
+
16
+ def <=>(other) = other.is_a?(Some) ? -1 : 0
17
+
18
+ class << self
19
+ alias [] instance
20
+ end
21
+
22
+ def unwrap = raise UnwrapError
23
+ def unwrap_or_else = yield
24
+
25
+ def unwrap_or(default) = default
26
+ def expect(message) = raise UnwrapError, message
27
+
28
+ def and(_other) = self
29
+ def and_then = self
30
+ def or(other) = other.is_a?(Some) ? other : self
31
+ alias or_else unwrap_or_else
32
+ alias xor or
33
+
34
+ def each = self
35
+ alias map each
36
+ alias filter each
37
+ alias flat_map each
38
+ alias flatten each
39
+
40
+ alias map_or unwrap_or
41
+ def map_or_else(default) = default.call
42
+
43
+ def some? = false
44
+ def none? = true
45
+
46
+ alias some_and? some?
47
+ alias none_or? none?
48
+
49
+ def inspect = 'None'
50
+ alias to_s inspect
51
+
52
+ def pretty_print(pp) = pp.text(inspect)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Data
4
+ module Option
5
+ module Refinement
6
+ refine Object do
7
+ def to_option = Option::Some[self]
8
+ end
9
+
10
+ refine NilClass do
11
+ def to_option = Option::None[]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Data
4
+ module Option
5
+ Some = Data.define(:value) do
6
+ include Comparable
7
+
8
+ def <=>(other)
9
+ return 1 if other.is_a?(None)
10
+
11
+ value <=> other.value
12
+ end
13
+
14
+ alias unwrap value
15
+ alias unwrap_or_else value
16
+
17
+ def unwrap_or(_default) = value
18
+ def expect(_message) = value
19
+
20
+ def and(other) = other.is_a?(Some) ? other : None[]
21
+ def and_then = yield value
22
+ def or(_other) = self
23
+ def or_else = self
24
+ def xor(other) = other.is_a?(Some) ? None[] : self
25
+
26
+ def each
27
+ yield value
28
+
29
+ self
30
+ end
31
+
32
+ def map = Some[yield value]
33
+ def filter = yield(value) ? self : None[]
34
+ def flat_map(&) = map(&).flatten
35
+
36
+ def flatten
37
+ case value
38
+ in None | Some
39
+ value
40
+ else
41
+ self
42
+ end
43
+ end
44
+
45
+ def map_or(_default) = yield value
46
+ alias map_or_else map_or
47
+
48
+ def some? = true
49
+ def none? = false
50
+
51
+ def some_and? = yield value
52
+ alias none_or? some_and?
53
+
54
+ def inspect = "Some[#{value.inspect}]"
55
+ alias to_s inspect
56
+
57
+ def pretty_print(pp)
58
+ pp.group(1, 'Some[', ']') do
59
+ pp.breakable('')
60
+ case value
61
+ in Some | None
62
+ value.pretty_print(pp)
63
+ else
64
+ pp.pp(value)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Data
4
+ module Option
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'option/ext/kernel'
4
+ require_relative 'option/none'
5
+ require_relative 'option/refinement'
6
+ require_relative 'option/some'
7
+ require_relative 'option/version'
8
+
9
+ class Data
10
+ module Option
11
+ # Creates an Option from a value.
12
+ # Returns `None` if the value is `nil`, otherwise returns `Some[value]`.
13
+ def self.from(value)
14
+ value.nil? ? None[] : Some[value]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,81 @@
1
+ type option[T] = Data::Option::Some[T] | Data::Option::None
2
+
3
+ class Data
4
+ module Option
5
+ VERSION: String
6
+ def self.from: [T] (T?) -> option[T]
7
+
8
+ class Some[T]
9
+ attr_reader value: T
10
+ def self.[]: [T] (T) -> Some[T]
11
+ def initialize: (T) -> void
12
+ def <=>: (None) -> 1
13
+ | (Some[untyped]) -> (1 | 0 | -1 | nil)
14
+ def unwrap: -> T
15
+ def unwrap_or: (untyped) -> T
16
+ def unwrap_or_else: -> T
17
+ def expect: (untyped) -> T
18
+ def and: (untyped) -> option[untyped]
19
+ def and_then: { (T) -> option[untyped] } -> option[untyped]
20
+ def or: (untyped) -> Some[T]
21
+ def or_else: -> Some[T]
22
+ def xor: (untyped) -> option[untyped]
23
+ def each: { (T) -> void } -> Some[T]
24
+ def map: { (T) -> untyped } -> Some[untyped]
25
+ def filter: { (T) -> boolish } -> option[T]
26
+ def flat_map: { (T) -> untyped } -> untyped
27
+ def flatten: -> untyped
28
+ def map_or: (untyped) { (T) -> untyped } -> untyped
29
+ def map_or_else: (untyped) { (T) -> untyped } -> untyped
30
+ def some?: -> true
31
+ def none?: -> false
32
+ def some_and?: { (T) -> boolish } -> boolish
33
+ def none_or?: { (T) -> boolish } -> boolish
34
+ def to_s: -> String
35
+ def inspect: -> String
36
+ def pretty_print: (PP) -> void
37
+ end
38
+
39
+ class None
40
+ class UnwrapError < StandardError
41
+ def initialize: (?String) -> void
42
+ end
43
+
44
+ def self.[]: -> None
45
+ def initialize: () -> void
46
+ def <=>: (Some[untyped]) -> -1
47
+ | (None) -> 0
48
+ def unwrap: -> untyped
49
+ def unwrap_or_else: { () -> untyped } -> untyped
50
+ def unwrap_or: (untyped) -> untyped
51
+ def expect: (untyped) -> untyped
52
+ def and: (untyped) -> None
53
+ def and_then: -> None
54
+ def or: (untyped) -> untyped
55
+ def or_else: { () -> untyped } -> untyped
56
+ def xor: (untyped) -> untyped
57
+ def each: { (untyped) -> void } -> None
58
+ def map: { (untyped) -> untyped } -> None
59
+ def filter: { (untyped) -> untyped } -> None
60
+ def flat_map: { (untyped) -> untyped } -> None
61
+ def flatten: -> None
62
+ def map_or: (untyped) { (untyped) -> untyped } -> untyped
63
+ def map_or_else: (untyped) -> untyped
64
+ def some?: -> false
65
+ def none?: -> true
66
+ def some_and?: { (untyped) -> untyped } -> false
67
+ def none_or?: { (untyped) -> untyped } -> true
68
+ def to_s: -> String
69
+ def inspect: -> String
70
+ def pretty_print: (PP) -> void
71
+ end
72
+
73
+ module Refinement
74
+ def to_option: () -> option[self]
75
+ end
76
+ end
77
+ end
78
+
79
+ module Kernel
80
+ def Option: (untyped) -> option[untyped]
81
+ end
metadata ADDED
@@ -0,0 +1,56 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: data-option
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shannon Skipper
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: Some and None Option classes with Rust-like semantics
13
+ email:
14
+ - shannonskipper@gmail.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - ".rubocop.yml"
20
+ - LICENSE.txt
21
+ - README.md
22
+ - Rakefile
23
+ - Steepfile
24
+ - examples/try_division.rb
25
+ - lib/data/option.rb
26
+ - lib/data/option/ext/kernel.rb
27
+ - lib/data/option/none.rb
28
+ - lib/data/option/refinement.rb
29
+ - lib/data/option/some.rb
30
+ - lib/data/option/version.rb
31
+ - sig/data/option.rbs
32
+ homepage: https://github.com/havenwood/data-option
33
+ licenses:
34
+ - MIT
35
+ metadata:
36
+ homepage_uri: https://github.com/havenwood/data-option
37
+ source_code_uri: https://github.com/havenwood/data-option
38
+ rubygems_mfa_required: 'true'
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 3.4.0
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubygems_version: 3.7.0.dev
54
+ specification_version: 4
55
+ summary: Option classes for Some and None
56
+ test_files: []