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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +27 -0
  3. data/.github/workflows/rubocop.yml +39 -0
  4. data/.github/workflows/spec.yml +42 -0
  5. data/.rubocop.yml +4 -60
  6. data/.simplecov +17 -0
  7. data/CHANGELOG.md +29 -1
  8. data/Gemfile +5 -5
  9. data/Gemfile.lock +86 -50
  10. data/README.md +240 -209
  11. data/Rakefile +72 -65
  12. data/examples/pattern_extracting.rb +10 -8
  13. data/examples/pattern_matching_binary_tree_set.rb +7 -2
  14. data/examples/pattern_matching_number_in_words.rb +48 -42
  15. data/fear.gemspec +33 -34
  16. data/lib/dry/types/fear/option.rb +125 -0
  17. data/lib/dry/types/fear.rb +8 -0
  18. data/lib/fear/await.rb +33 -0
  19. data/lib/fear/awaitable.rb +28 -0
  20. data/lib/fear/either.rb +15 -4
  21. data/lib/fear/either_api.rb +4 -0
  22. data/lib/fear/either_pattern_match.rb +9 -5
  23. data/lib/fear/empty_partial_function.rb +3 -1
  24. data/lib/fear/failure.rb +7 -7
  25. data/lib/fear/failure_pattern_match.rb +4 -0
  26. data/lib/fear/for.rb +4 -2
  27. data/lib/fear/for_api.rb +5 -1
  28. data/lib/fear/future.rb +157 -82
  29. data/lib/fear/future_api.rb +17 -4
  30. data/lib/fear/left.rb +3 -9
  31. data/lib/fear/left_pattern_match.rb +2 -0
  32. data/lib/fear/none.rb +28 -10
  33. data/lib/fear/none_pattern_match.rb +2 -0
  34. data/lib/fear/option.rb +30 -2
  35. data/lib/fear/option_api.rb +4 -0
  36. data/lib/fear/option_pattern_match.rb +8 -3
  37. data/lib/fear/partial_function/and_then.rb +4 -2
  38. data/lib/fear/partial_function/any.rb +2 -0
  39. data/lib/fear/partial_function/combined.rb +3 -1
  40. data/lib/fear/partial_function/empty.rb +6 -0
  41. data/lib/fear/partial_function/guard/and.rb +2 -0
  42. data/lib/fear/partial_function/guard/and3.rb +2 -0
  43. data/lib/fear/partial_function/guard/or.rb +2 -0
  44. data/lib/fear/partial_function/guard.rb +8 -6
  45. data/lib/fear/partial_function/lifted.rb +2 -0
  46. data/lib/fear/partial_function/or_else.rb +5 -1
  47. data/lib/fear/partial_function.rb +18 -9
  48. data/lib/fear/partial_function_class.rb +3 -1
  49. data/lib/fear/pattern_match.rb +3 -11
  50. data/lib/fear/pattern_matching_api.rb +6 -28
  51. data/lib/fear/promise.rb +7 -5
  52. data/lib/fear/right.rb +3 -9
  53. data/lib/fear/right_biased.rb +5 -3
  54. data/lib/fear/right_pattern_match.rb +4 -0
  55. data/lib/fear/some.rb +35 -8
  56. data/lib/fear/some_pattern_match.rb +2 -0
  57. data/lib/fear/struct.rb +237 -0
  58. data/lib/fear/success.rb +7 -8
  59. data/lib/fear/success_pattern_match.rb +4 -0
  60. data/lib/fear/try.rb +8 -2
  61. data/lib/fear/try_api.rb +4 -0
  62. data/lib/fear/try_pattern_match.rb +9 -5
  63. data/lib/fear/unit.rb +6 -2
  64. data/lib/fear/utils.rb +14 -2
  65. data/lib/fear/version.rb +4 -1
  66. data/lib/fear.rb +26 -44
  67. data/spec/dry/types/fear/option/constrained_spec.rb +22 -0
  68. data/spec/dry/types/fear/option/core_spec.rb +77 -0
  69. data/spec/dry/types/fear/option/default_spec.rb +21 -0
  70. data/spec/dry/types/fear/option/hash_spec.rb +58 -0
  71. data/spec/dry/types/fear/option/option_spec.rb +97 -0
  72. data/spec/fear/awaitable_spec.rb +19 -0
  73. data/spec/fear/done_spec.rb +7 -5
  74. data/spec/fear/either/mixin_spec.rb +4 -2
  75. data/spec/fear/either_pattern_match_spec.rb +10 -8
  76. data/spec/fear/either_pattern_matching_spec.rb +28 -0
  77. data/spec/fear/either_spec.rb +26 -0
  78. data/spec/fear/failure_spec.rb +57 -70
  79. data/spec/fear/for/mixin_spec.rb +15 -0
  80. data/spec/fear/for_spec.rb +19 -17
  81. data/spec/fear/future_spec.rb +477 -237
  82. data/spec/fear/guard_spec.rb +136 -24
  83. data/spec/fear/left_spec.rb +57 -70
  84. data/spec/fear/none_spec.rb +39 -43
  85. data/spec/fear/option/mixin_spec.rb +9 -7
  86. data/spec/fear/option_pattern_match_spec.rb +10 -8
  87. data/spec/fear/option_pattern_matching_spec.rb +34 -0
  88. data/spec/fear/option_spec.rb +142 -0
  89. data/spec/fear/partial_function/any_spec.rb +25 -0
  90. data/spec/fear/partial_function/empty_spec.rb +12 -10
  91. data/spec/fear/partial_function_and_then_spec.rb +39 -37
  92. data/spec/fear/partial_function_composition_spec.rb +46 -44
  93. data/spec/fear/partial_function_or_else_spec.rb +92 -90
  94. data/spec/fear/partial_function_spec.rb +91 -61
  95. data/spec/fear/pattern_match_spec.rb +19 -51
  96. data/spec/fear/pattern_matching_api_spec.rb +31 -0
  97. data/spec/fear/promise_spec.rb +23 -23
  98. data/spec/fear/right_biased/left.rb +28 -26
  99. data/spec/fear/right_biased/right.rb +51 -49
  100. data/spec/fear/right_spec.rb +48 -68
  101. data/spec/fear/some_spec.rb +30 -40
  102. data/spec/fear/success_spec.rb +40 -60
  103. data/spec/fear/try/mixin_spec.rb +19 -3
  104. data/spec/fear/try_api_spec.rb +23 -0
  105. data/spec/fear/try_pattern_match_spec.rb +10 -8
  106. data/spec/fear/try_pattern_matching_spec.rb +34 -0
  107. data/spec/fear/utils_spec.rb +16 -14
  108. data/spec/spec_helper.rb +13 -7
  109. data/spec/struct_pattern_matching_spec.rb +36 -0
  110. data/spec/struct_spec.rb +194 -0
  111. data/spec/support/dry_types.rb +6 -0
  112. metadata +128 -87
  113. data/.travis.yml +0 -13
  114. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -8
  115. data/lib/fear/extractor/any_matcher.rb +0 -15
  116. data/lib/fear/extractor/array_head_matcher.rb +0 -34
  117. data/lib/fear/extractor/array_matcher.rb +0 -38
  118. data/lib/fear/extractor/array_splat_matcher.rb +0 -14
  119. data/lib/fear/extractor/empty_list_matcher.rb +0 -18
  120. data/lib/fear/extractor/extractor_matcher.rb +0 -42
  121. data/lib/fear/extractor/grammar.rb +0 -201
  122. data/lib/fear/extractor/grammar.treetop +0 -129
  123. data/lib/fear/extractor/identifier_matcher.rb +0 -16
  124. data/lib/fear/extractor/matcher/and.rb +0 -36
  125. data/lib/fear/extractor/matcher.rb +0 -54
  126. data/lib/fear/extractor/named_array_splat_matcher.rb +0 -15
  127. data/lib/fear/extractor/pattern.rb +0 -55
  128. data/lib/fear/extractor/typed_identifier_matcher.rb +0 -24
  129. data/lib/fear/extractor/value_matcher.rb +0 -17
  130. data/lib/fear/extractor.rb +0 -108
  131. data/lib/fear/extractor_api.rb +0 -33
  132. data/spec/fear/extractor/array_matcher_spec.rb +0 -228
  133. data/spec/fear/extractor/extractor_matcher_spec.rb +0 -151
  134. data/spec/fear/extractor/grammar_array_spec.rb +0 -23
  135. data/spec/fear/extractor/identified_matcher_spec.rb +0 -47
  136. data/spec/fear/extractor/identifier_matcher_spec.rb +0 -66
  137. data/spec/fear/extractor/pattern_spec.rb +0 -32
  138. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -62
  139. data/spec/fear/extractor/value_matcher_number_spec.rb +0 -77
  140. data/spec/fear/extractor/value_matcher_string_spec.rb +0 -86
  141. data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -69
  142. data/spec/fear/extractor_api_spec.rb +0 -113
  143. data/spec/fear/extractor_spec.rb +0 -59
@@ -1,86 +0,0 @@
1
- RSpec.describe Fear::Extractor::ValueMatcher, 'String' do
2
- let(:parser) { Fear::Extractor::GrammarParser.new }
3
- let(:matcher) { parser.parse(pattern).to_matcher }
4
-
5
- describe '#defined_at?' do
6
- subject { matcher }
7
-
8
- context 'double quotas' do
9
- let(:pattern) { %("foo") }
10
-
11
- it { is_expected.to be_defined_at('foo') }
12
- it { is_expected.not_to be_defined_at('boo') }
13
- it { is_expected.not_to be_defined_at(2) }
14
-
15
- context 'single quotes inside' do
16
- let(:pattern) { %("f'o'o") }
17
-
18
- it { is_expected.to be_defined_at(%(f'o'o)) }
19
- it { is_expected.not_to be_defined_at(%(f"o"o)) }
20
- end
21
-
22
- context 'escaped double quotes inside' do
23
- let(:pattern) { '"f\"oo"' }
24
-
25
- it { is_expected.to be_defined_at('f"oo') }
26
- it { is_expected.not_to be_defined_at("f'oo") }
27
- end
28
- end
29
-
30
- context 'single quotas' do
31
- let(:pattern) { %('foo') }
32
-
33
- it { is_expected.to be_defined_at('foo') }
34
- it { is_expected.not_to be_defined_at('boo') }
35
- it { is_expected.not_to be_defined_at(2) }
36
-
37
- context 'double quotes inside' do
38
- let(:pattern) { %('f"o"o') }
39
-
40
- it { is_expected.to be_defined_at(%(f"o"o)) }
41
- it { is_expected.not_to be_defined_at(%(f'o'o)) }
42
- end
43
-
44
- context 'escaped single quotes inside' do
45
- let(:pattern) { "'f\\'oo'" }
46
-
47
- it { is_expected.to be_defined_at("f\\'oo") }
48
- it { is_expected.not_to be_defined_at("f'oo") }
49
- end
50
- end
51
- end
52
-
53
- describe '#call' do
54
- subject { matcher.call(other) }
55
-
56
- let(:pattern) { '"foo"' }
57
-
58
- context 'defined' do
59
- let(:other) { 'foo' }
60
-
61
- it { is_expected.to eq({}) }
62
- end
63
- end
64
-
65
- describe '#failure_reason' do
66
- subject { matcher.failure_reason(other) }
67
-
68
- context 'match' do
69
- let(:other) { 'foo' }
70
- let(:pattern) { '"foo"' }
71
-
72
- it { is_expected.to eq(Fear.none) }
73
- end
74
-
75
- context 'does not match' do
76
- let(:other) { 'bar' }
77
- let(:pattern) { '"foo"' }
78
-
79
- it { is_expected.to eq(Fear.some(<<-ERROR.strip)) }
80
- Expected `"bar"` to match:
81
- "foo"
82
- ^
83
- ERROR
84
- end
85
- end
86
- end
@@ -1,69 +0,0 @@
1
- RSpec.describe Fear::Extractor::ValueMatcher, 'Symbol' do
2
- let(:parser) { Fear::Extractor::GrammarParser.new }
3
- let(:matcher) { parser.parse(pattern).to_matcher }
4
-
5
- describe '#defined_at?' do
6
- subject { matcher }
7
-
8
- context 'no quotas' do
9
- let(:pattern) { ':foo' }
10
-
11
- it { is_expected.to be_defined_at(:foo) }
12
- it { is_expected.not_to be_defined_at('foo') }
13
- it { is_expected.not_to be_defined_at(:boo) }
14
- it { is_expected.not_to be_defined_at(2) }
15
- end
16
-
17
- context 'double quotas' do
18
- let(:pattern) { %(:"foo") }
19
-
20
- it { is_expected.to be_defined_at(:foo) }
21
- it { is_expected.not_to be_defined_at('foo') }
22
- it { is_expected.not_to be_defined_at(:boo) }
23
- it { is_expected.not_to be_defined_at(2) }
24
- end
25
-
26
- context 'single quotas' do
27
- let(:pattern) { %(:'foo') }
28
-
29
- it { is_expected.to be_defined_at(:foo) }
30
- it { is_expected.not_to be_defined_at('foo') }
31
- it { is_expected.not_to be_defined_at(:boo) }
32
- it { is_expected.not_to be_defined_at(2) }
33
- end
34
- end
35
-
36
- describe '#call' do
37
- subject { matcher.call(other) }
38
-
39
- let(:pattern) { ':foo' }
40
-
41
- context 'defined' do
42
- let(:other) { :foo }
43
-
44
- it { is_expected.to eq({}) }
45
- end
46
- end
47
-
48
- describe '#failure_reason' do
49
- subject { matcher.failure_reason(other) }
50
-
51
- context 'match' do
52
- let(:other) { :foo }
53
- let(:pattern) { ':foo' }
54
-
55
- it { is_expected.to eq(Fear.none) }
56
- end
57
-
58
- context 'does not match' do
59
- let(:other) { :bar }
60
- let(:pattern) { ':foo' }
61
-
62
- it { is_expected.to eq(Fear.some(<<-ERROR.strip)) }
63
- Expected `:bar` to match:
64
- :foo
65
- ^
66
- ERROR
67
- end
68
- end
69
- end
@@ -1,113 +0,0 @@
1
- RSpec.describe Fear::ExtractorApi do
2
- def assert(value)
3
- expect(value).to eq(true)
4
- end
5
-
6
- def assert_not(value)
7
- expect(value).not_to eq(true)
8
- end
9
-
10
- def assert_invalid_syntax
11
- expect do
12
- yield
13
- end.to raise_error(Fear::PatternSyntaxError)
14
- end
15
-
16
- def assert_valid_syntax
17
- expect { yield }.not_to raise_error
18
- end
19
-
20
- specify 'Array' do
21
- assert(Fear['[]'] === [])
22
- assert_not(Fear['[]'] === [1])
23
- assert(Fear['[1]'] === [1])
24
- assert_not(Fear['[1]'] === [1, 2])
25
- assert_not(Fear['[1]'] === [2])
26
- assert(Fear['[1, 2]'] === [1, 2])
27
- assert_not(Fear['[1, 2]'] === [1, 3])
28
- assert_not(Fear['[1, 2]'] === [1, 2, 4])
29
- assert_not(Fear['[1, 2]'] === [1])
30
- assert(Fear['[*]'] === [])
31
- assert(Fear['[*]'] === [1, 2])
32
- assert_not(Fear['[1, *]'] === [])
33
- assert(Fear['[1, *]'] === [1])
34
- assert(Fear['[1, *]'] === [1, 2])
35
- assert(Fear['[1, *]'] === [1, 2, 3])
36
- assert(Fear['[[1]]'] === [[1]])
37
- assert(Fear['[[1],2]'] === [[1], 2])
38
- assert(Fear['[[1],*]'] === [[1], 2])
39
- assert(Fear['[[*],*]'] === [[1], 2])
40
- assert_invalid_syntax { Fear['[*, 2]'] }
41
- assert_invalid_syntax { Fear['[*, ]'] }
42
- assert_invalid_syntax { Fear['[1, *, ]'] }
43
- assert_invalid_syntax { Fear['[1, *, 2]'] }
44
- assert_invalid_syntax { Fear['[1, *, *]'] }
45
- assert_invalid_syntax { Fear['[*, *]'] }
46
- assert(Fear['[a, b]'] === [1, 2])
47
- assert_not(Fear['[a, b, c]'] === [1, 2])
48
- assert(Fear['[a, b, _]'] === [1, 2, 3])
49
- assert(Fear['[a, b, *c]'] === [1, 2])
50
- assert_not(Fear['[a, b, c, *d]'] === [1, 2])
51
- end
52
-
53
- specify 'String' do
54
- assert(Fear['"foo"'] === 'foo')
55
- assert(Fear['"f\"oo"'] === 'f"oo')
56
- assert_not(Fear['"foo"'] === 'bar')
57
- assert(Fear["'foo'"] === 'foo')
58
- assert_not(Fear["'foo'"] === 'bar')
59
- end
60
-
61
- specify 'Symbol' do
62
- assert(Fear[':"foo"'] === :foo)
63
- assert(Fear[":'foo'"] === :foo)
64
- assert(Fear[':foo'] === :foo)
65
- assert_not(Fear[':foo'] === :bar)
66
- end
67
-
68
- specify 'Boolean' do
69
- assert(Fear['true'] === true)
70
- assert(Fear['false'] === false)
71
- assert_not(Fear['true'] === false)
72
- assert_not(Fear['false'] === true)
73
- end
74
-
75
- specify 'Nil' do
76
- assert(Fear['nil'] === nil) # rubocop:disable Style/NilComparison
77
- assert_not(Fear['nil'] === 42)
78
- end
79
-
80
- specify '_' do
81
- assert(Fear['_'] === nil) # rubocop:disable Style/NilComparison
82
- assert(Fear['_'] === true)
83
- assert(Fear['_'] === false)
84
- assert(Fear['_'] === 42)
85
- assert(Fear['_'] === 'foo')
86
- assert(Fear['_'] === [42])
87
- end
88
-
89
- specify 'type matching' do
90
- class Foo
91
- class Bar
92
- end
93
- end
94
-
95
- assert(Fear['Integer'] === 3)
96
- assert_not(Fear['Integer'] === '3')
97
- assert(Fear['Numeric'] === 3)
98
- assert(Fear['Foo::Bar'] === Foo::Bar.new)
99
- assert(Fear['var : Integer'] === 3)
100
- assert_not(Fear['var : Integer'] === '3')
101
- end
102
-
103
- specify 'capture matcher' do
104
- assert(Fear['array @ [head : Integer, *tail]'] === [1, 2])
105
- assert_not(Fear['array @ [head : Integer, *tail]'] === ['1', 2])
106
- end
107
-
108
- specify 'extractor' do
109
- assert_valid_syntax { Fear['Foo(a, b : Integer)'] }
110
- assert(Fear['Fear::Some(a : Integer)'] === Fear.some(42))
111
- assert_not(Fear['Fear::Some(a : Integer)'] === Fear.some('foo'))
112
- end
113
- end
@@ -1,59 +0,0 @@
1
- RSpec.describe Fear::Extractor do
2
- describe '.register_extractor' do
3
- Foo = Struct.new(:v1, :v2)
4
- let(:matcher) do
5
- Fear.matcher do |m|
6
- m.case(Fear['Foo(43, second : Integer)']) { |second| "43 and #{second}" }
7
- m.case(Fear['Foo(42, second : Integer)']) { |second| "42 and #{second}" }
8
- m.else { 'no match' }
9
- end
10
- end
11
-
12
- let(:extractor) do
13
- Fear.case(Foo) { |foo| [foo.v1, foo.v2] }.lift
14
- end
15
-
16
- context 'extractor not registered' do
17
- it 'raise Fear::Extractor::ExtractorNotFound' do
18
- expect do
19
- described_class.find_extractor('UnknownExtractor')
20
- end.to raise_error(Fear::Extractor::ExtractorNotFound)
21
- end
22
- end
23
-
24
- context 'register by name' do
25
- let(:extractor) { ->(*) { Fear.some('matched') } }
26
-
27
- before do
28
- described_class.register_extractor(
29
- 'ExtractorRegisteredByName',
30
- 'ExtractorRegisteredByName2',
31
- extractor,
32
- )
33
- end
34
-
35
- it 'returns extractor' do
36
- expect(described_class.find_extractor('ExtractorRegisteredByName')).to eq(extractor)
37
- expect(described_class.find_extractor('ExtractorRegisteredByName2')).to eq(extractor)
38
- end
39
- end
40
-
41
- context 'register by class' do
42
- let(:extractor) { ->(*) { Fear.some('matched') } }
43
- ExtractorRegisteredByClass = Class.new
44
-
45
- before do
46
- described_class.register_extractor(
47
- ExtractorRegisteredByClass,
48
- 'ExtractorRegisteredByClass2',
49
- extractor,
50
- )
51
- end
52
-
53
- it 'returns extractor' do
54
- expect(described_class.find_extractor('ExtractorRegisteredByClass')).to eq(extractor)
55
- expect(described_class.find_extractor('ExtractorRegisteredByClass2')).to eq(extractor)
56
- end
57
- end
58
- end
59
- end