fear 1.0.0 → 1.1.0

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