fear 1.0.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fear
2
4
  # @api private
3
5
  class SuccessPatternMatch < Fear::TryPatternMatch
@@ -7,4 +9,6 @@ module Fear
7
9
  self
8
10
  end
9
11
  end
12
+
13
+ private_constant :SuccessPatternMatch
10
14
  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(21)
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(21)
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,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fear/try"
4
+
1
5
  module Fear
2
6
  module TryApi
3
7
  # Constructs a +Try+ using the block. This
@@ -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, &SUCCESS_EXTRACTOR).and_then(Fear.case(*conditions, &effect))
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, &FAILURE_EXTRACTOR).and_then(Fear.case(*conditions, &effect))
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
- '#<Fear::Unit>'
22
+ "#<Fear::Unit>"
21
23
  end
22
24
 
23
25
  # @return [String]
24
26
  def unit.inspect
25
- '#<Fear::Unit>'
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(', ')} class"
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.call
41
+ value.()
30
42
  else
31
43
  value
32
44
  end
data/lib/fear/version.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fear
2
- VERSION = '1.0.0'.freeze
4
+ VERSION = "2.0.0"
5
+ public_constant :VERSION
3
6
  end
data/lib/fear.rb CHANGED
@@ -1,66 +1,48 @@
1
- require 'fear/either_api'
2
- require 'fear/extractor_api'
3
- require 'fear/for_api'
4
- require 'fear/future_api'
5
- require 'fear/option_api'
6
- require 'fear/pattern_matching_api'
7
- require 'fear/try_api'
8
- require 'fear/version'
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
@@ -1,17 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  RSpec.describe Fear::Unit do
2
- describe '#to_s' do
4
+ describe "#to_s" do
3
5
  subject { described_class.to_s }
4
6
 
5
- it { is_expected.to eq('#<Fear::Unit>') }
7
+ it { is_expected.to eq("#<Fear::Unit>") }
6
8
  end
7
9
 
8
- describe '#inspect' do
10
+ describe "#inspect" do
9
11
  subject { described_class.inspect }
10
12
 
11
- it { is_expected.to eq('#<Fear::Unit>') }
13
+ it { is_expected.to eq("#<Fear::Unit>") }
12
14
  end
13
15
 
14
- describe '#==' do
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 'Left()' do
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 'Right()' do
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 'Right' do
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.call(Fear.right(4))).to eq('4 is even')
12
- expect(matcher.call(Fear.right(3))).to eq('3 is odd')
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.call(Fear.left(44))
16
+ matcher.(Fear.left(44))
15
17
  end.to raise_error(Fear::MatchError)
16
18
  end
17
19
  end
18
20
 
19
- context 'Left' do
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.call(Fear.left(4))).to eq('4 is even')
29
- expect(matcher.call(Fear.left(3))).to eq('3 is odd')
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.call(Fear.right(44))
33
+ matcher.(Fear.right(44))
32
34
  end.to raise_error(Fear::MatchError)
33
35
  end
34
36
  end