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
data/lib/fear/success.rb
CHANGED
@@ -1,17 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
class Success
|
3
5
|
include Try
|
4
6
|
include RightBiased::Right
|
5
7
|
include SuccessPatternMatch.mixin
|
6
8
|
|
7
|
-
EXTRACTOR = proc do |try|
|
8
|
-
if Fear::Success === try
|
9
|
-
Fear.some([try.get])
|
10
|
-
else
|
11
|
-
Fear.none
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
9
|
attr_reader :value
|
16
10
|
protected :value
|
17
11
|
|
@@ -104,5 +98,10 @@ module Fear
|
|
104
98
|
|
105
99
|
# @return [String]
|
106
100
|
alias to_s inspect
|
101
|
+
|
102
|
+
# @return [<any>]
|
103
|
+
def deconstruct
|
104
|
+
[value]
|
105
|
+
end
|
107
106
|
end
|
108
107
|
end
|
data/lib/fear/try.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
# The +Try+ represents a computation that may either result
|
3
5
|
# in an exception, or return a successfully computed value. Instances of +Try+,
|
@@ -112,7 +114,7 @@ module Fear
|
|
112
114
|
# this is a +Failure+.
|
113
115
|
# @return [Option]
|
114
116
|
# @example
|
115
|
-
# Fear.success(42).to_option #=> Fear.some(
|
117
|
+
# Fear.success(42).to_option #=> Fear.some(42)
|
116
118
|
# Fear.failure(ArgumentError.new).to_option #=> Fear.none()
|
117
119
|
#
|
118
120
|
# @!method any?(&predicate)
|
@@ -170,7 +172,7 @@ module Fear
|
|
170
172
|
# @return [Try]
|
171
173
|
# @example
|
172
174
|
# Fear.success(42).select { |v| v > 40 }
|
173
|
-
# #=> Fear.success(
|
175
|
+
# #=> Fear.success(42)
|
174
176
|
# Fear.success(42).select { |v| v < 40 }
|
175
177
|
# #=> Fear.failure(Fear::NoSuchElementError.new("Predicate does not hold for 42"))
|
176
178
|
# Fear.failure(ArgumentError.new).select { |v| v < 40 }
|
@@ -315,3 +317,7 @@ module Fear
|
|
315
317
|
end
|
316
318
|
end
|
317
319
|
end
|
320
|
+
|
321
|
+
require "fear/try_pattern_match"
|
322
|
+
require "fear/success"
|
323
|
+
require "fear/failure"
|
data/lib/fear/try_api.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear/pattern_match"
|
4
|
+
|
1
5
|
module Fear
|
2
6
|
# Try pattern matcher
|
3
7
|
#
|
4
8
|
# @note it has two optimized subclasses +Fear::SuccessPatternMatch+ and +Fear::FailurePatternMatch+
|
5
9
|
# @api private
|
6
10
|
class TryPatternMatch < Fear::PatternMatch
|
7
|
-
SUCCESS_EXTRACTOR = :get.to_proc
|
8
|
-
FAILURE_EXTRACTOR = :exception.to_proc
|
9
|
-
|
10
11
|
# Match against +Fear::Success+
|
11
12
|
#
|
12
13
|
# @param conditions [<#==>]
|
13
14
|
# @return [Fear::TryPatternMatch]
|
14
15
|
def success(*conditions, &effect)
|
15
|
-
branch = Fear.case(Fear::Success,
|
16
|
+
branch = Fear.case(Fear::Success, &:get).and_then(Fear.case(*conditions, &effect))
|
16
17
|
or_else(branch)
|
17
18
|
end
|
18
19
|
|
@@ -21,8 +22,11 @@ module Fear
|
|
21
22
|
# @param conditions [<#==>]
|
22
23
|
# @return [Fear::TryPatternMatch]
|
23
24
|
def failure(*conditions, &effect)
|
24
|
-
branch = Fear.case(Fear::Failure,
|
25
|
+
branch = Fear.case(Fear::Failure, &:exception).and_then(Fear.case(*conditions, &effect))
|
25
26
|
or_else(branch)
|
26
27
|
end
|
27
28
|
end
|
28
29
|
end
|
30
|
+
|
31
|
+
require "fear/success_pattern_match"
|
32
|
+
require "fear/failure_pattern_match"
|
data/lib/fear/unit.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
# Represents lack of value. It's typically returned when function completed without a value.
|
3
5
|
#
|
@@ -17,12 +19,14 @@ module Fear
|
|
17
19
|
Unit = Object.new.tap do |unit|
|
18
20
|
# @return [String]
|
19
21
|
def unit.to_s
|
20
|
-
|
22
|
+
"#<Fear::Unit>"
|
21
23
|
end
|
22
24
|
|
23
25
|
# @return [String]
|
24
26
|
def unit.inspect
|
25
|
-
|
27
|
+
"#<Fear::Unit>"
|
26
28
|
end
|
27
29
|
end.freeze
|
30
|
+
|
31
|
+
public_constant :Unit
|
28
32
|
end
|
data/lib/fear/utils.rb
CHANGED
@@ -1,7 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Fear
|
2
4
|
# @private
|
3
5
|
module Utils
|
6
|
+
EMPTY_STRING = ""
|
7
|
+
public_constant :EMPTY_STRING
|
8
|
+
|
4
9
|
UNDEFINED = Object.new.freeze
|
10
|
+
public_constant :UNDEFINED
|
11
|
+
|
12
|
+
EMPTY_HASH = {}.freeze
|
13
|
+
public_constant :EMPTY_HASH
|
14
|
+
|
15
|
+
EMPTY_ARRAY = [].freeze
|
16
|
+
public_constant :EMPTY_ARRAY
|
5
17
|
|
6
18
|
class << self
|
7
19
|
def assert_arg_or_block!(method_name, *args)
|
@@ -20,13 +32,13 @@ module Fear
|
|
20
32
|
|
21
33
|
def assert_type!(value, *types)
|
22
34
|
if types.none? { |type| value.is_a?(type) }
|
23
|
-
raise TypeError, "expected `#{value.inspect}` to be of #{types.join(
|
35
|
+
raise TypeError, "expected `#{value.inspect}` to be of #{types.join(", ")} class"
|
24
36
|
end
|
25
37
|
end
|
26
38
|
|
27
39
|
def return_or_call_proc(value)
|
28
40
|
if value.respond_to?(:call)
|
29
|
-
value.
|
41
|
+
value.()
|
30
42
|
else
|
31
43
|
value
|
32
44
|
end
|
data/lib/fear/version.rb
CHANGED
data/lib/fear.rb
CHANGED
@@ -1,66 +1,48 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear/utils"
|
4
|
+
require "fear/right_biased"
|
5
|
+
require "fear/struct"
|
6
|
+
require "fear/unit"
|
7
|
+
require "fear/either_api"
|
8
|
+
require "fear/for_api"
|
9
|
+
require "fear/future_api"
|
10
|
+
require "fear/option_api"
|
11
|
+
require "fear/pattern_matching_api"
|
12
|
+
require "fear/try_api"
|
13
|
+
require "fear/version"
|
9
14
|
|
10
15
|
module Fear
|
11
16
|
Error = Class.new(StandardError)
|
17
|
+
public_constant :Error
|
18
|
+
|
12
19
|
IllegalStateException = Class.new(Error)
|
20
|
+
public_constant :IllegalStateException
|
21
|
+
|
13
22
|
MatchError = Class.new(Error)
|
23
|
+
public_constant :MatchError
|
24
|
+
|
14
25
|
NoSuchElementError = Class.new(Error)
|
26
|
+
public_constant :NoSuchElementError
|
27
|
+
|
15
28
|
PatternSyntaxError = Class.new(Error)
|
29
|
+
public_constant :PatternSyntaxError
|
16
30
|
|
17
31
|
extend EitherApi
|
18
|
-
extend ExtractorApi
|
19
32
|
extend ForApi
|
20
33
|
extend FutureApi
|
21
34
|
extend OptionApi
|
22
35
|
extend PatternMatchingApi
|
23
36
|
extend TryApi
|
24
37
|
|
25
|
-
autoload :EmptyPartialFunction, 'fear/empty_partial_function'
|
26
|
-
autoload :PartialFunction, 'fear/partial_function'
|
27
|
-
autoload :PartialFunctionClass, 'fear/partial_function_class'
|
28
|
-
autoload :PatternMatch, 'fear/pattern_match'
|
29
|
-
autoload :Extractor, 'fear/extractor'
|
30
|
-
|
31
|
-
autoload :Unit, 'fear/unit'
|
32
|
-
autoload :For, 'fear/for'
|
33
|
-
autoload :RightBiased, 'fear/right_biased'
|
34
|
-
autoload :Utils, 'fear/utils'
|
35
|
-
|
36
|
-
autoload :None, 'fear/none'
|
37
|
-
autoload :NoneClass, 'fear/none'
|
38
|
-
autoload :NonePatternMatch, 'fear/none_pattern_match'
|
39
|
-
autoload :Option, 'fear/option'
|
40
|
-
autoload :OptionPatternMatch, 'fear/option_pattern_match'
|
41
|
-
autoload :Some, 'fear/some'
|
42
|
-
autoload :SomePatternMatch, 'fear/some_pattern_match'
|
43
|
-
|
44
|
-
autoload :Failure, 'fear/failure'
|
45
|
-
autoload :FailurePatternMatch, 'fear/failure_pattern_match'
|
46
|
-
autoload :Success, 'fear/success'
|
47
|
-
autoload :SuccessPatternMatch, 'fear/success_pattern_match'
|
48
|
-
autoload :Try, 'fear/try'
|
49
|
-
autoload :TryPatternMatch, 'fear/try_pattern_match'
|
50
|
-
|
51
|
-
autoload :Either, 'fear/either'
|
52
|
-
autoload :EitherPatternMatch, 'fear/either_pattern_match'
|
53
|
-
autoload :Left, 'fear/left'
|
54
|
-
autoload :LeftPatternMatch, 'fear/left_pattern_match'
|
55
|
-
autoload :Right, 'fear/right'
|
56
|
-
autoload :RightPatternMatch, 'fear/right_pattern_match'
|
57
|
-
|
58
|
-
autoload :Future, 'fear/future'
|
59
|
-
|
60
38
|
module Mixin
|
61
39
|
include Either::Mixin
|
62
40
|
include For::Mixin
|
63
41
|
include Option::Mixin
|
64
42
|
include Try::Mixin
|
65
43
|
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
include Mixin
|
47
|
+
end
|
66
48
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "support/dry_types"
|
4
|
+
|
5
|
+
RSpec.describe Dry::Types::Constrained, :option do
|
6
|
+
context "with a option type" do
|
7
|
+
subject(:type) do
|
8
|
+
Dry::Types["nominal.string"].constrained(size: 4).option
|
9
|
+
end
|
10
|
+
|
11
|
+
it_behaves_like "Dry::Types::Nominal without primitive"
|
12
|
+
|
13
|
+
it "passes when constraints are not violated" do
|
14
|
+
expect(type[nil]).to be_none
|
15
|
+
expect(type["hell"]).to be_some_of("hell")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "raises when a given constraint is violated" do
|
19
|
+
expect { type["hel"] }.to raise_error(Dry::Types::ConstraintError, /hel/)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "support/dry_types"
|
4
|
+
|
5
|
+
RSpec.describe Dry::Types::Nominal, :option do
|
6
|
+
describe "with opt-in option types" do
|
7
|
+
context "with strict string" do
|
8
|
+
let(:string) { Dry::Types["option.strict.string"] }
|
9
|
+
|
10
|
+
it_behaves_like "Dry::Types::Nominal without primitive" do
|
11
|
+
let(:type) { string }
|
12
|
+
end
|
13
|
+
|
14
|
+
it "accepts nil" do
|
15
|
+
expect(string[nil]).to be_none
|
16
|
+
end
|
17
|
+
|
18
|
+
it "accepts a string" do
|
19
|
+
expect(string["something"]).to be_some_of("something")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "with coercible string" do
|
24
|
+
let(:string) { Dry::Types["option.coercible.string"] }
|
25
|
+
|
26
|
+
it_behaves_like "Dry::Types::Nominal without primitive" do
|
27
|
+
let(:type) { string }
|
28
|
+
end
|
29
|
+
|
30
|
+
it "accepts nil" do
|
31
|
+
expect(string[nil]).to be_none
|
32
|
+
end
|
33
|
+
|
34
|
+
it "accepts a string" do
|
35
|
+
expect(string[:something]).to be_some_of("something")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "defining coercible Option String" do
|
41
|
+
let(:option_string) { Dry::Types["coercible.string"].option }
|
42
|
+
|
43
|
+
it_behaves_like "Dry::Types::Nominal without primitive" do
|
44
|
+
let(:type) { option_string }
|
45
|
+
end
|
46
|
+
|
47
|
+
it "accepts nil" do
|
48
|
+
expect(option_string[nil]).to be_none
|
49
|
+
end
|
50
|
+
|
51
|
+
it "accepts an object coercible to a string" do
|
52
|
+
expect(option_string[123]).to be_some_of("123")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "defining Option String" do
|
57
|
+
let(:option_string) { Dry::Types["strict.string"].option }
|
58
|
+
|
59
|
+
it_behaves_like "Dry::Types::Nominal without primitive" do
|
60
|
+
let(:type) { option_string }
|
61
|
+
end
|
62
|
+
|
63
|
+
it "accepts nil and returns None instance" do
|
64
|
+
value = option_string[nil]
|
65
|
+
|
66
|
+
expect(value).to be_none
|
67
|
+
expect(value.map(&:downcase).map(&:upcase)).to be_none
|
68
|
+
end
|
69
|
+
|
70
|
+
it "accepts a string and returns Some instance" do
|
71
|
+
value = option_string["SomeThing"]
|
72
|
+
|
73
|
+
expect(value).to be_some_of("SomeThing")
|
74
|
+
expect(value.map(&:downcase).map(&:upcase)).to be_some_of("SOMETHING")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "support/dry_types"
|
4
|
+
|
5
|
+
RSpec.describe Dry::Types::Nominal, "#default", :option do
|
6
|
+
context "with a maybe" do
|
7
|
+
subject(:type) { Dry::Types["strict.integer"].option }
|
8
|
+
|
9
|
+
it_behaves_like "Dry::Types::Nominal without primitive" do
|
10
|
+
let(:type) { Dry::Types["strict.integer"].option.default(0) }
|
11
|
+
end
|
12
|
+
|
13
|
+
it "does not allow nil" do
|
14
|
+
expect { type.default(nil) }.to raise_error(ArgumentError, /nil/)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "accepts a non-nil value" do
|
18
|
+
expect(type.default(0)[0]).to be_some_of(0)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "support/dry_types"
|
4
|
+
|
5
|
+
RSpec.describe Dry::Types::Hash, :option do
|
6
|
+
let(:email) { Dry::Types["option.strict.string"] }
|
7
|
+
|
8
|
+
context "Symbolized constructor" do
|
9
|
+
subject(:hash) do
|
10
|
+
Dry::Types["nominal.hash"].schema(
|
11
|
+
name: "string",
|
12
|
+
email: email,
|
13
|
+
).with_key_transform(&:to_sym)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#[]" do
|
17
|
+
it "sets None as a default value for option" do
|
18
|
+
result = hash["name" => "Jane"]
|
19
|
+
|
20
|
+
expect(result[:email]).to be_none
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "Schema constructor" do
|
26
|
+
subject(:hash) do
|
27
|
+
Dry::Types["nominal.hash"].schema(
|
28
|
+
name: "string",
|
29
|
+
email: email,
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#[]" do
|
34
|
+
it "sets None as a default value for option types" do
|
35
|
+
result = hash[name: "Jane"]
|
36
|
+
|
37
|
+
expect(result[:email]).to be_none
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "Strict with defaults" do
|
43
|
+
subject(:hash) do
|
44
|
+
Dry::Types["nominal.hash"].schema(
|
45
|
+
name: "string",
|
46
|
+
email: email,
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "#[]" do
|
51
|
+
it "sets None as a default value for option types" do
|
52
|
+
result = hash[name: "Jane"]
|
53
|
+
|
54
|
+
expect(result[:email]).to be_none
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "support/dry_types"
|
4
|
+
|
5
|
+
RSpec.describe Dry::Types::Nominal, "#option", :option do
|
6
|
+
context "with a nominal" do
|
7
|
+
subject(:type) { Dry::Types["nominal.string"].option }
|
8
|
+
|
9
|
+
it_behaves_like "Dry::Types::Nominal without primitive"
|
10
|
+
|
11
|
+
it "returns None when value is nil" do
|
12
|
+
expect(type[nil]).to be_none
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns Some when value exists" do
|
16
|
+
expect(type["hello"]).to be_some_of("hello")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "returns original if input is already a option" do
|
20
|
+
expect(type[Fear.some("hello")]).to be_some_of("hello")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "aliases #[] as #call" do
|
24
|
+
expect(type.("hello")).to be_some_of("hello")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "does not have primitive" do
|
28
|
+
expect(type).to_not respond_to(:primitive)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with a strict type" do
|
33
|
+
subject(:type) { Dry::Types["strict.integer"].option }
|
34
|
+
|
35
|
+
it_behaves_like "Dry::Types::Nominal without primitive"
|
36
|
+
|
37
|
+
it "returns None when value is nil" do
|
38
|
+
expect(type[nil]).to be_none
|
39
|
+
end
|
40
|
+
|
41
|
+
it "returns Some when value exists" do
|
42
|
+
expect(type[231]).to be_some_of(231)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context "with a sum" do
|
47
|
+
subject(:type) { Dry::Types["nominal.bool"].option }
|
48
|
+
|
49
|
+
it_behaves_like "Dry::Types::Nominal without primitive"
|
50
|
+
|
51
|
+
it "returns None when value is nil" do
|
52
|
+
expect(type[nil]).to be_none
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns Some when value exists" do
|
56
|
+
expect(type[true]).to be_some_of(true)
|
57
|
+
expect(type[false]).to be_some_of(false)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "does not have primitive" do
|
61
|
+
expect(type).to_not respond_to(:primitive)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context "with keys" do
|
66
|
+
subject(:type) do
|
67
|
+
Dry::Types["hash"].schema(foo: Dry::Types["integer"]).key(:foo)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "gets wrapped by key type" do
|
71
|
+
expect(type.option).to be_a(Dry::Types::Schema::Key)
|
72
|
+
expect(type.option[nil]).to be_none
|
73
|
+
expect(type.option[1]).to be_some_of(1)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#try" do
|
78
|
+
subject(:type) { Dry::Types["coercible.integer"].option }
|
79
|
+
|
80
|
+
it "maps successful result" do
|
81
|
+
expect(type.try("1")).to eq(Dry::Types::Result::Success.new(Fear.some(1)))
|
82
|
+
expect(type.try(nil)).to eq(Dry::Types::Result::Success.new(Fear.none))
|
83
|
+
expect(type.try("a")).to be_a(Dry::Types::Result::Failure)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#call" do
|
88
|
+
describe "safe calls" do
|
89
|
+
subject(:type) { Dry::Types["coercible.integer"].option }
|
90
|
+
|
91
|
+
specify do
|
92
|
+
expect(type.("a") { :fallback }).to be(:fallback)
|
93
|
+
expect(type.(Fear.some(1)) { :fallback }).to eq(Fear.some(1))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fear/awaitable"
|
4
|
+
|
5
|
+
RSpec.describe Fear::Awaitable do
|
6
|
+
subject(:awaitable) { Object.new.extend(Fear::Awaitable) }
|
7
|
+
|
8
|
+
describe "#__ready__" do
|
9
|
+
it "must implement the method" do
|
10
|
+
expect { awaitable.__ready__(1) }.to raise_error(NotImplementedError)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#__result__" do
|
15
|
+
it "must implement the method" do
|
16
|
+
expect { awaitable.__result__(1) }.to raise_error(NotImplementedError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/spec/fear/done_spec.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe Fear::Unit do
|
2
|
-
describe
|
4
|
+
describe "#to_s" do
|
3
5
|
subject { described_class.to_s }
|
4
6
|
|
5
|
-
it { is_expected.to eq(
|
7
|
+
it { is_expected.to eq("#<Fear::Unit>") }
|
6
8
|
end
|
7
9
|
|
8
|
-
describe
|
10
|
+
describe "#inspect" do
|
9
11
|
subject { described_class.inspect }
|
10
12
|
|
11
|
-
it { is_expected.to eq(
|
13
|
+
it { is_expected.to eq("#<Fear::Unit>") }
|
12
14
|
end
|
13
15
|
|
14
|
-
describe
|
16
|
+
describe "#==" do
|
15
17
|
it { is_expected.to eq(described_class) }
|
16
18
|
end
|
17
19
|
end
|
@@ -1,13 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe Fear::Either::Mixin do
|
2
4
|
include Fear::Either::Mixin
|
3
5
|
|
4
|
-
describe
|
6
|
+
describe "Left()" do
|
5
7
|
subject { Left(42) }
|
6
8
|
|
7
9
|
it { is_expected.to eq(Fear::Left.new(42)) }
|
8
10
|
end
|
9
11
|
|
10
|
-
describe
|
12
|
+
describe "Right()" do
|
11
13
|
subject { Right(42) }
|
12
14
|
|
13
15
|
it { is_expected.to eq(Fear::Right.new(42)) }
|
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
RSpec.describe Fear::EitherPatternMatch do
|
2
|
-
context
|
4
|
+
context "Right" do
|
3
5
|
let(:matcher) do
|
4
6
|
described_class.new do |m|
|
5
7
|
m.right(:even?.to_proc) { |x| "#{x} is even" }
|
@@ -8,15 +10,15 @@ RSpec.describe Fear::EitherPatternMatch do
|
|
8
10
|
end
|
9
11
|
|
10
12
|
it do
|
11
|
-
expect(matcher.
|
12
|
-
expect(matcher.
|
13
|
+
expect(matcher.(Fear.right(4))).to eq("4 is even")
|
14
|
+
expect(matcher.(Fear.right(3))).to eq("3 is odd")
|
13
15
|
expect do
|
14
|
-
matcher.
|
16
|
+
matcher.(Fear.left(44))
|
15
17
|
end.to raise_error(Fear::MatchError)
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
|
-
context
|
21
|
+
context "Left" do
|
20
22
|
let(:matcher) do
|
21
23
|
described_class.new do |m|
|
22
24
|
m.left(:even?.to_proc) { |x| "#{x} is even" }
|
@@ -25,10 +27,10 @@ RSpec.describe Fear::EitherPatternMatch do
|
|
25
27
|
end
|
26
28
|
|
27
29
|
it do
|
28
|
-
expect(matcher.
|
29
|
-
expect(matcher.
|
30
|
+
expect(matcher.(Fear.left(4))).to eq("4 is even")
|
31
|
+
expect(matcher.(Fear.left(3))).to eq("3 is odd")
|
30
32
|
expect do
|
31
|
-
matcher.
|
33
|
+
matcher.(Fear.right(44))
|
32
34
|
end.to raise_error(Fear::MatchError)
|
33
35
|
end
|
34
36
|
end
|