fear 1.2.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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +27 -0
  3. data/.github/workflows/rubocop.yml +2 -2
  4. data/.github/workflows/spec.yml +1 -1
  5. data/CHANGELOG.md +13 -0
  6. data/Gemfile.lock +53 -56
  7. data/README.md +54 -186
  8. data/Rakefile +0 -21
  9. data/examples/pattern_extracting.rb +4 -4
  10. data/fear.gemspec +2 -4
  11. data/lib/fear/either.rb +8 -4
  12. data/lib/fear/either_api.rb +2 -0
  13. data/lib/fear/either_pattern_match.rb +7 -8
  14. data/lib/fear/failure.rb +0 -9
  15. data/lib/fear/failure_pattern_match.rb +2 -0
  16. data/lib/fear/for_api.rb +2 -0
  17. data/lib/fear/future.rb +12 -20
  18. data/lib/fear/future_api.rb +13 -2
  19. data/lib/fear/left.rb +0 -9
  20. data/lib/fear/none.rb +7 -9
  21. data/lib/fear/option.rb +5 -1
  22. data/lib/fear/option_api.rb +2 -0
  23. data/lib/fear/option_pattern_match.rb +6 -4
  24. data/lib/fear/partial_function/empty.rb +2 -0
  25. data/lib/fear/partial_function/guard.rb +4 -4
  26. data/lib/fear/partial_function/or_else.rb +2 -0
  27. data/lib/fear/partial_function.rb +9 -8
  28. data/lib/fear/pattern_match.rb +0 -10
  29. data/lib/fear/pattern_matching_api.rb +3 -28
  30. data/lib/fear/promise.rb +3 -9
  31. data/lib/fear/right.rb +0 -10
  32. data/lib/fear/right_biased.rb +1 -1
  33. data/lib/fear/right_pattern_match.rb +2 -0
  34. data/lib/fear/some.rb +7 -10
  35. data/lib/fear/struct.rb +3 -14
  36. data/lib/fear/success.rb +0 -9
  37. data/lib/fear/success_pattern_match.rb +2 -0
  38. data/lib/fear/try.rb +6 -2
  39. data/lib/fear/try_api.rb +2 -0
  40. data/lib/fear/try_pattern_match.rb +7 -8
  41. data/lib/fear/utils.rb +0 -3
  42. data/lib/fear/version.rb +1 -1
  43. data/lib/fear.rb +8 -42
  44. data/spec/fear/awaitable_spec.rb +2 -0
  45. data/spec/fear/either_spec.rb +26 -0
  46. data/spec/fear/failure_spec.rb +8 -23
  47. data/spec/fear/for/mixin_spec.rb +15 -0
  48. data/spec/fear/future_spec.rb +17 -2
  49. data/spec/fear/guard_spec.rb +110 -0
  50. data/spec/fear/left_spec.rb +7 -22
  51. data/spec/fear/none_spec.rb +11 -17
  52. data/spec/fear/option_spec.rb +15 -1
  53. data/spec/fear/partial_function/any_spec.rb +25 -0
  54. data/spec/fear/partial_function_spec.rb +2 -24
  55. data/spec/fear/pattern_match_spec.rb +0 -34
  56. data/spec/fear/promise_spec.rb +4 -6
  57. data/spec/fear/right_spec.rb +0 -22
  58. data/spec/fear/some_spec.rb +10 -22
  59. data/spec/fear/success_spec.rb +0 -22
  60. data/spec/fear/try/mixin_spec.rb +14 -0
  61. data/spec/fear/try_api_spec.rb +23 -0
  62. data/spec/struct_spec.rb +1 -33
  63. metadata +18 -80
  64. data/examples/pattern_extracting_ruby2.7.rb +0 -15
  65. data/lib/fear/extractor/anonymous_array_splat_matcher.rb +0 -10
  66. data/lib/fear/extractor/any_matcher.rb +0 -17
  67. data/lib/fear/extractor/array_head_matcher.rb +0 -36
  68. data/lib/fear/extractor/array_matcher.rb +0 -40
  69. data/lib/fear/extractor/array_splat_matcher.rb +0 -16
  70. data/lib/fear/extractor/empty_list_matcher.rb +0 -20
  71. data/lib/fear/extractor/extractor_matcher.rb +0 -44
  72. data/lib/fear/extractor/grammar.rb +0 -203
  73. data/lib/fear/extractor/grammar.treetop +0 -129
  74. data/lib/fear/extractor/identifier_matcher.rb +0 -18
  75. data/lib/fear/extractor/matcher/and.rb +0 -38
  76. data/lib/fear/extractor/matcher.rb +0 -53
  77. data/lib/fear/extractor/named_array_splat_matcher.rb +0 -17
  78. data/lib/fear/extractor/pattern.rb +0 -58
  79. data/lib/fear/extractor/typed_identifier_matcher.rb +0 -26
  80. data/lib/fear/extractor/value_matcher.rb +0 -19
  81. data/lib/fear/extractor.rb +0 -112
  82. data/lib/fear/extractor_api.rb +0 -35
  83. data/spec/fear/extractor/array_matcher_spec.rb +0 -230
  84. data/spec/fear/extractor/extractor_matcher_spec.rb +0 -153
  85. data/spec/fear/extractor/grammar_array_spec.rb +0 -25
  86. data/spec/fear/extractor/identified_matcher_spec.rb +0 -49
  87. data/spec/fear/extractor/identifier_matcher_spec.rb +0 -68
  88. data/spec/fear/extractor/pattern_spec.rb +0 -34
  89. data/spec/fear/extractor/typed_identifier_matcher_spec.rb +0 -64
  90. data/spec/fear/extractor/value_matcher_number_spec.rb +0 -79
  91. data/spec/fear/extractor/value_matcher_string_spec.rb +0 -88
  92. data/spec/fear/extractor/value_matcher_symbol_spec.rb +0 -71
  93. data/spec/fear/extractor_api_spec.rb +0 -115
  94. data/spec/fear/extractor_spec.rb +0 -61
@@ -1,203 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fear
4
- module Extractor
5
- # This module contains AST nodes for GrammarParser
6
- # generated by +treetop+. The sole purpose of them all is to
7
- # generate matchers
8
- module Grammar
9
- class Node < Treetop::Runtime::SyntaxNode
10
- end
11
-
12
- class EmptyArray < Node
13
- def to_matcher
14
- EmptyListMatcher.new(node: self)
15
- end
16
- end
17
-
18
- class ArrayLiteral < Node
19
- def to_matcher
20
- elements[1].to_matcher
21
- end
22
- end
23
-
24
- class NonEmptyArray < Node
25
- def to_matcher
26
- head, tail = elements
27
- ArrayMatcher.new(head: head.to_matcher, tail: tail.to_matcher, node: self)
28
- end
29
- end
30
-
31
- class ArrayTail < Node
32
- def to_matcher
33
- elements[1].to_matcher
34
- end
35
- end
36
-
37
- class ArrayHead < Node
38
- def to_matcher
39
- ArrayHeadMatcher.new(matcher: elements[1].to_matcher, node: elements[1])
40
- end
41
- end
42
-
43
- class ArraySplat < Node
44
- def to_matcher
45
- elements[1].to_matcher
46
- end
47
- end
48
-
49
- class AnonymousArraySplat < Node
50
- def to_matcher
51
- AnonymousArraySplatMatcher.new(node: self)
52
- end
53
- end
54
-
55
- class FloatLiteral < Node
56
- def to_matcher
57
- ValueMatcher.new(value: value, node: self)
58
- end
59
-
60
- def value
61
- Float(text_value)
62
- end
63
- end
64
-
65
- class IntegerLiteral < Node
66
- def to_matcher
67
- ValueMatcher.new(value: value, node: self)
68
- end
69
-
70
- def value
71
- Integer(text_value, 10)
72
- end
73
- end
74
-
75
- class StringLiteral < Node
76
- def to_matcher
77
- ValueMatcher.new(value: value, node: self)
78
- end
79
-
80
- def value
81
- elements[1].text_value
82
- end
83
- end
84
-
85
- require "yaml"
86
-
87
- class DoubleQuotedStringLiteral < StringLiteral
88
- def to_matcher
89
- ValueMatcher.new(value: value, node: self)
90
- end
91
-
92
- def value
93
- YAML.safe_load(%(---\n"#{super}"\n))
94
- end
95
- end
96
-
97
- class SymbolLiteral < Node
98
- def to_matcher
99
- ValueMatcher.new(value: value, node: self)
100
- end
101
-
102
- def value
103
- elements[1].value.to_sym
104
- end
105
- end
106
-
107
- class TrueLiteral < Node
108
- def to_matcher
109
- ValueMatcher.new(value: true, node: self)
110
- end
111
- end
112
-
113
- class FalseLiteral < Node
114
- def to_matcher
115
- ValueMatcher.new(value: false, node: self)
116
- end
117
- end
118
-
119
- class NilLiteral < Node
120
- def to_matcher
121
- ValueMatcher.new(value: nil, node: self)
122
- end
123
- end
124
-
125
- class AnyIdentifier < Node
126
- def to_matcher
127
- AnyMatcher.new(node: self)
128
- end
129
- end
130
-
131
- class Identifier < Node
132
- def to_matcher
133
- IdentifierMatcher.new(name: value, node: self)
134
- end
135
-
136
- def value
137
- text_value.to_sym
138
- end
139
- end
140
-
141
- class NamedArraySplat < Node
142
- def to_matcher
143
- NamedArraySplatMatcher.new(name: name, node: self)
144
- end
145
-
146
- def name
147
- text_value[1..-1].to_sym
148
- end
149
- end
150
-
151
- class TypeLiteral < Node
152
- def to_matcher
153
- ValueMatcher.new(value: value, node: self)
154
- end
155
-
156
- def value
157
- Object.const_get(text_value)
158
- end
159
- end
160
-
161
- class TypedIdentifier < Node
162
- def to_matcher
163
- identifier, type = elements.values_at(0, 2)
164
- type.to_matcher.and(identifier.to_matcher)
165
- end
166
- end
167
-
168
- class IdentifiedMatcher < Node
169
- def to_matcher
170
- identifier, matcher = elements.values_at(0, -1)
171
- identifier.to_matcher.and(matcher.to_matcher)
172
- end
173
- end
174
-
175
- class ExtractorLiteral < Node
176
- def to_matcher
177
- ExtractorMatcher.new(
178
- name: extractor_name,
179
- arguments_matcher: extractor_arguments,
180
- node: self,
181
- )
182
- end
183
-
184
- private def extractor_name
185
- name = elements[0].text_value
186
- if Object.const_defined?(name)
187
- Object.const_get(name)
188
- else
189
- name
190
- end
191
- end
192
-
193
- private def extractor_arguments
194
- if elements[2].empty?
195
- EmptyListMatcher.new(node: self)
196
- else
197
- elements[2].to_matcher
198
- end
199
- end
200
- end
201
- end
202
- end
203
- end
@@ -1,129 +0,0 @@
1
- # PEG grammar for pattern matching and extracting
2
-
3
- module Fear::Extractor
4
- grammar Grammar
5
- rule matcher
6
- identified_matcher / anonymous_matcher
7
- end
8
-
9
- rule identified_matcher
10
- identifier space '@' space anonymous_matcher <IdentifiedMatcher>
11
- end
12
-
13
- rule anonymous_matcher
14
- array / literal / identifier / extractor / type
15
- end
16
-
17
- rule array
18
- '[' (non_empty_array / array_splat / empty_array) ']' <ArrayLiteral>
19
- end
20
-
21
- rule empty_array
22
- '' <EmptyArray>
23
- end
24
-
25
- rule non_empty_array
26
- array_head (array_tail / empty_array) <NonEmptyArray>
27
- end
28
-
29
- rule array_tail
30
- ',' (non_empty_array / array_splat) <ArrayTail>
31
- end
32
-
33
- rule array_splat
34
- space? (named_array_splat / anonymous_array_splat) space? <ArraySplat>
35
- end
36
-
37
- rule array_splat_identifier
38
- space? anonymous_array_splat space? <ArraySplat>
39
- end
40
-
41
- rule anonymous_array_splat
42
- '*' '_'? <AnonymousArraySplat>
43
- end
44
-
45
- rule named_array_splat
46
- '*' [a-z] [a-z0-9_]* <NamedArraySplat>
47
- end
48
-
49
- rule array_head
50
- space? anonymous_matcher space? <ArrayHead>
51
- end
52
-
53
- rule space
54
- [\s]+
55
- end
56
-
57
- rule any
58
- '_' <AnyIdentifier>
59
- end
60
-
61
- rule variable_identifier
62
- [a-z_] [a-z0-9_]* <Identifier>
63
- end
64
-
65
- rule identifier
66
- typed_identifier / any / variable_identifier
67
- end
68
-
69
- rule typed_identifier
70
- (any / variable_identifier) ' : ' type <TypedIdentifier>
71
- end
72
-
73
- rule literal
74
- nil / true / false / number / string / symbol
75
- end
76
-
77
- rule number
78
- float / integer
79
- end
80
-
81
- rule integer
82
- ('+' / '-')? [0-9]+ <IntegerLiteral>
83
- end
84
-
85
- rule float
86
- ('+' / '-')? [0-9]+ '.' [0-9]+ <FloatLiteral>
87
- end
88
-
89
- rule symbol
90
- ':' (string / any / variable_identifier) <SymbolLiteral>
91
- end
92
-
93
- rule string
94
- double_quoted_string / single_quoted_string
95
- end
96
-
97
- rule double_quoted_string
98
- '"' ([^"\\] / '\\' . )* '"' <DoubleQuotedStringLiteral>
99
- end
100
-
101
- rule single_quoted_string
102
- "'" ([^'\\] / '\\' . )* "'" <StringLiteral>
103
- end
104
-
105
- rule true
106
- 'true' <TrueLiteral>
107
- end
108
-
109
- rule false
110
- 'false' <FalseLiteral>
111
- end
112
-
113
- rule nil
114
- 'nil' <NilLiteral>
115
- end
116
-
117
- rule extractor
118
- type '(' non_empty_array? ')' <ExtractorLiteral>
119
- end
120
-
121
- rule type
122
- constant ('::' constant)* <TypeLiteral>
123
- end
124
-
125
- rule constant
126
- [A-Z] [a-zA-Z0-9_]*
127
- end
128
- end
129
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fear
4
- module Extractor
5
- class IdentifierMatcher < Matcher
6
- # @!attribute name
7
- # @return [Types::Strict::Symbol]
8
-
9
- def defined_at?(_)
10
- true
11
- end
12
-
13
- def bindings(other)
14
- { name => other }
15
- end
16
- end
17
- end
18
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "ostruct"
4
-
5
- module Fear
6
- module Extractor
7
- class Matcher < OpenStruct
8
- # Combine two matchers, so both should pass
9
- class And < Matcher
10
- def initialize(matcher1, matcher2)
11
- @matcher1 = matcher1
12
- @matcher2 = matcher2
13
- end
14
- attr_reader :matcher1, :matcher2
15
-
16
- def defined_at?(arg)
17
- matcher1.defined_at?(arg) && matcher2.defined_at?(arg)
18
- end
19
-
20
- def bindings(arg)
21
- matcher1.bindings(arg).merge(matcher2.bindings(arg))
22
- end
23
-
24
- def failure_reason(arg)
25
- if matcher1.defined_at?(arg)
26
- if matcher2.defined_at?(arg)
27
- Fear.none
28
- else
29
- matcher2.failure_reason(arg)
30
- end
31
- else
32
- matcher1.failure_reason(arg)
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "ostruct"
4
-
5
- module Fear
6
- module Extractor
7
- # @abstract abstract matcher to inherit from.
8
- class Matcher < OpenStruct
9
- autoload :And, "fear/extractor/matcher/and"
10
-
11
- # @param node [Fear::Extractor::Grammar::Node]
12
- def initialize(node:, **attributes)
13
- @input = node.input
14
- @input_position = node.interval.first
15
- super(attributes)
16
- end
17
- attr_reader :input_position, :input
18
- private :input
19
- private :input_position
20
-
21
- def call(arg)
22
- call_or_else(arg, &PartialFunction::EMPTY)
23
- end
24
-
25
- def and(other)
26
- And.new(self, other)
27
- end
28
-
29
- # @param arg [any]
30
- # @yield [arg] if function not defined
31
- def call_or_else(arg)
32
- if defined_at?(arg)
33
- bindings(arg)
34
- else
35
- yield arg
36
- end
37
- end
38
-
39
- # Shows why matcher has failed. Use it for debugging.
40
- # @example
41
- # Fear['[1, 2, _]'].failure_reason([1, 3, 4])
42
- # # it will show that the second element hasn't match
43
- #
44
- def failure_reason(other)
45
- if defined_at?(other)
46
- Fear.none
47
- else
48
- Fear.some("Expected `#{other.inspect}` to match:\n#{input}\n#{"~" * input_position}^")
49
- end
50
- end
51
- end
52
- end
53
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fear
4
- module Extractor
5
- # Match against array splat, and capture rest of an array
6
- # E.g. +[1, 2, *tail]+
7
- #
8
- class NamedArraySplatMatcher < ArraySplatMatcher
9
- # @!attribute name
10
- # @return [Types::Strict::Symbol]
11
-
12
- def bindings(other)
13
- { name => other }
14
- end
15
- end
16
- end
17
- end
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "lru_redux"
4
-
5
- module Fear
6
- module Extractor
7
- # Parse pattern. Used within +Fear[]+
8
- class Pattern
9
- DEFAULT_PATTERN_CACHE_SIZE = 10_000
10
- private_constant :DEFAULT_PATTERN_CACHE_SIZE
11
- @pattern_cache = LruRedux::Cache.new(ENV.fetch("FEAR_PATTERNS_CACHE_SIZE", DEFAULT_PATTERN_CACHE_SIZE))
12
-
13
- class << self
14
- attr_reader :pattern_cache
15
- end
16
-
17
- def initialize(pattern)
18
- @matcher = compile_pattern(pattern)
19
- end
20
- attr_reader :matcher
21
- private :matcher
22
-
23
- private def compile_pattern(pattern)
24
- self.class.pattern_cache.getset(pattern) do
25
- compile_pattern_without_cache(pattern)
26
- end
27
- end
28
-
29
- private def compile_pattern_without_cache(pattern)
30
- parser = Extractor::GrammarParser.new
31
- if (result = parser.parse(pattern))
32
- result.to_matcher
33
- else
34
- raise PatternSyntaxError, syntax_error_message(parser, pattern)
35
- end
36
- end
37
-
38
- def ===(other)
39
- matcher.defined_at?(other)
40
- end
41
-
42
- def and_then(other)
43
- Fear::PartialFunction::Combined.new(matcher, other)
44
- end
45
-
46
- def failure_reason(other)
47
- matcher.failure_reason(other).get_or_else { "It matches" }
48
- end
49
-
50
- private def syntax_error_message(parser, pattern)
51
- parser.failure_reason =~ /^(Expected .+) after/m
52
- "#{Regexp.last_match(1).gsub("\n", "$NEWLINE")}:\n" +
53
- pattern.split("\n")[parser.failure_line - 1] + "\n" \
54
- "#{"~" * (parser.failure_column - 1)}^\n"
55
- end
56
- end
57
- end
58
- end
@@ -1,26 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fear
4
- module Extractor
5
- # Match and capture identifier with specific type. E.g. +foo : Integer+
6
- #
7
- class TypedIdentifierMatcher < Matcher
8
- # @!attribute identifier
9
- # @return [IdentifierMatcher]
10
- # @!attribute type
11
- # @return [ValueMatcher]
12
-
13
- def defined_at?(other)
14
- type.defined_at?(other)
15
- end
16
-
17
- def bindings(other)
18
- { identifier.name => other }
19
- end
20
-
21
- def failure_reason(other)
22
- type.failure_reason(other)
23
- end
24
- end
25
- end
26
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fear
4
- module Extractor
5
- # Match against values -- true, false, 1, "foo" etc.
6
- class ValueMatcher < Matcher
7
- # @!attribute value
8
- # @return [Any]
9
-
10
- def defined_at?(arg)
11
- value === arg
12
- end
13
-
14
- def bindings(_)
15
- Utils::EMPTY_HASH
16
- end
17
- end
18
- end
19
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "treetop"
4
- require "fear/extractor/grammar"
5
- Treetop.load File.expand_path("extractor/grammar.treetop", __dir__)
6
-
7
- module Fear
8
- # @api private
9
- module Extractor
10
- autoload :Pattern, "fear/extractor/pattern"
11
- autoload :Matcher, "fear/extractor/matcher"
12
-
13
- autoload :AnonymousArraySplatMatcher, "fear/extractor/anonymous_array_splat_matcher"
14
- autoload :AnyMatcher, "fear/extractor/any_matcher"
15
- autoload :ArrayHeadMatcher, "fear/extractor/array_head_matcher"
16
- autoload :ArrayMatcher, "fear/extractor/array_matcher"
17
- autoload :ArraySplatMatcher, "fear/extractor/array_splat_matcher"
18
- autoload :EmptyListMatcher, "fear/extractor/empty_list_matcher"
19
- autoload :ExtractorMatcher, "fear/extractor/extractor_matcher"
20
- autoload :IdentifierMatcher, "fear/extractor/identifier_matcher"
21
- autoload :NamedArraySplatMatcher, "fear/extractor/named_array_splat_matcher"
22
- autoload :TypedIdentifierMatcher, "fear/extractor/typed_identifier_matcher"
23
- autoload :ValueMatcher, "fear/extractor/value_matcher"
24
-
25
- ExtractorNotFound = Class.new(Error)
26
- public_constant :ExtractorNotFound
27
-
28
- @mutex = Mutex.new
29
- @registry = PartialFunction::EMPTY
30
-
31
- EXTRACTOR_NOT_FOUND = proc do |klass|
32
- raise ExtractorNotFound, "could not find extractor for " + klass.inspect
33
- end
34
- private_constant :EXTRACTOR_NOT_FOUND
35
-
36
- class << self
37
- # @param klass [Class, String]
38
- # @api private
39
- def find_extractor(klass)
40
- @registry.call_or_else(klass, &EXTRACTOR_NOT_FOUND)
41
- end
42
-
43
- # Register extractor for given class
44
- # @!method register_extractor(*names, extractor)
45
- # @param names [<Class, String>, Class, String] name of a class. You can also pass alias for the name
46
- # @param extractor [Proc<any => Fear::Option>] proc taking any argument and returned Option
47
- # of extracted value('s)
48
- #
49
- # @example
50
- # register_extractor(Fear::Some, Fear.case(Fear::Some) { |some| some.get }.lift)
51
- #
52
- # register_extractor(User, Fear.case(User) { |user|} [user.id, user.email] , )
53
- #
54
- # @example registering an alias. Alias should be CamelCased string
55
- # register_extractor(Fear::Some, 'Some', Fear.case(Fear::Some) { |some| some.get }.lift)
56
- #
57
- # # no you can extract Fear::Some's using Some alias
58
- # m.case(Fear['Some(value : Integer)']) { |value:| value * 2 }
59
- #
60
- def register_extractor(*args)
61
- *keys, extractor = *args
62
-
63
- @mutex.synchronize do
64
- keys.uniq.each do |key|
65
- @registry = BUILD_EXTRACTOR.(key, extractor).or_else(@registry)
66
- end
67
- end
68
- self
69
- end
70
-
71
- BUILD_EXTRACTOR = proc do |key, extractor|
72
- Fear.matcher do |m|
73
- case key
74
- when String
75
- m.case(Module, ->(lookup) { lookup.to_s == key }) { extractor }
76
- m.case(String, key) { extractor }
77
- when Module
78
- m.case(Module, ->(lookup) { lookup <= key }) { extractor }
79
- m.case(String, key.to_s) { extractor }
80
- else
81
- m.case(key) { extractor } # may it be useful to register other types of keys? lambda?
82
- end
83
- end
84
- end
85
- end
86
-
87
- # Multiple arguments extractor example
88
- register_extractor("Date", proc do |other|
89
- if other.class.name == "Date"
90
- Fear.some([other.year, other.month, other.day])
91
- else
92
- Fear.none
93
- end
94
- end)
95
- register_extractor(::Struct, Fear.case(::Struct, &:to_a).lift)
96
- # No argument boolean extractor example
97
- register_extractor("IsEven", proc do |int|
98
- if int.is_a?(Integer) && int.even?
99
- Fear.some([])
100
- else
101
- Fear.none
102
- end
103
- end)
104
- # Single argument extractor example
105
- register_extractor("Fear::Some", "Some", Some::EXTRACTOR)
106
- register_extractor("Fear::None", "None", NoneClass::EXTRACTOR)
107
- register_extractor("Fear::Right", "Right", Right::EXTRACTOR)
108
- register_extractor("Fear::Left", "Left", Left::EXTRACTOR)
109
- register_extractor("Fear::Success", "Success", Success::EXTRACTOR)
110
- register_extractor("Fear::Failure", "Failure", Failure::EXTRACTOR)
111
- end
112
- end