fear 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Fear::Extractor::ValueMatcher, "Number" do
4
- let(:parser) { Fear::Extractor::GrammarParser.new }
5
- let(:matcher) { parser.parse(pattern).to_matcher }
6
-
7
- describe "#defined_at?" do
8
- subject { matcher }
9
-
10
- context "Integer" do
11
- let(:pattern) { "1" }
12
-
13
- it { is_expected.to be_defined_at(1) }
14
- it { is_expected.to be_defined_at(1.0) }
15
- it { is_expected.not_to be_defined_at(2) }
16
- it { is_expected.not_to be_defined_at("1") }
17
- end
18
-
19
- context "Float" do
20
- context "against float" do
21
- let(:pattern) { "1.2" }
22
-
23
- it { is_expected.to be_defined_at(1.2) }
24
- it { is_expected.not_to be_defined_at(1.3) }
25
- end
26
-
27
- context "against integer" do
28
- let(:pattern) { "1.0" }
29
-
30
- it { is_expected.to be_defined_at(1) }
31
- it { is_expected.not_to be_defined_at(2) }
32
- it { is_expected.not_to be_defined_at("1") }
33
- end
34
- end
35
- end
36
-
37
- describe "#call" do
38
- subject { matcher.(other) }
39
-
40
- let(:pattern) { "1.0" }
41
-
42
- context "defined" do
43
- let(:other) { 1 }
44
-
45
- it { is_expected.to eq({}) }
46
- end
47
- end
48
-
49
- describe "#failure_reason" do
50
- subject { matcher.failure_reason(other) }
51
-
52
- let(:pattern) { "1.0" }
53
-
54
- context "match integer" do
55
- let(:other) { 1 }
56
- let(:pattern) { "1" }
57
-
58
- it { is_expected.to eq(Fear.none) }
59
- end
60
-
61
- context "match float" do
62
- let(:other) { 1.0 }
63
- let(:pattern) { "1" }
64
-
65
- it { is_expected.to eq(Fear.none) }
66
- end
67
-
68
- context "does not match another integer" do
69
- let(:other) { 2 }
70
- let(:pattern) { "1" }
71
-
72
- it { is_expected.to eq(Fear.some(<<~ERROR.strip)) }
73
- Expected `2` to match:
74
- 1
75
- ^
76
- ERROR
77
- end
78
- end
79
- end
@@ -1,88 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Fear::Extractor::ValueMatcher, "String" do
4
- let(:parser) { Fear::Extractor::GrammarParser.new }
5
- let(:matcher) { parser.parse(pattern).to_matcher }
6
-
7
- describe "#defined_at?" do
8
- subject { matcher }
9
-
10
- context "double quotas" do
11
- let(:pattern) { %("foo") }
12
-
13
- it { is_expected.to be_defined_at("foo") }
14
- it { is_expected.not_to be_defined_at("boo") }
15
- it { is_expected.not_to be_defined_at(2) }
16
-
17
- context "single quotes inside" do
18
- let(:pattern) { %("f'o'o") }
19
-
20
- it { is_expected.to be_defined_at(%(f'o'o)) }
21
- it { is_expected.not_to be_defined_at(%(f"o"o)) }
22
- end
23
-
24
- context "escaped double quotes inside" do
25
- let(:pattern) { '"f\"oo"' }
26
-
27
- it { is_expected.to be_defined_at('f"oo') }
28
- it { is_expected.not_to be_defined_at("f'oo") }
29
- end
30
- end
31
-
32
- context "single quotas" do
33
- let(:pattern) { %('foo') }
34
-
35
- it { is_expected.to be_defined_at("foo") }
36
- it { is_expected.not_to be_defined_at("boo") }
37
- it { is_expected.not_to be_defined_at(2) }
38
-
39
- context "double quotes inside" do
40
- let(:pattern) { %('f"o"o') }
41
-
42
- it { is_expected.to be_defined_at(%(f"o"o)) }
43
- it { is_expected.not_to be_defined_at(%(f'o'o)) }
44
- end
45
-
46
- context "escaped single quotes inside" do
47
- let(:pattern) { "'f\\'oo'" }
48
-
49
- it { is_expected.to be_defined_at("f\\'oo") }
50
- it { is_expected.not_to be_defined_at("f'oo") }
51
- end
52
- end
53
- end
54
-
55
- describe "#call" do
56
- subject { matcher.(other) }
57
-
58
- let(:pattern) { '"foo"' }
59
-
60
- context "defined" do
61
- let(:other) { "foo" }
62
-
63
- it { is_expected.to eq({}) }
64
- end
65
- end
66
-
67
- describe "#failure_reason" do
68
- subject { matcher.failure_reason(other) }
69
-
70
- context "match" do
71
- let(:other) { "foo" }
72
- let(:pattern) { '"foo"' }
73
-
74
- it { is_expected.to eq(Fear.none) }
75
- end
76
-
77
- context "does not match" do
78
- let(:other) { "bar" }
79
- let(:pattern) { '"foo"' }
80
-
81
- it { is_expected.to eq(Fear.some(<<~ERROR.strip)) }
82
- Expected `"bar"` to match:
83
- "foo"
84
- ^
85
- ERROR
86
- end
87
- end
88
- end
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Fear::Extractor::ValueMatcher, "Symbol" do
4
- let(:parser) { Fear::Extractor::GrammarParser.new }
5
- let(:matcher) { parser.parse(pattern).to_matcher }
6
-
7
- describe "#defined_at?" do
8
- subject { matcher }
9
-
10
- context "no quotas" do
11
- let(:pattern) { ":foo" }
12
-
13
- it { is_expected.to be_defined_at(:foo) }
14
- it { is_expected.not_to be_defined_at("foo") }
15
- it { is_expected.not_to be_defined_at(:boo) }
16
- it { is_expected.not_to be_defined_at(2) }
17
- end
18
-
19
- context "double quotas" do
20
- let(:pattern) { %(:"foo") }
21
-
22
- it { is_expected.to be_defined_at(:foo) }
23
- it { is_expected.not_to be_defined_at("foo") }
24
- it { is_expected.not_to be_defined_at(:boo) }
25
- it { is_expected.not_to be_defined_at(2) }
26
- end
27
-
28
- context "single quotas" do
29
- let(:pattern) { %(:'foo') }
30
-
31
- it { is_expected.to be_defined_at(:foo) }
32
- it { is_expected.not_to be_defined_at("foo") }
33
- it { is_expected.not_to be_defined_at(:boo) }
34
- it { is_expected.not_to be_defined_at(2) }
35
- end
36
- end
37
-
38
- describe "#call" do
39
- subject { matcher.(other) }
40
-
41
- let(:pattern) { ":foo" }
42
-
43
- context "defined" do
44
- let(:other) { :foo }
45
-
46
- it { is_expected.to eq({}) }
47
- end
48
- end
49
-
50
- describe "#failure_reason" do
51
- subject { matcher.failure_reason(other) }
52
-
53
- context "match" do
54
- let(:other) { :foo }
55
- let(:pattern) { ":foo" }
56
-
57
- it { is_expected.to eq(Fear.none) }
58
- end
59
-
60
- context "does not match" do
61
- let(:other) { :bar }
62
- let(:pattern) { ":foo" }
63
-
64
- it { is_expected.to eq(Fear.some(<<~ERROR.strip)) }
65
- Expected `:bar` to match:
66
- :foo
67
- ^
68
- ERROR
69
- end
70
- end
71
- end
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Fear::ExtractorApi do
4
- def assert(value)
5
- expect(value).to eq(true)
6
- end
7
-
8
- def assert_not(value)
9
- expect(value).not_to eq(true)
10
- end
11
-
12
- def assert_invalid_syntax
13
- expect do
14
- yield
15
- end.to raise_error(Fear::PatternSyntaxError)
16
- end
17
-
18
- def assert_valid_syntax
19
- expect { yield }.not_to raise_error
20
- end
21
-
22
- specify "Array" do
23
- assert(Fear["[]"] === [])
24
- assert_not(Fear["[]"] === [1])
25
- assert(Fear["[1]"] === [1])
26
- assert_not(Fear["[1]"] === [1, 2])
27
- assert_not(Fear["[1]"] === [2])
28
- assert(Fear["[1, 2]"] === [1, 2])
29
- assert_not(Fear["[1, 2]"] === [1, 3])
30
- assert_not(Fear["[1, 2]"] === [1, 2, 4])
31
- assert_not(Fear["[1, 2]"] === [1])
32
- assert(Fear["[*]"] === [])
33
- assert(Fear["[*]"] === [1, 2])
34
- assert_not(Fear["[1, *]"] === [])
35
- assert(Fear["[1, *]"] === [1])
36
- assert(Fear["[1, *]"] === [1, 2])
37
- assert(Fear["[1, *]"] === [1, 2, 3])
38
- assert(Fear["[[1]]"] === [[1]])
39
- assert(Fear["[[1],2]"] === [[1], 2])
40
- assert(Fear["[[1],*]"] === [[1], 2])
41
- assert(Fear["[[*],*]"] === [[1], 2])
42
- assert_invalid_syntax { Fear["[*, 2]"] }
43
- assert_invalid_syntax { Fear["[*, ]"] }
44
- assert_invalid_syntax { Fear["[1, *, ]"] }
45
- assert_invalid_syntax { Fear["[1, *, 2]"] }
46
- assert_invalid_syntax { Fear["[1, *, *]"] }
47
- assert_invalid_syntax { Fear["[*, *]"] }
48
- assert(Fear["[a, b]"] === [1, 2])
49
- assert_not(Fear["[a, b, c]"] === [1, 2])
50
- assert(Fear["[a, b, _]"] === [1, 2, 3])
51
- assert(Fear["[a, b, *c]"] === [1, 2])
52
- assert_not(Fear["[a, b, c, *d]"] === [1, 2])
53
- end
54
-
55
- specify "String" do
56
- assert(Fear['"foo"'] === "foo")
57
- assert(Fear['"f\"oo"'] === 'f"oo')
58
- assert_not(Fear['"foo"'] === "bar")
59
- assert(Fear["'foo'"] === "foo")
60
- assert_not(Fear["'foo'"] === "bar")
61
- end
62
-
63
- specify "Symbol" do
64
- assert(Fear[':"foo"'] === :foo)
65
- assert(Fear[":'foo'"] === :foo)
66
- assert(Fear[":foo"] === :foo)
67
- assert_not(Fear[":foo"] === :bar)
68
- end
69
-
70
- specify "Boolean" do
71
- assert(Fear["true"] === true)
72
- assert(Fear["false"] === false)
73
- assert_not(Fear["true"] === false)
74
- assert_not(Fear["false"] === true)
75
- end
76
-
77
- specify "Nil" do
78
- assert(Fear["nil"] === nil) # rubocop:disable Style/NilComparison
79
- assert_not(Fear["nil"] === 42)
80
- end
81
-
82
- specify "_" do
83
- assert(Fear["_"] === nil) # rubocop:disable Style/NilComparison
84
- assert(Fear["_"] === true)
85
- assert(Fear["_"] === false)
86
- assert(Fear["_"] === 42)
87
- assert(Fear["_"] === "foo")
88
- assert(Fear["_"] === [42])
89
- end
90
-
91
- specify "type matching" do
92
- class Foo
93
- class Bar
94
- end
95
- end
96
-
97
- assert(Fear["Integer"] === 3)
98
- assert_not(Fear["Integer"] === "3")
99
- assert(Fear["Numeric"] === 3)
100
- assert(Fear["Foo::Bar"] === Foo::Bar.new)
101
- assert(Fear["var : Integer"] === 3)
102
- assert_not(Fear["var : Integer"] === "3")
103
- end
104
-
105
- specify "capture matcher" do
106
- assert(Fear["array @ [head : Integer, *tail]"] === [1, 2])
107
- assert_not(Fear["array @ [head : Integer, *tail]"] === ["1", 2])
108
- end
109
-
110
- specify "extractor" do
111
- assert_valid_syntax { Fear["Foo(a, b : Integer)"] }
112
- assert(Fear["Fear::Some(a : Integer)"] === Fear.some(42))
113
- assert_not(Fear["Fear::Some(a : Integer)"] === Fear.some("foo"))
114
- end
115
- end
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Fear::Extractor do
4
- describe ".register_extractor" do
5
- Foo = ::Struct.new(:v1, :v2)
6
- let(:matcher) do
7
- Fear.matcher do |m|
8
- m.case(Fear["Foo(43, second : Integer)"]) { |second| "43 and #{second}" }
9
- m.case(Fear["Foo(42, second : Integer)"]) { |second| "42 and #{second}" }
10
- m.else { "no match" }
11
- end
12
- end
13
-
14
- let(:extractor) do
15
- Fear.case(Foo) { |foo| [foo.v1, foo.v2] }.lift
16
- end
17
-
18
- context "extractor not registered" do
19
- it "raise Fear::Extractor::ExtractorNotFound" do
20
- expect do
21
- described_class.find_extractor("UnknownExtractor")
22
- end.to raise_error(Fear::Extractor::ExtractorNotFound)
23
- end
24
- end
25
-
26
- context "register by name" do
27
- let(:extractor) { ->(*) { Fear.some("matched") } }
28
-
29
- before do
30
- described_class.register_extractor(
31
- "ExtractorRegisteredByName",
32
- "ExtractorRegisteredByName2",
33
- extractor,
34
- )
35
- end
36
-
37
- it "returns extractor" do
38
- expect(described_class.find_extractor("ExtractorRegisteredByName")).to eq(extractor)
39
- expect(described_class.find_extractor("ExtractorRegisteredByName2")).to eq(extractor)
40
- end
41
- end
42
-
43
- context "register by class" do
44
- let(:extractor) { ->(*) { Fear.some("matched") } }
45
- ExtractorRegisteredByClass = Class.new
46
-
47
- before do
48
- described_class.register_extractor(
49
- ExtractorRegisteredByClass,
50
- "ExtractorRegisteredByClass2",
51
- extractor,
52
- )
53
- end
54
-
55
- it "returns extractor" do
56
- expect(described_class.find_extractor("ExtractorRegisteredByClass")).to eq(extractor)
57
- expect(described_class.find_extractor("ExtractorRegisteredByClass2")).to eq(extractor)
58
- end
59
- end
60
- end
61
- end