fear 0.10.0 → 0.11.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +30 -4
  3. data/.travis.yml +2 -3
  4. data/Appraisals +5 -9
  5. data/CHANGELOG.md +9 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE.txt +1 -1
  8. data/README.md +255 -85
  9. data/Rakefile +393 -0
  10. data/fear.gemspec +13 -6
  11. data/gemfiles/dry_equalizer_0.1.0.gemfile +1 -0
  12. data/gemfiles/dry_equalizer_0.1.0.gemfile.lock +31 -27
  13. data/gemfiles/dry_equalizer_0.2.1.gemfile +1 -0
  14. data/gemfiles/dry_equalizer_0.2.1.gemfile.lock +31 -27
  15. data/lib/fear/either.rb +49 -14
  16. data/lib/fear/either_pattern_match.rb +48 -0
  17. data/lib/fear/empty_partial_function.rb +36 -0
  18. data/lib/fear/failure.rb +5 -4
  19. data/lib/fear/failure_pattern_match.rb +8 -0
  20. data/lib/fear/for.rb +46 -51
  21. data/lib/fear/left.rb +7 -1
  22. data/lib/fear/left_pattern_match.rb +9 -0
  23. data/lib/fear/none.rb +37 -2
  24. data/lib/fear/none_pattern_match.rb +12 -0
  25. data/lib/fear/option.rb +65 -31
  26. data/lib/fear/option_pattern_match.rb +45 -0
  27. data/lib/fear/partial_function/and_then.rb +48 -0
  28. data/lib/fear/partial_function/any.rb +26 -0
  29. data/lib/fear/partial_function/combined.rb +51 -0
  30. data/lib/fear/partial_function/empty.rb +6 -0
  31. data/lib/fear/partial_function/guard/and.rb +36 -0
  32. data/lib/fear/partial_function/guard/and3.rb +39 -0
  33. data/lib/fear/partial_function/guard/or.rb +36 -0
  34. data/lib/fear/partial_function/guard.rb +90 -0
  35. data/lib/fear/partial_function/lifted.rb +20 -0
  36. data/lib/fear/partial_function/or_else.rb +62 -0
  37. data/lib/fear/partial_function.rb +171 -0
  38. data/lib/fear/partial_function_class.rb +26 -0
  39. data/lib/fear/pattern_match.rb +102 -0
  40. data/lib/fear/pattern_matching_api.rb +110 -0
  41. data/lib/fear/right.rb +7 -1
  42. data/lib/fear/right_biased.rb +2 -12
  43. data/lib/fear/right_pattern_match.rb +9 -0
  44. data/lib/fear/some.rb +5 -2
  45. data/lib/fear/some_pattern_match.rb +11 -0
  46. data/lib/fear/success.rb +5 -4
  47. data/lib/fear/success_pattern_match.rb +10 -0
  48. data/lib/fear/try.rb +56 -16
  49. data/lib/fear/try_pattern_match.rb +28 -0
  50. data/lib/fear/utils.rb +24 -14
  51. data/lib/fear/version.rb +1 -1
  52. data/lib/fear.rb +21 -4
  53. data/spec/fear/either_pattern_match_spec.rb +37 -0
  54. data/spec/fear/failure_spec.rb +41 -3
  55. data/spec/fear/for_spec.rb +17 -29
  56. data/spec/fear/guard_spec.rb +101 -0
  57. data/spec/fear/left_spec.rb +38 -0
  58. data/spec/fear/none_spec.rb +80 -0
  59. data/spec/fear/option_pattern_match_spec.rb +35 -0
  60. data/spec/fear/partial_function/empty_spec.rb +36 -0
  61. data/spec/fear/partial_function_and_then_spec.rb +145 -0
  62. data/spec/fear/partial_function_composition_spec.rb +80 -0
  63. data/spec/fear/partial_function_or_else_spec.rb +274 -0
  64. data/spec/fear/partial_function_spec.rb +165 -0
  65. data/spec/fear/pattern_match_spec.rb +59 -0
  66. data/spec/fear/right_biased/left.rb +1 -6
  67. data/spec/fear/right_biased/right.rb +0 -5
  68. data/spec/fear/right_spec.rb +38 -0
  69. data/spec/fear/some_spec.rb +37 -0
  70. data/spec/fear/success_spec.rb +41 -4
  71. data/spec/fear/try_pattern_match_spec.rb +37 -0
  72. metadata +97 -23
  73. data/lib/fear/for/evaluation_context.rb +0 -91
data/lib/fear/option.rb CHANGED
@@ -11,12 +11,9 @@ module Fear
11
11
  # having to check for the existence of a value.
12
12
  #
13
13
  # @example A less-idiomatic way to use +Option+ values is via pattern matching
14
- # name = Option(params[:name])
15
- # case name
16
- # when Some
17
- # puts name.strip.upcase
18
- # when None
19
- # puts 'No name value'
14
+ # Option(params[:name]).match do |m|
15
+ # m.some { |name| name.strip.upcase }
16
+ # m.none { 'No name value' }
20
17
  # end
21
18
  #
22
19
  # @example or manually checking for non emptiness
@@ -35,20 +32,20 @@ module Fear
35
32
  # @return [any]
36
33
  # @example
37
34
  # Some(42).get_or_else { 24/2 } #=> 42
38
- # None().get_or_else { 24/2 } #=> 12
35
+ # None.get_or_else { 24/2 } #=> 12
39
36
  # @overload get_or_else(default)
40
37
  # @return [any]
41
38
  # @example
42
39
  # Some(42).get_or_else(12) #=> 42
43
- # None().get_or_else(12) #=> 12
40
+ # None.get_or_else(12) #=> 12
44
41
  #
45
42
  # @!method or_else(&alternative)
46
43
  # Returns this +Some+ or the given alternative if this is a +None+.
47
44
  # @return [Option]
48
45
  # @example
49
46
  # Some(42).or_else { Some(21) } #=> Some(42)
50
- # None().or_else { Some(21) } #=> Some(21)
51
- # None().or_else { None() } #=> None()
47
+ # None.or_else { Some(21) } #=> Some(21)
48
+ # None.or_else { None } #=> None
52
49
  #
53
50
  # @!method include?(other_value)
54
51
  # Returns +true+ if it has an element that is equal
@@ -58,7 +55,7 @@ module Fear
58
55
  # @example
59
56
  # Some(17).include?(17) #=> true
60
57
  # Some(17).include?(7) #=> false
61
- # None().include?(17) #=> false
58
+ # None.include?(17) #=> false
62
59
  #
63
60
  # @!method each(&block)
64
61
  # Performs the given block if this is a +Some+.
@@ -70,7 +67,7 @@ module Fear
70
67
  # puts value
71
68
  # end #=> prints 17
72
69
  #
73
- # None().each do |value|
70
+ # None.each do |value|
74
71
  # puts value
75
72
  # end #=> does nothing
76
73
  #
@@ -81,7 +78,7 @@ module Fear
81
78
  # @yieldreturn [any]
82
79
  # @example
83
80
  # Some(42).map { |v| v/2 } #=> Some(21)
84
- # None().map { |v| v/2 } #=> None()
81
+ # None.map { |v| v/2 } #=> None
85
82
  #
86
83
  # @!method flat_map(&block)
87
84
  # Returns the given block applied to the value from this +Some+
@@ -91,15 +88,7 @@ module Fear
91
88
  # @return [Option]
92
89
  # @example
93
90
  # Some(42).flat_map { |v| Some(v/2) } #=> Some(21)
94
- # None().flat_map { |v| Some(v/2) } #=> None()
95
- #
96
- # @!method to_a
97
- # Returns an +Array+ containing the +Some+ value or an
98
- # empty +Array+ if this is a +None+
99
- # @return [Array]
100
- # @example
101
- # Some(42).to_a #=> [21]
102
- # None().to_a #=> []
91
+ # None.flat_map { |v| Some(v/2) } #=> None
103
92
  #
104
93
  # @!method any?(&predicate)
105
94
  # Returns +false+ if +None+ or returns the result of the
@@ -110,7 +99,7 @@ module Fear
110
99
  # @example
111
100
  # Some(12).any?( |v| v > 10) #=> true
112
101
  # Some(7).any?( |v| v > 10) #=> false
113
- # None().any?( |v| v > 10) #=> false
102
+ # None.any?( |v| v > 10) #=> false
114
103
  #
115
104
  # @!method select(&predicate)
116
105
  # Returns self if it is nonempty and applying the predicate to this
@@ -120,8 +109,8 @@ module Fear
120
109
  # @return [Option]
121
110
  # @example
122
111
  # Some(42).select { |v| v > 40 } #=> Success(21)
123
- # Some(42).select { |v| v < 40 } #=> None()
124
- # None().select { |v| v < 40 } #=> None()
112
+ # Some(42).select { |v| v < 40 } #=> None
113
+ # None.select { |v| v < 40 } #=> None
125
114
  #
126
115
  # @!method reject(&predicate)
127
116
  # Returns +Some+ if applying the predicate to this
@@ -132,7 +121,7 @@ module Fear
132
121
  # @example
133
122
  # Some(42).reject { |v| v > 40 } #=> None
134
123
  # Some(42).reject { |v| v < 40 } #=> Some(42)
135
- # None().reject { |v| v < 40 } #=> None
124
+ # None.reject { |v| v < 40 } #=> None
136
125
  #
137
126
  # @!method get
138
127
  # @return [any] the +Option+'s value.
@@ -143,14 +132,31 @@ module Fear
143
132
  # @return [Boolean]
144
133
  # @example
145
134
  # Some(42).empty? #=> false
146
- # None().empty? #=> true
135
+ # None.empty? #=> true
136
+ #
137
+ # @!method match(&matcher)
138
+ # Pattern match against this +Option+
139
+ # @yield matcher [Fear::OptionPatternMatch]
140
+ # @example
141
+ # Option(val).match do |m|
142
+ # m.some(Integer) do |x|
143
+ # x * 2
144
+ # end
145
+ #
146
+ # m.some(String) do |x|
147
+ # x.to_i * 2
148
+ # end
149
+ #
150
+ # m.none { 'NaN' }
151
+ # m.else { 'error '}
152
+ # end
147
153
  #
148
154
  # @see https://github.com/scala/scala/blob/2.11.x/src/library/scala/Option.scala
149
155
  #
150
156
  module Option
151
157
  # @private
152
158
  def left_class
153
- None
159
+ NoneClass
154
160
  end
155
161
 
156
162
  # @private
@@ -158,6 +164,29 @@ module Fear
158
164
  Some
159
165
  end
160
166
 
167
+ class << self
168
+ # Build pattern matcher to be used later, despite off
169
+ # +Option#match+ method, id doesn't apply matcher immanently,
170
+ # but build it instead. Unusually in sake of efficiency it's better
171
+ # to statically build matcher and reuse it later.
172
+ #
173
+ # @example
174
+ # matcher =
175
+ # Option.matcher do |m|
176
+ # m.some(Integer) { |x| x * 2 }
177
+ # m.some(String) { |x| x.to_i * 2 }
178
+ # m.none { 'NaN' }
179
+ # m.else { 'error '}
180
+ # end
181
+ # matcher.call(Some(42))
182
+ #
183
+ # @yieldparam [OptionPatternMatch]
184
+ # @return [Fear::PartialFunction]
185
+ def matcher(&matcher)
186
+ OptionPatternMatch.new(&matcher)
187
+ end
188
+ end
189
+
161
190
  # Include this mixin to access convenient factory methods.
162
191
  # @example
163
192
  # include Fear::Option::Mixin
@@ -165,17 +194,22 @@ module Fear
165
194
  # Option(17) #=> #<Fear::Some value=17>
166
195
  # Option(nil) #=> #<Fear::None>
167
196
  # Some(17) #=> #<Fear::Some value=17>
168
- # None() #=> #<Fear::None>
197
+ # None #=> #<Fear::None>
169
198
  #
170
199
  module Mixin
200
+ None = Fear::None
201
+
171
202
  # An +Option+ factory which creates +Some+ if the argument is
172
203
  # not +nil+, and +None+ if it is +nil+.
173
204
  # @param value [any]
174
205
  # @return [Some, None]
175
206
  #
207
+ # @example
208
+ # Option(v)
209
+ #
176
210
  def Option(value)
177
211
  if value.nil?
178
- None()
212
+ None
179
213
  else
180
214
  Some(value)
181
215
  end
@@ -183,7 +217,7 @@ module Fear
183
217
 
184
218
  # @return [None]
185
219
  def None
186
- None.new
220
+ Fear::None
187
221
  end
188
222
 
189
223
  # @param value [any] except nil
@@ -0,0 +1,45 @@
1
+ module Fear
2
+ # Option pattern matcher
3
+ #
4
+ # @example
5
+ # pattern_match =
6
+ # OptionPatternMatch.new
7
+ # .some(Integer) { |x| x * 2 }
8
+ # .some(String) { |x| x.to_i * 2 }
9
+ # .none { 'NaN' }
10
+ # .else { 'error '}
11
+ #
12
+ # pattern_match.call(42) => 'NaN'
13
+ #
14
+ # @example the same matcher may be defined using block syntax
15
+ # OptionPatternMatch.new do |m|
16
+ # m.some(Integer) { |x| x * 2 }
17
+ # m.some(String) { |x| x.to_i * 2 }
18
+ # m.none { 'NaN' }
19
+ # m.else { 'error '}
20
+ # end
21
+ #
22
+ # @note it has two optimized subclasses +Fear::SomePatternMatch+ and +Fear::NonePatternMatch+
23
+ # @api private
24
+ class OptionPatternMatch < Fear::PatternMatch
25
+ GET_METHOD = :get.to_proc
26
+
27
+ # Match against Some
28
+ #
29
+ # @param conditions [<#==>]
30
+ # @return [Fear::OptionPatternMatch]
31
+ def some(*conditions, &effect)
32
+ branch = Fear.case(Fear::Some, &GET_METHOD).and_then(Fear.case(*conditions, &effect))
33
+ or_else(branch)
34
+ end
35
+
36
+ # Match against None
37
+ #
38
+ # @param effect [Proc]
39
+ # @return [Fear::OptionPatternMatch]
40
+ def none(&effect)
41
+ branch = Fear.case(Fear::None, &effect)
42
+ or_else(branch)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,48 @@
1
+ module Fear
2
+ module PartialFunction
3
+ # Composite function produced by +PartialFunction#and_then+ method
4
+ # @api private
5
+ class AndThen
6
+ include PartialFunction
7
+
8
+ # @param partial_function [Fear::PartialFunction]
9
+ # @param function [Proc]
10
+ def initialize(partial_function, &function)
11
+ @partial_function = partial_function
12
+ @function = function
13
+ end
14
+ # @!attribute partial_function
15
+ # @return [Fear::PartialFunction]
16
+ # @!attribute function
17
+ # @return [Proc]
18
+ attr_reader :partial_function
19
+ attr_reader :function
20
+ private :partial_function
21
+ private :function
22
+
23
+ # @param arg [any]
24
+ # @return [any ]
25
+ def call(arg)
26
+ function.call(partial_function.call(arg))
27
+ end
28
+
29
+ # @param arg [any]
30
+ # @return [Boolean]
31
+ def defined_at?(arg)
32
+ partial_function.defined_at?(arg)
33
+ end
34
+
35
+ # @param arg [any]
36
+ # @yield [arg]
37
+ # @return [any]
38
+ def call_or_else(arg)
39
+ result = partial_function.call_or_else(arg) do
40
+ return yield(arg)
41
+ end
42
+ function.call(result)
43
+ end
44
+ end
45
+
46
+ private_constant :AndThen
47
+ end
48
+ end
@@ -0,0 +1,26 @@
1
+ module Fear
2
+ module PartialFunction
3
+ # Any is an object which is always truthy
4
+ # @api private
5
+ class Any
6
+ class << self
7
+ # @param _other [any]
8
+ # @return [true]
9
+ def ===(_other)
10
+ true
11
+ end
12
+
13
+ # @param _other [any]
14
+ # @return [true]
15
+ def ==(_other)
16
+ true
17
+ end
18
+
19
+ # @return [Proc]
20
+ def to_proc
21
+ proc { true }
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,51 @@
1
+ module Fear
2
+ module PartialFunction
3
+ # Composite function produced by +PartialFunction#and_then+ method
4
+ # @api private
5
+ class Combined
6
+ include PartialFunction
7
+
8
+ # @param f1 [Fear::PartialFunction]
9
+ # @param f2 [Fear::PartialFunction]
10
+ def initialize(f1, f2)
11
+ @f1 = f1
12
+ @f2 = f2
13
+ end
14
+ # @!attribute f1
15
+ # @return [Fear::PartialFunction]
16
+ # @!attribute f2
17
+ # @return [Fear::PartialFunction]
18
+ attr_reader :f1, :f2
19
+ private :f1
20
+ private :f2
21
+
22
+ # @param arg [any]
23
+ # @return [any ]
24
+ def call(arg)
25
+ f2.call(f1.call(arg))
26
+ end
27
+
28
+ alias === call
29
+ alias [] call
30
+
31
+ # @param arg [any]
32
+ # @yieldparam arg [any]
33
+ # @return [any]
34
+ def call_or_else(arg)
35
+ result = f1.call_or_else(arg) { return yield(arg) }
36
+ f2.call_or_else(result) { |_| return yield(arg) }
37
+ end
38
+
39
+ # @param arg [any]
40
+ # @return [Boolean]
41
+ def defined_at?(arg)
42
+ result = f1.call_or_else(arg) do
43
+ return false
44
+ end
45
+ f2.defined_at?(result)
46
+ end
47
+ end
48
+
49
+ private_constant :AndThen
50
+ end
51
+ end
@@ -0,0 +1,6 @@
1
+ module Fear
2
+ module PartialFunction
3
+ EMPTY = Object.new.extend(EmptyPartialFunction)
4
+ EMPTY.freeze
5
+ end
6
+ end
@@ -0,0 +1,36 @@
1
+ module Fear
2
+ module PartialFunction
3
+ class Guard
4
+ # @api private
5
+ class And < Guard
6
+ # @param c1 [Fear::PartialFunction::Guard]
7
+ # @param c2 [Fear::PartialFunction::Guard]
8
+ def initialize(c1, c2)
9
+ @c1 = c1
10
+ @c2 = c2
11
+ end
12
+ attr_reader :c1, :c2
13
+ private :c1
14
+ private :c2
15
+
16
+ # @param other [Fear::PartialFunction::Guard]
17
+ # @return [Fear::PartialFunction::Guard]
18
+ def and(other)
19
+ Guard::And.new(self, other)
20
+ end
21
+
22
+ # @param other [Fear::PartialFunction::Guard]
23
+ # @return [Fear::PartialFunction::Guard]
24
+ def or(other)
25
+ Guard::Or.new(self, other)
26
+ end
27
+
28
+ # @param arg [any]
29
+ # @return [Boolean]
30
+ def ===(arg)
31
+ (c1 === arg) && (c2 === arg)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,39 @@
1
+ module Fear
2
+ module PartialFunction
3
+ class Guard
4
+ # @api private
5
+ class And3 < Guard
6
+ # @param c1 [#===]
7
+ # @param c2 [#===]
8
+ # @param c3 [#===]
9
+ def initialize(c1, c2, c3)
10
+ @c1 = c1
11
+ @c2 = c2
12
+ @c3 = c3
13
+ end
14
+ attr_reader :c1, :c2, :c3
15
+ private :c1
16
+ private :c2
17
+ private :c3
18
+
19
+ # @param other [Fear::PartialFunction::Guard]
20
+ # @return [Fear::PartialFunction::Guard]
21
+ def and(other)
22
+ Guard::And.new(self, other)
23
+ end
24
+
25
+ # @param other [Fear::PartialFunction::Guard]
26
+ # @return [Fear::PartialFunction::Guard]
27
+ def or(other)
28
+ Guard::Or.new(self, other)
29
+ end
30
+
31
+ # @param arg [any]
32
+ # @return [Boolean]
33
+ def ===(arg)
34
+ (c1 === arg) && (c2 === arg) && (c3 === arg)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,36 @@
1
+ module Fear
2
+ module PartialFunction
3
+ class Guard
4
+ # @api private
5
+ class Or < Guard
6
+ # @param c1 [Fear::PartialFunction::Guard]
7
+ # @param c2 [Fear::PartialFunction::Guard]
8
+ def initialize(c1, c2)
9
+ @c1 = c1
10
+ @c2 = c2
11
+ end
12
+ attr_reader :c1, :c2
13
+ private :c1
14
+ private :c2
15
+
16
+ # @param other [Fear::PartialFunction::Guard]
17
+ # @return [Fear::PartialFunction::Guard]
18
+ def and(other)
19
+ Guard::And.new(self, other)
20
+ end
21
+
22
+ # @param other [Fear::PartialFunction::Guard]
23
+ # @return [Fear::PartialFunction::Guard]
24
+ def or(other)
25
+ Guard::Or.new(self, other)
26
+ end
27
+
28
+ # @param arg [any]
29
+ # @return [Boolean]
30
+ def ===(arg)
31
+ (c1 === arg) || (c2 === arg)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,90 @@
1
+ module Fear
2
+ module PartialFunction
3
+ # Guard represents PartialFunction guardian
4
+ #
5
+ # @api private
6
+ class Guard
7
+ autoload :And, 'fear/partial_function/guard/and'
8
+ autoload :And3, 'fear/partial_function/guard/and3'
9
+ autoload :Or, 'fear/partial_function/guard/or'
10
+
11
+ class << self
12
+ # Optimized version for combination of two guardians
13
+ # Two guarding is a very common situation. For example checking for Some, and checking
14
+ # a value withing contianer.
15
+ #
16
+ def and2(c1, c2)
17
+ Guard::And.new(
18
+ (c1.is_a?(Symbol) ? c1.to_proc : c1),
19
+ (c2.is_a?(Symbol) ? c2.to_proc : c2),
20
+ )
21
+ end
22
+
23
+ def and3(c1, c2, c3)
24
+ Guard::And3.new(
25
+ (c1.is_a?(Symbol) ? c1.to_proc : c1),
26
+ (c2.is_a?(Symbol) ? c2.to_proc : c2),
27
+ (c3.is_a?(Symbol) ? c3.to_proc : c3),
28
+ )
29
+ end
30
+
31
+ def and1(c)
32
+ c.is_a?(Symbol) ? c.to_proc : c
33
+ end
34
+
35
+ # @param conditions [<#===, Symbol>]
36
+ # @return [Fear::PartialFunction::Guard]
37
+ def and(conditions)
38
+ case conditions.size
39
+ when 1 then and1(*conditions)
40
+ when 2 then and2(*conditions)
41
+ when 3 then and3(*conditions)
42
+ when 0 then Any
43
+ else
44
+ head, *tail = conditions
45
+ tail.inject(new(head)) { |acc, condition| acc.and(new(condition)) }
46
+ end
47
+ end
48
+
49
+ # @param conditions [<#===, Symbol>]
50
+ # @return [Fear::PartialFunction::Guard]
51
+ def or(conditions)
52
+ return Any if conditions.empty?
53
+
54
+ head, *tail = conditions
55
+ tail.inject(new(head)) { |acc, condition| acc.or(new(condition)) }
56
+ end
57
+ end
58
+
59
+ # @param condition [<#===, Symbol>]
60
+ def initialize(condition)
61
+ @condition =
62
+ if condition.is_a?(Symbol)
63
+ condition.to_proc
64
+ else
65
+ condition
66
+ end
67
+ end
68
+ attr_reader :condition
69
+ private :condition
70
+
71
+ # @param other [Fear::PartialFunction::Guard]
72
+ # @return [Fear::PartialFunction::Guard]
73
+ def and(other)
74
+ Guard::And.new(condition, other)
75
+ end
76
+
77
+ # @param other [Fear::PartialFunction::Guard]
78
+ # @return [Fear::PartialFunction::Guard]
79
+ def or(other)
80
+ Guard::Or.new(condition, other)
81
+ end
82
+
83
+ # @param arg [any]
84
+ # @return [Boolean]
85
+ def ===(arg)
86
+ condition === arg
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,20 @@
1
+ module Fear
2
+ module PartialFunction
3
+ # @api private
4
+ class Lifted
5
+ # @param pf [Fear::PartialFunction]
6
+ def initialize(pf)
7
+ @pf = pf
8
+ end
9
+ attr_reader :pf
10
+
11
+ # @param arg [any]
12
+ # @return [Fear::Option]
13
+ def call(arg)
14
+ Some.new(pf.call_or_else(arg) { return Fear::None })
15
+ end
16
+ end
17
+
18
+ private_constant :Lifted
19
+ end
20
+ end
@@ -0,0 +1,62 @@
1
+ module Fear
2
+ module PartialFunction
3
+ # Composite function produced by +PartialFunction#or_else+ method
4
+ # @api private
5
+ class OrElse
6
+ include PartialFunction
7
+
8
+ # @param f1 [Fear::PartialFunction]
9
+ # @param f2 [Fear::PartialFunction]
10
+ def initialize(f1, f2)
11
+ @f1 = f1
12
+ @f2 = f2
13
+ end
14
+ # @!attribute f1
15
+ # @return [Fear::PartialFunction]
16
+ # @!attribute f2
17
+ # @return [Fear::PartialFunction]
18
+ attr_reader :f1, :f2
19
+ private :f1
20
+ private :f2
21
+
22
+ # @param arg [any]
23
+ # @return [any]
24
+ def call(arg)
25
+ f1.call_or_else(arg, &f2)
26
+ end
27
+
28
+ alias === call
29
+ alias [] call
30
+
31
+ # @param other [Fear::PartialFunction]
32
+ # @return [Fear::PartialFunction]
33
+ def or_else(other)
34
+ OrElse.new(f1, f2.or_else(other))
35
+ end
36
+
37
+ # @see Fear::PartialFunction#and_then
38
+ def and_then(other = Utils::UNDEFINED, &block)
39
+ Utils.with_block_or_argument('Fear::PartialFunction::OrElse#and_then', other, block) do |fun|
40
+ OrElse.new(f1.and_then(&fun), f2.and_then(&fun))
41
+ end
42
+ end
43
+
44
+ # @param arg [any]
45
+ # @return [Boolean]
46
+ def defined_at?(arg)
47
+ f1.defined_at?(arg) || f2.defined_at?(arg)
48
+ end
49
+
50
+ # @param arg [any]
51
+ # @param fallback [Proc]
52
+ # @return [any]
53
+ def call_or_else(arg, &fallback)
54
+ f1.call_or_else(arg) do
55
+ return f2.call_or_else(arg, &fallback)
56
+ end
57
+ end
58
+ end
59
+
60
+ private_constant :OrElse
61
+ end
62
+ end