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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -60
  3. data/.travis.yml +8 -4
  4. data/CHANGELOG.md +7 -1
  5. data/Gemfile +5 -3
  6. data/Gemfile.lock +18 -20
  7. data/README.md +28 -14
  8. data/Rakefile +61 -60
  9. data/examples/pattern_extracting.rb +8 -6
  10. data/examples/pattern_matching_binary_tree_set.rb +4 -2
  11. data/examples/pattern_matching_number_in_words.rb +46 -42
  12. data/fear.gemspec +29 -27
  13. data/lib/fear.rb +44 -37
  14. data/lib/fear/await.rb +33 -0
  15. data/lib/fear/awaitable.rb +28 -0
  16. data/lib/fear/either.rb +2 -0
  17. data/lib/fear/either_api.rb +2 -0
  18. data/lib/fear/either_pattern_match.rb +2 -0
  19. data/lib/fear/empty_partial_function.rb +3 -1
  20. data/lib/fear/extractor.rb +30 -28
  21. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +2 -0
  22. data/lib/fear/extractor/any_matcher.rb +2 -0
  23. data/lib/fear/extractor/array_head_matcher.rb +2 -0
  24. data/lib/fear/extractor/array_matcher.rb +2 -0
  25. data/lib/fear/extractor/array_splat_matcher.rb +2 -0
  26. data/lib/fear/extractor/empty_list_matcher.rb +2 -0
  27. data/lib/fear/extractor/extractor_matcher.rb +5 -3
  28. data/lib/fear/extractor/grammar.rb +5 -3
  29. data/lib/fear/extractor/identifier_matcher.rb +2 -0
  30. data/lib/fear/extractor/matcher.rb +5 -3
  31. data/lib/fear/extractor/matcher/and.rb +3 -1
  32. data/lib/fear/extractor/named_array_splat_matcher.rb +2 -0
  33. data/lib/fear/extractor/pattern.rb +7 -5
  34. data/lib/fear/extractor/typed_identifier_matcher.rb +2 -0
  35. data/lib/fear/extractor/value_matcher.rb +2 -0
  36. data/lib/fear/extractor_api.rb +2 -0
  37. data/lib/fear/failure.rb +2 -0
  38. data/lib/fear/failure_pattern_match.rb +2 -0
  39. data/lib/fear/for.rb +4 -2
  40. data/lib/fear/for_api.rb +3 -1
  41. data/lib/fear/future.rb +141 -64
  42. data/lib/fear/future_api.rb +2 -0
  43. data/lib/fear/left.rb +3 -1
  44. data/lib/fear/left_pattern_match.rb +2 -0
  45. data/lib/fear/none.rb +4 -2
  46. data/lib/fear/none_pattern_match.rb +2 -0
  47. data/lib/fear/option.rb +3 -1
  48. data/lib/fear/option_api.rb +2 -0
  49. data/lib/fear/option_pattern_match.rb +2 -0
  50. data/lib/fear/partial_function.rb +10 -8
  51. data/lib/fear/partial_function/and_then.rb +4 -2
  52. data/lib/fear/partial_function/any.rb +2 -0
  53. data/lib/fear/partial_function/combined.rb +3 -1
  54. data/lib/fear/partial_function/empty.rb +2 -0
  55. data/lib/fear/partial_function/guard.rb +7 -5
  56. data/lib/fear/partial_function/guard/and.rb +2 -0
  57. data/lib/fear/partial_function/guard/and3.rb +2 -0
  58. data/lib/fear/partial_function/guard/or.rb +2 -0
  59. data/lib/fear/partial_function/lifted.rb +2 -0
  60. data/lib/fear/partial_function/or_else.rb +3 -1
  61. data/lib/fear/partial_function_class.rb +3 -1
  62. data/lib/fear/pattern_match.rb +3 -1
  63. data/lib/fear/pattern_matching_api.rb +3 -1
  64. data/lib/fear/promise.rb +11 -3
  65. data/lib/fear/right.rb +3 -1
  66. data/lib/fear/right_biased.rb +4 -2
  67. data/lib/fear/right_pattern_match.rb +2 -0
  68. data/lib/fear/some.rb +2 -0
  69. data/lib/fear/some_pattern_match.rb +2 -0
  70. data/lib/fear/struct.rb +235 -0
  71. data/lib/fear/success.rb +2 -0
  72. data/lib/fear/success_pattern_match.rb +2 -0
  73. data/lib/fear/try.rb +2 -0
  74. data/lib/fear/try_api.rb +2 -0
  75. data/lib/fear/try_pattern_match.rb +2 -0
  76. data/lib/fear/unit.rb +6 -2
  77. data/lib/fear/utils.rb +4 -2
  78. data/lib/fear/version.rb +4 -1
  79. data/spec/fear/done_spec.rb +7 -5
  80. data/spec/fear/either/mixin_spec.rb +4 -2
  81. data/spec/fear/either_pattern_match_spec.rb +10 -8
  82. data/spec/fear/extractor/array_matcher_spec.rb +65 -63
  83. data/spec/fear/extractor/extractor_matcher_spec.rb +64 -62
  84. data/spec/fear/extractor/grammar_array_spec.rb +5 -3
  85. data/spec/fear/extractor/identified_matcher_spec.rb +18 -16
  86. data/spec/fear/extractor/identifier_matcher_spec.rb +26 -24
  87. data/spec/fear/extractor/pattern_spec.rb +17 -15
  88. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +23 -21
  89. data/spec/fear/extractor/value_matcher_number_spec.rb +29 -27
  90. data/spec/fear/extractor/value_matcher_string_spec.rb +27 -25
  91. data/spec/fear/extractor/value_matcher_symbol_spec.rb +24 -22
  92. data/spec/fear/extractor_api_spec.rb +70 -68
  93. data/spec/fear/extractor_spec.rb +23 -21
  94. data/spec/fear/failure_spec.rb +59 -57
  95. data/spec/fear/for_spec.rb +19 -17
  96. data/spec/fear/future_spec.rb +456 -240
  97. data/spec/fear/guard_spec.rb +26 -24
  98. data/spec/fear/left_spec.rb +60 -58
  99. data/spec/fear/none_spec.rb +36 -34
  100. data/spec/fear/option/mixin_spec.rb +9 -7
  101. data/spec/fear/option_pattern_match_spec.rb +10 -8
  102. data/spec/fear/partial_function/empty_spec.rb +12 -10
  103. data/spec/fear/partial_function_and_then_spec.rb +39 -37
  104. data/spec/fear/partial_function_composition_spec.rb +46 -44
  105. data/spec/fear/partial_function_or_else_spec.rb +92 -90
  106. data/spec/fear/partial_function_spec.rb +46 -44
  107. data/spec/fear/pattern_match_spec.rb +31 -29
  108. data/spec/fear/promise_spec.rb +19 -17
  109. data/spec/fear/right_biased/left.rb +28 -26
  110. data/spec/fear/right_biased/right.rb +51 -49
  111. data/spec/fear/right_spec.rb +58 -56
  112. data/spec/fear/some_spec.rb +30 -28
  113. data/spec/fear/success_spec.rb +50 -48
  114. data/spec/fear/try/mixin_spec.rb +5 -3
  115. data/spec/fear/try_pattern_match_spec.rb +10 -8
  116. data/spec/fear/utils_spec.rb +16 -14
  117. data/spec/spec_helper.rb +7 -5
  118. data/spec/struct_spec.rb +226 -0
  119. metadata +18 -13
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Fear::PartialFunction do
2
- describe 'Fear.case()' do
3
- context 'condition is extractor' do
4
+ describe "Fear.case()" do
5
+ context "condition is extractor" do
4
6
  subject do
5
- Fear.xcase('[1, [2, second_of_second, *], 3, *rest]') do |second_of_second:, rest:|
7
+ Fear.xcase("[1, [2, second_of_second, *], 3, *rest]") do |second_of_second:, rest:|
6
8
  [second_of_second, rest]
7
9
  end
8
10
  end
@@ -12,25 +14,25 @@ RSpec.describe Fear::PartialFunction do
12
14
  it { is_expected.not_to be_defined_at([1, [1, 2, 3, 4], 4, 6, 7]) }
13
15
  end
14
16
 
15
- context 'condition as symbol' do
17
+ context "condition as symbol" do
16
18
  subject { Fear.case(:even?) { |x| x } }
17
19
 
18
- it 'matches against the same symbol' do
20
+ it "matches against the same symbol" do
19
21
  is_expected.to be_defined_at(:even?)
20
22
  is_expected.not_to be_defined_at(3)
21
23
  end
22
24
  end
23
25
 
24
- context 'condition as Class' do
26
+ context "condition as Class" do
25
27
  subject { Fear.case(Integer) { |x| x } }
26
28
 
27
29
  it do
28
30
  is_expected.to be_defined_at(4)
29
- is_expected.not_to be_defined_at('3')
31
+ is_expected.not_to be_defined_at("3")
30
32
  end
31
33
  end
32
34
 
33
- context 'condition as Proc' do
35
+ context "condition as Proc" do
34
36
  subject { Fear.case(->(x) { x.even? }) { |x| x } }
35
37
 
36
38
  it do
@@ -39,19 +41,19 @@ RSpec.describe Fear::PartialFunction do
39
41
  end
40
42
  end
41
43
 
42
- context 'multiple condition' do
44
+ context "multiple condition" do
43
45
  subject { Fear.case(Integer, :even?.to_proc, ->(x) { x % 3 == 0 }) { |x| x } }
44
46
 
45
47
  it do
46
48
  is_expected.to be_defined_at(12)
47
49
  is_expected.not_to be_defined_at(12.0)
48
- is_expected.not_to be_defined_at('3')
50
+ is_expected.not_to be_defined_at("3")
49
51
  is_expected.not_to be_defined_at(3)
50
52
  is_expected.not_to be_defined_at(4)
51
53
  end
52
54
  end
53
55
 
54
- context 'multiple condition 2' do
56
+ context "multiple condition 2" do
55
57
  subject { Fear.case(Integer, 4) { |x| x } }
56
58
 
57
59
  it do
@@ -61,124 +63,124 @@ RSpec.describe Fear::PartialFunction do
61
63
  end
62
64
  end
63
65
 
64
- describe '#lift' do
66
+ describe "#lift" do
65
67
  let(:lifted) { partial_function.lift }
66
68
 
67
69
  let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x } }
68
70
 
69
- context 'defined' do
70
- subject { lifted.call(2) }
71
+ context "defined" do
72
+ subject { lifted.(2) }
71
73
 
72
74
  it { is_expected.to eq(Fear::Some.new(2)) }
73
75
  end
74
76
 
75
- context 'not defined' do
76
- subject { lifted.call(0) }
77
+ context "not defined" do
78
+ subject { lifted.(0) }
77
79
 
78
80
  it { is_expected.to eq(Fear::None) }
79
81
  end
80
82
  end
81
83
 
82
- describe '#defined_at?' do
84
+ describe "#defined_at?" do
83
85
  let(:partial_function) { Fear.case(->(v) { v == 42 }) {} }
84
86
 
85
- it 'defined at' do
87
+ it "defined at" do
86
88
  expect(partial_function.defined_at?(42)).to eq(true)
87
89
  end
88
90
 
89
- it 'not defined at' do
91
+ it "not defined at" do
90
92
  expect(partial_function.defined_at?(24)).to eq(false)
91
93
  end
92
94
  end
93
95
 
94
- describe '#call' do
96
+ describe "#call" do
95
97
  let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x } }
96
98
 
97
- context 'defined' do
98
- subject { partial_function.call(2) }
99
+ context "defined" do
100
+ subject { partial_function.(2) }
99
101
 
100
102
  it { is_expected.to eq(2) }
101
103
  end
102
104
 
103
- context 'not defined' do
104
- subject { -> { partial_function.call(0) } }
105
+ context "not defined" do
106
+ subject { -> { partial_function.(0) } }
105
107
 
106
- it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 0') }
108
+ it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 0") }
107
109
  end
108
110
 
109
- context 'defined and condition is extractor' do
110
- subject { partial_function.call([1, 2, 3, 4, 5]) }
111
+ context "defined and condition is extractor" do
112
+ subject { partial_function.([1, 2, 3, 4, 5]) }
111
113
 
112
114
  let(:partial_function) do
113
- Fear.xcase('[1, second, 3, *rest]') { |second:, rest:| [second, rest] }
115
+ Fear.xcase("[1, second, 3, *rest]") { |second:, rest:| [second, rest] }
114
116
  end
115
117
 
116
118
  it { is_expected.to eq([2, [4, 5]]) }
117
119
  end
118
120
  end
119
121
 
120
- describe '#to_proc', '#call' do
122
+ describe "#to_proc", "#call" do
121
123
  let(:partial_function) { Fear.case(->(v) { v != 0 }) { |x| 4 / x }.to_proc }
122
124
 
123
- context 'defined' do
124
- subject { partial_function.call(2) }
125
+ context "defined" do
126
+ subject { partial_function.(2) }
125
127
 
126
128
  it { is_expected.to eq(2) }
127
129
  end
128
130
 
129
- context 'not defined' do
130
- subject { -> { partial_function.call(0) } }
131
+ context "not defined" do
132
+ subject { -> { partial_function.(0) } }
131
133
 
132
- it { is_expected.to raise_error(Fear::MatchError, 'partial function not defined at: 0') }
134
+ it { is_expected.to raise_error(Fear::MatchError, "partial function not defined at: 0") }
133
135
  end
134
136
  end
135
137
 
136
- describe '#call_or_else' do
138
+ describe "#call_or_else" do
137
139
  let(:default) { ->(x) { "division by #{x} impossible" } }
138
140
  let(:partial_function) { Fear.case(->(x) { x != 0 }) { |x| 4 / x } }
139
141
 
140
- context 'defined' do
142
+ context "defined" do
141
143
  subject { partial_function.call_or_else(2, &default) }
142
144
 
143
145
  it { is_expected.to eq(2) }
144
146
  end
145
147
 
146
- context 'not defined' do
148
+ context "not defined" do
147
149
  subject { partial_function.call_or_else(0, &default) }
148
150
 
149
- it { is_expected.to eq('division by 0 impossible') }
151
+ it { is_expected.to eq("division by 0 impossible") }
150
152
  end
151
153
  end
152
154
 
153
- describe '#and_then' do
155
+ describe "#and_then" do
154
156
  let(:partial_function) { Fear.case(->(v) { v == 42 }) {} }
155
157
  let(:and_then) { ->(x) { x } }
156
158
 
157
- context 'block given, arguments not given' do
159
+ context "block given, arguments not given" do
158
160
  subject { -> { partial_function.and_then(&and_then) } }
159
161
 
160
162
  it { is_expected.not_to raise_error }
161
163
  end
162
164
 
163
- context 'block given, argument given' do
165
+ context "block given, argument given" do
164
166
  subject { -> { partial_function.and_then(and_then, &and_then) } }
165
167
 
166
168
  it { is_expected.to raise_error(ArgumentError) }
167
169
  end
168
170
 
169
- context 'block given, arguments given' do
171
+ context "block given, arguments given" do
170
172
  subject { -> { partial_function.and_then(and_then, 42, &and_then) } }
171
173
 
172
174
  it { is_expected.to raise_error(ArgumentError) }
173
175
  end
174
176
 
175
- context 'block not given, arguments not given' do
177
+ context "block not given, arguments not given" do
176
178
  subject { -> { partial_function.and_then } }
177
179
 
178
180
  it { is_expected.to raise_error(ArgumentError) }
179
181
  end
180
182
 
181
- context 'block net given, arguments given' do
183
+ context "block net given, arguments given" do
182
184
  subject { -> { partial_function.and_then(and_then) } }
183
185
 
184
186
  it { is_expected.not_to raise_error }
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Fear::PatternMatch do
2
- context 'extracting' do
4
+ context "extracting" do
3
5
  let(:matcher) do
4
6
  described_class.new do |m|
5
- m.xcase('Date(year, 2, 29)', ->(year:) { year < 2000 }) do |year:|
7
+ m.xcase("Date(year, 2, 29)", ->(year:) { year < 2000 }) do |year:|
6
8
  "#{year} is a leap year before Millennium"
7
9
  end
8
- m.xcase('Date(year, 2, 29)') do |year:|
10
+ m.xcase("Date(year, 2, 29)") do |year:|
9
11
  "#{year} is a leap year after Millennium"
10
12
  end
11
13
  m.case(Date) do |date|
@@ -14,26 +16,26 @@ RSpec.describe Fear::PatternMatch do
14
16
  end
15
17
  end
16
18
 
17
- context 'before Millennium' do
18
- subject { matcher.call(Date.parse('1996-02-29')) }
19
+ context "before Millennium" do
20
+ subject { matcher.(Date.parse("1996-02-29")) }
19
21
 
20
- it { is_expected.to eq('1996 is a leap year before Millennium') }
22
+ it { is_expected.to eq("1996 is a leap year before Millennium") }
21
23
  end
22
24
 
23
- context 'after Millennium' do
24
- subject { matcher.call(Date.parse('2004-02-29')) }
25
+ context "after Millennium" do
26
+ subject { matcher.(Date.parse("2004-02-29")) }
25
27
 
26
- it { is_expected.to eq('2004 is a leap year after Millennium') }
28
+ it { is_expected.to eq("2004 is a leap year after Millennium") }
27
29
  end
28
30
 
29
- context 'not leap' do
30
- subject { matcher.call(Date.parse('2003-01-24')) }
31
+ context "not leap" do
32
+ subject { matcher.(Date.parse("2003-01-24")) }
31
33
 
32
- it { is_expected.to eq('2003 is not a leap year') }
34
+ it { is_expected.to eq("2003 is not a leap year") }
33
35
  end
34
36
  end
35
37
 
36
- context 'else at the end' do
38
+ context "else at the end" do
37
39
  let(:matcher) do
38
40
  described_class.new do |m|
39
41
  m.case(Integer) { |x| "#{x} is int" }
@@ -42,27 +44,27 @@ RSpec.describe Fear::PatternMatch do
42
44
  end
43
45
  end
44
46
 
45
- context 'Integer' do
46
- subject { matcher.call(4) }
47
+ context "Integer" do
48
+ subject { matcher.(4) }
47
49
 
48
- it { is_expected.to eq('4 is int') }
50
+ it { is_expected.to eq("4 is int") }
49
51
  end
50
52
 
51
- context 'String' do
52
- subject { matcher.call('4') }
53
+ context "String" do
54
+ subject { matcher.("4") }
53
55
 
54
- it { is_expected.to eq('4 is str') }
56
+ it { is_expected.to eq("4 is str") }
55
57
  end
56
58
 
57
- context 'Symbol' do
58
- subject { matcher.call(:a) }
59
+ context "Symbol" do
60
+ subject { matcher.(:a) }
59
61
 
60
- it { is_expected.to eq('a is something else') }
62
+ it { is_expected.to eq("a is something else") }
61
63
  end
62
64
  end
63
65
 
64
- context 'else before other branches' do
65
- subject { matcher.call(4) }
66
+ context "else before other branches" do
67
+ subject { matcher.(4) }
66
68
 
67
69
  let(:matcher) do
68
70
  described_class.new do |m|
@@ -71,11 +73,11 @@ RSpec.describe Fear::PatternMatch do
71
73
  end
72
74
  end
73
75
 
74
- it { is_expected.to eq('4 is something else') }
76
+ it { is_expected.to eq("4 is something else") }
75
77
  end
76
78
 
77
- context 'several else branches' do
78
- subject { matcher.call(4) }
79
+ context "several else branches" do
80
+ subject { matcher.(4) }
79
81
 
80
82
  let(:matcher) do
81
83
  described_class.new do |m|
@@ -84,8 +86,8 @@ RSpec.describe Fear::PatternMatch do
84
86
  end
85
87
  end
86
88
 
87
- it 'first one wins' do
88
- is_expected.to eq('4 else 1')
89
+ it "first one wins" do
90
+ is_expected.to eq("4 else 1")
89
91
  end
90
92
  end
91
93
  end
@@ -1,90 +1,92 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Fear::Promise do
2
4
  let(:value) { 42 }
3
- let(:error) { StandardError.new('something went wrong') }
5
+ let(:error) { StandardError.new("something went wrong") }
4
6
 
5
7
  def not_completed_promise
6
8
  Fear::Promise.new(executor: Concurrent::ImmediateExecutor.new)
7
9
  end
8
10
 
9
- context 'not completed' do
10
- it '#success! returns self' do
11
+ context "not completed" do
12
+ it "#success! returns self" do
11
13
  completed_promise = not_completed_promise.success!(value)
12
14
 
13
15
  expect(completed_promise).to eq completed_promise
14
16
  end
15
17
 
16
- it '#success returns true' do
18
+ it "#success returns true" do
17
19
  completed = not_completed_promise.success(value)
18
20
 
19
21
  expect(completed).to be true
20
22
  end
21
23
 
22
- it '#failure! returns self' do
24
+ it "#failure! returns self" do
23
25
  completed_promise = not_completed_promise.failure!(error)
24
26
 
25
27
  expect(completed_promise).to eq completed_promise
26
28
  end
27
29
 
28
- it '#failure returns true' do
30
+ it "#failure returns true" do
29
31
  completed = not_completed_promise.failure(error)
30
32
 
31
33
  expect(completed).to be true
32
34
  end
33
35
 
34
- it '#completed? returns true' do
36
+ it "#completed? returns true" do
35
37
  expect(not_completed_promise).not_to be_completed
36
38
  end
37
39
 
38
- it '#future returns not completed future' do
40
+ it "#future returns not completed future" do
39
41
  future = not_completed_promise.to_future
40
42
 
41
43
  expect(future).not_to be_completed
42
44
  end
43
45
  end
44
46
 
45
- context 'completed' do
47
+ context "completed" do
46
48
  def completed_promise
47
49
  not_completed_promise.success!(value)
48
50
  end
49
51
 
50
- it '#success! fails with exception' do
52
+ it "#success! fails with exception" do
51
53
  expect do
52
54
  completed_promise.success!(value)
53
55
  end.to raise_exception(Fear::IllegalStateException)
54
56
  end
55
57
 
56
- it '#success returns false' do
58
+ it "#success returns false" do
57
59
  completed = completed_promise.success(value)
58
60
 
59
61
  expect(completed).to be false
60
62
  end
61
63
 
62
- it '#failure! fails with exception' do
64
+ it "#failure! fails with exception" do
63
65
  expect do
64
66
  completed_promise.failure!(error)
65
67
  end.to raise_exception(Fear::IllegalStateException)
66
68
  end
67
69
 
68
- it '#failure returns false' do
70
+ it "#failure returns false" do
69
71
  completed = completed_promise.success(error)
70
72
 
71
73
  expect(completed).to be false
72
74
  end
73
75
 
74
- it '#completed? returns true' do
76
+ it "#completed? returns true" do
75
77
  expect(completed_promise).to be_completed
76
78
  end
77
79
 
78
- context '#future' do
80
+ context "#future" do
79
81
  subject(:future) do
80
82
  completed_promise.to_future
81
83
  end
82
84
 
83
- it 'is completed' do
85
+ it "is completed" do
84
86
  expect(future).to be_completed
85
87
  end
86
88
 
87
- it 'completed with value' do
89
+ it "completed with value" do
88
90
  future_value = future.value
89
91
 
90
92
  expect(future_value).to eq Fear.some(Fear.success(value))