fear 1.0.0 → 2.0.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 +4 -4
- data/.github/dependabot.yml +27 -0
- data/.github/workflows/rubocop.yml +39 -0
- data/.github/workflows/spec.yml +42 -0
- data/.rubocop.yml +4 -60
- data/.simplecov +17 -0
- data/CHANGELOG.md +29 -1
- data/Gemfile +5 -5
- data/Gemfile.lock +86 -50
- data/README.md +240 -209
- data/Rakefile +72 -65
- data/examples/pattern_extracting.rb +10 -8
- data/examples/pattern_matching_binary_tree_set.rb +7 -2
- data/examples/pattern_matching_number_in_words.rb +48 -42
- data/fear.gemspec +33 -34
- data/lib/dry/types/fear/option.rb +125 -0
- data/lib/dry/types/fear.rb +8 -0
- data/lib/fear/await.rb +33 -0
- data/lib/fear/awaitable.rb +28 -0
- data/lib/fear/either.rb +15 -4
- data/lib/fear/either_api.rb +4 -0
- data/lib/fear/either_pattern_match.rb +9 -5
- data/lib/fear/empty_partial_function.rb +3 -1
- data/lib/fear/failure.rb +7 -7
- data/lib/fear/failure_pattern_match.rb +4 -0
- data/lib/fear/for.rb +4 -2
- data/lib/fear/for_api.rb +5 -1
- data/lib/fear/future.rb +157 -82
- data/lib/fear/future_api.rb +17 -4
- data/lib/fear/left.rb +3 -9
- data/lib/fear/left_pattern_match.rb +2 -0
- data/lib/fear/none.rb +28 -10
- data/lib/fear/none_pattern_match.rb +2 -0
- data/lib/fear/option.rb +30 -2
- data/lib/fear/option_api.rb +4 -0
- data/lib/fear/option_pattern_match.rb +8 -3
- data/lib/fear/partial_function/and_then.rb +4 -2
- data/lib/fear/partial_function/any.rb +2 -0
- data/lib/fear/partial_function/combined.rb +3 -1
- data/lib/fear/partial_function/empty.rb +6 -0
- data/lib/fear/partial_function/guard/and.rb +2 -0
- data/lib/fear/partial_function/guard/and3.rb +2 -0
- data/lib/fear/partial_function/guard/or.rb +2 -0
- data/lib/fear/partial_function/guard.rb +8 -6
- data/lib/fear/partial_function/lifted.rb +2 -0
- data/lib/fear/partial_function/or_else.rb +5 -1
- data/lib/fear/partial_function.rb +18 -9
- data/lib/fear/partial_function_class.rb +3 -1
- data/lib/fear/pattern_match.rb +3 -11
- data/lib/fear/pattern_matching_api.rb +6 -28
- data/lib/fear/promise.rb +7 -5
- data/lib/fear/right.rb +3 -9
- data/lib/fear/right_biased.rb +5 -3
- data/lib/fear/right_pattern_match.rb +4 -0
- data/lib/fear/some.rb +35 -8
- data/lib/fear/some_pattern_match.rb +2 -0
- data/lib/fear/struct.rb +237 -0
- data/lib/fear/success.rb +7 -8
- data/lib/fear/success_pattern_match.rb +4 -0
- data/lib/fear/try.rb +8 -2
- data/lib/fear/try_api.rb +4 -0
- data/lib/fear/try_pattern_match.rb +9 -5
- data/lib/fear/unit.rb +6 -2
- data/lib/fear/utils.rb +14 -2
- data/lib/fear/version.rb +4 -1
- data/lib/fear.rb +26 -44
- data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
- data/spec/dry/types/fear/option/core_spec.rb +77 -0
- data/spec/dry/types/fear/option/default_spec.rb +21 -0
- data/spec/dry/types/fear/option/hash_spec.rb +58 -0
- data/spec/dry/types/fear/option/option_spec.rb +97 -0
- data/spec/fear/awaitable_spec.rb +19 -0
- data/spec/fear/done_spec.rb +7 -5
- data/spec/fear/either/mixin_spec.rb +4 -2
- data/spec/fear/either_pattern_match_spec.rb +10 -8
- data/spec/fear/either_pattern_matching_spec.rb +28 -0
- data/spec/fear/either_spec.rb +26 -0
- data/spec/fear/failure_spec.rb +57 -70
- data/spec/fear/for/mixin_spec.rb +15 -0
- data/spec/fear/for_spec.rb +19 -17
- data/spec/fear/future_spec.rb +477 -237
- data/spec/fear/guard_spec.rb +136 -24
- data/spec/fear/left_spec.rb +57 -70
- data/spec/fear/none_spec.rb +39 -43
- data/spec/fear/option/mixin_spec.rb +9 -7
- data/spec/fear/option_pattern_match_spec.rb +10 -8
- data/spec/fear/option_pattern_matching_spec.rb +34 -0
- data/spec/fear/option_spec.rb +142 -0
- data/spec/fear/partial_function/any_spec.rb +25 -0
- data/spec/fear/partial_function/empty_spec.rb +12 -10
- data/spec/fear/partial_function_and_then_spec.rb +39 -37
- data/spec/fear/partial_function_composition_spec.rb +46 -44
- data/spec/fear/partial_function_or_else_spec.rb +92 -90
- data/spec/fear/partial_function_spec.rb +91 -61
- data/spec/fear/pattern_match_spec.rb +19 -51
- data/spec/fear/pattern_matching_api_spec.rb +31 -0
- data/spec/fear/promise_spec.rb +23 -23
- data/spec/fear/right_biased/left.rb +28 -26
- data/spec/fear/right_biased/right.rb +51 -49
- data/spec/fear/right_spec.rb +48 -68
- data/spec/fear/some_spec.rb +30 -40
- data/spec/fear/success_spec.rb +40 -60
- data/spec/fear/try/mixin_spec.rb +19 -3
- data/spec/fear/try_api_spec.rb +23 -0
- data/spec/fear/try_pattern_match_spec.rb +10 -8
- data/spec/fear/try_pattern_matching_spec.rb +34 -0
- data/spec/fear/utils_spec.rb +16 -14
- data/spec/spec_helper.rb +13 -7
- data/spec/struct_pattern_matching_spec.rb +36 -0
- data/spec/struct_spec.rb +194 -0
- data/spec/support/dry_types.rb +6 -0
- metadata +128 -87
- data/.travis.yml +0 -13
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -8
- data/lib/fear/extractor/any_matcher.rb +0 -15
- data/lib/fear/extractor/array_head_matcher.rb +0 -34
- data/lib/fear/extractor/array_matcher.rb +0 -38
- data/lib/fear/extractor/array_splat_matcher.rb +0 -14
- data/lib/fear/extractor/empty_list_matcher.rb +0 -18
- data/lib/fear/extractor/extractor_matcher.rb +0 -42
- data/lib/fear/extractor/grammar.rb +0 -201
- data/lib/fear/extractor/grammar.treetop +0 -129
- data/lib/fear/extractor/identifier_matcher.rb +0 -16
- data/lib/fear/extractor/matcher/and.rb +0 -36
- data/lib/fear/extractor/matcher.rb +0 -54
- data/lib/fear/extractor/named_array_splat_matcher.rb +0 -15
- data/lib/fear/extractor/pattern.rb +0 -55
- data/lib/fear/extractor/typed_identifier_matcher.rb +0 -24
- data/lib/fear/extractor/value_matcher.rb +0 -17
- data/lib/fear/extractor.rb +0 -108
- data/lib/fear/extractor_api.rb +0 -33
- data/spec/fear/extractor/array_matcher_spec.rb +0 -228
- data/spec/fear/extractor/extractor_matcher_spec.rb +0 -151
- data/spec/fear/extractor/grammar_array_spec.rb +0 -23
- data/spec/fear/extractor/identified_matcher_spec.rb +0 -47
- data/spec/fear/extractor/identifier_matcher_spec.rb +0 -66
- data/spec/fear/extractor/pattern_spec.rb +0 -32
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -62
- data/spec/fear/extractor/value_matcher_number_spec.rb +0 -77
- data/spec/fear/extractor/value_matcher_string_spec.rb +0 -86
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -69
- data/spec/fear/extractor_api_spec.rb +0 -113
- data/spec/fear/extractor_spec.rb +0 -59
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module Types
|
5
|
+
class Option
|
6
|
+
include Type
|
7
|
+
include ::Dry::Equalizer(:type, :options, inspect: false, immutable: true)
|
8
|
+
include Decorator
|
9
|
+
include Builder
|
10
|
+
include Printable
|
11
|
+
|
12
|
+
# @param [Fear::Option, Object] input
|
13
|
+
#
|
14
|
+
# @return [Fear::Option]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def call_unsafe(input = Undefined)
|
18
|
+
case input
|
19
|
+
when ::Fear::Option
|
20
|
+
input
|
21
|
+
when Undefined
|
22
|
+
Fear.none
|
23
|
+
else
|
24
|
+
Fear.option(type.call_unsafe(input))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param [Fear::Option, Object] input
|
29
|
+
#
|
30
|
+
# @return [Fear::Option]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def call_safe(input = Undefined)
|
34
|
+
case input
|
35
|
+
when ::Fear::Option
|
36
|
+
input
|
37
|
+
when Undefined
|
38
|
+
Fear.none
|
39
|
+
else
|
40
|
+
Fear.option(type.call_safe(input) { |output = input| return yield(output) })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param [Object] input
|
45
|
+
#
|
46
|
+
# @return [Result::Success]
|
47
|
+
#
|
48
|
+
# @api public
|
49
|
+
def try(input = Undefined)
|
50
|
+
result = type.try(input)
|
51
|
+
|
52
|
+
if result.success?
|
53
|
+
Result::Success.new(Fear.option(result.input))
|
54
|
+
else
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [true]
|
60
|
+
#
|
61
|
+
# @api public
|
62
|
+
def default?
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [Object] value
|
67
|
+
#
|
68
|
+
# @see Dry::Types::Builder#default
|
69
|
+
#
|
70
|
+
# @raise [ArgumentError] if nil provided as default value
|
71
|
+
#
|
72
|
+
# @api public
|
73
|
+
def default(value)
|
74
|
+
if value.nil?
|
75
|
+
raise ArgumentError, "nil cannot be used as a default of a maybe type"
|
76
|
+
else
|
77
|
+
super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module Builder
|
83
|
+
# Turn a type into a maybe type
|
84
|
+
#
|
85
|
+
# @return [Option]
|
86
|
+
#
|
87
|
+
# @api public
|
88
|
+
def option
|
89
|
+
Option.new(Types["nil"] | self)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @api private
|
94
|
+
class Schema
|
95
|
+
class Key
|
96
|
+
# @api private
|
97
|
+
def option
|
98
|
+
__new__(type.option)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# @api private
|
104
|
+
class Printer
|
105
|
+
MAPPING[Option] = :visit_option
|
106
|
+
|
107
|
+
# @api private
|
108
|
+
def visit_option(maybe)
|
109
|
+
visit(maybe.type) do |type|
|
110
|
+
yield "Fear::Option<#{type}>"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Register non-coercible maybe types
|
116
|
+
NON_NIL.each_key do |name|
|
117
|
+
register("option.strict.#{name}", self[name.to_s].option)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Register coercible maybe types
|
121
|
+
COERCIBLE.each_key do |name|
|
122
|
+
register("option.coercible.#{name}", self["coercible.#{name}"].option)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
data/lib/fear/await.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
# You're strongly discouraged to use this module since it may lead to deadlocks,
|
5
|
+
# and reduced performance. Although, blocking may be useful in some cases (e.g. in tests)
|
6
|
+
#
|
7
|
+
# @see https://stackoverflow.com/questions/38155159/why-doesnt-scalas-future-have-a-get-getmaxduration-method-forcing-us-to
|
8
|
+
module Await
|
9
|
+
# Blocks until +Fear::Awaitable+ reached completed state and returns itself
|
10
|
+
# or raises +TimeoutError+
|
11
|
+
#
|
12
|
+
# @param awaitable [Fear::Awaitable]
|
13
|
+
# @param at_most [Fixnum] timeout in seconds
|
14
|
+
# @return [Fear::Awaitable]
|
15
|
+
# @raise [Timeout::Error]
|
16
|
+
#
|
17
|
+
module_function def ready(awaitable, at_most)
|
18
|
+
awaitable.__ready__(at_most)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Blocks until +Fear::Awaitable+ reached completed state and returns its value
|
22
|
+
# or raises +TimeoutError+
|
23
|
+
#
|
24
|
+
# @param awaitable [Fear::Awaitable]
|
25
|
+
# @param at_most [Fixnum] timeout in seconds
|
26
|
+
# @return [any]
|
27
|
+
# @raise [Timeout::Error]
|
28
|
+
#
|
29
|
+
module_function def result(awaitable, at_most)
|
30
|
+
awaitable.__result__(at_most)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Fear
|
4
|
+
# An object which may eventually be completed and awaited using blocking methods.
|
5
|
+
#
|
6
|
+
# @abstract
|
7
|
+
# @api private
|
8
|
+
# @see Fear::Await
|
9
|
+
module Awaitable
|
10
|
+
# Await +completed+ state of this +Awaitable+
|
11
|
+
#
|
12
|
+
# @param _at_most [Fixnum] maximum timeout in seconds
|
13
|
+
# @return [Fear::Awaitable]
|
14
|
+
# @raise [Timeout::Error]
|
15
|
+
def __ready__(_at_most)
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
# Await and return the result of this +Awaitable+
|
20
|
+
#
|
21
|
+
# @param _at_most [Fixnum] maximum timeout in seconds
|
22
|
+
# @return [any]
|
23
|
+
# @raise [Timeout::Error]
|
24
|
+
def __result__(_at_most)
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/fear/either.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
# Represents a value of one of two possible types (a disjoint union.)
|
3
5
|
# An instance of +Either+ is either an instance of +Left+ or +Right+.
|
@@ -70,7 +72,7 @@ module Fear
|
|
70
72
|
# Performs the given block if this is a +Right+.
|
71
73
|
# @yieldparam [any] value
|
72
74
|
# @yieldreturn [void]
|
73
|
-
# @return [
|
75
|
+
# @return [Fear::Either] itself
|
74
76
|
# @example
|
75
77
|
# Fear.right(17).each do |value|
|
76
78
|
# puts value
|
@@ -93,8 +95,8 @@ module Fear
|
|
93
95
|
# Returns the given block applied to the value from this +Right+
|
94
96
|
# or returns this if this is a +Left+.
|
95
97
|
# @yieldparam [any] value
|
96
|
-
# @yieldreturn [
|
97
|
-
# @return [
|
98
|
+
# @yieldreturn [Fear::Either]
|
99
|
+
# @return [Fear::Either]
|
98
100
|
# @example
|
99
101
|
# Fear.right(42).flat_map { |v| Fear.right(v/2) } #=> Fear.right(21)
|
100
102
|
# Fear.left('undefined').flat_map { |v| Fear.right(v/2) } #=> Fear.left('undefined')
|
@@ -104,7 +106,7 @@ module Fear
|
|
104
106
|
# this is a +Left+.
|
105
107
|
# @return [Option]
|
106
108
|
# @example
|
107
|
-
# Fear.right(42).to_option #=> Fear.some(
|
109
|
+
# Fear.right(42).to_option #=> Fear.some(42)
|
108
110
|
# Fear.left('undefined').to_option #=> Fear.none()
|
109
111
|
#
|
110
112
|
# @!method any?(&predicate)
|
@@ -273,6 +275,11 @@ module Fear
|
|
273
275
|
# @return [String]
|
274
276
|
alias to_s inspect
|
275
277
|
|
278
|
+
# @return [<any>]
|
279
|
+
def deconstruct
|
280
|
+
[value]
|
281
|
+
end
|
282
|
+
|
276
283
|
class << self
|
277
284
|
# Build pattern matcher to be used later, despite off
|
278
285
|
# +Either#match+ method, id doesn't apply matcher immanently,
|
@@ -324,3 +331,7 @@ module Fear
|
|
324
331
|
end
|
325
332
|
end
|
326
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,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear/pattern_match"
|
4
|
+
|
1
5
|
module Fear
|
2
6
|
# Either pattern matcher
|
3
7
|
#
|
@@ -22,15 +26,12 @@ module Fear
|
|
22
26
|
# @note it has two optimized subclasses +Fear::LeftPatternMatch+ and +Fear::RightPatternMatch+
|
23
27
|
# @api private
|
24
28
|
class EitherPatternMatch < Fear::PatternMatch
|
25
|
-
LEFT_EXTRACTOR = :left_value.to_proc
|
26
|
-
RIGHT_EXTRACTOR = :right_value.to_proc
|
27
|
-
|
28
29
|
# Match against +Fear::Right+
|
29
30
|
#
|
30
31
|
# @param conditions [<#==>]
|
31
32
|
# @return [Fear::EitherPatternMatch]
|
32
33
|
def right(*conditions, &effect)
|
33
|
-
branch = Fear.case(Fear::Right,
|
34
|
+
branch = Fear.case(Fear::Right, &:right_value).and_then(Fear.case(*conditions, &effect))
|
34
35
|
or_else(branch)
|
35
36
|
end
|
36
37
|
alias success right
|
@@ -40,9 +41,12 @@ module Fear
|
|
40
41
|
# @param conditions [<#==>]
|
41
42
|
# @return [Fear::EitherPatternMatch]
|
42
43
|
def left(*conditions, &effect)
|
43
|
-
branch = Fear.case(Fear::Left,
|
44
|
+
branch = Fear.case(Fear::Left, &:left_value).and_then(Fear.case(*conditions, &effect))
|
44
45
|
or_else(branch)
|
45
46
|
end
|
46
47
|
alias failure left
|
47
48
|
end
|
48
49
|
end
|
50
|
+
|
51
|
+
require "fear/left_pattern_match"
|
52
|
+
require "fear/right_pattern_match"
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
# Use singleton version of EmptyPartialFunction -- PartialFunction::EMPTY
|
3
5
|
# @api private
|
@@ -28,7 +30,7 @@ module Fear
|
|
28
30
|
end
|
29
31
|
|
30
32
|
def to_s
|
31
|
-
|
33
|
+
"Empty partial function"
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
data/lib/fear/failure.rb
CHANGED
@@ -1,15 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
class Failure
|
3
5
|
include Try
|
4
6
|
include RightBiased::Left
|
5
7
|
include FailurePatternMatch.mixin
|
6
|
-
EXTRACTOR = proc do |try|
|
7
|
-
if Fear::Failure === try
|
8
|
-
Fear.some([try.exception])
|
9
|
-
else
|
10
|
-
Fear.none
|
11
|
-
end
|
12
|
-
end
|
13
8
|
|
14
9
|
# @param [StandardError]
|
15
10
|
def initialize(exception)
|
@@ -101,5 +96,10 @@ module Fear
|
|
101
96
|
|
102
97
|
# @return [String]
|
103
98
|
alias to_s inspect
|
99
|
+
|
100
|
+
# @return [<StandardError>]
|
101
|
+
def deconstruct
|
102
|
+
[exception]
|
103
|
+
end
|
104
104
|
end
|
105
105
|
end
|
data/lib/fear/for.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
# @api private
|
3
5
|
# @see Fear.for
|
4
6
|
module For
|
5
|
-
module_function
|
7
|
+
module_function
|
6
8
|
|
7
9
|
# @param monads [<Fear::Option, Fear::Either, Fear::Try, Proc>]
|
8
10
|
#
|
@@ -30,7 +32,7 @@ module Fear
|
|
30
32
|
|
31
33
|
private def resolve(monad_or_proc, inner_values)
|
32
34
|
if monad_or_proc.respond_to?(:call)
|
33
|
-
monad_or_proc.
|
35
|
+
monad_or_proc.(*inner_values)
|
34
36
|
else
|
35
37
|
monad_or_proc
|
36
38
|
end
|
data/lib/fear/for_api.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear/for"
|
4
|
+
|
1
5
|
module Fear
|
2
6
|
module ForApi
|
3
7
|
# Syntactic sugar for composition of multiple monadic operations. It supports two such
|
@@ -60,7 +64,7 @@ module Fear
|
|
60
64
|
# @return [{#map, #flat_map}]
|
61
65
|
#
|
62
66
|
def for(*monads, &block)
|
63
|
-
Fear::For.
|
67
|
+
Fear::For.(monads, &block)
|
64
68
|
end
|
65
69
|
end
|
66
70
|
end
|