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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +27 -0
  3. data/.github/workflows/rubocop.yml +2 -2
  4. data/.github/workflows/spec.yml +1 -1
  5. data/CHANGELOG.md +13 -0
  6. data/Gemfile.lock +53 -56
  7. data/README.md +54 -186
  8. data/Rakefile +0 -21
  9. data/examples/pattern_extracting.rb +4 -4
  10. data/fear.gemspec +2 -4
  11. data/lib/fear/either.rb +8 -4
  12. data/lib/fear/either_api.rb +2 -0
  13. data/lib/fear/either_pattern_match.rb +7 -8
  14. data/lib/fear/failure.rb +0 -9
  15. data/lib/fear/failure_pattern_match.rb +2 -0
  16. data/lib/fear/for_api.rb +2 -0
  17. data/lib/fear/future.rb +12 -20
  18. data/lib/fear/future_api.rb +13 -2
  19. data/lib/fear/left.rb +0 -9
  20. data/lib/fear/none.rb +7 -9
  21. data/lib/fear/option.rb +5 -1
  22. data/lib/fear/option_api.rb +2 -0
  23. data/lib/fear/option_pattern_match.rb +6 -4
  24. data/lib/fear/partial_function/empty.rb +2 -0
  25. data/lib/fear/partial_function/guard.rb +4 -4
  26. data/lib/fear/partial_function/or_else.rb +2 -0
  27. data/lib/fear/partial_function.rb +9 -8
  28. data/lib/fear/pattern_match.rb +0 -10
  29. data/lib/fear/pattern_matching_api.rb +3 -28
  30. data/lib/fear/promise.rb +3 -9
  31. data/lib/fear/right.rb +0 -10
  32. data/lib/fear/right_biased.rb +1 -1
  33. data/lib/fear/right_pattern_match.rb +2 -0
  34. data/lib/fear/some.rb +7 -10
  35. data/lib/fear/struct.rb +3 -14
  36. data/lib/fear/success.rb +0 -9
  37. data/lib/fear/success_pattern_match.rb +2 -0
  38. data/lib/fear/try.rb +6 -2
  39. data/lib/fear/try_api.rb +2 -0
  40. data/lib/fear/try_pattern_match.rb +7 -8
  41. data/lib/fear/utils.rb +0 -3
  42. data/lib/fear/version.rb +1 -1
  43. data/lib/fear.rb +8 -42
  44. data/spec/fear/awaitable_spec.rb +2 -0
  45. data/spec/fear/either_spec.rb +26 -0
  46. data/spec/fear/failure_spec.rb +8 -23
  47. data/spec/fear/for/mixin_spec.rb +15 -0
  48. data/spec/fear/future_spec.rb +17 -2
  49. data/spec/fear/guard_spec.rb +110 -0
  50. data/spec/fear/left_spec.rb +7 -22
  51. data/spec/fear/none_spec.rb +11 -17
  52. data/spec/fear/option_spec.rb +15 -1
  53. data/spec/fear/partial_function/any_spec.rb +25 -0
  54. data/spec/fear/partial_function_spec.rb +2 -24
  55. data/spec/fear/pattern_match_spec.rb +0 -34
  56. data/spec/fear/promise_spec.rb +4 -6
  57. data/spec/fear/right_spec.rb +0 -22
  58. data/spec/fear/some_spec.rb +10 -22
  59. data/spec/fear/success_spec.rb +0 -22
  60. data/spec/fear/try/mixin_spec.rb +14 -0
  61. data/spec/fear/try_api_spec.rb +23 -0
  62. data/spec/struct_spec.rb +1 -33
  63. metadata +18 -80
  64. data/examples/pattern_extracting_ruby2.7.rb +0 -15
  65. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -10
  66. data/lib/fear/extractor/any_matcher.rb +0 -17
  67. data/lib/fear/extractor/array_head_matcher.rb +0 -36
  68. data/lib/fear/extractor/array_matcher.rb +0 -40
  69. data/lib/fear/extractor/array_splat_matcher.rb +0 -16
  70. data/lib/fear/extractor/empty_list_matcher.rb +0 -20
  71. data/lib/fear/extractor/extractor_matcher.rb +0 -44
  72. data/lib/fear/extractor/grammar.rb +0 -203
  73. data/lib/fear/extractor/grammar.treetop +0 -129
  74. data/lib/fear/extractor/identifier_matcher.rb +0 -18
  75. data/lib/fear/extractor/matcher/and.rb +0 -38
  76. data/lib/fear/extractor/matcher.rb +0 -53
  77. data/lib/fear/extractor/named_array_splat_matcher.rb +0 -17
  78. data/lib/fear/extractor/pattern.rb +0 -58
  79. data/lib/fear/extractor/typed_identifier_matcher.rb +0 -26
  80. data/lib/fear/extractor/value_matcher.rb +0 -19
  81. data/lib/fear/extractor.rb +0 -112
  82. data/lib/fear/extractor_api.rb +0 -35
  83. data/spec/fear/extractor/array_matcher_spec.rb +0 -230
  84. data/spec/fear/extractor/extractor_matcher_spec.rb +0 -153
  85. data/spec/fear/extractor/grammar_array_spec.rb +0 -25
  86. data/spec/fear/extractor/identified_matcher_spec.rb +0 -49
  87. data/spec/fear/extractor/identifier_matcher_spec.rb +0 -68
  88. data/spec/fear/extractor/pattern_spec.rb +0 -34
  89. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -64
  90. data/spec/fear/extractor/value_matcher_number_spec.rb +0 -79
  91. data/spec/fear/extractor/value_matcher_string_spec.rb +0 -88
  92. data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -71
  93. data/spec/fear/extractor_api_spec.rb +0 -115
  94. 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(21)
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(21)
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,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "fear/try"
4
+
3
5
  module Fear
4
6
  module TryApi
5
7
  # Constructs a +Try+ using the block. This
@@ -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, &SUCCESS_EXTRACTOR).and_then(Fear.case(*conditions, &effect))
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, &FAILURE_EXTRACTOR).and_then(Fear.case(*conditions, &effect))
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
@@ -6,9 +6,6 @@ module Fear
6
6
  EMPTY_STRING = ""
7
7
  public_constant :EMPTY_STRING
8
8
 
9
- IDENTITY = :itself.to_proc
10
- public_constant :IDENTITY
11
-
12
9
  UNDEFINED = Object.new.freeze
13
10
  public_constant :UNDEFINED
14
11
 
data/lib/fear/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fear
4
- VERSION = "1.2.0"
4
+ VERSION = "2.0.0"
5
5
  public_constant :VERSION
6
6
  end
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
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "fear/awaitable"
4
+
3
5
  RSpec.describe Fear::Awaitable do
4
6
  subject(:awaitable) { Object.new.extend(Fear::Awaitable) }
5
7
 
@@ -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
@@ -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 matches by class" do
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
@@ -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::Future.successful(5)
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::Future.successful(5).and_then { raise error }.and_then { |m| m.success(&callback) }
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
 
@@ -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
@@ -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
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- RSpec.describe "Fear::None" do
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
@@ -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, &Fear::Utils::IDENTITY) }
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, &Fear::Utils::IDENTITY) }
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|