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
@@ -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
|
data/lib/fear/left.rb
CHANGED
@@ -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.
|
57
|
+
def reduce(reduce_left, _reduce_right)
|
58
|
+
reduce_left.(value)
|
42
59
|
end
|
43
60
|
|
44
61
|
# @return [self]
|
data/lib/fear/none.rb
CHANGED
@@ -1,12 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
|
-
|
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
|
-
|
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
|
data/lib/fear/option.rb
CHANGED
@@ -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 =
|
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
|
-
#
|
15
|
-
#
|
16
|
-
#
|
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 =
|
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
|
-
#
|
38
|
-
#
|
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
|
-
#
|
43
|
-
#
|
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
|
-
#
|
50
|
-
#
|
51
|
-
#
|
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
|
-
#
|
60
|
-
#
|
61
|
-
#
|
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
|
-
#
|
68
|
+
# Fear.some(17).each do |value|
|
70
69
|
# puts value
|
71
70
|
# end #=> prints 17
|
72
71
|
#
|
73
|
-
#
|
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
|
-
#
|
84
|
-
#
|
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
|
-
#
|
94
|
-
#
|
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
|
-
#
|
112
|
-
#
|
113
|
-
#
|
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
|
-
#
|
123
|
-
#
|
124
|
-
#
|
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
|
-
#
|
134
|
-
#
|
135
|
-
#
|
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
|
-
#
|
146
|
-
#
|
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
|
-
|
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)
|
222
|
+
# Option(17) #=> #<Fear::Some get=17>
|
166
223
|
# Option(nil) #=> #<Fear::None>
|
167
|
-
# Some(17)
|
168
|
-
# 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
|
-
|
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
|
-
|
246
|
+
Fear.none
|
187
247
|
end
|
188
248
|
|
189
249
|
# @param value [any] except nil
|
190
|
-
# @return [
|
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
|
-
|
256
|
+
Fear.some(value)
|
193
257
|
end
|
194
258
|
end
|
195
259
|
end
|