fear 1.0.0 → 1.1.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 +4 -4
- data/.rubocop.yml +4 -60
- data/.travis.yml +8 -4
- data/CHANGELOG.md +7 -1
- data/Gemfile +5 -3
- data/Gemfile.lock +18 -20
- data/README.md +28 -14
- data/Rakefile +61 -60
- data/examples/pattern_extracting.rb +8 -6
- data/examples/pattern_matching_binary_tree_set.rb +4 -2
- data/examples/pattern_matching_number_in_words.rb +46 -42
- data/fear.gemspec +29 -27
- data/lib/fear.rb +44 -37
- data/lib/fear/await.rb +33 -0
- data/lib/fear/awaitable.rb +28 -0
- data/lib/fear/either.rb +2 -0
- data/lib/fear/either_api.rb +2 -0
- data/lib/fear/either_pattern_match.rb +2 -0
- data/lib/fear/empty_partial_function.rb +3 -1
- data/lib/fear/extractor.rb +30 -28
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +2 -0
- data/lib/fear/extractor/any_matcher.rb +2 -0
- data/lib/fear/extractor/array_head_matcher.rb +2 -0
- data/lib/fear/extractor/array_matcher.rb +2 -0
- data/lib/fear/extractor/array_splat_matcher.rb +2 -0
- data/lib/fear/extractor/empty_list_matcher.rb +2 -0
- data/lib/fear/extractor/extractor_matcher.rb +5 -3
- data/lib/fear/extractor/grammar.rb +5 -3
- data/lib/fear/extractor/identifier_matcher.rb +2 -0
- data/lib/fear/extractor/matcher.rb +5 -3
- data/lib/fear/extractor/matcher/and.rb +3 -1
- data/lib/fear/extractor/named_array_splat_matcher.rb +2 -0
- data/lib/fear/extractor/pattern.rb +7 -5
- data/lib/fear/extractor/typed_identifier_matcher.rb +2 -0
- data/lib/fear/extractor/value_matcher.rb +2 -0
- data/lib/fear/extractor_api.rb +2 -0
- data/lib/fear/failure.rb +2 -0
- data/lib/fear/failure_pattern_match.rb +2 -0
- data/lib/fear/for.rb +4 -2
- data/lib/fear/for_api.rb +3 -1
- data/lib/fear/future.rb +141 -64
- data/lib/fear/future_api.rb +2 -0
- data/lib/fear/left.rb +3 -1
- data/lib/fear/left_pattern_match.rb +2 -0
- data/lib/fear/none.rb +4 -2
- data/lib/fear/none_pattern_match.rb +2 -0
- data/lib/fear/option.rb +3 -1
- data/lib/fear/option_api.rb +2 -0
- data/lib/fear/option_pattern_match.rb +2 -0
- data/lib/fear/partial_function.rb +10 -8
- data/lib/fear/partial_function/and_then.rb +4 -2
- data/lib/fear/partial_function/any.rb +2 -0
- data/lib/fear/partial_function/combined.rb +3 -1
- data/lib/fear/partial_function/empty.rb +2 -0
- data/lib/fear/partial_function/guard.rb +7 -5
- data/lib/fear/partial_function/guard/and.rb +2 -0
- data/lib/fear/partial_function/guard/and3.rb +2 -0
- data/lib/fear/partial_function/guard/or.rb +2 -0
- data/lib/fear/partial_function/lifted.rb +2 -0
- data/lib/fear/partial_function/or_else.rb +3 -1
- data/lib/fear/partial_function_class.rb +3 -1
- data/lib/fear/pattern_match.rb +3 -1
- data/lib/fear/pattern_matching_api.rb +3 -1
- data/lib/fear/promise.rb +11 -3
- data/lib/fear/right.rb +3 -1
- data/lib/fear/right_biased.rb +4 -2
- data/lib/fear/right_pattern_match.rb +2 -0
- data/lib/fear/some.rb +2 -0
- data/lib/fear/some_pattern_match.rb +2 -0
- data/lib/fear/struct.rb +235 -0
- data/lib/fear/success.rb +2 -0
- data/lib/fear/success_pattern_match.rb +2 -0
- data/lib/fear/try.rb +2 -0
- data/lib/fear/try_api.rb +2 -0
- data/lib/fear/try_pattern_match.rb +2 -0
- data/lib/fear/unit.rb +6 -2
- data/lib/fear/utils.rb +4 -2
- data/lib/fear/version.rb +4 -1
- data/spec/fear/done_spec.rb +7 -5
- data/spec/fear/either/mixin_spec.rb +4 -2
- data/spec/fear/either_pattern_match_spec.rb +10 -8
- data/spec/fear/extractor/array_matcher_spec.rb +65 -63
- data/spec/fear/extractor/extractor_matcher_spec.rb +64 -62
- data/spec/fear/extractor/grammar_array_spec.rb +5 -3
- data/spec/fear/extractor/identified_matcher_spec.rb +18 -16
- data/spec/fear/extractor/identifier_matcher_spec.rb +26 -24
- data/spec/fear/extractor/pattern_spec.rb +17 -15
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +23 -21
- data/spec/fear/extractor/value_matcher_number_spec.rb +29 -27
- data/spec/fear/extractor/value_matcher_string_spec.rb +27 -25
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +24 -22
- data/spec/fear/extractor_api_spec.rb +70 -68
- data/spec/fear/extractor_spec.rb +23 -21
- data/spec/fear/failure_spec.rb +59 -57
- data/spec/fear/for_spec.rb +19 -17
- data/spec/fear/future_spec.rb +456 -240
- data/spec/fear/guard_spec.rb +26 -24
- data/spec/fear/left_spec.rb +60 -58
- data/spec/fear/none_spec.rb +36 -34
- data/spec/fear/option/mixin_spec.rb +9 -7
- data/spec/fear/option_pattern_match_spec.rb +10 -8
- data/spec/fear/partial_function/empty_spec.rb +12 -10
- data/spec/fear/partial_function_and_then_spec.rb +39 -37
- data/spec/fear/partial_function_composition_spec.rb +46 -44
- data/spec/fear/partial_function_or_else_spec.rb +92 -90
- data/spec/fear/partial_function_spec.rb +46 -44
- data/spec/fear/pattern_match_spec.rb +31 -29
- data/spec/fear/promise_spec.rb +19 -17
- data/spec/fear/right_biased/left.rb +28 -26
- data/spec/fear/right_biased/right.rb +51 -49
- data/spec/fear/right_spec.rb +58 -56
- data/spec/fear/some_spec.rb +30 -28
- data/spec/fear/success_spec.rb +50 -48
- data/spec/fear/try/mixin_spec.rb +5 -3
- data/spec/fear/try_pattern_match_spec.rb +10 -8
- data/spec/fear/utils_spec.rb +16 -14
- data/spec/spec_helper.rb +7 -5
- data/spec/struct_spec.rb +226 -0
- metadata +18 -13
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
module Extractor
|
3
5
|
# Match and extract pattern using registered extractor objects
|
@@ -19,19 +21,19 @@ module Fear
|
|
19
21
|
|
20
22
|
def defined_at?(other)
|
21
23
|
extractor
|
22
|
-
.
|
24
|
+
.(other)
|
23
25
|
.map { |v| arguments_matcher.defined_at?(v) }
|
24
26
|
.get_or_else(false)
|
25
27
|
end
|
26
28
|
|
27
29
|
def call_or_else(arg)
|
28
|
-
extractor.
|
30
|
+
extractor.(arg)
|
29
31
|
.map { |v| arguments_matcher.call_or_else(v) { yield arg } }
|
30
32
|
.get_or_else { yield arg }
|
31
33
|
end
|
32
34
|
|
33
35
|
def failure_reason(other)
|
34
|
-
extractor.
|
36
|
+
extractor.(other).match do |m|
|
35
37
|
m.some(->(v) { arguments_matcher.defined_at?(v) }) { Fear.none }
|
36
38
|
m.some { |v| arguments_matcher.failure_reason(v) }
|
37
39
|
m.none { super }
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
module Extractor
|
3
5
|
# This module contains AST nodes for GrammarParser
|
@@ -56,7 +58,7 @@ module Fear
|
|
56
58
|
end
|
57
59
|
|
58
60
|
def value
|
59
|
-
text_value
|
61
|
+
Float(text_value)
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
@@ -66,7 +68,7 @@ module Fear
|
|
66
68
|
end
|
67
69
|
|
68
70
|
def value
|
69
|
-
text_value
|
71
|
+
Integer(text_value, 10)
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
@@ -80,7 +82,7 @@ module Fear
|
|
80
82
|
end
|
81
83
|
end
|
82
84
|
|
83
|
-
require
|
85
|
+
require "yaml"
|
84
86
|
|
85
87
|
class DoubleQuotedStringLiteral < StringLiteral
|
86
88
|
def to_matcher
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "ostruct"
|
2
4
|
|
3
5
|
module Fear
|
4
6
|
module Extractor
|
5
7
|
# @abstract abstract matcher to inherit from.
|
6
8
|
class Matcher < OpenStruct
|
7
|
-
autoload :And,
|
9
|
+
autoload :And, "fear/extractor/matcher/and"
|
8
10
|
|
9
11
|
EMPTY_HASH = {}.freeze
|
10
12
|
EMPTY_ARRAY = [].freeze
|
@@ -46,7 +48,7 @@ module Fear
|
|
46
48
|
if defined_at?(other)
|
47
49
|
Fear.none
|
48
50
|
else
|
49
|
-
Fear.some("Expected `#{other.inspect}` to match:\n#{input}\n#{
|
51
|
+
Fear.some("Expected `#{other.inspect}` to match:\n#{input}\n#{"~" * input_position}^")
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
@@ -1,11 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lru_redux"
|
2
4
|
|
3
5
|
module Fear
|
4
6
|
module Extractor
|
5
7
|
# Parse pattern. Used within +Fear[]+
|
6
8
|
class Pattern
|
7
9
|
DEFAULT_PATTERN_CACHE_SIZE = 10_000
|
8
|
-
@pattern_cache = LruRedux::Cache.new(ENV.fetch(
|
10
|
+
@pattern_cache = LruRedux::Cache.new(ENV.fetch("FEAR_PATTERNS_CACHE_SIZE", DEFAULT_PATTERN_CACHE_SIZE))
|
9
11
|
|
10
12
|
class << self
|
11
13
|
attr_reader :pattern_cache
|
@@ -41,14 +43,14 @@ module Fear
|
|
41
43
|
end
|
42
44
|
|
43
45
|
def failure_reason(other)
|
44
|
-
matcher.failure_reason(other).get_or_else {
|
46
|
+
matcher.failure_reason(other).get_or_else { "It matches" }
|
45
47
|
end
|
46
48
|
|
47
49
|
private def syntax_error_message(parser, pattern)
|
48
50
|
parser.failure_reason =~ /^(Expected .+) after/m
|
49
|
-
"#{Regexp.last_match(1).gsub("\n",
|
51
|
+
"#{Regexp.last_match(1).gsub("\n", "$NEWLINE")}:\n" +
|
50
52
|
pattern.split("\n")[parser.failure_line - 1] + "\n" \
|
51
|
-
"#{
|
53
|
+
"#{"~" * (parser.failure_column - 1)}^\n"
|
52
54
|
end
|
53
55
|
end
|
54
56
|
end
|
data/lib/fear/extractor_api.rb
CHANGED
data/lib/fear/failure.rb
CHANGED
data/lib/fear/for.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
# @api private
|
3
5
|
# @see Fear.for
|
4
6
|
module For
|
5
|
-
module_function
|
7
|
+
module_function
|
6
8
|
|
7
9
|
# @param monads [<Fear::Option, Fear::Either, Fear::Try, Proc>]
|
8
10
|
#
|
@@ -30,7 +32,7 @@ module Fear
|
|
30
32
|
|
31
33
|
private def resolve(monad_or_proc, inner_values)
|
32
34
|
if monad_or_proc.respond_to?(:call)
|
33
|
-
monad_or_proc.
|
35
|
+
monad_or_proc.(*inner_values)
|
34
36
|
else
|
35
37
|
monad_or_proc
|
36
38
|
end
|
data/lib/fear/for_api.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
module ForApi
|
3
5
|
# Syntactic sugar for composition of multiple monadic operations. It supports two such
|
@@ -60,7 +62,7 @@ module Fear
|
|
60
62
|
# @return [{#map, #flat_map}]
|
61
63
|
#
|
62
64
|
def for(*monads, &block)
|
63
|
-
Fear::For.
|
65
|
+
Fear::For.(monads, &block)
|
64
66
|
end
|
65
67
|
end
|
66
68
|
end
|
data/lib/fear/future.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
begin
|
2
|
-
require
|
4
|
+
require "concurrent"
|
3
5
|
rescue LoadError
|
4
6
|
puts "You must add 'concurrent-ruby' to your Gemfile in order to use Fear::Future"
|
5
7
|
end
|
6
|
-
require_relative 'promise'
|
7
8
|
|
8
9
|
module Fear
|
9
10
|
# Asynchronous computations that yield futures are created
|
10
11
|
# with the +Fear.future+ call:
|
11
12
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# end
|
13
|
+
# success = "Hello"
|
14
|
+
# f = Fear.future { success + ' future!' }
|
15
|
+
# f.on_success do |result|
|
16
|
+
# puts result
|
17
|
+
# end
|
18
18
|
#
|
19
19
|
# Multiple callbacks may be registered; there is no guarantee
|
20
20
|
# that they will be executed in a particular order.
|
@@ -23,30 +23,45 @@ module Fear
|
|
23
23
|
# that the future failed. Futures obtained through combinators
|
24
24
|
# have the same error as the future they were obtained from.
|
25
25
|
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
26
|
+
# f = Fear.future { 5 }
|
27
|
+
# g = Fear.future { 3 }
|
28
|
+
# f.flat_map do |x|
|
29
|
+
# g.map { |y| x + y }
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# The same program may be written using +Fear.for+
|
33
|
+
#
|
34
|
+
# Fear.for(Fear.future { 5 }, Fear.future { 3 }) do |x, y|
|
35
|
+
# x + y
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Futures use +Concurrent::Promise+ under the hood. +Fear.future+ accepts optional configuration Hash passed
|
39
|
+
# directly to underlying promise. For example, run it on custom thread pool.
|
32
40
|
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
41
|
+
# require 'open-uri'
|
42
|
+
#
|
43
|
+
# future = Fear.future(executor: :io) { open('https://example.com/') }
|
44
|
+
#
|
45
|
+
# future.map(executor: :fast, &:read).each do |body|
|
46
|
+
# puts "#{body}"
|
47
|
+
# end
|
37
48
|
#
|
38
49
|
# @see https://github.com/scala/scala/blob/2.11.x/src/library/scala/concurrent/Future.scala
|
39
50
|
#
|
40
51
|
class Future
|
52
|
+
include Awaitable
|
53
|
+
|
41
54
|
# @param promise [nil, Concurrent::Future] converts
|
42
|
-
# +Concurrent::
|
55
|
+
# +Concurrent::Promise+ into +Fear::Future+.
|
43
56
|
# @param options [see Concurrent::Future] options will be passed
|
44
|
-
# directly to +Concurrent::
|
57
|
+
# directly to +Concurrent::Promise+
|
45
58
|
# @yield given block and evaluate it in the future.
|
46
59
|
# @api private
|
60
|
+
# @see Fear.future
|
61
|
+
#
|
47
62
|
def initialize(promise = nil, **options, &block)
|
48
63
|
if block_given? && promise
|
49
|
-
raise ArgumentError,
|
64
|
+
raise ArgumentError, "pass block or future"
|
50
65
|
end
|
51
66
|
|
52
67
|
@options = options
|
@@ -57,11 +72,11 @@ module Fear
|
|
57
72
|
attr_reader :promise
|
58
73
|
private :promise
|
59
74
|
|
60
|
-
# Calls the provided callback
|
75
|
+
# Calls the provided callback when this future is completed successfully.
|
61
76
|
#
|
62
77
|
# If the future has already been completed with a value,
|
63
78
|
# this will either be applied immediately or be scheduled asynchronously.
|
64
|
-
# @yieldparam [value
|
79
|
+
# @yieldparam [any] value
|
65
80
|
# @return [self]
|
66
81
|
# @see #transform
|
67
82
|
#
|
@@ -76,6 +91,24 @@ module Fear
|
|
76
91
|
end
|
77
92
|
end
|
78
93
|
|
94
|
+
# When this future is completed successfully match against its result
|
95
|
+
#
|
96
|
+
# If the future has already been completed with a value,
|
97
|
+
# this will either be applied immediately or be scheduled asynchronously.
|
98
|
+
# @yieldparam [Fear::PatternMatch] m
|
99
|
+
# @return [self]
|
100
|
+
#
|
101
|
+
# @example
|
102
|
+
# Fear.future { }.on_success_match do |m|
|
103
|
+
# m.case(42) { ... }
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
def on_success_match
|
107
|
+
on_success do |value|
|
108
|
+
Fear.matcher { |m| yield(m) }.call_or_else(value, &:itself)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
79
112
|
# When this future is completed with a failure apply the provided callback to the error.
|
80
113
|
#
|
81
114
|
# If the future has already been completed with a failure,
|
@@ -100,6 +133,26 @@ module Fear
|
|
100
133
|
end
|
101
134
|
end
|
102
135
|
|
136
|
+
# When this future is completed with a failure match against the error.
|
137
|
+
#
|
138
|
+
# If the future has already been completed with a failure,
|
139
|
+
# this will either be applied immediately or be scheduled asynchronously.
|
140
|
+
#
|
141
|
+
# Will not be called in case that the future is completed with a value.
|
142
|
+
# @yieldparam [Fear::PatternMatch] m
|
143
|
+
# @return [self]
|
144
|
+
#
|
145
|
+
# @example
|
146
|
+
# Fear.future { }.on_failure_match do |m|
|
147
|
+
# m.case(HTTPError) { |error| ... }
|
148
|
+
# end
|
149
|
+
#
|
150
|
+
def on_failure_match
|
151
|
+
on_failure do |error|
|
152
|
+
Fear.matcher { |m| yield(m) }.call_or_else(error, &:itself)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
103
156
|
# When this future is completed call the provided block.
|
104
157
|
#
|
105
158
|
# If the future has already been completed,
|
@@ -119,6 +172,26 @@ module Fear
|
|
119
172
|
self
|
120
173
|
end
|
121
174
|
|
175
|
+
# When this future is completed match against result.
|
176
|
+
#
|
177
|
+
# If the future has already been completed,
|
178
|
+
# this will either be applied immediately or be scheduled asynchronously.
|
179
|
+
# @yieldparam [Fear::TryPatternMatch]
|
180
|
+
# @return [self]
|
181
|
+
#
|
182
|
+
# @example
|
183
|
+
# Fear.future { }.on_complete_match do |m|
|
184
|
+
# m.success { |result| }
|
185
|
+
# m.failure { |error| }
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
def on_complete_match
|
189
|
+
promise.add_observer do |_time, try, _error|
|
190
|
+
Fear::Try.matcher { |m| yield(m) }.call_or_else(try, &:itself)
|
191
|
+
end
|
192
|
+
self
|
193
|
+
end
|
194
|
+
|
122
195
|
# Returns whether the future has already been completed with
|
123
196
|
# a value or an error.
|
124
197
|
#
|
@@ -177,11 +250,9 @@ module Fear
|
|
177
250
|
#
|
178
251
|
def transform(success, failure)
|
179
252
|
promise = Promise.new(@options)
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
m.failure { |error| promise.failure(failure.call(error)) }
|
184
|
-
end
|
253
|
+
on_complete_match do |m|
|
254
|
+
m.success { |value| promise.success(success.(value)) }
|
255
|
+
m.failure { |error| promise.failure(failure.(error)) }
|
185
256
|
end
|
186
257
|
promise.to_future
|
187
258
|
end
|
@@ -222,17 +293,15 @@ module Fear
|
|
222
293
|
# end
|
223
294
|
# end
|
224
295
|
#
|
225
|
-
def flat_map
|
296
|
+
def flat_map
|
226
297
|
promise = Promise.new(@options)
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
promise.failure!(error)
|
235
|
-
end
|
298
|
+
on_complete_match do |m|
|
299
|
+
m.case(Fear::Failure) { |failure| promise.complete!(failure) }
|
300
|
+
m.success do |value|
|
301
|
+
begin
|
302
|
+
yield(value).on_complete { |callback_result| promise.complete!(callback_result) }
|
303
|
+
rescue StandardError => error
|
304
|
+
promise.failure!(error)
|
236
305
|
end
|
237
306
|
end
|
238
307
|
end
|
@@ -261,7 +330,7 @@ module Fear
|
|
261
330
|
if yield(result)
|
262
331
|
result
|
263
332
|
else
|
264
|
-
raise NoSuchElementError,
|
333
|
+
raise NoSuchElementError, "#select predicate is not satisfied"
|
265
334
|
end
|
266
335
|
end
|
267
336
|
end
|
@@ -306,19 +375,17 @@ module Fear
|
|
306
375
|
# future1.zip(future2) #=> returns the same result as Fear.future { [call_service1, call_service2] },
|
307
376
|
# # but it performs two calls asynchronously
|
308
377
|
#
|
309
|
-
def zip(other)
|
378
|
+
def zip(other)
|
310
379
|
promise = Promise.new(@options)
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
promise.complete!(try_of_other.map { |other_value| [value, other_value] })
|
316
|
-
end
|
317
|
-
end
|
318
|
-
m.failure do |error|
|
319
|
-
promise.failure!(error)
|
380
|
+
on_complete_match do |m|
|
381
|
+
m.success do |value|
|
382
|
+
other.on_complete do |other_try|
|
383
|
+
promise.complete!(other_try.map { |other_value| [value, other_value] })
|
320
384
|
end
|
321
385
|
end
|
386
|
+
m.failure do |error|
|
387
|
+
promise.failure!(error)
|
388
|
+
end
|
322
389
|
end
|
323
390
|
|
324
391
|
promise.to_future
|
@@ -338,26 +405,20 @@ module Fear
|
|
338
405
|
# g = Fear.future { 5 }
|
339
406
|
# f.fallback_to(g) # evaluates to 5
|
340
407
|
#
|
341
|
-
# rubocop: disable Metrics/MethodLength
|
342
408
|
def fallback_to(fallback)
|
343
409
|
promise = Promise.new(@options)
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
m2.success { |value| promise.complete!(value) }
|
351
|
-
m2.failure { promise.failure!(error) }
|
352
|
-
end
|
353
|
-
end
|
410
|
+
on_complete_match do |m|
|
411
|
+
m.success { |value| promise.complete!(value) }
|
412
|
+
m.failure do |error|
|
413
|
+
fallback.on_complete_match do |m2|
|
414
|
+
m2.success { |value| promise.complete!(value) }
|
415
|
+
m2.failure { promise.failure!(error) }
|
354
416
|
end
|
355
417
|
end
|
356
418
|
end
|
357
419
|
|
358
420
|
promise.to_future
|
359
421
|
end
|
360
|
-
# rubocop: enable Metrics/MethodLength
|
361
422
|
|
362
423
|
# Applies the side-effecting block to the result of +self+ future,
|
363
424
|
# and returns a new future with the result of this future.
|
@@ -373,22 +434,38 @@ module Fear
|
|
373
434
|
# @example The following example prints out +5+:
|
374
435
|
# f = Fear.future { 5 }
|
375
436
|
# f.and_then do
|
376
|
-
# fail 'runtime error'
|
437
|
+
# m.success { }fail| 'runtime error' }
|
377
438
|
# end.and_then do |m|
|
378
439
|
# m.success { |value| puts value } # it evaluates this branch
|
379
440
|
# m.failure { |error| puts error.massage }
|
380
441
|
# end
|
381
442
|
#
|
382
|
-
def and_then
|
443
|
+
def and_then
|
383
444
|
promise = Promise.new(@options)
|
384
445
|
on_complete do |try|
|
385
|
-
Fear.try
|
446
|
+
Fear.try do
|
447
|
+
Fear::Try.matcher { |m| yield(m) }.call_or_else(try, &:itself)
|
448
|
+
end
|
386
449
|
promise.complete!(try)
|
387
450
|
end
|
388
451
|
|
389
452
|
promise.to_future
|
390
453
|
end
|
391
454
|
|
455
|
+
# @api private
|
456
|
+
def __result__(at_most)
|
457
|
+
__ready__(at_most).value.get_or_else { raise "promise not completed" }
|
458
|
+
end
|
459
|
+
|
460
|
+
# @api private
|
461
|
+
def __ready__(at_most)
|
462
|
+
if promise.wait(at_most).complete?
|
463
|
+
self
|
464
|
+
else
|
465
|
+
raise Timeout::Error
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
392
469
|
class << self
|
393
470
|
# Creates an already completed +Future+ with the specified error.
|
394
471
|
# @param exception [StandardError]
|