fear 1.2.0 → 2.0.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/.github/dependabot.yml +27 -0
- data/.github/workflows/rubocop.yml +2 -2
- data/.github/workflows/spec.yml +1 -1
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +53 -56
- data/README.md +54 -186
- data/Rakefile +0 -21
- data/examples/pattern_extracting.rb +4 -4
- data/fear.gemspec +2 -4
- data/lib/fear/either.rb +8 -4
- data/lib/fear/either_api.rb +2 -0
- data/lib/fear/either_pattern_match.rb +7 -8
- data/lib/fear/failure.rb +0 -9
- data/lib/fear/failure_pattern_match.rb +2 -0
- data/lib/fear/for_api.rb +2 -0
- data/lib/fear/future.rb +12 -20
- data/lib/fear/future_api.rb +13 -2
- data/lib/fear/left.rb +0 -9
- data/lib/fear/none.rb +7 -9
- data/lib/fear/option.rb +5 -1
- data/lib/fear/option_api.rb +2 -0
- data/lib/fear/option_pattern_match.rb +6 -4
- data/lib/fear/partial_function/empty.rb +2 -0
- data/lib/fear/partial_function/guard.rb +4 -4
- data/lib/fear/partial_function/or_else.rb +2 -0
- data/lib/fear/partial_function.rb +9 -8
- data/lib/fear/pattern_match.rb +0 -10
- data/lib/fear/pattern_matching_api.rb +3 -28
- data/lib/fear/promise.rb +3 -9
- data/lib/fear/right.rb +0 -10
- data/lib/fear/right_biased.rb +1 -1
- data/lib/fear/right_pattern_match.rb +2 -0
- data/lib/fear/some.rb +7 -10
- data/lib/fear/struct.rb +3 -14
- data/lib/fear/success.rb +0 -9
- data/lib/fear/success_pattern_match.rb +2 -0
- data/lib/fear/try.rb +6 -2
- data/lib/fear/try_api.rb +2 -0
- data/lib/fear/try_pattern_match.rb +7 -8
- data/lib/fear/utils.rb +0 -3
- data/lib/fear/version.rb +1 -1
- data/lib/fear.rb +8 -42
- data/spec/fear/awaitable_spec.rb +2 -0
- data/spec/fear/either_spec.rb +26 -0
- data/spec/fear/failure_spec.rb +8 -23
- data/spec/fear/for/mixin_spec.rb +15 -0
- data/spec/fear/future_spec.rb +17 -2
- data/spec/fear/guard_spec.rb +110 -0
- data/spec/fear/left_spec.rb +7 -22
- data/spec/fear/none_spec.rb +11 -17
- data/spec/fear/option_spec.rb +15 -1
- data/spec/fear/partial_function/any_spec.rb +25 -0
- data/spec/fear/partial_function_spec.rb +2 -24
- data/spec/fear/pattern_match_spec.rb +0 -34
- data/spec/fear/promise_spec.rb +4 -6
- data/spec/fear/right_spec.rb +0 -22
- data/spec/fear/some_spec.rb +10 -22
- data/spec/fear/success_spec.rb +0 -22
- data/spec/fear/try/mixin_spec.rb +14 -0
- data/spec/fear/try_api_spec.rb +23 -0
- data/spec/struct_spec.rb +1 -33
- metadata +18 -80
- data/examples/pattern_extracting_ruby2.7.rb +0 -15
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -10
- data/lib/fear/extractor/any_matcher.rb +0 -17
- data/lib/fear/extractor/array_head_matcher.rb +0 -36
- data/lib/fear/extractor/array_matcher.rb +0 -40
- data/lib/fear/extractor/array_splat_matcher.rb +0 -16
- data/lib/fear/extractor/empty_list_matcher.rb +0 -20
- data/lib/fear/extractor/extractor_matcher.rb +0 -44
- data/lib/fear/extractor/grammar.rb +0 -203
- data/lib/fear/extractor/grammar.treetop +0 -129
- data/lib/fear/extractor/identifier_matcher.rb +0 -18
- data/lib/fear/extractor/matcher/and.rb +0 -38
- data/lib/fear/extractor/matcher.rb +0 -53
- data/lib/fear/extractor/named_array_splat_matcher.rb +0 -17
- data/lib/fear/extractor/pattern.rb +0 -58
- data/lib/fear/extractor/typed_identifier_matcher.rb +0 -26
- data/lib/fear/extractor/value_matcher.rb +0 -19
- data/lib/fear/extractor.rb +0 -112
- data/lib/fear/extractor_api.rb +0 -35
- data/spec/fear/extractor/array_matcher_spec.rb +0 -230
- data/spec/fear/extractor/extractor_matcher_spec.rb +0 -153
- data/spec/fear/extractor/grammar_array_spec.rb +0 -25
- data/spec/fear/extractor/identified_matcher_spec.rb +0 -49
- data/spec/fear/extractor/identifier_matcher_spec.rb +0 -68
- data/spec/fear/extractor/pattern_spec.rb +0 -34
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -64
- data/spec/fear/extractor/value_matcher_number_spec.rb +0 -79
- data/spec/fear/extractor/value_matcher_string_spec.rb +0 -88
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -71
- data/spec/fear/extractor_api_spec.rb +0 -115
- data/spec/fear/extractor_spec.rb +0 -61
data/lib/fear/try.rb
CHANGED
@@ -114,7 +114,7 @@ module Fear
|
|
114
114
|
# this is a +Failure+.
|
115
115
|
# @return [Option]
|
116
116
|
# @example
|
117
|
-
# Fear.success(42).to_option #=> Fear.some(
|
117
|
+
# Fear.success(42).to_option #=> Fear.some(42)
|
118
118
|
# Fear.failure(ArgumentError.new).to_option #=> Fear.none()
|
119
119
|
#
|
120
120
|
# @!method any?(&predicate)
|
@@ -172,7 +172,7 @@ module Fear
|
|
172
172
|
# @return [Try]
|
173
173
|
# @example
|
174
174
|
# Fear.success(42).select { |v| v > 40 }
|
175
|
-
# #=> Fear.success(
|
175
|
+
# #=> Fear.success(42)
|
176
176
|
# Fear.success(42).select { |v| v < 40 }
|
177
177
|
# #=> Fear.failure(Fear::NoSuchElementError.new("Predicate does not hold for 42"))
|
178
178
|
# Fear.failure(ArgumentError.new).select { |v| v < 40 }
|
@@ -317,3 +317,7 @@ module Fear
|
|
317
317
|
end
|
318
318
|
end
|
319
319
|
end
|
320
|
+
|
321
|
+
require "fear/try_pattern_match"
|
322
|
+
require "fear/success"
|
323
|
+
require "fear/failure"
|
data/lib/fear/try_api.rb
CHANGED
@@ -1,23 +1,19 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fear/pattern_match"
|
4
|
+
|
3
5
|
module Fear
|
4
6
|
# Try pattern matcher
|
5
7
|
#
|
6
8
|
# @note it has two optimized subclasses +Fear::SuccessPatternMatch+ and +Fear::FailurePatternMatch+
|
7
9
|
# @api private
|
8
10
|
class TryPatternMatch < Fear::PatternMatch
|
9
|
-
SUCCESS_EXTRACTOR = :get.to_proc
|
10
|
-
private_constant :SUCCESS_EXTRACTOR
|
11
|
-
|
12
|
-
FAILURE_EXTRACTOR = :exception.to_proc
|
13
|
-
private_constant :FAILURE_EXTRACTOR
|
14
|
-
|
15
11
|
# Match against +Fear::Success+
|
16
12
|
#
|
17
13
|
# @param conditions [<#==>]
|
18
14
|
# @return [Fear::TryPatternMatch]
|
19
15
|
def success(*conditions, &effect)
|
20
|
-
branch = Fear.case(Fear::Success,
|
16
|
+
branch = Fear.case(Fear::Success, &:get).and_then(Fear.case(*conditions, &effect))
|
21
17
|
or_else(branch)
|
22
18
|
end
|
23
19
|
|
@@ -26,8 +22,11 @@ module Fear
|
|
26
22
|
# @param conditions [<#==>]
|
27
23
|
# @return [Fear::TryPatternMatch]
|
28
24
|
def failure(*conditions, &effect)
|
29
|
-
branch = Fear.case(Fear::Failure,
|
25
|
+
branch = Fear.case(Fear::Failure, &:exception).and_then(Fear.case(*conditions, &effect))
|
30
26
|
or_else(branch)
|
31
27
|
end
|
32
28
|
end
|
33
29
|
end
|
30
|
+
|
31
|
+
require "fear/success_pattern_match"
|
32
|
+
require "fear/failure_pattern_match"
|
data/lib/fear/utils.rb
CHANGED
data/lib/fear/version.rb
CHANGED
data/lib/fear.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "fear/utils"
|
4
|
+
require "fear/right_biased"
|
5
|
+
require "fear/struct"
|
6
|
+
require "fear/unit"
|
3
7
|
require "fear/either_api"
|
4
|
-
require "fear/extractor_api"
|
5
8
|
require "fear/for_api"
|
6
9
|
require "fear/future_api"
|
7
10
|
require "fear/option_api"
|
@@ -26,57 +29,20 @@ module Fear
|
|
26
29
|
public_constant :PatternSyntaxError
|
27
30
|
|
28
31
|
extend EitherApi
|
29
|
-
extend ExtractorApi
|
30
32
|
extend ForApi
|
31
33
|
extend FutureApi
|
32
34
|
extend OptionApi
|
33
35
|
extend PatternMatchingApi
|
34
36
|
extend TryApi
|
35
37
|
|
36
|
-
autoload :EmptyPartialFunction, "fear/empty_partial_function"
|
37
|
-
autoload :PartialFunction, "fear/partial_function"
|
38
|
-
autoload :PartialFunctionClass, "fear/partial_function_class"
|
39
|
-
autoload :PatternMatch, "fear/pattern_match"
|
40
|
-
autoload :Extractor, "fear/extractor"
|
41
|
-
|
42
|
-
autoload :Unit, "fear/unit"
|
43
|
-
autoload :For, "fear/for"
|
44
|
-
autoload :RightBiased, "fear/right_biased"
|
45
|
-
autoload :Utils, "fear/utils"
|
46
|
-
|
47
|
-
autoload :None, "fear/none"
|
48
|
-
autoload :NoneClass, "fear/none"
|
49
|
-
autoload :NonePatternMatch, "fear/none_pattern_match"
|
50
|
-
autoload :Option, "fear/option"
|
51
|
-
autoload :OptionPatternMatch, "fear/option_pattern_match"
|
52
|
-
autoload :Some, "fear/some"
|
53
|
-
autoload :SomePatternMatch, "fear/some_pattern_match"
|
54
|
-
|
55
|
-
autoload :Failure, "fear/failure"
|
56
|
-
autoload :FailurePatternMatch, "fear/failure_pattern_match"
|
57
|
-
autoload :Success, "fear/success"
|
58
|
-
autoload :SuccessPatternMatch, "fear/success_pattern_match"
|
59
|
-
autoload :Try, "fear/try"
|
60
|
-
autoload :TryPatternMatch, "fear/try_pattern_match"
|
61
|
-
|
62
|
-
autoload :Either, "fear/either"
|
63
|
-
autoload :EitherPatternMatch, "fear/either_pattern_match"
|
64
|
-
autoload :Left, "fear/left"
|
65
|
-
autoload :LeftPatternMatch, "fear/left_pattern_match"
|
66
|
-
autoload :Right, "fear/right"
|
67
|
-
autoload :RightPatternMatch, "fear/right_pattern_match"
|
68
|
-
|
69
|
-
autoload :Await, "fear/await"
|
70
|
-
autoload :Awaitable, "fear/awaitable"
|
71
|
-
autoload :Future, "fear/future"
|
72
|
-
autoload :Promise, "fear/promise"
|
73
|
-
|
74
|
-
autoload :Struct, "fear/struct"
|
75
|
-
|
76
38
|
module Mixin
|
77
39
|
include Either::Mixin
|
78
40
|
include For::Mixin
|
79
41
|
include Option::Mixin
|
80
42
|
include Try::Mixin
|
81
43
|
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
include Mixin
|
47
|
+
end
|
82
48
|
end
|
data/spec/fear/awaitable_spec.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::Either do
|
4
|
+
describe "#matcher" do
|
5
|
+
subject(:result) { matcher.(value) }
|
6
|
+
|
7
|
+
let(:matcher) do
|
8
|
+
described_class.matcher do |m|
|
9
|
+
m.right { |x| "right of #{x}" }
|
10
|
+
m.left { |x| "left of #{x}" }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when matches the right branch" do
|
15
|
+
let(:value) { Fear.right(42) }
|
16
|
+
|
17
|
+
it { is_expected.to eq("right of 42") }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "when matches the left branch" do
|
21
|
+
let(:value) { Fear.left(42) }
|
22
|
+
|
23
|
+
it { is_expected.to eq("left of 42") }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/fear/failure_spec.rb
CHANGED
@@ -144,10 +144,17 @@ RSpec.describe Fear::Failure do
|
|
144
144
|
it { is_expected.to eq(true) }
|
145
145
|
end
|
146
146
|
|
147
|
-
context "does not
|
147
|
+
context "does not match by class" do
|
148
148
|
let(:match) { Fear.failure(ArgumentError) }
|
149
149
|
it { is_expected.to eq(false) }
|
150
150
|
end
|
151
|
+
|
152
|
+
context "does not match non-try" do
|
153
|
+
let(:match) { Fear.failure(ArgumentError) }
|
154
|
+
let(:failure) { ArgumentError.new }
|
155
|
+
|
156
|
+
it { is_expected.to eq(false) }
|
157
|
+
end
|
151
158
|
end
|
152
159
|
|
153
160
|
describe "#match" do
|
@@ -193,26 +200,4 @@ RSpec.describe Fear::Failure do
|
|
193
200
|
|
194
201
|
it { is_expected.to eq("#<Fear::Failure exception=#<RuntimeError: error>>") }
|
195
202
|
end
|
196
|
-
|
197
|
-
describe "pattern matching" do
|
198
|
-
subject { Fear.xcase("Failure(v : ArgumentError)") { "matched" }.call_or_else(var) { "nothing" } }
|
199
|
-
|
200
|
-
context "failure of ArgumentError" do
|
201
|
-
let(:var) { Fear.failure(ArgumentError.new) }
|
202
|
-
|
203
|
-
it { is_expected.to eq("matched") }
|
204
|
-
end
|
205
|
-
|
206
|
-
context "failure of RuntimeError" do
|
207
|
-
let(:var) { Fear.failure(RuntimeError.new) }
|
208
|
-
|
209
|
-
it { is_expected.to eq("nothing") }
|
210
|
-
end
|
211
|
-
|
212
|
-
context "not failure" do
|
213
|
-
let(:var) { "42" }
|
214
|
-
|
215
|
-
it { is_expected.to eq("nothing") }
|
216
|
-
end
|
217
|
-
end
|
218
203
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::For::Mixin do
|
4
|
+
include Fear::For::Mixin
|
5
|
+
|
6
|
+
describe "For()" do
|
7
|
+
subject do
|
8
|
+
For([1, 2], [2, 3], [3, 4]) do |a, b, c|
|
9
|
+
a * b * c
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it { is_expected.to eq([6, 8, 9, 12, 12, 16, 18, 24]) }
|
14
|
+
end
|
15
|
+
end
|
data/spec/fear/future_spec.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Fear::Future do
|
4
|
+
describe "#initialize" do
|
5
|
+
context "when promise and block are given at the same time" do
|
6
|
+
let(:promise) do
|
7
|
+
Concurrent::Promise.execute { 42 }
|
8
|
+
end
|
9
|
+
|
10
|
+
specify do
|
11
|
+
expect { described_class.new(promise) { 43 } }.to raise_error(ArgumentError, "pass block or promise")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
4
16
|
context "#on_complete" do
|
5
17
|
it "run callback with value" do
|
6
18
|
expect do |callback|
|
@@ -536,9 +548,11 @@ RSpec.describe Fear::Future do
|
|
536
548
|
it "ensure callbacks are called" do
|
537
549
|
expect do |first|
|
538
550
|
expect do |second|
|
539
|
-
Fear
|
551
|
+
future = Fear.future { 5 }
|
540
552
|
.and_then { |m| m.success(&first) }
|
541
553
|
.and_then { |m| m.success(&second) }
|
554
|
+
|
555
|
+
Fear::Await.ready(future, 2)
|
542
556
|
end.to yield_with_args(5)
|
543
557
|
end.to yield_with_args(5)
|
544
558
|
end
|
@@ -591,7 +605,8 @@ RSpec.describe Fear::Future do
|
|
591
605
|
context "first callback is failing" do
|
592
606
|
it "calls second callback" do
|
593
607
|
expect do |callback|
|
594
|
-
Fear
|
608
|
+
future = Fear.future { 5 }.and_then { raise error }.and_then { |m| m.success(&callback) }
|
609
|
+
Fear::Await.ready(future, 2)
|
595
610
|
end.to yield_with_args(5)
|
596
611
|
end
|
597
612
|
|
data/spec/fear/guard_spec.rb
CHANGED
@@ -77,6 +77,87 @@ RSpec.describe Fear::PartialFunction::Guard do
|
|
77
77
|
expect { guard === 4 }.not_to raise_error
|
78
78
|
end
|
79
79
|
end
|
80
|
+
|
81
|
+
context "with many arguments" do
|
82
|
+
let(:guard) { Fear::PartialFunction::Guard.and([guard_1, guard_2, guard_3, guard_4]) }
|
83
|
+
|
84
|
+
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
85
|
+
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
86
|
+
let(:guard_3) { ->(x) { x % 6 == 0 } }
|
87
|
+
let(:guard_4) { ->(x) { x % 7 == 0 } }
|
88
|
+
let(:guard_4) { ->(x) { x % 8 == 0 } }
|
89
|
+
|
90
|
+
it { expect(guard === 3360).to eq(true) }
|
91
|
+
it { expect(guard === 10).to eq(false) }
|
92
|
+
it { expect(guard === 8).to eq(false) }
|
93
|
+
it { expect(guard === 5).to eq(false) }
|
94
|
+
it { expect(guard === 7).to eq(false) }
|
95
|
+
it { expect(guard === 6).to eq(false) }
|
96
|
+
it { expect(guard === 2).to eq(false) }
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#and" do
|
100
|
+
let(:guard) { guard_1_and_guard_2.and(guard_3) }
|
101
|
+
let(:guard_1_and_guard_2) { Fear::PartialFunction::Guard.and([guard_1, guard_2]) }
|
102
|
+
|
103
|
+
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
104
|
+
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
105
|
+
let(:guard_3) { ->(x) { x % 6 == 0 } }
|
106
|
+
|
107
|
+
it { expect(guard === 30).to eq(true) }
|
108
|
+
it { expect(guard === 10).to eq(false) }
|
109
|
+
it { expect(guard === 5).to eq(false) }
|
110
|
+
it { expect(guard === 2).to eq(false) }
|
111
|
+
it { expect(guard === 3).to eq(false) }
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "#and", "with three arguments" do
|
115
|
+
let(:guard) { guard_123.and(guard_4) }
|
116
|
+
let(:guard_123) { Fear::PartialFunction::Guard.and([guard_1, guard_2, guard_3]) }
|
117
|
+
|
118
|
+
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
119
|
+
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
120
|
+
let(:guard_3) { ->(x) { x % 6 == 0 } }
|
121
|
+
let(:guard_4) { ->(x) { x % 7 == 0 } }
|
122
|
+
|
123
|
+
it { expect(guard === 420).to eq(true) }
|
124
|
+
it { expect(guard === 10).to eq(false) }
|
125
|
+
it { expect(guard === 5).to eq(false) }
|
126
|
+
it { expect(guard === 7).to eq(false) }
|
127
|
+
it { expect(guard === 6).to eq(false) }
|
128
|
+
it { expect(guard === 2).to eq(false) }
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#or" do
|
132
|
+
let(:guard) { guard_1_and_guard_2.or(guard_3) }
|
133
|
+
let(:guard_1_and_guard_2) { Fear::PartialFunction::Guard.and([guard_1, guard_2]) }
|
134
|
+
|
135
|
+
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
136
|
+
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
137
|
+
let(:guard_3) { ->(x) { x % 3 == 0 } }
|
138
|
+
|
139
|
+
it { expect(guard === 10).to eq(true) }
|
140
|
+
it { expect(guard === 3).to eq(true) }
|
141
|
+
it { expect(guard === 5).to eq(false) }
|
142
|
+
it { expect(guard === 2).to eq(false) }
|
143
|
+
it { expect(guard === 7).to eq(false) }
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "#or", "with three arguments" do
|
147
|
+
let(:guard) { guard_123.or(guard_4) }
|
148
|
+
let(:guard_123) { Fear::PartialFunction::Guard.and([guard_1, guard_2, guard_3]) }
|
149
|
+
|
150
|
+
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
151
|
+
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
152
|
+
let(:guard_3) { ->(x) { x % 6 == 0 } }
|
153
|
+
let(:guard_4) { ->(x) { x % 7 == 0 } }
|
154
|
+
|
155
|
+
it { expect(guard === 30).to eq(true) }
|
156
|
+
it { expect(guard === 7).to eq(true) }
|
157
|
+
it { expect(guard === 5).to eq(false) }
|
158
|
+
it { expect(guard === 2).to eq(false) }
|
159
|
+
it { expect(guard === 6).to eq(false) }
|
160
|
+
end
|
80
161
|
end
|
81
162
|
|
82
163
|
describe ".or" do
|
@@ -99,5 +180,34 @@ RSpec.describe Fear::PartialFunction::Guard do
|
|
99
180
|
|
100
181
|
it { is_expected.to eq(false) }
|
101
182
|
end
|
183
|
+
|
184
|
+
describe "#and" do
|
185
|
+
let(:guard) { guard_1_or_guard_2.and(guard_3) }
|
186
|
+
let(:guard_1_or_guard_2) { Fear::PartialFunction::Guard.or([guard_1, guard_2]) }
|
187
|
+
|
188
|
+
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
189
|
+
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
190
|
+
let(:guard_3) { ->(x) { x % 3 == 0 } }
|
191
|
+
|
192
|
+
it { expect(guard === 6).to eq(true) }
|
193
|
+
it { expect(guard === 15).to eq(true) }
|
194
|
+
it { expect(guard === 5).to eq(false) }
|
195
|
+
it { expect(guard === 2).to eq(false) }
|
196
|
+
it { expect(guard === 3).to eq(false) }
|
197
|
+
end
|
198
|
+
|
199
|
+
describe "#or" do
|
200
|
+
let(:guard) { guard_1_or_guard_2.or(guard_3) }
|
201
|
+
let(:guard_1_or_guard_2) { Fear::PartialFunction::Guard.or([guard_1, guard_2]) }
|
202
|
+
|
203
|
+
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
204
|
+
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
205
|
+
let(:guard_3) { ->(x) { x % 3 == 0 } }
|
206
|
+
|
207
|
+
it { expect(guard === 5).to eq(true) }
|
208
|
+
it { expect(guard === 2).to eq(true) }
|
209
|
+
it { expect(guard === 3).to eq(true) }
|
210
|
+
it { expect(guard === 7).to eq(false) }
|
211
|
+
end
|
102
212
|
end
|
103
213
|
end
|
data/spec/fear/left_spec.rb
CHANGED
@@ -140,6 +140,13 @@ RSpec.describe Fear::Left do
|
|
140
140
|
let(:match) { Fear.left(Integer) }
|
141
141
|
it { is_expected.to eq(false) }
|
142
142
|
end
|
143
|
+
|
144
|
+
context "does non-either" do
|
145
|
+
let(:match) { Fear.left(42) }
|
146
|
+
let(:left) { 42 }
|
147
|
+
|
148
|
+
it { is_expected.to eq(false) }
|
149
|
+
end
|
143
150
|
end
|
144
151
|
|
145
152
|
describe "#match" do
|
@@ -185,26 +192,4 @@ RSpec.describe Fear::Left do
|
|
185
192
|
|
186
193
|
it { is_expected.to eq('#<Fear::Left value="value">') }
|
187
194
|
end
|
188
|
-
|
189
|
-
describe "pattern matching" do
|
190
|
-
subject { Fear.xcase("Left(v : Integer)") { |v:| "matched #{v}" }.call_or_else(var) { "nothing" } }
|
191
|
-
|
192
|
-
context "left of int" do
|
193
|
-
let(:var) { Fear.left(42) }
|
194
|
-
|
195
|
-
it { is_expected.to eq("matched 42") }
|
196
|
-
end
|
197
|
-
|
198
|
-
context "left of string" do
|
199
|
-
let(:var) { Fear.left("42") }
|
200
|
-
|
201
|
-
it { is_expected.to eq("nothing") }
|
202
|
-
end
|
203
|
-
|
204
|
-
context "not left" do
|
205
|
-
let(:var) { "42" }
|
206
|
-
|
207
|
-
it { is_expected.to eq("nothing") }
|
208
|
-
end
|
209
|
-
end
|
210
195
|
end
|
data/spec/fear/none_spec.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
RSpec.describe
|
3
|
+
RSpec.describe Fear::None do
|
4
4
|
it_behaves_like Fear::RightBiased::Left do
|
5
5
|
let(:left) { Fear.none }
|
6
6
|
end
|
@@ -31,6 +31,16 @@ RSpec.describe "Fear::None" do
|
|
31
31
|
it { is_expected.to eq(true) }
|
32
32
|
end
|
33
33
|
|
34
|
+
describe "#blank?" do
|
35
|
+
subject { none.blank? }
|
36
|
+
it { is_expected.to eq(true) }
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#present?" do
|
40
|
+
subject { none.present? }
|
41
|
+
it { is_expected.to be_falsey }
|
42
|
+
end
|
43
|
+
|
34
44
|
describe "#select" do
|
35
45
|
subject { none.select { |value| value > 42 } }
|
36
46
|
|
@@ -128,20 +138,4 @@ RSpec.describe "Fear::None" do
|
|
128
138
|
it { is_expected.to eq(:default) }
|
129
139
|
end
|
130
140
|
end
|
131
|
-
|
132
|
-
describe "pattern matching" do
|
133
|
-
subject { Fear.xcase("None()") { "matched" }.call_or_else(var) { "nothing" } }
|
134
|
-
|
135
|
-
context "none" do
|
136
|
-
let(:var) { Fear.none }
|
137
|
-
|
138
|
-
it { is_expected.to eq("matched") }
|
139
|
-
end
|
140
|
-
|
141
|
-
context "not none" do
|
142
|
-
let(:var) { "42" }
|
143
|
-
|
144
|
-
it { is_expected.to eq("nothing") }
|
145
|
-
end
|
146
|
-
end
|
147
141
|
end
|
data/spec/fear/option_spec.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
RSpec.describe Fear::Option do
|
4
4
|
describe "#zip" do
|
5
|
-
subject { left.zip(right) }
|
5
|
+
subject(:zip) { left.zip(right) }
|
6
6
|
|
7
7
|
context "some with some" do
|
8
8
|
let(:left) { Fear.some(42) }
|
@@ -28,6 +28,13 @@ RSpec.describe Fear::Option do
|
|
28
28
|
it { is_expected.to eq(Fear.none) }
|
29
29
|
end
|
30
30
|
|
31
|
+
context "some with non-option" do
|
32
|
+
let(:left) { Fear.some(42) }
|
33
|
+
let(:right) { 42 }
|
34
|
+
|
35
|
+
it { expect { zip }.to raise_error(TypeError) }
|
36
|
+
end
|
37
|
+
|
31
38
|
context "none with some" do
|
32
39
|
let(:left) { Fear.none }
|
33
40
|
let(:right) { Fear.some(42) }
|
@@ -41,6 +48,13 @@ RSpec.describe Fear::Option do
|
|
41
48
|
|
42
49
|
it { is_expected.to eq(Fear.none) }
|
43
50
|
end
|
51
|
+
|
52
|
+
context "none with non-option" do
|
53
|
+
let(:left) { Fear.none }
|
54
|
+
let(:right) { 42 }
|
55
|
+
|
56
|
+
it { expect { zip }.to raise_error(TypeError) }
|
57
|
+
end
|
44
58
|
end
|
45
59
|
|
46
60
|
describe "#filter_map" do
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::PartialFunction::Any do
|
4
|
+
subject(:any) { described_class }
|
5
|
+
|
6
|
+
describe ".===" do
|
7
|
+
it { expect(any === 42).to eq(true) }
|
8
|
+
it { expect(any === "foo").to eq(true) }
|
9
|
+
it { expect(any === Object.new).to eq(true) }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ".==" do
|
13
|
+
it { expect(any == 42).to eq(true) }
|
14
|
+
it { expect(any == "foo").to eq(true) }
|
15
|
+
it { expect(any == Object.new).to eq(true) }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".to_proc" do
|
19
|
+
subject(:any_proc) { any.to_proc }
|
20
|
+
|
21
|
+
it { expect(any_proc.(42)).to eq(true) }
|
22
|
+
it { expect(any_proc.("foo")).to eq(true) }
|
23
|
+
it { expect(any_proc.(Object.new)).to eq(true) }
|
24
|
+
end
|
25
|
+
end
|
@@ -2,18 +2,6 @@
|
|
2
2
|
|
3
3
|
RSpec.describe Fear::PartialFunction do
|
4
4
|
describe "Fear.case()" do
|
5
|
-
context "condition is extractor" do
|
6
|
-
subject do
|
7
|
-
Fear.xcase("[1, [2, second_of_second, *], 3, *rest]") do |second_of_second:, rest:|
|
8
|
-
[second_of_second, rest]
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
it { is_expected.to be_defined_at([1, [2, 2, 3, 4], 3, 6, 7]) }
|
13
|
-
it { is_expected.not_to be_defined_at([1, [1, 3, 3, 4], 3, 6, 7]) }
|
14
|
-
it { is_expected.not_to be_defined_at([1, [1, 2, 3, 4], 4, 6, 7]) }
|
15
|
-
end
|
16
|
-
|
17
5
|
context "condition as symbol" do
|
18
6
|
subject { Fear.case(:even?) { |x| x } }
|
19
7
|
|
@@ -64,7 +52,7 @@ RSpec.describe Fear::PartialFunction do
|
|
64
52
|
end
|
65
53
|
|
66
54
|
describe ".or" do
|
67
|
-
subject { described_class.or(guard_1, guard_2,
|
55
|
+
subject { described_class.or(guard_1, guard_2, &:itself) }
|
68
56
|
|
69
57
|
let(:guard_1) { ->(x) { x == 42 } }
|
70
58
|
let(:guard_2) { ->(x) { x == 21 } }
|
@@ -75,7 +63,7 @@ RSpec.describe Fear::PartialFunction do
|
|
75
63
|
end
|
76
64
|
|
77
65
|
describe ".and" do
|
78
|
-
subject { described_class.and(guard_1, guard_2,
|
66
|
+
subject { described_class.and(guard_1, guard_2, &:itself) }
|
79
67
|
|
80
68
|
let(:guard_1) { ->(x) { x % 5 == 0 } }
|
81
69
|
let(:guard_2) { ->(x) { x % 2 == 0 } }
|
@@ -130,16 +118,6 @@ RSpec.describe Fear::PartialFunction do
|
|
130
118
|
|
131
119
|
it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 0") }
|
132
120
|
end
|
133
|
-
|
134
|
-
context "defined and condition is extractor" do
|
135
|
-
subject { partial_function.([1, 2, 3, 4, 5]) }
|
136
|
-
|
137
|
-
let(:partial_function) do
|
138
|
-
Fear.xcase("[1, second, 3, *rest]") { |second:, rest:| [second, rest] }
|
139
|
-
end
|
140
|
-
|
141
|
-
it { is_expected.to eq([2, [4, 5]]) }
|
142
|
-
end
|
143
121
|
end
|
144
122
|
|
145
123
|
describe "#to_proc", "#call" do
|
@@ -1,40 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Fear::PatternMatch do
|
4
|
-
context "extracting" do
|
5
|
-
let(:matcher) do
|
6
|
-
described_class.new do |m|
|
7
|
-
m.xcase("Date(year, 2, 29)", ->(year:) { year < 2000 }) do |year:|
|
8
|
-
"#{year} is a leap year before Millennium"
|
9
|
-
end
|
10
|
-
m.xcase("Date(year, 2, 29)") do |year:|
|
11
|
-
"#{year} is a leap year after Millennium"
|
12
|
-
end
|
13
|
-
m.case(Date) do |date|
|
14
|
-
"#{date.year} is not a leap year"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
context "before Millennium" do
|
20
|
-
subject { matcher.(Date.parse("1996-02-29")) }
|
21
|
-
|
22
|
-
it { is_expected.to eq("1996 is a leap year before Millennium") }
|
23
|
-
end
|
24
|
-
|
25
|
-
context "after Millennium" do
|
26
|
-
subject { matcher.(Date.parse("2004-02-29")) }
|
27
|
-
|
28
|
-
it { is_expected.to eq("2004 is a leap year after Millennium") }
|
29
|
-
end
|
30
|
-
|
31
|
-
context "not leap" do
|
32
|
-
subject { matcher.(Date.parse("2003-01-24")) }
|
33
|
-
|
34
|
-
it { is_expected.to eq("2003 is not a leap year") }
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
4
|
context "else at the end" do
|
39
5
|
let(:matcher) do
|
40
6
|
described_class.new do |m|
|