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