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
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ # rubocop: disable Layout/LineLength
5
+ module FutureApi
6
+ # Asynchronously evaluates the block
7
+ # @param options [Hash] options will be passed directly to underlying +Concurrent::Promise+
8
+ # @see https://ruby-concurrency.github.io/concurrent-ruby/1.1.5/Concurrent/Promise.html#constructor_details Constructor Details
9
+ # @return [Fear::Future]
10
+ #
11
+ # @example
12
+ # require 'open-uri'
13
+ # f = Fear.future(executor: :io) { open('http://example.com') }
14
+ # f.map(&:read).each { |body| puts body }
15
+ #
16
+ def future(options = {}, &block)
17
+ Future.new(options, &block)
18
+ end
19
+ end
20
+ # rubocop: enable Layout/LineLength
21
+ end
@@ -1,7 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fear
2
4
  class Left
3
5
  include Either
4
6
  include RightBiased::Left
7
+ include LeftPatternMatch.mixin
8
+
9
+ EXTRACTOR = proc do |either|
10
+ if Fear::Left === either
11
+ Fear.some([either.left_value])
12
+ else
13
+ Fear.none
14
+ end
15
+ end
16
+ public_constant :EXTRACTOR
17
+
18
+ # @api private
19
+ def left_value
20
+ value
21
+ end
5
22
 
6
23
  # @return [false]
7
24
  def right?
@@ -37,8 +54,8 @@ module Fear
37
54
 
38
55
  # @param reduce_left [Proc]
39
56
  # @return [any]
40
- def reduce(reduce_left, _)
41
- reduce_left.call(value)
57
+ def reduce(reduce_left, _reduce_right)
58
+ reduce_left.(value)
42
59
  end
43
60
 
44
61
  # @return [self]
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ # @api private
5
+ class LeftPatternMatch < Fear::EitherPatternMatch
6
+ def right(*)
7
+ self
8
+ end
9
+ alias success right
10
+ end
11
+ end
@@ -1,12 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fear
2
- class None
4
+ # @api private
5
+ class NoneClass
3
6
  include Option
4
- include Dry::Equalizer()
5
7
  include RightBiased::Left
8
+ include NonePatternMatch.mixin
9
+
10
+ EXTRACTOR = proc do |option|
11
+ if Fear::None === option
12
+ Fear.some([])
13
+ else
14
+ Fear.none
15
+ end
16
+ end
17
+ public_constant :EXTRACTOR
6
18
 
7
19
  # @raise [NoSuchElementError]
8
20
  def get
9
- fail NoSuchElementError
21
+ raise NoSuchElementError
10
22
  end
11
23
 
12
24
  # @return [nil]
@@ -28,5 +40,57 @@ module Fear
28
40
  def reject(*)
29
41
  self
30
42
  end
43
+
44
+ # @return [String]
45
+ def inspect
46
+ "#<Fear::NoneClass>"
47
+ end
48
+
49
+ # @return [String]
50
+ alias to_s inspect
51
+
52
+ # @param other [Any]
53
+ # @return [Boolean]
54
+ def ==(other)
55
+ other.is_a?(NoneClass)
56
+ end
57
+
58
+ # @param other
59
+ # @return [Boolean]
60
+ def ===(other)
61
+ self == other
62
+ end
63
+
64
+ # @param other [Fear::Option]
65
+ # @return [Fear::Option]
66
+ def zip(other)
67
+ if other.is_a?(Option)
68
+ Fear.none
69
+ else
70
+ raise TypeError, "can't zip with #{other.class}"
71
+ end
72
+ end
73
+
74
+ # @return [RightBiased::Left]
75
+ def filter_map
76
+ self
77
+ end
78
+ end
79
+
80
+ private_constant(:NoneClass)
81
+
82
+ # The only instance of NoneClass
83
+ # @api private
84
+ None = NoneClass.new.freeze
85
+ public_constant :None
86
+
87
+ class << NoneClass
88
+ def new
89
+ None
90
+ end
91
+
92
+ def inherited(*)
93
+ raise "you are not allowed to inherit from NoneClass, use Fear::None instead"
94
+ end
31
95
  end
32
96
  end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ # @api private
5
+ class NonePatternMatch < OptionPatternMatch
6
+ # @param conditions [<#==>]
7
+ # @return [Fear::OptionPatternMatch]
8
+ def some(*_conditions)
9
+ self
10
+ end
11
+ end
12
+
13
+ private_constant :NonePatternMatch
14
+ end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fear
2
4
  # Represents optional values. Instances of +Option+
3
5
  # are either an instance of +Some+ or the object +None+.
4
6
  #
5
7
  # @example The most idiomatic way to use an +Option+ instance is to treat it as a collection
6
- # name = Option(params[:name])
8
+ # name = Fear.option(params[:name])
7
9
  # upper = name.map(&:strip).select { |n| n.length != 0 }.map(&:upcase)
8
10
  # puts upper.get_or_else('')
9
11
  #
@@ -11,16 +13,13 @@ module Fear
11
13
  # having to check for the existence of a value.
12
14
  #
13
15
  # @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'
16
+ # Fear.option(params[:name]).match do |m|
17
+ # m.some { |name| name.strip.upcase }
18
+ # m.none { 'No name value' }
20
19
  # end
21
20
  #
22
21
  # @example or manually checking for non emptiness
23
- # name = Option(params[:name])
22
+ # name = Fear.option(params[:name])
24
23
  # if name.empty?
25
24
  # puts 'No name value'
26
25
  # else
@@ -34,21 +33,21 @@ module Fear
34
33
  # @yieldreturn [any]
35
34
  # @return [any]
36
35
  # @example
37
- # Some(42).get_or_else { 24/2 } #=> 42
38
- # None().get_or_else { 24/2 } #=> 12
36
+ # Fear.some(42).get_or_else { 24/2 } #=> 42
37
+ # Fear.none.get_or_else { 24/2 } #=> 12
39
38
  # @overload get_or_else(default)
40
39
  # @return [any]
41
40
  # @example
42
- # Some(42).get_or_else(12) #=> 42
43
- # None().get_or_else(12) #=> 12
41
+ # Fear.some(42).get_or_else(12) #=> 42
42
+ # Fear.none.get_or_else(12) #=> 12
44
43
  #
45
44
  # @!method or_else(&alternative)
46
45
  # Returns this +Some+ or the given alternative if this is a +None+.
47
46
  # @return [Option]
48
47
  # @example
49
- # Some(42).or_else { Some(21) } #=> Some(42)
50
- # None().or_else { Some(21) } #=> Some(21)
51
- # None().or_else { None() } #=> None()
48
+ # Fear.some(42).or_else { Fear.some(21) } #=> Fear.some(42)
49
+ # Fear.none.or_else { Fear.some(21) } #=> Fear.some(21)
50
+ # Fear.none.or_else { None } #=> None
52
51
  #
53
52
  # @!method include?(other_value)
54
53
  # Returns +true+ if it has an element that is equal
@@ -56,9 +55,9 @@ module Fear
56
55
  # @param [any]
57
56
  # @return [Boolean]
58
57
  # @example
59
- # Some(17).include?(17) #=> true
60
- # Some(17).include?(7) #=> false
61
- # None().include?(17) #=> false
58
+ # Fear.some(17).include?(17) #=> true
59
+ # Fear.some(17).include?(7) #=> false
60
+ # Fear.none.include?(17) #=> false
62
61
  #
63
62
  # @!method each(&block)
64
63
  # Performs the given block if this is a +Some+.
@@ -66,11 +65,11 @@ module Fear
66
65
  # @yieldreturn [void]
67
66
  # @return [Option] itself
68
67
  # @example
69
- # Some(17).each do |value|
68
+ # Fear.some(17).each do |value|
70
69
  # puts value
71
70
  # end #=> prints 17
72
71
  #
73
- # None().each do |value|
72
+ # Fear.none.each do |value|
74
73
  # puts value
75
74
  # end #=> does nothing
76
75
  #
@@ -80,8 +79,19 @@ module Fear
80
79
  # @yieldparam [any] value
81
80
  # @yieldreturn [any]
82
81
  # @example
83
- # Some(42).map { |v| v/2 } #=> Some(21)
84
- # None().map { |v| v/2 } #=> None()
82
+ # Fear.some(42).map { |v| v/2 } #=> Fear.some(21)
83
+ # Fear.none.map { |v| v/2 } #=> None
84
+ #
85
+ # @!method filter_map(&block)
86
+ # Returns a new +Some+ of truthy results (everything except +false+ or +nil+) of
87
+ # running the block or +None+ otherwise.
88
+ # @yieldparam [any] value
89
+ # @yieldreturn [any]
90
+ # @example
91
+ # Fear.some(42).filter_map { |v| v/2 if v.even? } #=> Fear.some(21)
92
+ # Fear.some(42).filter_map { |v| v/2 if v.odd? } #=> Fear.none
93
+ # Fear.some(42).filter_map { |v| false } #=> Fear.none
94
+ # Fear.none.filter_map { |v| v/2 } #=> Fear.none
85
95
  #
86
96
  # @!method flat_map(&block)
87
97
  # Returns the given block applied to the value from this +Some+
@@ -90,16 +100,8 @@ module Fear
90
100
  # @yieldreturn [Option]
91
101
  # @return [Option]
92
102
  # @example
93
- # 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 #=> []
103
+ # Fear.some(42).flat_map { |v| Fear.some(v/2) } #=> Fear.some(21)
104
+ # Fear.none.flat_map { |v| Fear.some(v/2) } #=> None
103
105
  #
104
106
  # @!method any?(&predicate)
105
107
  # Returns +false+ if +None+ or returns the result of the
@@ -108,9 +110,9 @@ module Fear
108
110
  # @yieldreturn [Boolean]
109
111
  # @return [Boolean]
110
112
  # @example
111
- # Some(12).any?( |v| v > 10) #=> true
112
- # Some(7).any?( |v| v > 10) #=> false
113
- # None().any?( |v| v > 10) #=> false
113
+ # Fear.some(12).any?( |v| v > 10) #=> true
114
+ # Fear.some(7).any?( |v| v > 10) #=> false
115
+ # Fear.none.any?( |v| v > 10) #=> false
114
116
  #
115
117
  # @!method select(&predicate)
116
118
  # Returns self if it is nonempty and applying the predicate to this
@@ -119,9 +121,9 @@ module Fear
119
121
  # @yieldreturn [Boolean]
120
122
  # @return [Option]
121
123
  # @example
122
- # Some(42).select { |v| v > 40 } #=> Success(21)
123
- # Some(42).select { |v| v < 40 } #=> None()
124
- # None().select { |v| v < 40 } #=> None()
124
+ # Fear.some(42).select { |v| v > 40 } #=> Fear.success(21)
125
+ # Fear.some(42).select { |v| v < 40 } #=> None
126
+ # Fear.none.select { |v| v < 40 } #=> None
125
127
  #
126
128
  # @!method reject(&predicate)
127
129
  # Returns +Some+ if applying the predicate to this
@@ -130,9 +132,9 @@ module Fear
130
132
  # @yieldreturn [Boolean]
131
133
  # @return [Option]
132
134
  # @example
133
- # Some(42).reject { |v| v > 40 } #=> None
134
- # Some(42).reject { |v| v < 40 } #=> Some(42)
135
- # None().reject { |v| v < 40 } #=> None
135
+ # Fear.some(42).reject { |v| v > 40 } #=> None
136
+ # Fear.some(42).reject { |v| v < 40 } #=> Fear.some(42)
137
+ # Fear.none.reject { |v| v < 40 } #=> None
136
138
  #
137
139
  # @!method get
138
140
  # @return [any] the +Option+'s value.
@@ -142,15 +144,43 @@ module Fear
142
144
  # Returns +true+ if the +Option+ is +None+, +false+ otherwise.
143
145
  # @return [Boolean]
144
146
  # @example
145
- # Some(42).empty? #=> false
146
- # None().empty? #=> true
147
+ # Fear.some(42).empty? #=> false
148
+ # Fear.none.empty? #=> true
149
+ #
150
+ # @!method match(&matcher)
151
+ # Pattern match against this +Option+
152
+ # @yield matcher [Fear::OptionPatternMatch]
153
+ # @example
154
+ # Fear.option(val).match do |m|
155
+ # m.some(Integer) do |x|
156
+ # x * 2
157
+ # end
158
+ #
159
+ # m.some(String) do |x|
160
+ # x.to_i * 2
161
+ # end
162
+ #
163
+ # m.none { 'NaN' }
164
+ # m.else { 'error '}
165
+ # end
166
+ #
167
+ # @!method zip(other)
168
+ # @param other [Fear::Option]
169
+ # @return [Fear::Option] a +Fear::Some+ formed from this option and another option by
170
+ # combining the corresponding elements in an array.
171
+ #
172
+ # @example
173
+ # Fear.some("foo").zip(Fear.some("bar")) #=> Fear.some(["foo", "bar"])
174
+ # Fear.some("foo").zip(Fear.some("bar")) { |x, y| x + y } #=> Fear.some("foobar")
175
+ # Fear.some("foo").zip(Fear.none) #=> Fear.none
176
+ # Fear.none.zip(Fear.some("bar")) #=> Fear.none
147
177
  #
148
178
  # @see https://github.com/scala/scala/blob/2.11.x/src/library/scala/Option.scala
149
179
  #
150
180
  module Option
151
181
  # @private
152
182
  def left_class
153
- None
183
+ NoneClass
154
184
  end
155
185
 
156
186
  # @private
@@ -158,38 +188,72 @@ module Fear
158
188
  Some
159
189
  end
160
190
 
191
+ class << self
192
+ # Build pattern matcher to be used later, despite off
193
+ # +Option#match+ method, it doesn't apply matcher immanently,
194
+ # but build it instead. Usually in sake of efficiency it's better
195
+ # to statically build matcher and reuse it later.
196
+ #
197
+ # @example
198
+ # matcher =
199
+ # Option.matcher do |m|
200
+ # m.some(Integer) { |x| x * 2 }
201
+ # m.some(String) { |x| x.to_i * 2 }
202
+ # m.none { 'NaN' }
203
+ # m.else { 'error '}
204
+ # end
205
+ # matcher.call(Fear.some(42))
206
+ #
207
+ # @yieldparam [OptionPatternMatch]
208
+ # @return [Fear::PartialFunction]
209
+ def matcher(&matcher)
210
+ OptionPatternMatch.new(&matcher)
211
+ end
212
+
213
+ def match(value, &block)
214
+ matcher(&block).(value)
215
+ end
216
+ end
217
+
161
218
  # Include this mixin to access convenient factory methods.
162
219
  # @example
163
220
  # include Fear::Option::Mixin
164
221
  #
165
- # Option(17) #=> #<Fear::Some value=17>
222
+ # Option(17) #=> #<Fear::Some get=17>
166
223
  # Option(nil) #=> #<Fear::None>
167
- # Some(17) #=> #<Fear::Some value=17>
168
- # None() #=> #<Fear::None>
224
+ # Some(17) #=> #<Fear::Some get=17>
225
+ # None() #=> #<Fear::None>
169
226
  #
170
227
  module Mixin
171
228
  # An +Option+ factory which creates +Some+ if the argument is
172
229
  # not +nil+, and +None+ if it is +nil+.
173
230
  # @param value [any]
174
- # @return [Some, None]
231
+ # @return [Fear::Some, Fear::None]
232
+ #
233
+ # @example
234
+ # Option(17) #=> #<Fear::Some get=17>
235
+ # Option(nil) #=> #<Fear::None>
175
236
  #
176
237
  def Option(value)
177
- if value.nil?
178
- None()
179
- else
180
- Some(value)
181
- end
238
+ Fear.option(value)
182
239
  end
183
240
 
184
241
  # @return [None]
242
+ # @example
243
+ # None() #=> #<Fear::None>
244
+ #
185
245
  def None
186
- None.new
246
+ Fear.none
187
247
  end
188
248
 
189
249
  # @param value [any] except nil
190
- # @return [None]
250
+ # @return [Fear::Some]
251
+ # @example
252
+ # Some(17) #=> #<Fear::Some get=17>
253
+ # Some(nil) #=> #<Fear::Some get=nil>
254
+ #
191
255
  def Some(value)
192
- Some.new(value)
256
+ Fear.some(value)
193
257
  end
194
258
  end
195
259
  end