fear 2.0.1 → 3.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 (85) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/spec.yml +1 -5
  3. data/CHANGELOG.md +8 -0
  4. data/Gemfile +14 -2
  5. data/Gemfile.lock +48 -61
  6. data/LICENSE.txt +1 -1
  7. data/README.md +18 -70
  8. data/Rakefile +32 -119
  9. data/benchmarks/dry_do_vs_fear_for.txt +7 -6
  10. data/benchmarks/dry_some_fmap_vs_fear_some_map.txt +7 -6
  11. data/benchmarks/factorial.txt +7 -9
  12. data/benchmarks/fear_gaurd_and1_vs_new.txt +7 -6
  13. data/benchmarks/fear_gaurd_and2_vs_and.txt +8 -7
  14. data/benchmarks/fear_gaurd_and3_vs_and_and.txt +7 -6
  15. data/benchmarks/fear_pattern_matching_construction_vs_execution.txt +7 -6
  16. data/benchmarks/pattern_matching_dry_vs_qo_vs_fear_try.txt +8 -10
  17. data/fear.gemspec +4 -19
  18. data/lib/fear/either/left_projection.rb +237 -0
  19. data/lib/fear/either/pattern_match.rb +49 -0
  20. data/lib/fear/either.rb +20 -11
  21. data/lib/fear/either_api.rb +2 -4
  22. data/lib/fear/empty_partial_function.rb +1 -1
  23. data/lib/fear/failure/pattern_match.rb +14 -0
  24. data/lib/fear/failure.rb +1 -1
  25. data/lib/fear/for_api.rb +0 -2
  26. data/lib/fear/future.rb +1 -1
  27. data/lib/fear/future_api.rb +0 -5
  28. data/lib/fear/left/pattern_match.rb +15 -0
  29. data/lib/fear/left.rb +1 -1
  30. data/lib/fear/none.rb +0 -87
  31. data/lib/fear/none_class/pattern_match.rb +16 -0
  32. data/lib/fear/none_class.rb +85 -0
  33. data/lib/fear/option/pattern_match.rb +47 -0
  34. data/lib/fear/option.rb +1 -5
  35. data/lib/fear/option_api.rb +1 -3
  36. data/lib/fear/partial_function/empty.rb +3 -5
  37. data/lib/fear/partial_function/guard.rb +0 -4
  38. data/lib/fear/partial_function/or_else.rb +0 -2
  39. data/lib/fear/partial_function.rb +0 -9
  40. data/lib/fear/partial_function_class.rb +1 -1
  41. data/lib/fear/pattern_match.rb +3 -2
  42. data/lib/fear/pattern_matching_api.rb +0 -3
  43. data/lib/fear/right/pattern_match.rb +15 -0
  44. data/lib/fear/right.rb +1 -1
  45. data/lib/fear/right_biased.rb +2 -0
  46. data/lib/fear/some/pattern_match.rb +15 -0
  47. data/lib/fear/some.rb +1 -1
  48. data/lib/fear/success/pattern_match.rb +16 -0
  49. data/lib/fear/success.rb +1 -1
  50. data/lib/fear/try/pattern_match.rb +29 -0
  51. data/lib/fear/try.rb +3 -7
  52. data/lib/fear/try_api.rb +0 -2
  53. data/lib/fear/version.rb +1 -1
  54. data/lib/fear.rb +3 -14
  55. data/spec/fear/awaitable_spec.rb +0 -2
  56. data/spec/fear/either/left_projection_spec.rb +289 -0
  57. data/spec/fear/{either_pattern_match_spec.rb → either/pattern_match_spec.rb} +1 -1
  58. data/spec/fear/{option_pattern_match_spec.rb → option/pattern_match_spec.rb} +1 -1
  59. data/spec/fear/partial_function/empty_spec.rb +1 -1
  60. data/spec/fear/{try_pattern_match_spec.rb → try/try_pattern_match_spec.rb} +1 -1
  61. data/spec/support/.keep +0 -0
  62. metadata +29 -255
  63. data/benchmarks/fear_pattern_extracting_with_vs_without_cache.txt +0 -11
  64. data/benchmarks/pattern_matching_qo_vs_fear_pattern_extraction.txt +0 -11
  65. data/benchmarks/pattern_matching_qo_vs_fear_try_execution.txt +0 -11
  66. data/lib/dry/types/fear/option.rb +0 -125
  67. data/lib/dry/types/fear.rb +0 -8
  68. data/lib/fear/either_pattern_match.rb +0 -52
  69. data/lib/fear/failure_pattern_match.rb +0 -12
  70. data/lib/fear/left_pattern_match.rb +0 -11
  71. data/lib/fear/none_pattern_match.rb +0 -14
  72. data/lib/fear/option_pattern_match.rb +0 -50
  73. data/lib/fear/right_pattern_match.rb +0 -13
  74. data/lib/fear/some_pattern_match.rb +0 -13
  75. data/lib/fear/struct.rb +0 -237
  76. data/lib/fear/success_pattern_match.rb +0 -14
  77. data/lib/fear/try_pattern_match.rb +0 -32
  78. data/spec/dry/types/fear/option/constrained_spec.rb +0 -22
  79. data/spec/dry/types/fear/option/core_spec.rb +0 -77
  80. data/spec/dry/types/fear/option/default_spec.rb +0 -21
  81. data/spec/dry/types/fear/option/hash_spec.rb +0 -58
  82. data/spec/dry/types/fear/option/option_spec.rb +0 -97
  83. data/spec/struct_pattern_matching_spec.rb +0 -36
  84. data/spec/struct_spec.rb +0 -194
  85. data/spec/support/dry_types.rb +0 -6
data/lib/fear/none.rb CHANGED
@@ -1,94 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fear
4
- # @api private
5
- class NoneClass
6
- include Option
7
- include RightBiased::Left
8
- include NonePatternMatch.mixin
9
-
10
- # @raise [NoSuchElementError]
11
- def get
12
- raise NoSuchElementError
13
- end
14
-
15
- # @return [nil]
16
- def or_nil
17
- nil
18
- end
19
-
20
- # @return [true]
21
- def empty?
22
- true
23
- end
24
-
25
- alias :blank? :empty?
26
-
27
- # @return [false]
28
- def present?
29
- false
30
- end
31
-
32
- # @return [None]
33
- def select(*)
34
- self
35
- end
36
-
37
- # @return [None]
38
- def reject(*)
39
- self
40
- end
41
-
42
- # @return [String]
43
- def inspect
44
- "#<Fear::NoneClass>"
45
- end
46
-
47
- # @return [String]
48
- alias to_s inspect
49
-
50
- # @param other [Any]
51
- # @return [Boolean]
52
- def ==(other)
53
- other.is_a?(NoneClass)
54
- end
55
-
56
- # @param other
57
- # @return [Boolean]
58
- def ===(other)
59
- self == other
60
- end
61
-
62
- # @param other [Fear::Option]
63
- # @return [Fear::Option]
64
- def zip(other)
65
- if other.is_a?(Option)
66
- Fear.none
67
- else
68
- raise TypeError, "can't zip with #{other.class}"
69
- end
70
- end
71
-
72
- # @return [RightBiased::Left]
73
- def filter_map
74
- self
75
- end
76
- end
77
-
78
- private_constant(:NoneClass)
79
-
80
4
  # The only instance of NoneClass
81
- # @api private
82
5
  None = NoneClass.new.freeze
83
6
  public_constant :None
84
-
85
- class << NoneClass
86
- def new
87
- None
88
- end
89
-
90
- def inherited(*)
91
- raise "you are not allowed to inherit from NoneClass, use Fear::None instead"
92
- end
93
- end
94
7
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ class NoneClass
5
+ # @api private
6
+ class PatternMatch < Option::PatternMatch
7
+ # @param conditions [<#==>]
8
+ # @return [Fear::OptionPatternMatch]
9
+ def some(*conditions)
10
+ self
11
+ end
12
+ end
13
+
14
+ private_constant :PatternMatch
15
+ end
16
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ # @api private
5
+ class NoneClass
6
+ include Option
7
+ include RightBiased::Left
8
+ include PatternMatch.mixin
9
+
10
+ class << self
11
+ def inherited(*)
12
+ raise "you are not allowed to inherit from NoneClass, use Fear::None instead"
13
+ end
14
+ end
15
+
16
+ # @raise [NoSuchElementError]
17
+ def get
18
+ raise NoSuchElementError
19
+ end
20
+
21
+ # @return [nil]
22
+ def or_nil
23
+ nil
24
+ end
25
+
26
+ # @return [true]
27
+ def empty?
28
+ true
29
+ end
30
+
31
+ alias :blank? :empty?
32
+
33
+ # @return [false]
34
+ def present?
35
+ false
36
+ end
37
+
38
+ # @return [None]
39
+ def select(*)
40
+ self
41
+ end
42
+
43
+ # @return [None]
44
+ def reject(*)
45
+ self
46
+ end
47
+
48
+ # @return [String]
49
+ def inspect
50
+ "#<Fear::NoneClass>"
51
+ end
52
+
53
+ # @return [String]
54
+ alias to_s inspect
55
+
56
+ # @param other [Any]
57
+ # @return [Boolean]
58
+ def ==(other)
59
+ other.is_a?(NoneClass)
60
+ end
61
+
62
+ # @param other
63
+ # @return [Boolean]
64
+ def ===(other)
65
+ self == other
66
+ end
67
+
68
+ # @param other [Fear::Option]
69
+ # @return [Fear::Option]
70
+ def zip(other)
71
+ if other.is_a?(Option)
72
+ Fear.none
73
+ else
74
+ raise TypeError, "can't zip with #{other.class}"
75
+ end
76
+ end
77
+
78
+ # @return [RightBiased::Left]
79
+ def filter_map
80
+ self
81
+ end
82
+ end
83
+
84
+ private_constant(:NoneClass)
85
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Option
5
+ # Option pattern matcher
6
+ #
7
+ # @example
8
+ # pattern_match =
9
+ # Option::PatternMatch.new
10
+ # .some(Integer) { |x| x * 2 }
11
+ # .some(String) { |x| x.to_i * 2 }
12
+ # .none { 'NaN' }
13
+ # .else { 'error '}
14
+ #
15
+ # pattern_match.call(42) => 'NaN'
16
+ #
17
+ # @example the same matcher may be defined using block syntax
18
+ # Option::PatternMatch.new do |m|
19
+ # m.some(Integer) { |x| x * 2 }
20
+ # m.some(String) { |x| x.to_i * 2 }
21
+ # m.none { 'NaN' }
22
+ # m.else { 'error '}
23
+ # end
24
+ #
25
+ # @note it has two optimized subclasses +Fear::SomePatternMatch+ and +Fear::NonePatternMatch+
26
+ # @api private
27
+ class PatternMatch < Fear::PatternMatch
28
+ # Match against Some
29
+ #
30
+ # @param conditions [<#==>]
31
+ # @return [Fear::Option::PatternMatch]
32
+ def some(*conditions, &effect)
33
+ branch = Fear.case(Fear::Some, &:get).and_then(Fear.case(*conditions, &effect))
34
+ or_else(branch)
35
+ end
36
+
37
+ # Match against None
38
+ #
39
+ # @param effect [Proc]
40
+ # @return [Fear::Option::PatternMatch]
41
+ def none(&effect)
42
+ branch = Fear.case(Fear::None, &effect)
43
+ or_else(branch)
44
+ end
45
+ end
46
+ end
47
+ end
data/lib/fear/option.rb CHANGED
@@ -207,7 +207,7 @@ module Fear
207
207
  # @yieldparam [OptionPatternMatch]
208
208
  # @return [Fear::PartialFunction]
209
209
  def matcher(&matcher)
210
- OptionPatternMatch.new(&matcher)
210
+ Option::PatternMatch.new(&matcher)
211
211
  end
212
212
 
213
213
  def match(value, &block)
@@ -258,7 +258,3 @@ module Fear
258
258
  end
259
259
  end
260
260
  end
261
-
262
- require "fear/option_pattern_match"
263
- require "fear/some"
264
- require "fear/none"
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/option"
4
-
5
3
  module Fear
6
4
  module OptionApi
7
5
  # An +Option+ factory which creates +Some+ if the argument is
@@ -29,7 +27,7 @@ module Fear
29
27
  Fear::None
30
28
  end
31
29
 
32
- # @param value [any]
30
+ # @param value [Object]
33
31
  # @return [Fear::Some]
34
32
  # @example
35
33
  # Fear.some(17) #=> #<Fear::Some get=17>
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/empty_partial_function"
4
-
5
3
  module Fear
6
4
  module PartialFunction
7
- EMPTY = EmptyPartialFunction.new
8
- EMPTY.freeze
5
+ Empty = EmptyPartialFunction.new
6
+ Empty.freeze
9
7
 
10
- public_constant :EMPTY
8
+ public_constant :Empty
11
9
  end
12
10
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/partial_function/guard/or"
4
- require "fear/partial_function/guard/and"
5
- require "fear/partial_function/guard/and3"
6
-
7
3
  module Fear
8
4
  module PartialFunction
9
5
  # Guard represents PartialFunction guardian
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/utils"
4
-
5
3
  module Fear
6
4
  module PartialFunction
7
5
  # Composite function produced by +PartialFunction#or_else+ method
@@ -1,14 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/partial_function/and_then"
4
- require "fear/partial_function/any"
5
- require "fear/partial_function/combined"
6
- require "fear/partial_function/empty"
7
- require "fear/partial_function/guard"
8
- require "fear/partial_function/lifted"
9
- require "fear/partial_function/or_else"
10
- require "fear/partial_function_class"
11
-
12
3
  module Fear
13
4
  # A partial function is a unary function defined on subset of all possible inputs.
14
5
  # The method +defined_at?+ allows to test dynamically if an arg is in
@@ -20,7 +20,7 @@ module Fear
20
20
  # is contained in the function domain.
21
21
  # @raise [MatchError] when this partial function is not defined.
22
22
  def call(arg)
23
- call_or_else(arg, &PartialFunction::EMPTY)
23
+ call_or_else(arg, &PartialFunction::Empty)
24
24
  end
25
25
 
26
26
  # @param arg [any]
@@ -37,7 +37,7 @@ module Fear
37
37
 
38
38
  # @return [Fear::PartialFunction]
39
39
  def new
40
- builder = __new__(PartialFunction::EMPTY)
40
+ builder = __new__(PartialFunction::Empty)
41
41
  yield builder
42
42
  builder.result
43
43
  end
@@ -89,12 +89,13 @@ module Fear
89
89
  #
90
90
  # @param guards [<#===>]
91
91
  # @param effect [Proc]
92
- # @return [Fear::PartialFunction]
92
+ # @return [Fear::PatternMatch]
93
93
  # @see #or_else for details
94
94
  def case(*guards, &effect)
95
95
  or_else(Fear.case(*guards, &effect))
96
96
  end
97
97
 
98
+ # @return [Fear::PatternMatch]
98
99
  # @see Fear::PartialFunction#or_else
99
100
  def or_else(other)
100
101
  self.result = result.or_else(other)
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/partial_function"
4
- require "fear/pattern_match"
5
-
6
3
  module Fear
7
4
  # @api private
8
5
  module PatternMatchingApi
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ class Right
5
+ # @api private
6
+ class PatternMatch < Either::PatternMatch
7
+ def left(*)
8
+ self
9
+ end
10
+ alias failure left
11
+ end
12
+
13
+ private_constant :PatternMatch
14
+ end
15
+ end
data/lib/fear/right.rb CHANGED
@@ -4,7 +4,7 @@ module Fear
4
4
  class Right
5
5
  include Either
6
6
  include RightBiased::Right
7
- include RightPatternMatch.mixin
7
+ include PatternMatch.mixin
8
8
 
9
9
  # @api private
10
10
  def right_value
@@ -70,6 +70,7 @@ module Fear
70
70
  yield(value)
71
71
  self
72
72
  end
73
+ alias apply each
73
74
 
74
75
  # Maps the value using given block.
75
76
  #
@@ -144,6 +145,7 @@ module Fear
144
145
  def each
145
146
  self
146
147
  end
148
+ alias apply each
147
149
 
148
150
  # Ignores the given block and return self.
149
151
  #
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ class Some
5
+ # @api private
6
+ class PatternMatch < Option::PatternMatch
7
+ # @return [Fear::OptionPatternMatch]
8
+ def none
9
+ self
10
+ end
11
+ end
12
+
13
+ private_constant :PatternMatch
14
+ end
15
+ end
data/lib/fear/some.rb CHANGED
@@ -4,7 +4,7 @@ module Fear
4
4
  class Some
5
5
  include Option
6
6
  include RightBiased::Right
7
- include SomePatternMatch.mixin
7
+ include PatternMatch.mixin
8
8
 
9
9
  attr_reader :value
10
10
  protected :value
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ class Success
5
+ # @api private
6
+ class PatternMatch < Try::PatternMatch
7
+ # @param conditions [<#==>]
8
+ # @return [Fear::TryPatternMatch]
9
+ def failure(*conditions)
10
+ self
11
+ end
12
+ end
13
+
14
+ private_constant :PatternMatch
15
+ end
16
+ end
data/lib/fear/success.rb CHANGED
@@ -4,7 +4,7 @@ module Fear
4
4
  class Success
5
5
  include Try
6
6
  include RightBiased::Right
7
- include SuccessPatternMatch.mixin
7
+ include PatternMatch.mixin
8
8
 
9
9
  attr_reader :value
10
10
  protected :value
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fear
4
+ module Try
5
+ # Try pattern matcher
6
+ #
7
+ # @note it has two optimized subclasses +Fear::Success::PatternMatch+ and +Fear::FailurePatternMatch+
8
+ # @api private
9
+ class PatternMatch < Fear::PatternMatch
10
+ # Match against +Fear::Success+
11
+ #
12
+ # @param conditions [<#==>]
13
+ # @return [Fear::Try::PatternMatch]
14
+ def success(*conditions, &effect)
15
+ branch = Fear.case(Fear::Success, &:get).and_then(Fear.case(*conditions, &effect))
16
+ or_else(branch)
17
+ end
18
+
19
+ # Match against +Fear::Failure+
20
+ #
21
+ # @param conditions [<#==>]
22
+ # @return [Fear::Try::PatternMatch]
23
+ def failure(*conditions, &effect)
24
+ branch = Fear.case(Fear::Failure, &:exception).and_then(Fear.case(*conditions, &effect))
25
+ or_else(branch)
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/fear/try.rb CHANGED
@@ -231,7 +231,7 @@ module Fear
231
231
  #
232
232
  # @!method match(&matcher)
233
233
  # Pattern match against this +Try+
234
- # @yield matcher [Fear::TryPatternMatch]
234
+ # @yield matcher [Fear::Try::PatternMatch]
235
235
  # @example
236
236
  # Fear.try { ... }.match do |m|
237
237
  # m.success(Integer) do |x|
@@ -276,10 +276,10 @@ module Fear
276
276
  # end
277
277
  # matcher.call(try)
278
278
  #
279
- # @yieldparam [Fear::TryPatternMatch]
279
+ # @yieldparam [Fear::Try::PatternMatch]
280
280
  # @return [Fear::PartialFunction]
281
281
  def matcher(&matcher)
282
- TryPatternMatch.new(&matcher)
282
+ Try::PatternMatch.new(&matcher)
283
283
  end
284
284
  end
285
285
 
@@ -317,7 +317,3 @@ module Fear
317
317
  end
318
318
  end
319
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,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/try"
4
-
5
3
  module Fear
6
4
  module TryApi
7
5
  # Constructs a +Try+ using the block. This
data/lib/fear/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fear
4
- VERSION = "2.0.1"
4
+ VERSION = "3.0.0"
5
5
  public_constant :VERSION
6
6
  end
data/lib/fear.rb CHANGED
@@ -1,16 +1,8 @@
1
1
  # frozen_string_literal: true
2
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"
3
+ require "zeitwerk"
4
+ loader = Zeitwerk::Loader.for_gem
5
+ loader.setup
14
6
 
15
7
  module Fear
16
8
  Error = Class.new(StandardError)
@@ -25,9 +17,6 @@ module Fear
25
17
  NoSuchElementError = Class.new(Error)
26
18
  public_constant :NoSuchElementError
27
19
 
28
- PatternSyntaxError = Class.new(Error)
29
- public_constant :PatternSyntaxError
30
-
31
20
  extend EitherApi
32
21
  extend ForApi
33
22
  extend FutureApi
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "fear/awaitable"
4
-
5
3
  RSpec.describe Fear::Awaitable do
6
4
  subject(:awaitable) { Object.new.extend(Fear::Awaitable) }
7
5