fear 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +27 -0
- data/.github/workflows/rubocop.yml +2 -2
- data/.github/workflows/spec.yml +1 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +53 -56
- data/README.md +54 -186
- data/Rakefile +0 -21
- data/examples/pattern_extracting.rb +4 -4
- data/fear.gemspec +2 -4
- data/lib/fear/either.rb +8 -4
- data/lib/fear/either_api.rb +2 -0
- data/lib/fear/either_pattern_match.rb +7 -8
- data/lib/fear/failure.rb +0 -9
- data/lib/fear/failure_pattern_match.rb +2 -0
- data/lib/fear/for_api.rb +2 -0
- data/lib/fear/future.rb +12 -20
- data/lib/fear/future_api.rb +13 -2
- data/lib/fear/left.rb +0 -9
- data/lib/fear/none.rb +7 -9
- data/lib/fear/option.rb +5 -1
- data/lib/fear/option_api.rb +2 -0
- data/lib/fear/option_pattern_match.rb +6 -4
- data/lib/fear/partial_function/empty.rb +2 -0
- data/lib/fear/partial_function/guard.rb +4 -4
- data/lib/fear/partial_function/or_else.rb +2 -0
- data/lib/fear/partial_function.rb +9 -8
- data/lib/fear/pattern_match.rb +0 -10
- data/lib/fear/pattern_matching_api.rb +3 -28
- data/lib/fear/promise.rb +3 -9
- data/lib/fear/right.rb +0 -10
- data/lib/fear/right_biased.rb +1 -1
- data/lib/fear/right_pattern_match.rb +2 -0
- data/lib/fear/some.rb +7 -10
- data/lib/fear/struct.rb +3 -14
- data/lib/fear/success.rb +0 -9
- data/lib/fear/success_pattern_match.rb +2 -0
- data/lib/fear/try.rb +6 -2
- data/lib/fear/try_api.rb +2 -0
- data/lib/fear/try_pattern_match.rb +7 -8
- data/lib/fear/utils.rb +0 -3
- data/lib/fear/version.rb +1 -1
- data/lib/fear.rb +8 -42
- data/spec/fear/awaitable_spec.rb +2 -0
- data/spec/fear/either_spec.rb +26 -0
- data/spec/fear/failure_spec.rb +8 -23
- data/spec/fear/for/mixin_spec.rb +15 -0
- data/spec/fear/future_spec.rb +17 -2
- data/spec/fear/guard_spec.rb +110 -0
- data/spec/fear/left_spec.rb +7 -22
- data/spec/fear/none_spec.rb +11 -17
- data/spec/fear/option_spec.rb +15 -1
- data/spec/fear/partial_function/any_spec.rb +25 -0
- data/spec/fear/partial_function_spec.rb +2 -24
- data/spec/fear/pattern_match_spec.rb +0 -34
- data/spec/fear/promise_spec.rb +4 -6
- data/spec/fear/right_spec.rb +0 -22
- data/spec/fear/some_spec.rb +10 -22
- data/spec/fear/success_spec.rb +0 -22
- data/spec/fear/try/mixin_spec.rb +14 -0
- data/spec/fear/try_api_spec.rb +23 -0
- data/spec/struct_spec.rb +1 -33
- metadata +18 -80
- data/examples/pattern_extracting_ruby2.7.rb +0 -15
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -10
- data/lib/fear/extractor/any_matcher.rb +0 -17
- data/lib/fear/extractor/array_head_matcher.rb +0 -36
- data/lib/fear/extractor/array_matcher.rb +0 -40
- data/lib/fear/extractor/array_splat_matcher.rb +0 -16
- data/lib/fear/extractor/empty_list_matcher.rb +0 -20
- data/lib/fear/extractor/extractor_matcher.rb +0 -44
- data/lib/fear/extractor/grammar.rb +0 -203
- data/lib/fear/extractor/grammar.treetop +0 -129
- data/lib/fear/extractor/identifier_matcher.rb +0 -18
- data/lib/fear/extractor/matcher/and.rb +0 -38
- data/lib/fear/extractor/matcher.rb +0 -53
- data/lib/fear/extractor/named_array_splat_matcher.rb +0 -17
- data/lib/fear/extractor/pattern.rb +0 -58
- data/lib/fear/extractor/typed_identifier_matcher.rb +0 -26
- data/lib/fear/extractor/value_matcher.rb +0 -19
- data/lib/fear/extractor.rb +0 -112
- data/lib/fear/extractor_api.rb +0 -35
- data/spec/fear/extractor/array_matcher_spec.rb +0 -230
- data/spec/fear/extractor/extractor_matcher_spec.rb +0 -153
- data/spec/fear/extractor/grammar_array_spec.rb +0 -25
- data/spec/fear/extractor/identified_matcher_spec.rb +0 -49
- data/spec/fear/extractor/identifier_matcher_spec.rb +0 -68
- data/spec/fear/extractor/pattern_spec.rb +0 -34
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -64
- data/spec/fear/extractor/value_matcher_number_spec.rb +0 -79
- data/spec/fear/extractor/value_matcher_string_spec.rb +0 -88
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -71
- data/spec/fear/extractor_api_spec.rb +0 -115
- data/spec/fear/extractor_spec.rb +0 -61
data/lib/fear/either.rb
CHANGED
@@ -72,7 +72,7 @@ module Fear
|
|
72
72
|
# Performs the given block if this is a +Right+.
|
73
73
|
# @yieldparam [any] value
|
74
74
|
# @yieldreturn [void]
|
75
|
-
# @return [
|
75
|
+
# @return [Fear::Either] itself
|
76
76
|
# @example
|
77
77
|
# Fear.right(17).each do |value|
|
78
78
|
# puts value
|
@@ -95,8 +95,8 @@ module Fear
|
|
95
95
|
# Returns the given block applied to the value from this +Right+
|
96
96
|
# or returns this if this is a +Left+.
|
97
97
|
# @yieldparam [any] value
|
98
|
-
# @yieldreturn [
|
99
|
-
# @return [
|
98
|
+
# @yieldreturn [Fear::Either]
|
99
|
+
# @return [Fear::Either]
|
100
100
|
# @example
|
101
101
|
# Fear.right(42).flat_map { |v| Fear.right(v/2) } #=> Fear.right(21)
|
102
102
|
# Fear.left('undefined').flat_map { |v| Fear.right(v/2) } #=> Fear.left('undefined')
|
@@ -106,7 +106,7 @@ module Fear
|
|
106
106
|
# this is a +Left+.
|
107
107
|
# @return [Option]
|
108
108
|
# @example
|
109
|
-
# Fear.right(42).to_option #=> Fear.some(
|
109
|
+
# Fear.right(42).to_option #=> Fear.some(42)
|
110
110
|
# Fear.left('undefined').to_option #=> Fear.none()
|
111
111
|
#
|
112
112
|
# @!method any?(&predicate)
|
@@ -331,3 +331,7 @@ module Fear
|
|
331
331
|
end
|
332
332
|
end
|
333
333
|
end
|
334
|
+
|
335
|
+
require "fear/either_pattern_match"
|
336
|
+
require "fear/left"
|
337
|
+
require "fear/right"
|
data/lib/fear/either_api.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fear/pattern_match"
|
4
|
+
|
3
5
|
module Fear
|
4
6
|
# Either pattern matcher
|
5
7
|
#
|
@@ -24,18 +26,12 @@ module Fear
|
|
24
26
|
# @note it has two optimized subclasses +Fear::LeftPatternMatch+ and +Fear::RightPatternMatch+
|
25
27
|
# @api private
|
26
28
|
class EitherPatternMatch < Fear::PatternMatch
|
27
|
-
LEFT_EXTRACTOR = :left_value.to_proc
|
28
|
-
public_constant :LEFT_EXTRACTOR
|
29
|
-
|
30
|
-
RIGHT_EXTRACTOR = :right_value.to_proc
|
31
|
-
public_constant :RIGHT_EXTRACTOR
|
32
|
-
|
33
29
|
# Match against +Fear::Right+
|
34
30
|
#
|
35
31
|
# @param conditions [<#==>]
|
36
32
|
# @return [Fear::EitherPatternMatch]
|
37
33
|
def right(*conditions, &effect)
|
38
|
-
branch = Fear.case(Fear::Right,
|
34
|
+
branch = Fear.case(Fear::Right, &:right_value).and_then(Fear.case(*conditions, &effect))
|
39
35
|
or_else(branch)
|
40
36
|
end
|
41
37
|
alias success right
|
@@ -45,9 +41,12 @@ module Fear
|
|
45
41
|
# @param conditions [<#==>]
|
46
42
|
# @return [Fear::EitherPatternMatch]
|
47
43
|
def left(*conditions, &effect)
|
48
|
-
branch = Fear.case(Fear::Left,
|
44
|
+
branch = Fear.case(Fear::Left, &:left_value).and_then(Fear.case(*conditions, &effect))
|
49
45
|
or_else(branch)
|
50
46
|
end
|
51
47
|
alias failure left
|
52
48
|
end
|
53
49
|
end
|
50
|
+
|
51
|
+
require "fear/left_pattern_match"
|
52
|
+
require "fear/right_pattern_match"
|
data/lib/fear/failure.rb
CHANGED
@@ -6,15 +6,6 @@ module Fear
|
|
6
6
|
include RightBiased::Left
|
7
7
|
include FailurePatternMatch.mixin
|
8
8
|
|
9
|
-
EXTRACTOR = proc do |try|
|
10
|
-
if Fear::Failure === try
|
11
|
-
Fear.some([try.exception])
|
12
|
-
else
|
13
|
-
Fear.none
|
14
|
-
end
|
15
|
-
end
|
16
|
-
public_constant :EXTRACTOR
|
17
|
-
|
18
9
|
# @param [StandardError]
|
19
10
|
def initialize(exception)
|
20
11
|
@exception = exception
|
data/lib/fear/for_api.rb
CHANGED
data/lib/fear/future.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
begin
|
4
|
-
require "concurrent"
|
5
|
-
rescue LoadError
|
6
|
-
puts "You must add 'concurrent-ruby' to your Gemfile in order to use Fear::Future"
|
7
|
-
end
|
8
|
-
|
9
3
|
module Fear
|
10
4
|
# Asynchronous computations that yield futures are created
|
11
5
|
# with the +Fear.future+ call:
|
@@ -61,7 +55,7 @@ module Fear
|
|
61
55
|
#
|
62
56
|
def initialize(promise = nil, **options, &block)
|
63
57
|
if block_given? && promise
|
64
|
-
raise ArgumentError, "pass block or
|
58
|
+
raise ArgumentError, "pass block or promise"
|
65
59
|
end
|
66
60
|
|
67
61
|
@options = options
|
@@ -249,7 +243,7 @@ module Fear
|
|
249
243
|
# )
|
250
244
|
#
|
251
245
|
def transform(success, failure)
|
252
|
-
promise = Promise.new(
|
246
|
+
promise = Promise.new(**@options)
|
253
247
|
on_complete_match do |m|
|
254
248
|
m.success { |value| promise.success(success.(value)) }
|
255
249
|
m.failure { |error| promise.failure(failure.(error)) }
|
@@ -268,7 +262,7 @@ module Fear
|
|
268
262
|
# future.map { |v| v * 2 } #=> the same as Fear.future { 2 * 2 }
|
269
263
|
#
|
270
264
|
def map(&block)
|
271
|
-
promise = Promise.new(
|
265
|
+
promise = Promise.new(**@options)
|
272
266
|
on_complete do |try|
|
273
267
|
promise.complete!(try.map(&block))
|
274
268
|
end
|
@@ -294,7 +288,7 @@ module Fear
|
|
294
288
|
# end
|
295
289
|
#
|
296
290
|
def flat_map
|
297
|
-
promise = Promise.new(
|
291
|
+
promise = Promise.new(**@options)
|
298
292
|
on_complete_match do |m|
|
299
293
|
m.case(Fear::Failure) { |failure| promise.complete!(failure) }
|
300
294
|
m.success do |value|
|
@@ -348,7 +342,7 @@ module Fear
|
|
348
342
|
#
|
349
343
|
#
|
350
344
|
def recover(&block)
|
351
|
-
promise = Promise.new(
|
345
|
+
promise = Promise.new(**@options)
|
352
346
|
on_complete do |try|
|
353
347
|
promise.complete!(try.recover(&block))
|
354
348
|
end
|
@@ -374,7 +368,7 @@ module Fear
|
|
374
368
|
# # but it performs two calls asynchronously
|
375
369
|
#
|
376
370
|
def zip(other)
|
377
|
-
promise = Promise.new(
|
371
|
+
promise = Promise.new(**@options)
|
378
372
|
on_complete_match do |m|
|
379
373
|
m.success do |value|
|
380
374
|
other.on_complete do |other_try|
|
@@ -412,7 +406,7 @@ module Fear
|
|
412
406
|
# f.fallback_to(g) # evaluates to 5
|
413
407
|
#
|
414
408
|
def fallback_to(fallback)
|
415
|
-
promise = Promise.new(
|
409
|
+
promise = Promise.new(**@options)
|
416
410
|
on_complete_match do |m|
|
417
411
|
m.success { |value| promise.complete!(value) }
|
418
412
|
m.failure do |error|
|
@@ -447,7 +441,7 @@ module Fear
|
|
447
441
|
# end
|
448
442
|
#
|
449
443
|
def and_then
|
450
|
-
promise = Promise.new(
|
444
|
+
promise = Promise.new(**@options)
|
451
445
|
on_complete do |try|
|
452
446
|
Fear.try do
|
453
447
|
Fear::Try.matcher { |m| yield(m) }.call_or_else(try, &:itself)
|
@@ -478,9 +472,8 @@ module Fear
|
|
478
472
|
# @return [Fear::Future]
|
479
473
|
#
|
480
474
|
def failed(exception)
|
481
|
-
new
|
482
|
-
|
483
|
-
end
|
475
|
+
new { raise exception }
|
476
|
+
.yield_self { |future| Fear::Await.ready(future, 10) }
|
484
477
|
end
|
485
478
|
|
486
479
|
# Creates an already completed +Future+ with the specified result.
|
@@ -488,9 +481,8 @@ module Fear
|
|
488
481
|
# @return [Fear::Future]
|
489
482
|
#
|
490
483
|
def successful(result)
|
491
|
-
new
|
492
|
-
|
493
|
-
end
|
484
|
+
new { result }
|
485
|
+
.yield_self { |future| Fear::Await.ready(future, 10) }
|
494
486
|
end
|
495
487
|
end
|
496
488
|
end
|
data/lib/fear/future_api.rb
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
begin
|
4
|
+
require "concurrent"
|
5
|
+
rescue LoadError
|
6
|
+
puts "You must add 'concurrent-ruby' to your Gemfile in order to use Fear::Future"
|
7
|
+
end
|
8
|
+
|
9
|
+
require "fear/awaitable"
|
10
|
+
require "fear/await"
|
11
|
+
require "fear/future"
|
12
|
+
require "fear/promise"
|
13
|
+
|
3
14
|
module Fear
|
4
15
|
# rubocop: disable Layout/LineLength
|
5
16
|
module FutureApi
|
@@ -13,8 +24,8 @@ module Fear
|
|
13
24
|
# f = Fear.future(executor: :io) { open('http://example.com') }
|
14
25
|
# f.map(&:read).each { |body| puts body }
|
15
26
|
#
|
16
|
-
def future(options
|
17
|
-
Future.new(options, &block)
|
27
|
+
def future(**options, &block)
|
28
|
+
Future.new(nil, **options, &block)
|
18
29
|
end
|
19
30
|
end
|
20
31
|
# rubocop: enable Layout/LineLength
|
data/lib/fear/left.rb
CHANGED
@@ -6,15 +6,6 @@ module Fear
|
|
6
6
|
include RightBiased::Left
|
7
7
|
include LeftPatternMatch.mixin
|
8
8
|
|
9
|
-
EXTRACTOR = proc do |either|
|
10
|
-
if Fear::Left === either
|
11
|
-
Fear.some([either.left_value])
|
12
|
-
else
|
13
|
-
Fear.none
|
14
|
-
end
|
15
|
-
end
|
16
|
-
public_constant :EXTRACTOR
|
17
|
-
|
18
9
|
# @api private
|
19
10
|
def left_value
|
20
11
|
value
|
data/lib/fear/none.rb
CHANGED
@@ -7,15 +7,6 @@ module Fear
|
|
7
7
|
include RightBiased::Left
|
8
8
|
include NonePatternMatch.mixin
|
9
9
|
|
10
|
-
EXTRACTOR = proc do |option|
|
11
|
-
if Fear::None === option
|
12
|
-
Fear.some([])
|
13
|
-
else
|
14
|
-
Fear.none
|
15
|
-
end
|
16
|
-
end
|
17
|
-
public_constant :EXTRACTOR
|
18
|
-
|
19
10
|
# @raise [NoSuchElementError]
|
20
11
|
def get
|
21
12
|
raise NoSuchElementError
|
@@ -31,6 +22,13 @@ module Fear
|
|
31
22
|
true
|
32
23
|
end
|
33
24
|
|
25
|
+
alias :blank? :empty?
|
26
|
+
|
27
|
+
# @return [false]
|
28
|
+
def present?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
34
32
|
# @return [None]
|
35
33
|
def select(*)
|
36
34
|
self
|
data/lib/fear/option.rb
CHANGED
@@ -121,7 +121,7 @@ module Fear
|
|
121
121
|
# @yieldreturn [Boolean]
|
122
122
|
# @return [Option]
|
123
123
|
# @example
|
124
|
-
# Fear.some(42).select { |v| v > 40 } #=> Fear.success(
|
124
|
+
# Fear.some(42).select { |v| v > 40 } #=> Fear.success(42)
|
125
125
|
# Fear.some(42).select { |v| v < 40 } #=> None
|
126
126
|
# Fear.none.select { |v| v < 40 } #=> None
|
127
127
|
#
|
@@ -258,3 +258,7 @@ module Fear
|
|
258
258
|
end
|
259
259
|
end
|
260
260
|
end
|
261
|
+
|
262
|
+
require "fear/option_pattern_match"
|
263
|
+
require "fear/some"
|
264
|
+
require "fear/none"
|
data/lib/fear/option_api.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fear/pattern_match"
|
4
|
+
|
3
5
|
module Fear
|
4
6
|
# Option pattern matcher
|
5
7
|
#
|
@@ -24,15 +26,12 @@ module Fear
|
|
24
26
|
# @note it has two optimized subclasses +Fear::SomePatternMatch+ and +Fear::NonePatternMatch+
|
25
27
|
# @api private
|
26
28
|
class OptionPatternMatch < Fear::PatternMatch
|
27
|
-
GET_METHOD = :get.to_proc
|
28
|
-
private_constant :GET_METHOD
|
29
|
-
|
30
29
|
# Match against Some
|
31
30
|
#
|
32
31
|
# @param conditions [<#==>]
|
33
32
|
# @return [Fear::OptionPatternMatch]
|
34
33
|
def some(*conditions, &effect)
|
35
|
-
branch = Fear.case(Fear::Some,
|
34
|
+
branch = Fear.case(Fear::Some, &:get).and_then(Fear.case(*conditions, &effect))
|
36
35
|
or_else(branch)
|
37
36
|
end
|
38
37
|
|
@@ -46,3 +45,6 @@ module Fear
|
|
46
45
|
end
|
47
46
|
end
|
48
47
|
end
|
48
|
+
|
49
|
+
require "fear/some_pattern_match"
|
50
|
+
require "fear/none_pattern_match"
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fear/partial_function/guard/or"
|
4
|
+
require "fear/partial_function/guard/and"
|
5
|
+
require "fear/partial_function/guard/and3"
|
6
|
+
|
3
7
|
module Fear
|
4
8
|
module PartialFunction
|
5
9
|
# Guard represents PartialFunction guardian
|
6
10
|
#
|
7
11
|
# @api private
|
8
12
|
class Guard
|
9
|
-
autoload :And, "fear/partial_function/guard/and"
|
10
|
-
autoload :And3, "fear/partial_function/guard/and3"
|
11
|
-
autoload :Or, "fear/partial_function/guard/or"
|
12
|
-
|
13
13
|
class << self
|
14
14
|
# Optimized version for combination of two guardians
|
15
15
|
# Two guarding is a very common situation. For example checking for Some, and checking
|
@@ -1,5 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fear/partial_function/and_then"
|
4
|
+
require "fear/partial_function/any"
|
5
|
+
require "fear/partial_function/combined"
|
6
|
+
require "fear/partial_function/empty"
|
7
|
+
require "fear/partial_function/guard"
|
8
|
+
require "fear/partial_function/lifted"
|
9
|
+
require "fear/partial_function/or_else"
|
10
|
+
require "fear/partial_function_class"
|
11
|
+
|
3
12
|
module Fear
|
4
13
|
# A partial function is a unary function defined on subset of all possible inputs.
|
5
14
|
# The method +defined_at?+ allows to test dynamically if an arg is in
|
@@ -45,14 +54,6 @@ module Fear
|
|
45
54
|
# @return [#call]
|
46
55
|
# @abstract
|
47
56
|
module PartialFunction
|
48
|
-
autoload :AndThen, "fear/partial_function/and_then"
|
49
|
-
autoload :Any, "fear/partial_function/any"
|
50
|
-
autoload :Combined, "fear/partial_function/combined"
|
51
|
-
autoload :EMPTY, "fear/partial_function/empty"
|
52
|
-
autoload :Guard, "fear/partial_function/guard"
|
53
|
-
autoload :Lifted, "fear/partial_function/lifted"
|
54
|
-
autoload :OrElse, "fear/partial_function/or_else"
|
55
|
-
|
56
57
|
# Checks if a value is contained in the function's domain.
|
57
58
|
#
|
58
59
|
# @param arg [any]
|
data/lib/fear/pattern_match.rb
CHANGED
@@ -95,16 +95,6 @@ module Fear
|
|
95
95
|
or_else(Fear.case(*guards, &effect))
|
96
96
|
end
|
97
97
|
|
98
|
-
# @param pattern [String]
|
99
|
-
# @param guards [<#===>]
|
100
|
-
# @param effect [Proc]
|
101
|
-
# @return [Fear::PartialFunction]
|
102
|
-
# @see #case for details
|
103
|
-
# @see Fear.xcase for details
|
104
|
-
def xcase(pattern, *guards, &effect)
|
105
|
-
or_else(Fear.xcase(pattern, *guards, &effect))
|
106
|
-
end
|
107
|
-
|
108
98
|
# @see Fear::PartialFunction#or_else
|
109
99
|
def or_else(other)
|
110
100
|
self.result = result.or_else(other)
|
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fear/partial_function"
|
4
|
+
require "fear/pattern_match"
|
5
|
+
|
3
6
|
module Fear
|
4
7
|
# @api private
|
5
8
|
module PatternMatchingApi
|
@@ -44,12 +47,6 @@ module Fear
|
|
44
47
|
# m.case(Integer, :even?.to_proc) { |x| ... }
|
45
48
|
# m.case(Integer, :odd?.to_proc) { |x| ... }
|
46
49
|
#
|
47
|
-
# If you want to perform pattern destruction, use +#xcase+ method
|
48
|
-
#
|
49
|
-
# m.xcase('Date(year, 12, 31)') { |year:| "Last day of the year #{year}" }
|
50
|
-
#
|
51
|
-
# The pattern above ensures that it's 31 of December and extracts year to block named parameter
|
52
|
-
#
|
53
50
|
# Since matcher returns +Fear::PartialFunction+, you can combine matchers using
|
54
51
|
# partial function API:
|
55
52
|
#
|
@@ -111,27 +108,5 @@ module Fear
|
|
111
108
|
def case(*guards, &function)
|
112
109
|
PartialFunction.and(*guards, &function)
|
113
110
|
end
|
114
|
-
|
115
|
-
# Creates partial function defined on domain described with guard
|
116
|
-
# and perform pattern extraction.
|
117
|
-
#
|
118
|
-
# @param pattern [String] pattern to match against
|
119
|
-
# @param guards [<#===>] other guards against extracted pattern
|
120
|
-
# @yieldparam hash [{Symbol => any}]
|
121
|
-
# @return [Fear::PartialFunction]
|
122
|
-
#
|
123
|
-
# @example
|
124
|
-
# pf = Fear.xcase('['ok', Some(body)]') { |body:| ... }
|
125
|
-
# pf.defined_at?(['ok', Fear.some(body)]) #=> true
|
126
|
-
# pf.defined_at?(['err', Fear.none]) #=> false
|
127
|
-
#
|
128
|
-
# @example pattern and guards. It matches against non-empty body
|
129
|
-
#
|
130
|
-
# pf = Fear.xcase('['ok', Some(body)]', ->(body:) { !body.empty? }) { }
|
131
|
-
#
|
132
|
-
def xcase(pattern, *guards, &function)
|
133
|
-
warn "NOTE: Fear.xcase is deprecated and will be removed in a future version. Use `case .. in ..` instead."
|
134
|
-
Fear[pattern].and_then(self.case(*guards, &function))
|
135
|
-
end
|
136
111
|
end
|
137
112
|
end
|
data/lib/fear/promise.rb
CHANGED
@@ -1,16 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
begin
|
4
|
-
require "concurrent"
|
5
|
-
rescue LoadError
|
6
|
-
puts "You must add 'concurrent-ruby' to your Gemfile in order to use Fear::Future"
|
7
|
-
end
|
8
|
-
|
9
3
|
module Fear
|
10
4
|
# @api private
|
11
5
|
class Promise < Concurrent::IVar
|
12
6
|
# @param options [Hash] options passed to underlying +Concurrent::Promise+
|
13
|
-
def initialize(**options)
|
7
|
+
def initialize(*_, **options)
|
14
8
|
super()
|
15
9
|
@options = options
|
16
10
|
@promise = Concurrent::Promise.new(options) do
|
@@ -27,7 +21,7 @@ module Fear
|
|
27
21
|
|
28
22
|
# @return [Fear::Future]
|
29
23
|
def to_future
|
30
|
-
Future.new(promise, options)
|
24
|
+
Future.new(promise, **options)
|
31
25
|
end
|
32
26
|
|
33
27
|
# Complete this promise with successful result
|
@@ -38,7 +32,7 @@ module Fear
|
|
38
32
|
complete(Fear.success(value))
|
39
33
|
end
|
40
34
|
|
41
|
-
# Complete this promise with
|
35
|
+
# Complete this promise with value
|
42
36
|
# @param value [any]
|
43
37
|
# @return [self]
|
44
38
|
# @raise [IllegalStateException]
|
data/lib/fear/right.rb
CHANGED
@@ -6,16 +6,6 @@ module Fear
|
|
6
6
|
include RightBiased::Right
|
7
7
|
include RightPatternMatch.mixin
|
8
8
|
|
9
|
-
EXTRACTOR = proc do |either|
|
10
|
-
if Fear::Right === either
|
11
|
-
Fear.some([either.right_value])
|
12
|
-
else
|
13
|
-
Fear.none
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
public_constant :EXTRACTOR
|
18
|
-
|
19
9
|
# @api private
|
20
10
|
def right_value
|
21
11
|
value
|
data/lib/fear/right_biased.rb
CHANGED
data/lib/fear/some.rb
CHANGED
@@ -6,16 +6,6 @@ module Fear
|
|
6
6
|
include RightBiased::Right
|
7
7
|
include SomePatternMatch.mixin
|
8
8
|
|
9
|
-
EXTRACTOR = proc do |option|
|
10
|
-
if Fear::Some === option
|
11
|
-
Fear.some([option.get])
|
12
|
-
else
|
13
|
-
Fear.none
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
public_constant :EXTRACTOR
|
18
|
-
|
19
9
|
attr_reader :value
|
20
10
|
protected :value
|
21
11
|
|
@@ -38,6 +28,13 @@ module Fear
|
|
38
28
|
false
|
39
29
|
end
|
40
30
|
|
31
|
+
alias :blank? :empty?
|
32
|
+
|
33
|
+
# @return [true]
|
34
|
+
def present?
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
41
38
|
# @return [Option]
|
42
39
|
def select
|
43
40
|
if yield(value)
|
data/lib/fear/struct.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fear/pattern_match"
|
4
|
+
|
3
5
|
module Fear
|
4
6
|
# Structs are like regular classes and good for modeling immutable data.
|
5
7
|
#
|
@@ -36,18 +38,6 @@ module Fear
|
|
36
38
|
# john.admin #=> false
|
37
39
|
# admin_john.admin #=> true
|
38
40
|
#
|
39
|
-
# It's possible to match against struct attributes. The following example extracts email from
|
40
|
-
# user only if user is admin
|
41
|
-
#
|
42
|
-
# john = User.new(id: 2, email: 'john@example.com', admin: false)
|
43
|
-
# john.match |m|
|
44
|
-
# m.xcase('Fear::Struct(_, email, true)') do |email|
|
45
|
-
# email
|
46
|
-
# end
|
47
|
-
# end
|
48
|
-
#
|
49
|
-
# Note, parameters got extracted in order they was defined.
|
50
|
-
#
|
51
41
|
class Struct
|
52
42
|
include PatternMatch.mixin
|
53
43
|
|
@@ -58,7 +48,6 @@ module Fear
|
|
58
48
|
# @api private
|
59
49
|
def inherited(base)
|
60
50
|
base.instance_variable_set(:@attributes, attributes)
|
61
|
-
Fear.register_extractor(base, Fear.case(base, &:to_a).lift)
|
62
51
|
end
|
63
52
|
|
64
53
|
# Defines attribute
|
@@ -132,7 +121,7 @@ module Fear
|
|
132
121
|
# admin_john.admin #=> true
|
133
122
|
#
|
134
123
|
def copy(**attributes)
|
135
|
-
self.class.new(to_h.merge(attributes))
|
124
|
+
self.class.new(**to_h.merge(attributes))
|
136
125
|
end
|
137
126
|
|
138
127
|
# Returns the struct attributes as an array of symbols
|
data/lib/fear/success.rb
CHANGED
@@ -6,15 +6,6 @@ module Fear
|
|
6
6
|
include RightBiased::Right
|
7
7
|
include SuccessPatternMatch.mixin
|
8
8
|
|
9
|
-
EXTRACTOR = proc do |try|
|
10
|
-
if Fear::Success === try
|
11
|
-
Fear.some([try.get])
|
12
|
-
else
|
13
|
-
Fear.none
|
14
|
-
end
|
15
|
-
end
|
16
|
-
public_constant :EXTRACTOR
|
17
|
-
|
18
9
|
attr_reader :value
|
19
10
|
protected :value
|
20
11
|
|