fear 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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