fear 0.9.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rubocop.yml +39 -0
  3. data/.github/workflows/spec.yml +42 -0
  4. data/.gitignore +0 -1
  5. data/.rubocop.yml +4 -12
  6. data/.simplecov +17 -0
  7. data/CHANGELOG.md +40 -0
  8. data/Gemfile +5 -2
  9. data/Gemfile.lock +130 -0
  10. data/LICENSE.txt +1 -1
  11. data/README.md +1293 -97
  12. data/Rakefile +369 -1
  13. data/benchmarks/README.md +1 -0
  14. data/benchmarks/dry_do_vs_fear_for.txt +11 -0
  15. data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +11 -0
  16. data/benchmarks/factorial.txt +16 -0
  17. data/benchmarks/fear_gaurd_and1_vs_new.txt +13 -0
  18. data/benchmarks/fear_gaurd_and2_vs_and.txt +13 -0
  19. data/benchmarks/fear_gaurd_and3_vs_and_and.txt +13 -0
  20. data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +11 -0
  21. data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +13 -0
  22. data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +14 -0
  23. data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +11 -0
  24. data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +11 -0
  25. data/examples/pattern_extracting.rb +17 -0
  26. data/examples/pattern_extracting_ruby2.7.rb +15 -0
  27. data/examples/pattern_matching_binary_tree_set.rb +101 -0
  28. data/examples/pattern_matching_number_in_words.rb +60 -0
  29. data/fear.gemspec +34 -23
  30. data/lib/dry/types/fear.rb +8 -0
  31. data/lib/dry/types/fear/option.rb +125 -0
  32. data/lib/fear.rb +65 -15
  33. data/lib/fear/await.rb +33 -0
  34. data/lib/fear/awaitable.rb +28 -0
  35. data/lib/fear/either.rb +131 -71
  36. data/lib/fear/either_api.rb +23 -0
  37. data/lib/fear/either_pattern_match.rb +53 -0
  38. data/lib/fear/empty_partial_function.rb +38 -0
  39. data/lib/fear/extractor.rb +112 -0
  40. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +10 -0
  41. data/lib/fear/extractor/any_matcher.rb +17 -0
  42. data/lib/fear/extractor/array_head_matcher.rb +36 -0
  43. data/lib/fear/extractor/array_matcher.rb +40 -0
  44. data/lib/fear/extractor/array_splat_matcher.rb +16 -0
  45. data/lib/fear/extractor/empty_list_matcher.rb +20 -0
  46. data/lib/fear/extractor/extractor_matcher.rb +44 -0
  47. data/lib/fear/extractor/grammar.rb +203 -0
  48. data/lib/fear/extractor/grammar.treetop +129 -0
  49. data/lib/fear/extractor/identifier_matcher.rb +18 -0
  50. data/lib/fear/extractor/matcher.rb +53 -0
  51. data/lib/fear/extractor/matcher/and.rb +38 -0
  52. data/lib/fear/extractor/named_array_splat_matcher.rb +17 -0
  53. data/lib/fear/extractor/pattern.rb +58 -0
  54. data/lib/fear/extractor/typed_identifier_matcher.rb +26 -0
  55. data/lib/fear/extractor/value_matcher.rb +19 -0
  56. data/lib/fear/extractor_api.rb +35 -0
  57. data/lib/fear/failure.rb +46 -14
  58. data/lib/fear/failure_pattern_match.rb +10 -0
  59. data/lib/fear/for.rb +37 -95
  60. data/lib/fear/for_api.rb +68 -0
  61. data/lib/fear/future.rb +497 -0
  62. data/lib/fear/future_api.rb +21 -0
  63. data/lib/fear/left.rb +19 -2
  64. data/lib/fear/left_pattern_match.rb +11 -0
  65. data/lib/fear/none.rb +67 -3
  66. data/lib/fear/none_pattern_match.rb +14 -0
  67. data/lib/fear/option.rb +120 -56
  68. data/lib/fear/option_api.rb +40 -0
  69. data/lib/fear/option_pattern_match.rb +48 -0
  70. data/lib/fear/partial_function.rb +176 -0
  71. data/lib/fear/partial_function/and_then.rb +50 -0
  72. data/lib/fear/partial_function/any.rb +28 -0
  73. data/lib/fear/partial_function/combined.rb +53 -0
  74. data/lib/fear/partial_function/empty.rb +10 -0
  75. data/lib/fear/partial_function/guard.rb +80 -0
  76. data/lib/fear/partial_function/guard/and.rb +38 -0
  77. data/lib/fear/partial_function/guard/and3.rb +41 -0
  78. data/lib/fear/partial_function/guard/or.rb +38 -0
  79. data/lib/fear/partial_function/lifted.rb +23 -0
  80. data/lib/fear/partial_function/or_else.rb +64 -0
  81. data/lib/fear/partial_function_class.rb +38 -0
  82. data/lib/fear/pattern_match.rb +114 -0
  83. data/lib/fear/pattern_matching_api.rb +137 -0
  84. data/lib/fear/promise.rb +95 -0
  85. data/lib/fear/right.rb +20 -2
  86. data/lib/fear/right_biased.rb +6 -14
  87. data/lib/fear/right_pattern_match.rb +11 -0
  88. data/lib/fear/some.rb +55 -3
  89. data/lib/fear/some_pattern_match.rb +13 -0
  90. data/lib/fear/struct.rb +248 -0
  91. data/lib/fear/success.rb +35 -5
  92. data/lib/fear/success_pattern_match.rb +12 -0
  93. data/lib/fear/try.rb +136 -79
  94. data/lib/fear/try_api.rb +33 -0
  95. data/lib/fear/try_pattern_match.rb +33 -0
  96. data/lib/fear/unit.rb +32 -0
  97. data/lib/fear/utils.rb +39 -14
  98. data/lib/fear/version.rb +4 -1
  99. data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
  100. data/spec/dry/types/fear/option/core_spec.rb +77 -0
  101. data/spec/dry/types/fear/option/default_spec.rb +21 -0
  102. data/spec/dry/types/fear/option/hash_spec.rb +58 -0
  103. data/spec/dry/types/fear/option/option_spec.rb +97 -0
  104. data/spec/fear/awaitable_spec.rb +17 -0
  105. data/spec/fear/done_spec.rb +8 -6
  106. data/spec/fear/either/mixin_spec.rb +17 -0
  107. data/spec/fear/either_pattern_match_spec.rb +37 -0
  108. data/spec/fear/either_pattern_matching_spec.rb +28 -0
  109. data/spec/fear/extractor/array_matcher_spec.rb +230 -0
  110. data/spec/fear/extractor/extractor_matcher_spec.rb +153 -0
  111. data/spec/fear/extractor/grammar_array_spec.rb +25 -0
  112. data/spec/fear/extractor/identified_matcher_spec.rb +49 -0
  113. data/spec/fear/extractor/identifier_matcher_spec.rb +68 -0
  114. data/spec/fear/extractor/pattern_spec.rb +34 -0
  115. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +64 -0
  116. data/spec/fear/extractor/value_matcher_number_spec.rb +79 -0
  117. data/spec/fear/extractor/value_matcher_string_spec.rb +88 -0
  118. data/spec/fear/extractor/value_matcher_symbol_spec.rb +71 -0
  119. data/spec/fear/extractor_api_spec.rb +115 -0
  120. data/spec/fear/extractor_spec.rb +61 -0
  121. data/spec/fear/failure_spec.rb +145 -45
  122. data/spec/fear/for_spec.rb +57 -67
  123. data/spec/fear/future_spec.rb +691 -0
  124. data/spec/fear/guard_spec.rb +103 -0
  125. data/spec/fear/left_spec.rb +112 -46
  126. data/spec/fear/none_spec.rb +114 -16
  127. data/spec/fear/option/mixin_spec.rb +39 -0
  128. data/spec/fear/option_pattern_match_spec.rb +35 -0
  129. data/spec/fear/option_pattern_matching_spec.rb +34 -0
  130. data/spec/fear/option_spec.rb +121 -8
  131. data/spec/fear/partial_function/empty_spec.rb +38 -0
  132. data/spec/fear/partial_function_and_then_spec.rb +147 -0
  133. data/spec/fear/partial_function_composition_spec.rb +82 -0
  134. data/spec/fear/partial_function_or_else_spec.rb +276 -0
  135. data/spec/fear/partial_function_spec.rb +239 -0
  136. data/spec/fear/pattern_match_spec.rb +93 -0
  137. data/spec/fear/pattern_matching_api_spec.rb +31 -0
  138. data/spec/fear/promise_spec.rb +96 -0
  139. data/spec/fear/right_biased/left.rb +29 -32
  140. data/spec/fear/right_biased/right.rb +51 -54
  141. data/spec/fear/right_spec.rb +109 -41
  142. data/spec/fear/some_spec.rb +80 -15
  143. data/spec/fear/success_spec.rb +99 -32
  144. data/spec/fear/try/mixin_spec.rb +19 -0
  145. data/spec/fear/try_pattern_match_spec.rb +37 -0
  146. data/spec/fear/try_pattern_matching_spec.rb +34 -0
  147. data/spec/fear/utils_spec.rb +16 -14
  148. data/spec/spec_helper.rb +13 -7
  149. data/spec/struct_pattern_matching_spec.rb +36 -0
  150. data/spec/struct_spec.rb +226 -0
  151. data/spec/support/dry_types.rb +6 -0
  152. metadata +320 -29
  153. data/.travis.yml +0 -9
  154. data/lib/fear/done.rb +0 -22
  155. data/lib/fear/for/evaluation_context.rb +0 -91
@@ -1,27 +1,77 @@
1
- require 'dry-equalizer'
2
- require 'fear/version'
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 :Done, 'fear/done'
10
- autoload :For, 'fear/for'
11
- autoload :RightBiased, 'fear/right_biased'
12
- autoload :Utils, 'fear/utils'
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 :Option, 'fear/option'
15
- autoload :Some, 'fear/some'
16
- autoload :None, 'fear/none'
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 :Try, 'fear/try'
19
- autoload :Success, 'fear/success'
20
- autoload :Failure, 'fear/failure'
69
+ autoload :Await, "fear/await"
70
+ autoload :Awaitable, "fear/awaitable"
71
+ autoload :Future, "fear/future"
72
+ autoload :Promise, "fear/promise"
21
73
 
22
- autoload :Either, 'fear/either'
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
@@ -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
@@ -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
- # Right(Integer(in))
19
+ # Fear.right(Integer(in))
18
20
  # rescue ArgumentError
19
- # Left(in)
21
+ # Fear.left(in)
20
22
  # end
21
23
  #
22
- # puts(
23
- # result.reduce(
24
- # -> (x) { "You passed me the String: #{x}" },
25
- # -> (x) { "You passed me the Int: #{x}, which I will increment. #{x} + 1 = #{x+1}" }
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
- # Right(42).get_or_else { 24/2 } #=> 42
41
- # Left('undefined').get_or_else { 24/2 } #=> 12
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
- # Right(42).get_or_else(12) #=> 42
46
- # Left('undefined').get_or_else(12) #=> 12
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
- # Right(42).or_else { Right(21) } #=> Right(42)
53
- # Left('unknown').or_else { Right(21) } #=> Right(21)
54
- # Left('unknown').or_else { Left('empty') } #=> Left('empty')
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
- # Right(17).include?(17) #=> true
63
- # Right(17).include?(7) #=> false
64
- # Left('undefined').include?(17) #=> false
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
- # Right(17).each do |value|
77
+ # Fear.right(17).each do |value|
73
78
  # puts value
74
79
  # end #=> prints 17
75
80
  #
76
- # Left('undefined').each do |value|
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
- # Right(42).map { |v| v/2 } #=> Right(21)
87
- # Left('undefined').map { |v| v/2 } #=> Left('undefined')
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
- # Right(42).flat_map { |v| Right(v/2) } #=> Right(21)
97
- # Left('undefined').flat_map { |v| Right(v/2) } #=> Left('undefined')
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
- # Right(42).to_option #=> Some(21)
113
- # Left('undefined').to_option #=> None()
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
- # Right(12).any?( |v| v > 10) #=> true
123
- # Right(7).any?( |v| v > 10) #=> false
124
- # Left('undefined').any?( |v| v > 10) #=> false
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
- # Right(42).right? #=> true
134
- # Left('err').right? #=> false
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
- # Right(42).left? #=> false
142
- # Left('err').left? #=> true
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
- # Right(12).select_or_else(-1, &:even?) #=> Right(12)
153
- # Right(7).select_or_else(-1, &:even?) #=> Left(-1)
154
- # Left(12).select_or_else(-1, &:even?) #=> Left(12)
155
- # Left(12).select_or_else(-> { -1 }, &:even?) #=> Left(12)
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
- # Right(12).select(&:even?) #=> Right(12)
165
- # Right(7).select(&:even?) #=> Left(7)
166
- # Left(12).select(&:even?) #=> Left(12)
167
- # Left(7).select(&:even?) #=> Left(7)
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
- # Right(12).reject(&:even?) #=> Left(12)
177
- # Right(7).reject(&:even?) #=> Right(7)
178
- # Left(12).reject(&:even?) #=> Left(12)
179
- # Left(7).reject(&:even?) #=> Left(7)
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
- # Left('left').swap #=> Right('left')
186
- # Right('right').swap #=> Light('left')
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
- # Right(Right(12)).join_right #=> Right(12)
213
- # Right(Left("flower")).join_right #=> Left("flower")
214
- # Left("flower").join_right #=> Left("flower")
215
- # Left(Right("flower")).join_right #=> Left(Right("flower"))
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
- # Left(Right("flower")).join_left #=> Right("flower")
226
- # Left(Left(12)).join_left #=> Left(12)
227
- # Right("daisy").join_left #=> Right("daisy")
228
- # Right(Left("daisy")).join_left #=> Right(Left("daisy"))
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
- Left.new(value)
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
- Right.new(value)
329
+ Fear.right(value)
270
330
  end
271
331
  end
272
332
  end