fear 0.9.0 → 1.2.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 +5 -5
- data/.github/workflows/rubocop.yml +39 -0
- data/.github/workflows/spec.yml +42 -0
- data/.gitignore +0 -1
- data/.rubocop.yml +4 -12
- data/.simplecov +17 -0
- data/CHANGELOG.md +40 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +130 -0
- data/LICENSE.txt +1 -1
- data/README.md +1293 -97
- data/Rakefile +369 -1
- data/benchmarks/README.md +1 -0
- data/benchmarks/dry_do_vs_fear_for.txt +11 -0
- data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
- data/benchmarks/factorial.txt +16 -0
- data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
- data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
- data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
- data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
- data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
- data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
- data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
- data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
- data/examples/pattern_extracting.rb +17 -0
- data/examples/pattern_extracting_ruby2.7.rb +15 -0
- data/examples/pattern_matching_binary_tree_set.rb +101 -0
- data/examples/pattern_matching_number_in_words.rb +60 -0
- data/fear.gemspec +34 -23
- data/lib/dry/types/fear.rb +8 -0
- data/lib/dry/types/fear/option.rb +125 -0
- data/lib/fear.rb +65 -15
- data/lib/fear/await.rb +33 -0
- data/lib/fear/awaitable.rb +28 -0
- data/lib/fear/either.rb +131 -71
- data/lib/fear/either_api.rb +23 -0
- data/lib/fear/either_pattern_match.rb +53 -0
- data/lib/fear/empty_partial_function.rb +38 -0
- data/lib/fear/extractor.rb +112 -0
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +10 -0
- data/lib/fear/extractor/any_matcher.rb +17 -0
- data/lib/fear/extractor/array_head_matcher.rb +36 -0
- data/lib/fear/extractor/array_matcher.rb +40 -0
- data/lib/fear/extractor/array_splat_matcher.rb +16 -0
- data/lib/fear/extractor/empty_list_matcher.rb +20 -0
- data/lib/fear/extractor/extractor_matcher.rb +44 -0
- data/lib/fear/extractor/grammar.rb +203 -0
- data/lib/fear/extractor/grammar.treetop +129 -0
- data/lib/fear/extractor/identifier_matcher.rb +18 -0
- data/lib/fear/extractor/matcher.rb +53 -0
- data/lib/fear/extractor/matcher/and.rb +38 -0
- data/lib/fear/extractor/named_array_splat_matcher.rb +17 -0
- data/lib/fear/extractor/pattern.rb +58 -0
- data/lib/fear/extractor/typed_identifier_matcher.rb +26 -0
- data/lib/fear/extractor/value_matcher.rb +19 -0
- data/lib/fear/extractor_api.rb +35 -0
- data/lib/fear/failure.rb +46 -14
- data/lib/fear/failure_pattern_match.rb +10 -0
- data/lib/fear/for.rb +37 -95
- data/lib/fear/for_api.rb +68 -0
- data/lib/fear/future.rb +497 -0
- data/lib/fear/future_api.rb +21 -0
- data/lib/fear/left.rb +19 -2
- data/lib/fear/left_pattern_match.rb +11 -0
- data/lib/fear/none.rb +67 -3
- data/lib/fear/none_pattern_match.rb +14 -0
- data/lib/fear/option.rb +120 -56
- data/lib/fear/option_api.rb +40 -0
- data/lib/fear/option_pattern_match.rb +48 -0
- data/lib/fear/partial_function.rb +176 -0
- data/lib/fear/partial_function/and_then.rb +50 -0
- data/lib/fear/partial_function/any.rb +28 -0
- data/lib/fear/partial_function/combined.rb +53 -0
- data/lib/fear/partial_function/empty.rb +10 -0
- data/lib/fear/partial_function/guard.rb +80 -0
- data/lib/fear/partial_function/guard/and.rb +38 -0
- data/lib/fear/partial_function/guard/and3.rb +41 -0
- data/lib/fear/partial_function/guard/or.rb +38 -0
- data/lib/fear/partial_function/lifted.rb +23 -0
- data/lib/fear/partial_function/or_else.rb +64 -0
- data/lib/fear/partial_function_class.rb +38 -0
- data/lib/fear/pattern_match.rb +114 -0
- data/lib/fear/pattern_matching_api.rb +137 -0
- data/lib/fear/promise.rb +95 -0
- data/lib/fear/right.rb +20 -2
- data/lib/fear/right_biased.rb +6 -14
- data/lib/fear/right_pattern_match.rb +11 -0
- data/lib/fear/some.rb +55 -3
- data/lib/fear/some_pattern_match.rb +13 -0
- data/lib/fear/struct.rb +248 -0
- data/lib/fear/success.rb +35 -5
- data/lib/fear/success_pattern_match.rb +12 -0
- data/lib/fear/try.rb +136 -79
- data/lib/fear/try_api.rb +33 -0
- data/lib/fear/try_pattern_match.rb +33 -0
- data/lib/fear/unit.rb +32 -0
- data/lib/fear/utils.rb +39 -14
- data/lib/fear/version.rb +4 -1
- 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 +17 -0
- data/spec/fear/done_spec.rb +8 -6
- data/spec/fear/either/mixin_spec.rb +17 -0
- data/spec/fear/either_pattern_match_spec.rb +37 -0
- data/spec/fear/either_pattern_matching_spec.rb +28 -0
- data/spec/fear/extractor/array_matcher_spec.rb +230 -0
- data/spec/fear/extractor/extractor_matcher_spec.rb +153 -0
- data/spec/fear/extractor/grammar_array_spec.rb +25 -0
- data/spec/fear/extractor/identified_matcher_spec.rb +49 -0
- data/spec/fear/extractor/identifier_matcher_spec.rb +68 -0
- data/spec/fear/extractor/pattern_spec.rb +34 -0
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +64 -0
- data/spec/fear/extractor/value_matcher_number_spec.rb +79 -0
- data/spec/fear/extractor/value_matcher_string_spec.rb +88 -0
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +71 -0
- data/spec/fear/extractor_api_spec.rb +115 -0
- data/spec/fear/extractor_spec.rb +61 -0
- data/spec/fear/failure_spec.rb +145 -45
- data/spec/fear/for_spec.rb +57 -67
- data/spec/fear/future_spec.rb +691 -0
- data/spec/fear/guard_spec.rb +103 -0
- data/spec/fear/left_spec.rb +112 -46
- data/spec/fear/none_spec.rb +114 -16
- data/spec/fear/option/mixin_spec.rb +39 -0
- data/spec/fear/option_pattern_match_spec.rb +35 -0
- data/spec/fear/option_pattern_matching_spec.rb +34 -0
- data/spec/fear/option_spec.rb +121 -8
- data/spec/fear/partial_function/empty_spec.rb +38 -0
- data/spec/fear/partial_function_and_then_spec.rb +147 -0
- data/spec/fear/partial_function_composition_spec.rb +82 -0
- data/spec/fear/partial_function_or_else_spec.rb +276 -0
- data/spec/fear/partial_function_spec.rb +239 -0
- data/spec/fear/pattern_match_spec.rb +93 -0
- data/spec/fear/pattern_matching_api_spec.rb +31 -0
- data/spec/fear/promise_spec.rb +96 -0
- data/spec/fear/right_biased/left.rb +29 -32
- data/spec/fear/right_biased/right.rb +51 -54
- data/spec/fear/right_spec.rb +109 -41
- data/spec/fear/some_spec.rb +80 -15
- data/spec/fear/success_spec.rb +99 -32
- data/spec/fear/try/mixin_spec.rb +19 -0
- data/spec/fear/try_pattern_match_spec.rb +37 -0
- 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 +226 -0
- data/spec/support/dry_types.rb +6 -0
- metadata +320 -29
- data/.travis.yml +0 -9
- data/lib/fear/done.rb +0 -22
- data/lib/fear/for/evaluation_context.rb +0 -91
data/lib/fear.rb
CHANGED
@@ -1,27 +1,77 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear/either_api"
|
4
|
+
require "fear/extractor_api"
|
5
|
+
require "fear/for_api"
|
6
|
+
require "fear/future_api"
|
7
|
+
require "fear/option_api"
|
8
|
+
require "fear/pattern_matching_api"
|
9
|
+
require "fear/try_api"
|
10
|
+
require "fear/version"
|
3
11
|
|
4
12
|
module Fear
|
5
13
|
Error = Class.new(StandardError)
|
14
|
+
public_constant :Error
|
15
|
+
|
6
16
|
IllegalStateException = Class.new(Error)
|
17
|
+
public_constant :IllegalStateException
|
18
|
+
|
19
|
+
MatchError = Class.new(Error)
|
20
|
+
public_constant :MatchError
|
21
|
+
|
7
22
|
NoSuchElementError = Class.new(Error)
|
23
|
+
public_constant :NoSuchElementError
|
24
|
+
|
25
|
+
PatternSyntaxError = Class.new(Error)
|
26
|
+
public_constant :PatternSyntaxError
|
27
|
+
|
28
|
+
extend EitherApi
|
29
|
+
extend ExtractorApi
|
30
|
+
extend ForApi
|
31
|
+
extend FutureApi
|
32
|
+
extend OptionApi
|
33
|
+
extend PatternMatchingApi
|
34
|
+
extend TryApi
|
35
|
+
|
36
|
+
autoload :EmptyPartialFunction, "fear/empty_partial_function"
|
37
|
+
autoload :PartialFunction, "fear/partial_function"
|
38
|
+
autoload :PartialFunctionClass, "fear/partial_function_class"
|
39
|
+
autoload :PatternMatch, "fear/pattern_match"
|
40
|
+
autoload :Extractor, "fear/extractor"
|
41
|
+
|
42
|
+
autoload :Unit, "fear/unit"
|
43
|
+
autoload :For, "fear/for"
|
44
|
+
autoload :RightBiased, "fear/right_biased"
|
45
|
+
autoload :Utils, "fear/utils"
|
46
|
+
|
47
|
+
autoload :None, "fear/none"
|
48
|
+
autoload :NoneClass, "fear/none"
|
49
|
+
autoload :NonePatternMatch, "fear/none_pattern_match"
|
50
|
+
autoload :Option, "fear/option"
|
51
|
+
autoload :OptionPatternMatch, "fear/option_pattern_match"
|
52
|
+
autoload :Some, "fear/some"
|
53
|
+
autoload :SomePatternMatch, "fear/some_pattern_match"
|
8
54
|
|
9
|
-
autoload :
|
10
|
-
autoload :
|
11
|
-
autoload :
|
12
|
-
autoload :
|
55
|
+
autoload :Failure, "fear/failure"
|
56
|
+
autoload :FailurePatternMatch, "fear/failure_pattern_match"
|
57
|
+
autoload :Success, "fear/success"
|
58
|
+
autoload :SuccessPatternMatch, "fear/success_pattern_match"
|
59
|
+
autoload :Try, "fear/try"
|
60
|
+
autoload :TryPatternMatch, "fear/try_pattern_match"
|
13
61
|
|
14
|
-
autoload :
|
15
|
-
autoload :
|
16
|
-
autoload :
|
62
|
+
autoload :Either, "fear/either"
|
63
|
+
autoload :EitherPatternMatch, "fear/either_pattern_match"
|
64
|
+
autoload :Left, "fear/left"
|
65
|
+
autoload :LeftPatternMatch, "fear/left_pattern_match"
|
66
|
+
autoload :Right, "fear/right"
|
67
|
+
autoload :RightPatternMatch, "fear/right_pattern_match"
|
17
68
|
|
18
|
-
autoload :
|
19
|
-
autoload :
|
20
|
-
autoload :
|
69
|
+
autoload :Await, "fear/await"
|
70
|
+
autoload :Awaitable, "fear/awaitable"
|
71
|
+
autoload :Future, "fear/future"
|
72
|
+
autoload :Promise, "fear/promise"
|
21
73
|
|
22
|
-
autoload :
|
23
|
-
autoload :Left, 'fear/left'
|
24
|
-
autoload :Right, 'fear/right'
|
74
|
+
autoload :Struct, "fear/struct"
|
25
75
|
|
26
76
|
module Mixin
|
27
77
|
include Either::Mixin
|
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+.
|
@@ -14,17 +16,20 @@ module Fear
|
|
14
16
|
# @example
|
15
17
|
# in = Readline.readline('Type Either a string or an Int: ', true)
|
16
18
|
# result = begin
|
17
|
-
#
|
19
|
+
# Fear.right(Integer(in))
|
18
20
|
# rescue ArgumentError
|
19
|
-
#
|
21
|
+
# Fear.left(in)
|
20
22
|
# end
|
21
23
|
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
24
|
+
# result.match do |m|
|
25
|
+
# m.right do |x|
|
26
|
+
# "You passed me the Int: #{x}, which I will increment. #{x} + 1 = #{x+1}"
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# m.left do |x|
|
30
|
+
# "You passed me the String: #{x}"
|
31
|
+
# end
|
32
|
+
# end
|
28
33
|
#
|
29
34
|
# Either is right-biased, which means that +Right+ is assumed to be the default case to
|
30
35
|
# operate on. If it is +Left+, operations like +#map+, +#flat_map+, ... return the +Left+ value
|
@@ -37,21 +42,21 @@ module Fear
|
|
37
42
|
# @yieldreturn [any]
|
38
43
|
# @return [any]
|
39
44
|
# @example
|
40
|
-
#
|
41
|
-
#
|
45
|
+
# Fear.right(42).get_or_else { 24/2 } #=> 42
|
46
|
+
# Fear.left('undefined').get_or_else { 24/2 } #=> 12
|
42
47
|
# @overload get_or_else(default)
|
43
48
|
# @return [any]
|
44
49
|
# @example
|
45
|
-
#
|
46
|
-
#
|
50
|
+
# Fear.right(42).get_or_else(12) #=> 42
|
51
|
+
# Fear.left('undefined').get_or_else(12) #=> 12
|
47
52
|
#
|
48
53
|
# @!method or_else(&alternative)
|
49
54
|
# Returns this +Right+ or the given alternative if this is a +Left+.
|
50
55
|
# @return [Either]
|
51
56
|
# @example
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
57
|
+
# Fear.right(42).or_else { Fear.right(21) } #=> Fear.right(42)
|
58
|
+
# Fear.left('unknown').or_else { Fear.right(21) } #=> Fear.right(21)
|
59
|
+
# Fear.left('unknown').or_else { Fear.left('empty') } #=> Fear.left('empty')
|
55
60
|
#
|
56
61
|
# @!method include?(other_value)
|
57
62
|
# Returns +true+ if +Right+ has an element that is equal
|
@@ -59,9 +64,9 @@ module Fear
|
|
59
64
|
# @param [any]
|
60
65
|
# @return [Boolean]
|
61
66
|
# @example
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
67
|
+
# Fear.right(17).include?(17) #=> true
|
68
|
+
# Fear.right(17).include?(7) #=> false
|
69
|
+
# Fear.left('undefined').include?(17) #=> false
|
65
70
|
#
|
66
71
|
# @!method each(&block)
|
67
72
|
# Performs the given block if this is a +Right+.
|
@@ -69,11 +74,11 @@ module Fear
|
|
69
74
|
# @yieldreturn [void]
|
70
75
|
# @return [Option] itself
|
71
76
|
# @example
|
72
|
-
#
|
77
|
+
# Fear.right(17).each do |value|
|
73
78
|
# puts value
|
74
79
|
# end #=> prints 17
|
75
80
|
#
|
76
|
-
#
|
81
|
+
# Fear.left('undefined').each do |value|
|
77
82
|
# puts value
|
78
83
|
# end #=> does nothing
|
79
84
|
#
|
@@ -83,8 +88,8 @@ module Fear
|
|
83
88
|
# @yieldparam [any] value
|
84
89
|
# @yieldreturn [any]
|
85
90
|
# @example
|
86
|
-
#
|
87
|
-
#
|
91
|
+
# Fear.right(42).map { |v| v/2 } #=> Fear.right(21)
|
92
|
+
# Fear.left('undefined').map { |v| v/2 } #=> Fear.left('undefined')
|
88
93
|
#
|
89
94
|
# @!method flat_map(&block)
|
90
95
|
# Returns the given block applied to the value from this +Right+
|
@@ -93,24 +98,16 @@ module Fear
|
|
93
98
|
# @yieldreturn [Option]
|
94
99
|
# @return [Option]
|
95
100
|
# @example
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
# @!method to_a
|
100
|
-
# Returns an +Array+ containing the +Right+ value or an
|
101
|
-
# empty +Array+ if this is a +Left+.
|
102
|
-
# @return [Array]
|
103
|
-
# @example
|
104
|
-
# Right(42).to_a #=> [21]
|
105
|
-
# Left('undefined').to_a #=> []
|
101
|
+
# Fear.right(42).flat_map { |v| Fear.right(v/2) } #=> Fear.right(21)
|
102
|
+
# Fear.left('undefined').flat_map { |v| Fear.right(v/2) } #=> Fear.left('undefined')
|
106
103
|
#
|
107
104
|
# @!method to_option
|
108
105
|
# Returns an +Some+ containing the +Right+ value or a +None+ if
|
109
106
|
# this is a +Left+.
|
110
107
|
# @return [Option]
|
111
108
|
# @example
|
112
|
-
#
|
113
|
-
#
|
109
|
+
# Fear.right(42).to_option #=> Fear.some(21)
|
110
|
+
# Fear.left('undefined').to_option #=> Fear.none()
|
114
111
|
#
|
115
112
|
# @!method any?(&predicate)
|
116
113
|
# Returns +false+ if +Left+ or returns the result of the
|
@@ -119,9 +116,9 @@ module Fear
|
|
119
116
|
# @yieldreturn [Boolean]
|
120
117
|
# @return [Boolean]
|
121
118
|
# @example
|
122
|
-
#
|
123
|
-
#
|
124
|
-
#
|
119
|
+
# Fear.right(12).any?( |v| v > 10) #=> true
|
120
|
+
# Fear.right(7).any?( |v| v > 10) #=> false
|
121
|
+
# Fear.left('undefined').any?( |v| v > 10) #=> false
|
125
122
|
#
|
126
123
|
# -----
|
127
124
|
#
|
@@ -130,16 +127,16 @@ module Fear
|
|
130
127
|
# @note this method is also aliased as +#success?+
|
131
128
|
# @return [Boolean]
|
132
129
|
# @example
|
133
|
-
#
|
134
|
-
#
|
130
|
+
# Fear.right(42).right? #=> true
|
131
|
+
# Fear.left('err').right? #=> false
|
135
132
|
#
|
136
133
|
# @!method left?
|
137
134
|
# Returns +true+ if this is a +Left+, +false+ otherwise.
|
138
135
|
# @note this method is also aliased as +#failure?+
|
139
136
|
# @return [Boolean]
|
140
137
|
# @example
|
141
|
-
#
|
142
|
-
#
|
138
|
+
# Fear.right(42).left? #=> false
|
139
|
+
# Fear.left('err').left? #=> true
|
143
140
|
#
|
144
141
|
# @!method select_or_else(default, &predicate)
|
145
142
|
# Returns +Left+ of the default if the given predicate
|
@@ -149,10 +146,10 @@ module Fear
|
|
149
146
|
# @yieldreturn [Boolean]
|
150
147
|
# @return [Either]
|
151
148
|
# @example
|
152
|
-
#
|
153
|
-
#
|
154
|
-
#
|
155
|
-
#
|
149
|
+
# Fear.right(12).select_or_else(-1, &:even?) #=> Fear.right(12)
|
150
|
+
# Fear.right(7).select_or_else(-1, &:even?) #=> Fear.left(-1)
|
151
|
+
# Fear.left(12).select_or_else(-1, &:even?) #=> Fear.left(12)
|
152
|
+
# Fear.left(12).select_or_else(-> { -1 }, &:even?) #=> Fear.left(12)
|
156
153
|
#
|
157
154
|
# @!method select(&predicate)
|
158
155
|
# Returns +Left+ of value if the given predicate
|
@@ -161,10 +158,10 @@ module Fear
|
|
161
158
|
# @yieldreturn [Boolean]
|
162
159
|
# @return [Either]
|
163
160
|
# @example
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
161
|
+
# Fear.right(12).select(&:even?) #=> Fear.right(12)
|
162
|
+
# Fear.right(7).select(&:even?) #=> Fear.left(7)
|
163
|
+
# Fear.left(12).select(&:even?) #=> Fear.left(12)
|
164
|
+
# Fear.left(7).select(&:even?) #=> Fear.left(7)
|
168
165
|
#
|
169
166
|
# @!method reject(&predicate)
|
170
167
|
# Returns +Left+ of value if the given predicate holds for the
|
@@ -173,17 +170,17 @@ module Fear
|
|
173
170
|
# @yieldreturn [Boolean]
|
174
171
|
# @return [Either]
|
175
172
|
# @example
|
176
|
-
#
|
177
|
-
#
|
178
|
-
#
|
179
|
-
#
|
173
|
+
# Fear.right(12).reject(&:even?) #=> Fear.left(12)
|
174
|
+
# Fear.right(7).reject(&:even?) #=> Fear.right(7)
|
175
|
+
# Fear.left(12).reject(&:even?) #=> Fear.left(12)
|
176
|
+
# Fear.left(7).reject(&:even?) #=> Fear.left(7)
|
180
177
|
#
|
181
178
|
# @!method swap
|
182
179
|
# If this is a +Left+, then return the left value in +Right+ or vice versa.
|
183
180
|
# @return [Either]
|
184
181
|
# @example
|
185
|
-
#
|
186
|
-
#
|
182
|
+
# Fear.left('left').swap #=> Fear.right('left')
|
183
|
+
# Fear.right('right').swap #=> Fear.left('left')
|
187
184
|
#
|
188
185
|
# @!method reduce(reduce_left, reduce_right)
|
189
186
|
# Applies +reduce_left+ if this is a +Left+ or +reduce_right+ if
|
@@ -209,10 +206,10 @@ module Fear
|
|
209
206
|
# @return [Either]
|
210
207
|
# @raise [TypeError] if it does not contain +Either+.
|
211
208
|
# @example
|
212
|
-
#
|
213
|
-
#
|
214
|
-
#
|
215
|
-
#
|
209
|
+
# Fear.right(Fear.right(12)).join_right #=> Fear.right(12)
|
210
|
+
# Fear.right(Fear.left("flower")).join_right #=> Fear.left("flower")
|
211
|
+
# Fear.left("flower").join_right #=> Fear.left("flower")
|
212
|
+
# Fear.left(Fear.right("flower")).join_right #=> Fear.left(Fear.right("flower"))
|
216
213
|
#
|
217
214
|
# @!method join_right
|
218
215
|
# Joins an +Either+ through +Left+. This method requires
|
@@ -222,16 +219,31 @@ module Fear
|
|
222
219
|
# @return [Either]
|
223
220
|
# @raise [TypeError] if it does not contain +Either+.
|
224
221
|
# @example
|
225
|
-
#
|
226
|
-
#
|
227
|
-
#
|
228
|
-
#
|
222
|
+
# Fear.left(Fear.right("flower")).join_left #=> Fear.right("flower")
|
223
|
+
# Fear.left(Fear.left(12)).join_left #=> Fear.left(12)
|
224
|
+
# Fear.right("daisy").join_left #=> Fear.right("daisy")
|
225
|
+
# Fear.right(Fear.left("daisy")).join_left #=> Fear.right(Fear.left("daisy"))
|
226
|
+
#
|
227
|
+
# @!method match(&matcher)
|
228
|
+
# Pattern match against this +Either+
|
229
|
+
# @yield matcher [Fear::EitherPatternMatch]
|
230
|
+
# @example
|
231
|
+
# either.match do |m|
|
232
|
+
# m.right(Integer) do |x|
|
233
|
+
# x * 2
|
234
|
+
# end
|
235
|
+
#
|
236
|
+
# m.right(String) do |x|
|
237
|
+
# x.to_i * 2
|
238
|
+
# end
|
239
|
+
#
|
240
|
+
# m.left { |x| x }
|
241
|
+
# m.else { 'something unexpected' }
|
242
|
+
# end
|
229
243
|
#
|
230
244
|
# @see https://github.com/scala/scala/blob/2.12.x/src/library/scala/util/Either.scala
|
231
245
|
#
|
232
246
|
module Either
|
233
|
-
include Dry::Equalizer(:value)
|
234
|
-
|
235
247
|
# @private
|
236
248
|
def left_class
|
237
249
|
Left
|
@@ -249,6 +261,48 @@ module Fear
|
|
249
261
|
attr_reader :value
|
250
262
|
protected :value
|
251
263
|
|
264
|
+
# @param other [Any]
|
265
|
+
# @return [Boolean]
|
266
|
+
def ==(other)
|
267
|
+
other.is_a?(self.class) && value == other.value
|
268
|
+
end
|
269
|
+
|
270
|
+
# @return [String]
|
271
|
+
def inspect
|
272
|
+
"#<#{self.class} value=#{value.inspect}>"
|
273
|
+
end
|
274
|
+
|
275
|
+
# @return [String]
|
276
|
+
alias to_s inspect
|
277
|
+
|
278
|
+
# @return [<any>]
|
279
|
+
def deconstruct
|
280
|
+
[value]
|
281
|
+
end
|
282
|
+
|
283
|
+
class << self
|
284
|
+
# Build pattern matcher to be used later, despite off
|
285
|
+
# +Either#match+ method, id doesn't apply matcher immanently,
|
286
|
+
# but build it instead. Unusually in sake of efficiency it's better
|
287
|
+
# to statically build matcher and reuse it later.
|
288
|
+
#
|
289
|
+
# @example
|
290
|
+
# matcher =
|
291
|
+
# Either.matcher do |m|
|
292
|
+
# m.right(Integer, ->(x) { x > 2 }) { |x| x * 2 }
|
293
|
+
# m.right(String) { |x| x.to_i * 2 }
|
294
|
+
# m.left(String) { :err }
|
295
|
+
# m.else { 'error '}
|
296
|
+
# end
|
297
|
+
# matcher.call(Fear.right(42))
|
298
|
+
#
|
299
|
+
# @yieldparam [Fear::EitherPatternMatch]
|
300
|
+
# @return [Fear::PartialFunction]
|
301
|
+
def matcher(&matcher)
|
302
|
+
EitherPatternMatch.new(&matcher)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
252
306
|
# Include this mixin to access convenient factory methods.
|
253
307
|
# @example
|
254
308
|
# include Fear::Either::Mixin
|
@@ -257,16 +311,22 @@ module Fear
|
|
257
311
|
# Left('beaf') #=> #<Fear::Legt value='beaf'>
|
258
312
|
#
|
259
313
|
module Mixin
|
260
|
-
# @param [any]
|
261
|
-
# @return [Left]
|
314
|
+
# @param value [any]
|
315
|
+
# @return [Fear::Left]
|
316
|
+
# @example
|
317
|
+
# Left(42) #=> #<Fear::Left value=42>
|
318
|
+
#
|
262
319
|
def Left(value)
|
263
|
-
|
320
|
+
Fear.left(value)
|
264
321
|
end
|
265
322
|
|
266
|
-
# @param [any]
|
267
|
-
# @return [Right]
|
323
|
+
# @param value [any]
|
324
|
+
# @return [Fear::Right]
|
325
|
+
# @example
|
326
|
+
# Right(42) #=> #<Fear::Right value=42>
|
327
|
+
#
|
268
328
|
def Right(value)
|
269
|
-
|
329
|
+
Fear.right(value)
|
270
330
|
end
|
271
331
|
end
|
272
332
|
end
|