fear 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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