kind 3.1.0 → 5.2.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/.tool-versions +1 -0
- data/.travis.sh +67 -12
- data/.travis.yml +7 -5
- data/CHANGELOG.md +1647 -0
- data/Gemfile +22 -7
- data/README.md +920 -486
- data/kind.gemspec +1 -1
- data/lib/kind.rb +2 -314
- data/lib/kind/__lib__/attributes.rb +66 -0
- data/lib/kind/__lib__/kind.rb +71 -0
- data/lib/kind/__lib__/undefined.rb +14 -0
- data/lib/kind/action.rb +92 -0
- data/lib/kind/active_model/validation.rb +3 -4
- data/lib/kind/basic.rb +73 -0
- data/lib/kind/basic/error.rb +29 -0
- data/lib/kind/{undefined.rb → basic/undefined.rb} +8 -1
- data/lib/kind/dig.rb +31 -11
- data/lib/kind/either.rb +30 -0
- data/lib/kind/either/left.rb +29 -0
- data/lib/kind/either/methods.rb +17 -0
- data/lib/kind/either/monad.rb +65 -0
- data/lib/kind/either/monad/wrapper.rb +19 -0
- data/lib/kind/either/right.rb +38 -0
- data/lib/kind/empty.rb +4 -10
- data/lib/kind/empty/constant.rb +7 -0
- data/lib/kind/enum.rb +63 -0
- data/lib/kind/enum/item.rb +40 -0
- data/lib/kind/enum/methods.rb +72 -0
- data/lib/kind/function.rb +47 -0
- data/lib/kind/functional.rb +89 -0
- data/lib/kind/functional/action.rb +89 -0
- data/lib/kind/immutable_attributes.rb +34 -0
- data/lib/kind/immutable_attributes/initializer.rb +70 -0
- data/lib/kind/immutable_attributes/reader.rb +38 -0
- data/lib/kind/maybe.rb +35 -159
- data/lib/kind/maybe/methods.rb +21 -0
- data/lib/kind/maybe/monad.rb +82 -0
- data/lib/kind/maybe/monad/wrapper.rb +19 -0
- data/lib/kind/maybe/none.rb +50 -0
- data/lib/kind/maybe/some.rb +132 -0
- data/lib/kind/maybe/typed.rb +35 -0
- data/lib/kind/maybe/wrapper.rb +37 -0
- data/lib/kind/monad.rb +22 -0
- data/lib/kind/monads.rb +5 -0
- data/lib/kind/objects.rb +17 -0
- data/lib/kind/objects/basic_object.rb +45 -0
- data/lib/kind/objects/modules.rb +32 -0
- data/lib/kind/objects/modules/core/array.rb +19 -0
- data/lib/kind/objects/modules/core/class.rb +13 -0
- data/lib/kind/objects/modules/core/comparable.rb +13 -0
- data/lib/kind/objects/modules/core/enumerable.rb +13 -0
- data/lib/kind/objects/modules/core/enumerator.rb +13 -0
- data/lib/kind/objects/modules/core/file.rb +13 -0
- data/lib/kind/objects/modules/core/float.rb +13 -0
- data/lib/kind/objects/modules/core/hash.rb +19 -0
- data/lib/kind/objects/modules/core/integer.rb +13 -0
- data/lib/kind/objects/modules/core/io.rb +13 -0
- data/lib/kind/objects/modules/core/method.rb +13 -0
- data/lib/kind/objects/modules/core/module.rb +17 -0
- data/lib/kind/objects/modules/core/numeric.rb +13 -0
- data/lib/kind/objects/modules/core/proc.rb +13 -0
- data/lib/kind/objects/modules/core/queue.rb +14 -0
- data/lib/kind/objects/modules/core/range.rb +13 -0
- data/lib/kind/objects/modules/core/regexp.rb +13 -0
- data/lib/kind/objects/modules/core/string.rb +19 -0
- data/lib/kind/objects/modules/core/struct.rb +13 -0
- data/lib/kind/objects/modules/core/symbol.rb +13 -0
- data/lib/kind/objects/modules/core/time.rb +13 -0
- data/lib/kind/objects/modules/custom/boolean.rb +19 -0
- data/lib/kind/objects/modules/custom/callable.rb +19 -0
- data/lib/kind/objects/modules/custom/lambda.rb +19 -0
- data/lib/kind/objects/modules/stdlib/open_struct.rb +15 -0
- data/lib/kind/objects/modules/stdlib/set.rb +19 -0
- data/lib/kind/objects/nil.rb +17 -0
- data/lib/kind/objects/not_nil.rb +13 -0
- data/lib/kind/objects/object.rb +56 -0
- data/lib/kind/objects/respond_to.rb +30 -0
- data/lib/kind/objects/union_type.rb +44 -0
- data/lib/kind/presence.rb +35 -0
- data/lib/kind/result.rb +31 -0
- data/lib/kind/result/abstract.rb +53 -0
- data/lib/kind/result/failure.rb +31 -0
- data/lib/kind/result/methods.rb +17 -0
- data/lib/kind/result/monad.rb +69 -0
- data/lib/kind/result/monad/wrapper.rb +19 -0
- data/lib/kind/result/success.rb +40 -0
- data/lib/kind/try.rb +46 -0
- data/lib/kind/validator.rb +112 -1
- data/lib/kind/version.rb +1 -1
- data/test.sh +4 -4
- metadata +81 -13
- data/lib/kind/active_model/kind_validator.rb +0 -96
- data/lib/kind/checker.rb +0 -15
- data/lib/kind/checker/factory.rb +0 -35
- data/lib/kind/checker/protocol.rb +0 -73
- data/lib/kind/error.rb +0 -19
- data/lib/kind/is.rb +0 -19
- data/lib/kind/of.rb +0 -11
- data/lib/kind/types.rb +0 -115
data/lib/kind/action.rb
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'kind/basic'
|
|
4
|
+
require 'kind/result'
|
|
5
|
+
require 'kind/immutable_attributes'
|
|
6
|
+
|
|
7
|
+
module Kind
|
|
8
|
+
module Action
|
|
9
|
+
CALL_TMPL = [
|
|
10
|
+
'def self.call(arg)',
|
|
11
|
+
' new(Kind.of!(::Hash, arg)).call',
|
|
12
|
+
'end',
|
|
13
|
+
'',
|
|
14
|
+
'def call',
|
|
15
|
+
' result = call!',
|
|
16
|
+
'',
|
|
17
|
+
' return result if Kind::Result::Monad === result',
|
|
18
|
+
'',
|
|
19
|
+
' raise Kind::Error, "#{self.class.name}#call! must return a Success() or Failure()"',
|
|
20
|
+
'end'
|
|
21
|
+
].join("\n").freeze
|
|
22
|
+
|
|
23
|
+
module ClassMethods
|
|
24
|
+
include ImmutableAttributes::ClassMethods
|
|
25
|
+
|
|
26
|
+
def to_proc
|
|
27
|
+
@to_proc ||= ->(arg) { call(arg) }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
ATTRIBUTE_METHODS = [
|
|
31
|
+
:attributes, :attribute,
|
|
32
|
+
:attribute?, :attribute!,
|
|
33
|
+
:with_attribute, :with_attributes,
|
|
34
|
+
:nil_attributes, :nil_attributes?
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
private_constant :ATTRIBUTE_METHODS
|
|
38
|
+
|
|
39
|
+
def kind_action!
|
|
40
|
+
return self if respond_to?(:call)
|
|
41
|
+
|
|
42
|
+
public_methods = self.public_instance_methods - ::Object.new.methods
|
|
43
|
+
|
|
44
|
+
remaining_methods = public_methods - (__attributes__.keys + ATTRIBUTE_METHODS)
|
|
45
|
+
|
|
46
|
+
unless remaining_methods.include?(:call!)
|
|
47
|
+
raise Kind::Error.new("expected #{self} to implement `#call!`")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
if remaining_methods.size > 1
|
|
51
|
+
raise Kind::Error.new("#{self} can only have `#call!` as its public method")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
call_parameters = public_instance_method(:call!).parameters
|
|
55
|
+
|
|
56
|
+
unless call_parameters.empty?
|
|
57
|
+
raise ArgumentError, "#{self.name}#call! must receive no arguments"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.inherited(_)
|
|
61
|
+
raise RuntimeError, "#{self.name} is a Kind::Action and it can't be inherited"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
self.send(:private_class_method, :new)
|
|
65
|
+
|
|
66
|
+
self.class_eval(CALL_TMPL)
|
|
67
|
+
|
|
68
|
+
self.send(:alias_method, :[], :call)
|
|
69
|
+
self.send(:alias_method, :===, :call)
|
|
70
|
+
self.send(:alias_method, :yield, :call)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def self.included(base)
|
|
75
|
+
KIND.of!(::Class, base).extend(ClassMethods)
|
|
76
|
+
|
|
77
|
+
base.send(:include, ImmutableAttributes::Reader)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
include ImmutableAttributes::Initializer
|
|
81
|
+
|
|
82
|
+
private
|
|
83
|
+
|
|
84
|
+
def Failure(arg1 = UNDEFINED, arg2 = UNDEFINED)
|
|
85
|
+
Result::Failure[arg1, arg2, value_must_be_a: ::Hash]
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def Success(arg1 = UNDEFINED, arg2 = UNDEFINED)
|
|
89
|
+
Result::Success[arg1, arg2, value_must_be_a: ::Hash]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
warn '[DEPRECATION] "kind/active_model/validation" is deprecated; use "kind/validator" instead. ' \
|
|
4
|
+
'It will be removed on next major release.'
|
|
5
|
+
|
|
4
6
|
require 'kind/validator'
|
|
5
|
-
require 'active_model'
|
|
6
|
-
require 'active_model/validations'
|
|
7
|
-
require_relative 'kind_validator'
|
data/lib/kind/basic.rb
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'kind/version'
|
|
4
|
+
|
|
5
|
+
require 'kind/__lib__/kind'
|
|
6
|
+
require 'kind/__lib__/undefined'
|
|
7
|
+
|
|
8
|
+
require 'kind/basic/undefined'
|
|
9
|
+
require 'kind/basic/error'
|
|
10
|
+
|
|
11
|
+
module Kind
|
|
12
|
+
extend self
|
|
13
|
+
|
|
14
|
+
def is?(kind, arg)
|
|
15
|
+
KIND.is?(kind, arg)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def is(*args)
|
|
19
|
+
warn '[DEPRECATION] Kind.is will behave like Kind.is! in the next major release; ' \
|
|
20
|
+
'use Kind.is? instead.'
|
|
21
|
+
|
|
22
|
+
is?(*args)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def is!(kind, arg, label: nil)
|
|
26
|
+
return arg if KIND.is?(kind, arg)
|
|
27
|
+
|
|
28
|
+
label_text = label ? "#{label}: " : ''
|
|
29
|
+
|
|
30
|
+
raise Kind::Error.new("#{label_text}#{arg} expected to be a #{kind}")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def of?(kind, *args)
|
|
34
|
+
KIND.of?(kind, args)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def of_class?(value)
|
|
38
|
+
KIND.of_class?(value)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def of_module?(value)
|
|
42
|
+
KIND.of_module?(value)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def respond_to?(value, *method_names)
|
|
46
|
+
return super(value) if method_names.empty?
|
|
47
|
+
|
|
48
|
+
KIND.interface?(method_names, value)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def of(kind, value, label: nil)
|
|
52
|
+
return value if kind === value
|
|
53
|
+
|
|
54
|
+
KIND.error!(kind.name, value, label)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
alias_method :of!, :of
|
|
58
|
+
|
|
59
|
+
def of_module_or_class(value)
|
|
60
|
+
KIND.of_module_or_class!(value)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def respond_to(value, *method_names)
|
|
64
|
+
method_names.each { |method_name| KIND.respond_to!(method_name, value) }
|
|
65
|
+
|
|
66
|
+
value
|
|
67
|
+
end
|
|
68
|
+
alias_method :respond_to!, :respond_to
|
|
69
|
+
|
|
70
|
+
def value(kind, value, default:)
|
|
71
|
+
KIND.value(kind, value, of(kind, default))
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kind
|
|
4
|
+
class Error < StandardError
|
|
5
|
+
INVALID_DEFAULT_ARG = 'the default value must be defined as an argument or block'.freeze
|
|
6
|
+
|
|
7
|
+
def self.wrong_number_of_args!(given:, expected:)
|
|
8
|
+
raise ArgumentError, "wrong number of arguments (given #{given}, expected #{expected})"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.invalid_default_arg!
|
|
12
|
+
raise ArgumentError, INVALID_DEFAULT_ARG
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(arg, object = UNDEFINED, label: nil)
|
|
16
|
+
if UNDEFINED == object
|
|
17
|
+
# Will be used when the exception was raised with a message. e.g:
|
|
18
|
+
# raise Kind::Error, "some message"
|
|
19
|
+
super(arg)
|
|
20
|
+
else
|
|
21
|
+
label_text = label ? "#{label}: " : ''
|
|
22
|
+
|
|
23
|
+
super("#{label_text}#{object.inspect} expected to be a kind of #{arg}")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private_constant :INVALID_DEFAULT_ARG
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -5,6 +5,11 @@ module Kind
|
|
|
5
5
|
def undefined.inspect
|
|
6
6
|
@inspect ||= 'Kind::Undefined'.freeze
|
|
7
7
|
end
|
|
8
|
+
undefined.inspect
|
|
9
|
+
|
|
10
|
+
def undefined.empty?
|
|
11
|
+
true
|
|
12
|
+
end
|
|
8
13
|
|
|
9
14
|
def undefined.to_s
|
|
10
15
|
inspect
|
|
@@ -19,9 +24,11 @@ module Kind
|
|
|
19
24
|
end
|
|
20
25
|
|
|
21
26
|
def undefined.default(value, default)
|
|
22
|
-
return
|
|
27
|
+
return value if self != value
|
|
23
28
|
|
|
24
29
|
default.respond_to?(:call) ? default.call : default
|
|
25
30
|
end
|
|
31
|
+
|
|
32
|
+
undefined.freeze
|
|
26
33
|
end
|
|
27
34
|
end
|
data/lib/kind/dig.rb
CHANGED
|
@@ -1,35 +1,55 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'kind/basic'
|
|
4
|
+
require 'kind/empty'
|
|
5
|
+
require 'kind/presence'
|
|
6
|
+
|
|
3
7
|
module Kind
|
|
4
8
|
module Dig
|
|
5
9
|
extend self
|
|
6
10
|
|
|
7
|
-
def call(data, keys)
|
|
8
|
-
return unless keys.is_a?(Array)
|
|
9
|
-
|
|
11
|
+
def call!(data, keys = Empty::ARRAY) # :nodoc
|
|
10
12
|
keys.reduce(data) do |memo, key|
|
|
11
13
|
value = get(memo, key)
|
|
12
14
|
|
|
13
|
-
break if
|
|
15
|
+
break if KIND.null?(value)
|
|
14
16
|
|
|
15
17
|
value
|
|
16
18
|
end
|
|
17
19
|
end
|
|
18
20
|
|
|
21
|
+
def call(data, *input)
|
|
22
|
+
args = input.size == 1 && input[0].kind_of?(::Array) ? input[0] : input
|
|
23
|
+
|
|
24
|
+
result = call!(data, args)
|
|
25
|
+
|
|
26
|
+
return result unless block_given?
|
|
27
|
+
|
|
28
|
+
yield(result) unless KIND.null?(result)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def presence(*args, &block)
|
|
32
|
+
Presence.(call(*args, &block))
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def [](*keys)
|
|
36
|
+
->(data) { call!(data, keys) }
|
|
37
|
+
end
|
|
38
|
+
|
|
19
39
|
private
|
|
20
40
|
|
|
21
41
|
def get(data, key)
|
|
22
|
-
return data[key] if Hash === data
|
|
42
|
+
return data[key] if ::Hash === data
|
|
23
43
|
|
|
24
44
|
case data
|
|
25
|
-
when Array
|
|
45
|
+
when ::Array
|
|
26
46
|
data[key] if key.respond_to?(:to_int)
|
|
27
|
-
when OpenStruct
|
|
47
|
+
when ::OpenStruct
|
|
28
48
|
data[key] if key.respond_to?(:to_sym)
|
|
29
|
-
when Struct
|
|
30
|
-
if key.respond_to?(:to_int) || key.respond_to?(:to_sym)
|
|
31
|
-
|
|
32
|
-
|
|
49
|
+
when ::Struct
|
|
50
|
+
data[key] rescue nil if key.respond_to?(:to_int) || key.respond_to?(:to_sym)
|
|
51
|
+
else
|
|
52
|
+
data.public_send(key) if key.respond_to?(:to_sym) && data.respond_to?(key)
|
|
33
53
|
end
|
|
34
54
|
end
|
|
35
55
|
end
|
data/lib/kind/either.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'kind/basic'
|
|
4
|
+
|
|
5
|
+
module Kind
|
|
6
|
+
module Either
|
|
7
|
+
require 'kind/either/monad'
|
|
8
|
+
require 'kind/either/left'
|
|
9
|
+
require 'kind/either/right'
|
|
10
|
+
require 'kind/either/methods'
|
|
11
|
+
|
|
12
|
+
extend self
|
|
13
|
+
|
|
14
|
+
def new(value)
|
|
15
|
+
Right[value]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
alias_method :[], :new
|
|
19
|
+
|
|
20
|
+
def self.from
|
|
21
|
+
result = yield
|
|
22
|
+
|
|
23
|
+
Either::Monad === result ? result : Either::Right[result]
|
|
24
|
+
rescue StandardError => e
|
|
25
|
+
Either::Left[e]
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
extend Either::Methods
|
|
30
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kind
|
|
4
|
+
class Either::Left < Either::Monad
|
|
5
|
+
def left?
|
|
6
|
+
true
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def value_or(default = UNDEFINED, &block)
|
|
10
|
+
Error.invalid_default_arg! if UNDEFINED == default && !block
|
|
11
|
+
|
|
12
|
+
UNDEFINED != default ? default : block.call
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def map(&_)
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
alias_method :map!, :map
|
|
20
|
+
alias_method :then, :map
|
|
21
|
+
alias_method :then!, :map
|
|
22
|
+
alias_method :and_then, :map
|
|
23
|
+
alias_method :and_then!, :map
|
|
24
|
+
|
|
25
|
+
def inspect
|
|
26
|
+
'#<%s value=%p>' % ['Kind::Left', value]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kind
|
|
4
|
+
module Either::Methods
|
|
5
|
+
def Left(value)
|
|
6
|
+
Either::Left[value]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def Right(value)
|
|
10
|
+
Either::Right[value]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.included(base)
|
|
14
|
+
base.send(:private, :Left, :Right)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Kind
|
|
4
|
+
class Either::Monad
|
|
5
|
+
require 'kind/either/monad/wrapper'
|
|
6
|
+
|
|
7
|
+
attr_reader :value
|
|
8
|
+
|
|
9
|
+
singleton_class.send(:alias_method, :[], :new)
|
|
10
|
+
|
|
11
|
+
def initialize(value)
|
|
12
|
+
@value = value
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def left?
|
|
16
|
+
false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def right?
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def value_or(_method_name = UNDEFINED, &block)
|
|
24
|
+
raise NotImplementedError
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def map(&_)
|
|
28
|
+
raise NotImplementedError
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
alias_method :map!, :map
|
|
32
|
+
alias_method :then, :map
|
|
33
|
+
alias_method :then!, :map
|
|
34
|
+
alias_method :and_then, :map
|
|
35
|
+
alias_method :and_then!, :map
|
|
36
|
+
|
|
37
|
+
def on
|
|
38
|
+
monad = Wrapper.new(self)
|
|
39
|
+
|
|
40
|
+
yield(monad)
|
|
41
|
+
|
|
42
|
+
monad.output
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def on_right(matcher = UNDEFINED)
|
|
46
|
+
yield(value) if right? && either?(matcher)
|
|
47
|
+
|
|
48
|
+
self
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def on_left(matcher = UNDEFINED)
|
|
52
|
+
yield(value) if left? && either?(matcher)
|
|
53
|
+
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def either?(matcher)
|
|
58
|
+
UNDEFINED == matcher || matcher === value
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def ===(monad)
|
|
62
|
+
self.class === monad && self.value === monad.value
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|