fear 1.0.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 +39 -0
- data/.github/workflows/spec.yml +42 -0
- data/.rubocop.yml +4 -60
- data/.simplecov +17 -0
- data/CHANGELOG.md +29 -1
- data/Gemfile +5 -5
- data/Gemfile.lock +86 -50
- data/README.md +240 -209
- data/Rakefile +72 -65
- data/examples/pattern_extracting.rb +10 -8
- data/examples/pattern_matching_binary_tree_set.rb +7 -2
- data/examples/pattern_matching_number_in_words.rb +48 -42
- data/fear.gemspec +33 -34
- data/lib/dry/types/fear/option.rb +125 -0
- data/lib/dry/types/fear.rb +8 -0
- data/lib/fear/await.rb +33 -0
- data/lib/fear/awaitable.rb +28 -0
- data/lib/fear/either.rb +15 -4
- data/lib/fear/either_api.rb +4 -0
- data/lib/fear/either_pattern_match.rb +9 -5
- data/lib/fear/empty_partial_function.rb +3 -1
- data/lib/fear/failure.rb +7 -7
- data/lib/fear/failure_pattern_match.rb +4 -0
- data/lib/fear/for.rb +4 -2
- data/lib/fear/for_api.rb +5 -1
- data/lib/fear/future.rb +157 -82
- data/lib/fear/future_api.rb +17 -4
- data/lib/fear/left.rb +3 -9
- data/lib/fear/left_pattern_match.rb +2 -0
- data/lib/fear/none.rb +28 -10
- data/lib/fear/none_pattern_match.rb +2 -0
- data/lib/fear/option.rb +30 -2
- data/lib/fear/option_api.rb +4 -0
- data/lib/fear/option_pattern_match.rb +8 -3
- 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 +6 -0
- 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/guard.rb +8 -6
- data/lib/fear/partial_function/lifted.rb +2 -0
- data/lib/fear/partial_function/or_else.rb +5 -1
- data/lib/fear/partial_function.rb +18 -9
- data/lib/fear/partial_function_class.rb +3 -1
- data/lib/fear/pattern_match.rb +3 -11
- data/lib/fear/pattern_matching_api.rb +6 -28
- data/lib/fear/promise.rb +7 -5
- data/lib/fear/right.rb +3 -9
- data/lib/fear/right_biased.rb +5 -3
- data/lib/fear/right_pattern_match.rb +4 -0
- data/lib/fear/some.rb +35 -8
- data/lib/fear/some_pattern_match.rb +2 -0
- data/lib/fear/struct.rb +237 -0
- data/lib/fear/success.rb +7 -8
- data/lib/fear/success_pattern_match.rb +4 -0
- data/lib/fear/try.rb +8 -2
- data/lib/fear/try_api.rb +4 -0
- data/lib/fear/try_pattern_match.rb +9 -5
- data/lib/fear/unit.rb +6 -2
- data/lib/fear/utils.rb +14 -2
- data/lib/fear/version.rb +4 -1
- data/lib/fear.rb +26 -44
- data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
- data/spec/dry/types/fear/option/core_spec.rb +77 -0
- data/spec/dry/types/fear/option/default_spec.rb +21 -0
- data/spec/dry/types/fear/option/hash_spec.rb +58 -0
- data/spec/dry/types/fear/option/option_spec.rb +97 -0
- data/spec/fear/awaitable_spec.rb +19 -0
- 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/either_pattern_matching_spec.rb +28 -0
- data/spec/fear/either_spec.rb +26 -0
- data/spec/fear/failure_spec.rb +57 -70
- data/spec/fear/for/mixin_spec.rb +15 -0
- data/spec/fear/for_spec.rb +19 -17
- data/spec/fear/future_spec.rb +477 -237
- data/spec/fear/guard_spec.rb +136 -24
- data/spec/fear/left_spec.rb +57 -70
- data/spec/fear/none_spec.rb +39 -43
- data/spec/fear/option/mixin_spec.rb +9 -7
- data/spec/fear/option_pattern_match_spec.rb +10 -8
- data/spec/fear/option_pattern_matching_spec.rb +34 -0
- data/spec/fear/option_spec.rb +142 -0
- data/spec/fear/partial_function/any_spec.rb +25 -0
- 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 +91 -61
- data/spec/fear/pattern_match_spec.rb +19 -51
- data/spec/fear/pattern_matching_api_spec.rb +31 -0
- data/spec/fear/promise_spec.rb +23 -23
- data/spec/fear/right_biased/left.rb +28 -26
- data/spec/fear/right_biased/right.rb +51 -49
- data/spec/fear/right_spec.rb +48 -68
- data/spec/fear/some_spec.rb +30 -40
- data/spec/fear/success_spec.rb +40 -60
- data/spec/fear/try/mixin_spec.rb +19 -3
- data/spec/fear/try_api_spec.rb +23 -0
- data/spec/fear/try_pattern_match_spec.rb +10 -8
- data/spec/fear/try_pattern_matching_spec.rb +34 -0
- data/spec/fear/utils_spec.rb +16 -14
- data/spec/spec_helper.rb +13 -7
- data/spec/struct_pattern_matching_spec.rb +36 -0
- data/spec/struct_spec.rb +194 -0
- data/spec/support/dry_types.rb +6 -0
- metadata +128 -87
- data/.travis.yml +0 -13
- data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -8
- data/lib/fear/extractor/any_matcher.rb +0 -15
- data/lib/fear/extractor/array_head_matcher.rb +0 -34
- data/lib/fear/extractor/array_matcher.rb +0 -38
- data/lib/fear/extractor/array_splat_matcher.rb +0 -14
- data/lib/fear/extractor/empty_list_matcher.rb +0 -18
- data/lib/fear/extractor/extractor_matcher.rb +0 -42
- data/lib/fear/extractor/grammar.rb +0 -201
- data/lib/fear/extractor/grammar.treetop +0 -129
- data/lib/fear/extractor/identifier_matcher.rb +0 -16
- data/lib/fear/extractor/matcher/and.rb +0 -36
- data/lib/fear/extractor/matcher.rb +0 -54
- data/lib/fear/extractor/named_array_splat_matcher.rb +0 -15
- data/lib/fear/extractor/pattern.rb +0 -55
- data/lib/fear/extractor/typed_identifier_matcher.rb +0 -24
- data/lib/fear/extractor/value_matcher.rb +0 -17
- data/lib/fear/extractor.rb +0 -108
- data/lib/fear/extractor_api.rb +0 -33
- data/spec/fear/extractor/array_matcher_spec.rb +0 -228
- data/spec/fear/extractor/extractor_matcher_spec.rb +0 -151
- data/spec/fear/extractor/grammar_array_spec.rb +0 -23
- data/spec/fear/extractor/identified_matcher_spec.rb +0 -47
- data/spec/fear/extractor/identifier_matcher_spec.rb +0 -66
- data/spec/fear/extractor/pattern_spec.rb +0 -32
- data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -62
- data/spec/fear/extractor/value_matcher_number_spec.rb +0 -77
- data/spec/fear/extractor/value_matcher_string_spec.rb +0 -86
- data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -69
- data/spec/fear/extractor_api_spec.rb +0 -113
- data/spec/fear/extractor_spec.rb +0 -59
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::Try do
|
4
|
+
describe "pattern matching" do
|
5
|
+
subject do
|
6
|
+
case value
|
7
|
+
in Fear::Success[Integer => int]
|
8
|
+
"success of #{int}"
|
9
|
+
in Fear::Failure[RuntimeError]
|
10
|
+
"runtime error"
|
11
|
+
else
|
12
|
+
"something else"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context "when value is success of integer" do
|
17
|
+
let(:value) { Fear.try { 42 } }
|
18
|
+
|
19
|
+
it { is_expected.to eq("success of 42") }
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when value is failure runtime error" do
|
23
|
+
let(:value) { Fear.try { raise } }
|
24
|
+
|
25
|
+
it { is_expected.to eq("runtime error") }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when value is something else" do
|
29
|
+
let(:value) { Fear.try { raise StandardError } }
|
30
|
+
|
31
|
+
it { is_expected.to eq("something else") }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/spec/fear/utils_spec.rb
CHANGED
@@ -1,58 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe Fear::Utils do
|
2
|
-
describe
|
4
|
+
describe ".assert_arg_or_block!" do
|
3
5
|
def assert_arg_or_block!(*args, &block)
|
4
6
|
described_class.assert_arg_or_block!(:the_method, *args, &block)
|
5
7
|
end
|
6
8
|
|
7
|
-
context
|
9
|
+
context "block given, argument does not given" do
|
8
10
|
subject { proc { assert_arg_or_block! {} } }
|
9
11
|
|
10
12
|
it { is_expected.not_to raise_error }
|
11
13
|
end
|
12
14
|
|
13
|
-
context
|
15
|
+
context "argument given, block does not given" do
|
14
16
|
subject { proc { assert_arg_or_block!(42) } }
|
15
17
|
|
16
18
|
it { is_expected.not_to raise_error }
|
17
19
|
end
|
18
20
|
|
19
|
-
context
|
21
|
+
context "argument and block given at the same time" do
|
20
22
|
subject { proc { assert_arg_or_block!(42) {} } }
|
21
23
|
|
22
|
-
it
|
24
|
+
it "fails with argument error" do
|
23
25
|
is_expected.to raise_error(
|
24
26
|
ArgumentError,
|
25
|
-
|
27
|
+
"#the_method accepts either one argument or block",
|
26
28
|
)
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
context
|
32
|
+
context "no argument and no block given" do
|
31
33
|
subject { proc { assert_arg_or_block! } }
|
32
34
|
|
33
|
-
it
|
35
|
+
it "fails with argument error" do
|
34
36
|
is_expected.to raise_error(
|
35
37
|
ArgumentError,
|
36
|
-
|
38
|
+
"#the_method accepts either one argument or block",
|
37
39
|
)
|
38
40
|
end
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
42
|
-
describe
|
43
|
-
context
|
44
|
+
describe "assert_type!" do
|
45
|
+
context "value is of the given type" do
|
44
46
|
subject { proc { described_class.assert_type!(24, Integer) } }
|
45
47
|
|
46
48
|
it { is_expected.not_to raise_error }
|
47
49
|
end
|
48
50
|
|
49
|
-
context
|
51
|
+
context "value is not of the given type" do
|
50
52
|
subject { proc { described_class.assert_type!(24, String) } }
|
51
53
|
|
52
|
-
it
|
54
|
+
it "raises TypeError" do
|
53
55
|
is_expected.to raise_error(
|
54
56
|
TypeError,
|
55
|
-
|
57
|
+
"expected `24` to be of String class",
|
56
58
|
)
|
57
59
|
end
|
58
60
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
|
-
#
|
2
|
-
# CodeClimate::TestReporter.start
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
require
|
5
|
-
|
6
|
-
require
|
7
|
-
require
|
3
|
+
require "simplecov"
|
4
|
+
|
5
|
+
require "fear"
|
6
|
+
require File.expand_path("spec/fear/right_biased/right")
|
7
|
+
require File.expand_path("spec/fear/right_biased/left")
|
8
|
+
require "date"
|
9
|
+
require "fear/rspec"
|
8
10
|
|
9
11
|
RSpec.configure do |config|
|
12
|
+
unless RUBY_VERSION >= "2.7"
|
13
|
+
config.exclude_pattern = "**/*pattern_matching_spec.rb"
|
14
|
+
end
|
15
|
+
|
10
16
|
# rspec-expectations config goes here. You can use an alternate
|
11
17
|
# assertion/expectation library such as wrong or the stdlib/minitest
|
12
18
|
# assertions if you prefer.
|
@@ -56,7 +62,7 @@ RSpec.configure do |config|
|
|
56
62
|
# Use the documentation formatter for detailed output,
|
57
63
|
# unless a formatter has already been configured
|
58
64
|
# (e.g. via a command-line flag).
|
59
|
-
config.default_formatter =
|
65
|
+
config.default_formatter = "doc"
|
60
66
|
end
|
61
67
|
|
62
68
|
# Print the 10 slowest examples and example groups at the
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::Struct do
|
4
|
+
describe "pattern matching" do
|
5
|
+
subject do
|
6
|
+
case struct
|
7
|
+
in Fear::Struct(a: 42)
|
8
|
+
"a = 42"
|
9
|
+
in Fear::Struct(a: 43, **rest)
|
10
|
+
"a = 43, #{rest}"
|
11
|
+
in Fear::Struct(a:)
|
12
|
+
"a = #{a}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
17
|
+
|
18
|
+
context "when match single value" do
|
19
|
+
let(:struct) { struct_class.new(b: 43, a: 42) }
|
20
|
+
|
21
|
+
it { is_expected.to eq("a = 42") }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "when match single value and capture the rest" do
|
25
|
+
let(:struct) { struct_class.new(b: 42, a: 43) }
|
26
|
+
|
27
|
+
it { is_expected.to eq("a = 43, {:b=>42}") }
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when capture a value" do
|
31
|
+
let(:struct) { struct_class.new(b: 45, a: 44) }
|
32
|
+
|
33
|
+
it { is_expected.to eq("a = 44") }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/spec/struct_spec.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe Fear::Struct do
|
4
|
+
describe ".with_attributes" do
|
5
|
+
context "same arguments" do
|
6
|
+
subject { struct_class.new(a: 42, b: 43) }
|
7
|
+
|
8
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
9
|
+
|
10
|
+
it { is_expected.to have_attributes(a: 42, b: 43) }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "string arguments" do
|
14
|
+
subject { -> { struct_class.new("a" => 42, "b" => 43) } }
|
15
|
+
|
16
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
17
|
+
|
18
|
+
it { is_expected.to raise_error(ArgumentError) }
|
19
|
+
end
|
20
|
+
|
21
|
+
context "extra argument" do
|
22
|
+
subject { -> { struct_class.new(a: 42, b: 41, c: 43, d: 44) } }
|
23
|
+
|
24
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
25
|
+
|
26
|
+
it { is_expected.to raise_error(ArgumentError, "unknown keywords: c, d") }
|
27
|
+
end
|
28
|
+
|
29
|
+
context "missing argument" do
|
30
|
+
subject { -> { struct_class.new } }
|
31
|
+
|
32
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
33
|
+
|
34
|
+
it { is_expected.to raise_error(ArgumentError, "missing keywords: a, b") }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "inheritance" do
|
38
|
+
let(:parent_struct) { described_class.with_attributes(:a, :b) }
|
39
|
+
|
40
|
+
it "does not change parent attributes" do
|
41
|
+
expect do
|
42
|
+
parent_struct.with_attributes(:c)
|
43
|
+
end.not_to change { parent_struct.attributes }.from([:a, :b])
|
44
|
+
end
|
45
|
+
|
46
|
+
it "extends parent attributes" do
|
47
|
+
child_struct = parent_struct.with_attributes(:c)
|
48
|
+
expect(child_struct.attributes).to eq([:a, :b, :c])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "with block" do
|
53
|
+
subject { struct_class.new(a: 42, b: 43).a_plus_b }
|
54
|
+
|
55
|
+
let(:struct_class) do
|
56
|
+
described_class.with_attributes(:a, :b) do
|
57
|
+
def a_plus_b
|
58
|
+
a + b
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "evaluates block in context of struct" do
|
64
|
+
is_expected.to eq(85)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "#==" do
|
70
|
+
context "with members" do
|
71
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
72
|
+
|
73
|
+
context "same class and members" do
|
74
|
+
subject { struct_class.new(a: 42, b: 43) == struct_class.new(a: 42, b: 43) } # rubocop: disable Lint/BinaryOperatorWithIdenticalOperands
|
75
|
+
|
76
|
+
it { is_expected.to eq(true) }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "same class and different members" do
|
80
|
+
subject { struct_class.new(a: 42, b: 43) == struct_class.new(a: 42, b: 0) }
|
81
|
+
|
82
|
+
it { is_expected.to eq(false) }
|
83
|
+
end
|
84
|
+
|
85
|
+
context "different class and same members" do
|
86
|
+
subject { struct_class.new(a: 42, b: 43) == struct_class_1.new(a: 42, b: 43) }
|
87
|
+
|
88
|
+
let(:struct_class_1) { described_class.with_attributes(:a, :b) }
|
89
|
+
|
90
|
+
it { is_expected.to eq(true) }
|
91
|
+
end
|
92
|
+
|
93
|
+
context "different class and different members" do
|
94
|
+
subject { struct_class.new(a: 42, b: 43) == struct_class.new(a: 42, b: 0) }
|
95
|
+
|
96
|
+
let(:struct_class_1) { described_class.with_attributes(:a, :b) }
|
97
|
+
|
98
|
+
it { is_expected.to eq(false) }
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "#members" do
|
104
|
+
let(:struct) { struct_class.new(b: 43, a: 42) }
|
105
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
106
|
+
|
107
|
+
it "returns members in the order they defined" do
|
108
|
+
expect(struct.members).to eq([:a, :b])
|
109
|
+
end
|
110
|
+
|
111
|
+
it "is immutable" do
|
112
|
+
expect { struct.members << :c }.not_to change { struct.members }.from([:a, :b])
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "#to_a" do
|
117
|
+
let(:struct) { struct_class.new(b: 43, a: 42) }
|
118
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
119
|
+
|
120
|
+
it "returns members values in the order they defined" do
|
121
|
+
expect(struct.to_a).to eq([42, 43])
|
122
|
+
end
|
123
|
+
|
124
|
+
it "is immutable" do
|
125
|
+
expect { struct.to_a << 44 }.not_to change { struct.to_a }.from([42, 43])
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe "#to_h" do
|
130
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
131
|
+
|
132
|
+
context "without block" do
|
133
|
+
let(:struct) { struct_class.new(b: 43, a: 42) }
|
134
|
+
|
135
|
+
it "returns a Hash containing the names and values for the structs members" do
|
136
|
+
expect(struct.to_h).to eq(a: 42, b: 43)
|
137
|
+
end
|
138
|
+
|
139
|
+
it "is immutable" do
|
140
|
+
expect { struct.to_h.merge(c: 44) }.not_to change { struct.to_h }.from(a: 42, b: 43)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "with block" do
|
145
|
+
subject do
|
146
|
+
struct.to_h do |key, value|
|
147
|
+
[key.upcase, value / 2]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
let(:struct) { struct_class.new(b: 2, a: 4) }
|
151
|
+
|
152
|
+
it "returns a Hash containing the names and values for the structs members" do
|
153
|
+
is_expected.to eq(A: 2, B: 1)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "#copy" do
|
159
|
+
let(:struct_class) { described_class.with_attributes(:a, :b) }
|
160
|
+
let(:struct) { struct_class.new(b: 43, a: 42) }
|
161
|
+
|
162
|
+
context "attributes given" do
|
163
|
+
subject { struct.copy(b: 44) }
|
164
|
+
|
165
|
+
it { is_expected.to eq(struct_class.new(a: 42, b: 44)) }
|
166
|
+
end
|
167
|
+
|
168
|
+
context "string attributes" do
|
169
|
+
subject { -> { struct.copy("a" => 44) } }
|
170
|
+
|
171
|
+
it { is_expected.to raise_error(ArgumentError) }
|
172
|
+
end
|
173
|
+
|
174
|
+
context "no attributes given" do
|
175
|
+
subject { struct.copy == struct }
|
176
|
+
|
177
|
+
it { is_expected.to eq(true) }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe "#inspect" do
|
182
|
+
subject { StrInspect.new(a: 2, b: nil).inspect }
|
183
|
+
StrInspect = Fear::Struct.with_attributes(:a, :b)
|
184
|
+
|
185
|
+
it { is_expected.to eq("<#Fear::Struct StrInspect a=2, b=nil>") }
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "#inspect" do
|
189
|
+
subject { StrToS.new(a: 2, b: nil).inspect }
|
190
|
+
StrToS = Fear::Struct.with_attributes(:a, :b)
|
191
|
+
|
192
|
+
it { is_expected.to eq("<#Fear::Struct StrToS a=2, b=nil>") }
|
193
|
+
end
|
194
|
+
end
|