mayak 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,619 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module Mayak
5
+ module Monads
6
+ module Try
7
+ extend T::Sig
8
+ extend T::Generic
9
+
10
+ abstract!
11
+ sealed!
12
+
13
+ Value = type_member
14
+
15
+ sig {
16
+ abstract
17
+ .type_parameters(:NewValue)
18
+ .params(blk: T.proc.params(arg0: Value).returns(T.type_parameter(:NewValue)))
19
+ .returns(Try[T.type_parameter(:NewValue)])
20
+ }
21
+ def map(&blk)
22
+ end
23
+
24
+ sig {
25
+ abstract
26
+ .type_parameters(:NewValue)
27
+ .params(
28
+ blk: T.proc.params(arg0: Value).returns(Try[T.type_parameter(:NewValue)])
29
+ )
30
+ .returns(Try[T.type_parameter(:NewValue)])
31
+ }
32
+ def flat_map(&blk)
33
+ end
34
+
35
+ sig {
36
+ abstract
37
+ .params(error: StandardError, blk: T.proc.params(arg0: Value).returns(T::Boolean))
38
+ .returns(Try[Value])
39
+ }
40
+ def filter_or(error, &blk)
41
+ end
42
+
43
+ sig { abstract.returns(T::Boolean) }
44
+ def success?
45
+ end
46
+
47
+ sig { abstract.returns(T::Boolean) }
48
+ def failure?
49
+ end
50
+
51
+ sig { abstract.params(value: Value).returns(Value) }
52
+ def success_or(value)
53
+ end
54
+
55
+ sig { abstract.params(value: StandardError).returns(StandardError) }
56
+ def failure_or(value)
57
+ end
58
+
59
+ sig {
60
+ abstract
61
+ .type_parameters(:Result)
62
+ .params(
63
+ failure_branch: T.proc.params(arg0: StandardError).returns(T.type_parameter(:Result)),
64
+ success_branch: T.proc.params(arg0: Value).returns(T.type_parameter(:Result))
65
+ ).returns(
66
+ T.type_parameter(:Result)
67
+ )
68
+ }
69
+ def either(failure_branch, success_branch)
70
+ end
71
+
72
+ sig {
73
+ abstract
74
+ .params(blk: T.proc.params(arg0: Value).void)
75
+ .returns(Try[Value])
76
+ }
77
+ def tee(&blk)
78
+ end
79
+
80
+ sig {
81
+ abstract
82
+ .params(blk: T.proc.params(arg0: StandardError).returns(StandardError))
83
+ .returns(Try[Value])
84
+ }
85
+ def map_failure(&blk)
86
+ end
87
+
88
+ sig {
89
+ abstract
90
+ .params(blk: T.proc.params(arg0: StandardError).returns(Try[Value]))
91
+ .returns(Try[Value])
92
+ }
93
+ def flat_map_failure(&blk)
94
+ end
95
+
96
+ sig {
97
+ abstract
98
+ .type_parameters(:Failure)
99
+ .params(blk: T.proc.params(arg0: StandardError).returns(T.type_parameter(:Failure)))
100
+ .returns(Mayak::Monads::Result[T.type_parameter(:Failure), Value])
101
+ }
102
+ def to_result(&blk)
103
+ end
104
+
105
+ sig { abstract.returns(Mayak::Monads::Maybe[Value]) }
106
+ def to_maybe
107
+ end
108
+
109
+ sig(:final) { params(other: Mayak::Monads::Try[T.untyped]).returns(T::Boolean) }
110
+ def ==(other)
111
+ case self
112
+ when Mayak::Monads::Try::Success
113
+ case other
114
+ when Mayak::Monads::Try::Success then T.unsafe(success) == other.success
115
+ when Mayak::Monads::Try::Failure then false
116
+ else T.absurd(other)
117
+ end
118
+ when Mayak::Monads::Try::Failure
119
+ case other
120
+ when Mayak::Monads::Try::Success then false
121
+ when Mayak::Monads::Try::Failure then T.unsafe(failure) == other.failure
122
+ else T.absurd(other)
123
+ end
124
+ else
125
+ T.absurd(self)
126
+ end
127
+ end
128
+
129
+ sig(:final) {
130
+ type_parameters(:NewValue)
131
+ .params(new_value: T.type_parameter(:NewValue))
132
+ .returns(Try[T.type_parameter(:NewValue)])
133
+ }
134
+ def as(new_value)
135
+ map { |_| new_value }
136
+ end
137
+
138
+ sig(:final) { params(new_failure: StandardError).returns(Try[Value]) }
139
+ def failure_as(new_failure)
140
+ map_failure { |_| new_failure }
141
+ end
142
+
143
+ sig {
144
+ abstract
145
+ .params(value: Value)
146
+ .returns(Try[Value])
147
+ }
148
+ def recover(value)
149
+ end
150
+
151
+ sig {
152
+ abstract
153
+ .params(blk: T.proc.params(arg0: StandardError).returns(Value))
154
+ .returns(Try[Value])
155
+ }
156
+ def recover_with(&blk)
157
+ end
158
+
159
+ sig {
160
+ abstract
161
+ .params(
162
+ error_type: T.class_of(StandardError),
163
+ blk: T.proc.params(arg0: StandardError).returns(Value)
164
+ )
165
+ .returns(Try[Value])
166
+ }
167
+ def recover_on(error_type, &blk)
168
+ end
169
+
170
+ sig(:final) {
171
+ params(blk: T.proc.params(arg0: StandardError).returns(Try[Value])).returns(Try[Value])
172
+ }
173
+ def recover_with_try(&blk)
174
+ flat_map_failure(&blk)
175
+ end
176
+
177
+ sig {
178
+ type_parameters(:Value)
179
+ .params(results: T::Array[Mayak::Monads::Try[T.type_parameter(:Value)]])
180
+ .returns(Mayak::Monads::Try[T::Array[T.type_parameter(:Value)]])
181
+ }
182
+ def self.sequence(results)
183
+ init = T.let(Try::Success.new([]), Try[T::Array[T.type_parameter(:Value)]])
184
+ results.reduce(init) do |result, element|
185
+ result.flat_map do |array|
186
+ element.map { |value| array + [value] }
187
+ end
188
+ end
189
+ end
190
+
191
+ sig {
192
+ type_parameters(:Value)
193
+ .params(
194
+ value: T.type_parameter(:Value),
195
+ error: StandardError,
196
+ blk: T.proc.returns(T::Boolean)
197
+ ).returns(Mayak::Monads::Try[T.type_parameter(:Value)])
198
+ }
199
+ def self.check(value, error, &blk)
200
+ if blk.call
201
+ Mayak::Monads::Try::Success[T.type_parameter(:Value)].new(value)
202
+ else
203
+ Mayak::Monads::Try::Failure[T.type_parameter(:Value)].new(error)
204
+ end
205
+ end
206
+
207
+ sig { params(error: StandardError, blk: T.proc.returns(T::Boolean)).returns(Mayak::Monads::Try[NilClass]) }
208
+ def self.guard(error, &blk)
209
+ check(nil, error, &blk)
210
+ end
211
+
212
+ class Success
213
+ extend T::Sig
214
+ extend T::Generic
215
+
216
+ final!
217
+
218
+ Value = type_member
219
+
220
+ include Mayak::Monads::Try
221
+
222
+ sig(:final) { params(value: Value).void }
223
+ def initialize(value)
224
+ @value = T.let(value, Value)
225
+ end
226
+
227
+ sig(:final) {
228
+ override
229
+ .type_parameters(:NewValue)
230
+ .params(blk: T.proc.params(arg0: Value).returns(T.type_parameter(:NewValue)))
231
+ .returns(Try[T.type_parameter(:NewValue)])
232
+ }
233
+ def map(&blk)
234
+ Mayak::Monads::Try::Success.new(blk.call(@value))
235
+ end
236
+
237
+ sig(:final) {
238
+ override
239
+ .type_parameters(:NewValue)
240
+ .params(blk: T.proc.params(arg0: Value).returns(Try[T.type_parameter(:NewValue)]))
241
+ .returns(Try[T.type_parameter(:NewValue)])
242
+ }
243
+ def flat_map(&blk)
244
+ blk.call(@value)
245
+ end
246
+
247
+ sig(:final) {
248
+ override
249
+ .params(error: StandardError, blk: T.proc.params(arg0: Value).returns(T::Boolean))
250
+ .returns(Try[Value])
251
+ }
252
+ def filter_or(error, &blk)
253
+ if blk.call(@value)
254
+ self
255
+ else
256
+ Mayak::Monads::Try::Failure[Value].new(error)
257
+ end
258
+ end
259
+
260
+ sig(:final) { returns(Value) }
261
+ def success
262
+ @value
263
+ end
264
+
265
+ sig(:final) { override.returns(T::Boolean) }
266
+ def success?
267
+ true
268
+ end
269
+
270
+ sig(:final) { override.returns(T::Boolean) }
271
+ def failure?
272
+ false
273
+ end
274
+
275
+ sig(:final) { override.params(value: Value).returns(Value) }
276
+ def success_or(value)
277
+ @value
278
+ end
279
+
280
+ sig(:final) { override.params(value: StandardError).returns(StandardError) }
281
+ def failure_or(value)
282
+ value
283
+ end
284
+
285
+ sig(:final) {
286
+ override
287
+ .type_parameters(:Result)
288
+ .params(
289
+ failure_branch: T.proc.params(arg0: StandardError).returns(T.type_parameter(:Result)),
290
+ success_branch: T.proc.params(arg0: Value).returns(T.type_parameter(:Result))
291
+ ).returns(
292
+ T.type_parameter(:Result)
293
+ )
294
+ }
295
+ def either(failure_branch, success_branch)
296
+ success_branch.call(@value)
297
+ end
298
+
299
+ sig(:final) {
300
+ override
301
+ .params(blk: T.proc.params(arg0: Value).void)
302
+ .returns(Try[Value])
303
+ }
304
+ def tee(&blk)
305
+ blk.call(@value)
306
+ self
307
+ end
308
+
309
+ sig(:final) {
310
+ override
311
+ .params(blk: T.proc.params(arg0: StandardError).returns(StandardError))
312
+ .returns(Try[Value])
313
+ }
314
+ def map_failure(&blk)
315
+ self
316
+ end
317
+
318
+ sig(:final) {
319
+ override
320
+ .params(blk: T.proc.params(arg0: StandardError).returns(Try[Value]))
321
+ .returns(Try[Value])
322
+ }
323
+ def flat_map_failure(&blk)
324
+ self
325
+ end
326
+
327
+ sig(:final) {
328
+ override
329
+ .type_parameters(:Failure)
330
+ .params(blk: T.proc.params(arg0: StandardError).returns(T.type_parameter(:Failure)))
331
+ .returns(Mayak::Monads::Result[T.type_parameter(:Failure), Value])
332
+ }
333
+ def to_result(&blk)
334
+ Mayak::Monads::Result::Success.new(@value)
335
+ end
336
+
337
+ sig(:final) { override.returns(Mayak::Monads::Maybe[Value]) }
338
+ def to_maybe
339
+ Mayak::Monads::Maybe::Some.new(@value)
340
+ end
341
+
342
+ sig(:final) {
343
+ override
344
+ .params(
345
+ error_type: T.class_of(StandardError),
346
+ blk: T.proc.params(arg0: StandardError).returns(Value)
347
+ )
348
+ .returns(Try[Value])
349
+ }
350
+ def recover_on(error_type, &blk)
351
+ self
352
+ end
353
+
354
+ sig(:final) {
355
+ override
356
+ .params(value: Value)
357
+ .returns(Try[Value])
358
+ }
359
+ def recover(value)
360
+ self
361
+ end
362
+
363
+ sig(:final) { override.params(blk: T.proc.params(arg0: StandardError).returns(Value)).returns(Try[Value]) }
364
+ def recover_with(&blk)
365
+ self
366
+ end
367
+ end
368
+
369
+ class Failure
370
+ extend T::Sig
371
+ extend T::Generic
372
+
373
+ final!
374
+
375
+ Value = type_member
376
+
377
+ include Mayak::Monads::Try
378
+
379
+ sig(:final) { params(value: StandardError).void }
380
+ def initialize(value)
381
+ @failure = T.let(value, StandardError)
382
+ end
383
+
384
+ sig(:final) {
385
+ override
386
+ .type_parameters(:NewValue)
387
+ .params(blk: T.proc.params(arg0: Value).returns(T.type_parameter(:NewValue)))
388
+ .returns(Try[T.type_parameter(:NewValue)])
389
+ }
390
+ def map(&blk)
391
+ T.cast(
392
+ self,
393
+ Try[T.type_parameter(:NewValue)]
394
+ )
395
+ end
396
+
397
+ sig(:final) {
398
+ override
399
+ .type_parameters(:NewValue)
400
+ .params(blk: T.proc.params(arg0: Value).returns(Try[T.type_parameter(:NewValue)]))
401
+ .returns(Try[T.type_parameter(:NewValue)])
402
+ }
403
+ def flat_map(&blk)
404
+ T.cast(
405
+ self,
406
+ Try[T.type_parameter(:NewValue)]
407
+ )
408
+ end
409
+
410
+ sig(:final) {
411
+ override
412
+ .params(error: StandardError, blk: T.proc.params(arg0: Value).returns(T::Boolean))
413
+ .returns(Try[Value])
414
+ }
415
+ def filter_or(error, &blk)
416
+ self
417
+ end
418
+
419
+ sig(:final) { returns(StandardError) }
420
+ def failure
421
+ @failure
422
+ end
423
+
424
+ sig(:final) { override.returns(T::Boolean) }
425
+ def success?
426
+ false
427
+ end
428
+
429
+ sig(:final) { override.returns(T::Boolean) }
430
+ def failure?
431
+ true
432
+ end
433
+
434
+ sig(:final) { override.params(value: Value).returns(Value) }
435
+ def success_or(value)
436
+ value
437
+ end
438
+
439
+ sig(:final) { override.params(value: StandardError).returns(StandardError) }
440
+ def failure_or(value)
441
+ @failure
442
+ end
443
+
444
+ sig(:final) {
445
+ override
446
+ .type_parameters(:Result)
447
+ .params(
448
+ failure_branch: T.proc.params(arg0: StandardError).returns(T.type_parameter(:Result)),
449
+ success_branch: T.proc.params(arg0: Value).returns(T.type_parameter(:Result))
450
+ ).returns(
451
+ T.type_parameter(:Result)
452
+ )
453
+ }
454
+ def either(failure_branch, success_branch)
455
+ failure_branch.call(@failure)
456
+ end
457
+
458
+ sig(:final) {
459
+ override
460
+ .params(blk: T.proc.params(arg0: Value).void)
461
+ .returns(Try[Value])
462
+ }
463
+ def tee(&blk)
464
+ self
465
+ end
466
+
467
+ sig(:final) {
468
+ override
469
+ .params(blk: T.proc.params(arg0: StandardError).returns(StandardError))
470
+ .returns(Try[Value])
471
+ }
472
+ def map_failure(&blk)
473
+ Mayak::Monads::Try::Failure[Value].new(blk.call(@failure))
474
+ end
475
+
476
+ sig(:final) {
477
+ override
478
+ .params(blk: T.proc.params(arg0: StandardError).returns(Try[Value]))
479
+ .returns(Try[Value])
480
+ }
481
+ def flat_map_failure(&blk)
482
+ blk.call(@failure)
483
+ end
484
+
485
+ sig(:final) {
486
+ override
487
+ .type_parameters(:Failure)
488
+ .params(blk: T.proc.params(arg0: StandardError).returns(T.type_parameter(:Failure)))
489
+ .returns(Mayak::Monads::Result[T.type_parameter(:Failure), Value])
490
+ }
491
+ def to_result(&blk)
492
+ Mayak::Monads::Result::Failure.new(blk.call(@failure))
493
+ end
494
+
495
+ sig(:final) { override.returns(Mayak::Monads::Maybe[Value]) }
496
+ def to_maybe
497
+ Mayak::Monads::Maybe::None.new
498
+ end
499
+
500
+ sig(:final) {
501
+ override
502
+ .params(
503
+ error_type: T.class_of(StandardError),
504
+ blk: T.proc.params(arg0: StandardError).returns(Value)
505
+ )
506
+ .returns(Try[Value])
507
+ }
508
+ def recover_on(error_type, &blk)
509
+ if @failure.is_a?(error_type)
510
+ Mayak::Monads::Try::Success[Value].new(blk.call(@failure))
511
+ else
512
+ self
513
+ end
514
+ end
515
+
516
+ sig(:final) {
517
+ override
518
+ .params(value: Value)
519
+ .returns(Try[Value])
520
+ }
521
+ def recover(value)
522
+ Mayak::Monads::Try::Success[Value].new(value)
523
+ end
524
+
525
+ sig(:final) { override.params(blk: T.proc.params(arg0: StandardError).returns(Value)).returns(Try[Value]) }
526
+ def recover_with(&blk)
527
+ Mayak::Monads::Try::Success[Value].new(blk.call(@failure))
528
+ end
529
+ end
530
+
531
+ module Mixin
532
+ extend T::Sig
533
+
534
+ include Kernel
535
+
536
+ sig {
537
+ type_parameters(:Value)
538
+ .params(
539
+ exception_classes: T.class_of(StandardError),
540
+ blk: T.proc.returns(T.type_parameter(:Value))
541
+ )
542
+ .returns(Try[T.type_parameter(:Value)])
543
+ }
544
+ def Try(*exception_classes, &blk)
545
+ exception_classes = [StandardError] if exception_classes.empty?
546
+ begin
547
+ Mayak::Monads::Try::Success[T.type_parameter(:Value)].new(blk.call)
548
+ rescue *exception_classes => e
549
+ Mayak::Monads::Try::Failure[T.type_parameter(:Value)].new(T.unsafe(e))
550
+ end
551
+ end
552
+
553
+ sig {
554
+ type_parameters(:Value)
555
+ .params(blk: T.proc.returns(T.type_parameter(:Value)))
556
+ .returns(Try[T.type_parameter(:Value)])
557
+ }
558
+ def for_try(&blk)
559
+ result = blk.call
560
+ Mayak::Monads::Try::Success[T.type_parameter(:Value)].new(result)
561
+ rescue Halt => e
562
+ e.result
563
+ end
564
+
565
+ sig {
566
+ type_parameters(:Value)
567
+ .params(value: Try[T.type_parameter(:Value)])
568
+ .returns(T.type_parameter(:Value))
569
+ }
570
+ def do_try!(value)
571
+ case value
572
+ when Mayak::Monads::Try::Success
573
+ value.success
574
+ when Mayak::Monads::Try::Failure
575
+ raise Halt[T.type_parameter(:Value)].new(value)
576
+ else
577
+ T.absurd(value)
578
+ end
579
+ end
580
+
581
+ sig {
582
+ type_parameters(:Value)
583
+ .params(
584
+ value: T.type_parameter(:Value),
585
+ error: StandardError,
586
+ blk: T.proc.returns(T::Boolean)
587
+ ).returns(T.type_parameter(:Value))
588
+ }
589
+ def check_try!(value, error, &blk)
590
+ do_try!(Mayak::Monads::Try.check(value, error, &blk))
591
+ end
592
+
593
+ sig { params(error: StandardError, blk: T.proc.returns(T::Boolean)).void }
594
+ def guard_try!(error, &blk)
595
+ do_try!(Mayak::Monads::Try.guard(error, &blk))
596
+ end
597
+
598
+ class Halt < StandardError
599
+ extend T::Sig
600
+ extend T::Generic
601
+ extend T::Helpers
602
+
603
+ SuccessType = type_member
604
+
605
+ sig { returns(Mayak::Monads::Try[SuccessType]) }
606
+ attr_reader :result
607
+
608
+ sig { params(result: Mayak::Monads::Try[SuccessType]).void }
609
+ def initialize(result)
610
+ super()
611
+
612
+ @result = T.let(result, Mayak::Monads::Try[SuccessType])
613
+ end
614
+ end
615
+ private_constant :Halt
616
+ end
617
+ end
618
+ end
619
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+ # typed: strict
3
+
4
+ module Mayak
5
+ module Numeric
6
+ extend T::Sig
7
+
8
+ sig { params(value: T.any(NilClass, String, BigDecimal, Integer, Float)).returns(Mayak::Monads::Maybe[Float]) }
9
+ def self.parse_float(value)
10
+ return Mayak::Monads::Maybe::None[Float].new if value.nil?
11
+
12
+ Mayak::Monads::Maybe::Some[Float].new(Float(value))
13
+ rescue ArgumentError, TypeError, FloatDomainError
14
+ Mayak::Monads::Maybe::None[Float].new
15
+ end
16
+
17
+ sig { params(value: T.any(NilClass, String, BigDecimal, Integer)).returns(Mayak::Monads::Maybe[Integer]) }
18
+ def self.parse_integer(value)
19
+ return Mayak::Monads::Maybe::None[Integer].new if value.nil?
20
+
21
+ Mayak::Monads::Maybe::Some[Integer].new(Integer(value))
22
+ rescue ArgumentError, TypeError
23
+ Mayak::Monads::Maybe::None[Integer].new
24
+ end
25
+
26
+ sig { params(value: T.any(NilClass, String, Integer, BigDecimal, Float)).returns(Mayak::Monads::Maybe[BigDecimal]) }
27
+ def self.parse_decimal(value)
28
+ return Mayak::Monads::Maybe::None[BigDecimal].new if value.nil?
29
+
30
+ case value
31
+ when String
32
+ Mayak::Monads::Maybe::Some[BigDecimal].new(BigDecimal(value))
33
+ when Integer
34
+ Mayak::Monads::Maybe::Some[BigDecimal].new(BigDecimal(value))
35
+ when BigDecimal
36
+ Mayak::Monads::Maybe::Some[BigDecimal].new(value)
37
+ when Float
38
+ Mayak::Monads::Maybe::Some[BigDecimal].new(value.to_d)
39
+ end
40
+ rescue ArgumentError, TypeError
41
+ Mayak::Monads::Maybe::None[BigDecimal].new
42
+ end
43
+ end
44
+ end