kind 4.0.0 → 5.3.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 -1
- data/.travis.sh +39 -7
- data/.travis.yml +1 -2
- data/CHANGELOG.md +486 -28
- data/Gemfile +13 -6
- data/README.md +153 -49
- data/kind.gemspec +1 -1
- data/lib/kind.rb +2 -84
- data/lib/kind/__lib__/action_steps.rb +57 -0
- data/lib/kind/__lib__/attributes.rb +66 -0
- data/lib/kind/__lib__/kind.rb +51 -0
- data/lib/kind/__lib__/of.rb +17 -0
- data/lib/kind/__lib__/strict.rb +49 -0
- data/lib/kind/__lib__/undefined.rb +14 -0
- data/lib/kind/action.rb +127 -0
- data/lib/kind/active_model/validation.rb +3 -4
- data/lib/kind/basic.rb +79 -0
- data/lib/kind/basic/error.rb +29 -0
- data/lib/kind/{undefined.rb → basic/undefined.rb} +6 -1
- data/lib/kind/dig.rb +21 -5
- 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 +2 -2
- 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 +45 -0
- data/lib/kind/functional.rb +89 -0
- data/lib/kind/functional/action.rb +90 -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 +37 -12
- 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 +12 -19
- data/lib/kind/maybe/some.rb +68 -26
- data/lib/kind/maybe/typed.rb +11 -5
- data/lib/kind/maybe/{wrappable.rb → wrapper.rb} +9 -7
- 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 +43 -0
- data/lib/kind/objects/modules.rb +32 -0
- data/lib/kind/{type_checkers → objects/modules}/core/array.rb +3 -1
- data/lib/kind/{type_checkers → objects/modules}/core/class.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/comparable.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/enumerable.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/enumerator.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/file.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/float.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/hash.rb +3 -1
- data/lib/kind/{type_checkers → objects/modules}/core/integer.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/io.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/method.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/module.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/numeric.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/proc.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/queue.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/range.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/regexp.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/string.rb +3 -1
- data/lib/kind/{type_checkers → objects/modules}/core/struct.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/symbol.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/core/time.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/custom/boolean.rb +2 -2
- data/lib/kind/{type_checkers → objects/modules}/custom/callable.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/custom/lambda.rb +1 -1
- data/lib/kind/{type_checkers → objects/modules}/stdlib/open_struct.rb +3 -1
- data/lib/kind/{type_checkers → objects/modules}/stdlib/set.rb +3 -1
- data/lib/kind/objects/nil.rb +17 -0
- data/lib/kind/objects/not_nil.rb +9 -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 +4 -2
- data/lib/kind/result.rb +31 -0
- data/lib/kind/result/abstract.rb +53 -0
- data/lib/kind/result/failure.rb +33 -0
- data/lib/kind/result/methods.rb +17 -0
- data/lib/kind/result/monad.rb +74 -0
- data/lib/kind/result/monad/wrapper.rb +19 -0
- data/lib/kind/result/success.rb +53 -0
- data/lib/kind/strict/disabled.rb +34 -0
- data/lib/kind/try.rb +21 -11
- data/lib/kind/validator.rb +111 -0
- data/lib/kind/version.rb +1 -1
- metadata +78 -48
- data/lib/kind/active_model/kind_validator.rb +0 -96
- data/lib/kind/core.rb +0 -9
- data/lib/kind/core/deprecation.rb +0 -29
- data/lib/kind/core/kind.rb +0 -61
- data/lib/kind/core/undefined.rb +0 -7
- data/lib/kind/deprecations/built_in_type_checkers.rb +0 -23
- data/lib/kind/deprecations/checker.rb +0 -16
- data/lib/kind/deprecations/checker/factory.rb +0 -31
- data/lib/kind/deprecations/checker/protocol.rb +0 -73
- data/lib/kind/deprecations/is.rb +0 -35
- data/lib/kind/deprecations/of.rb +0 -258
- data/lib/kind/deprecations/types.rb +0 -121
- data/lib/kind/error.rb +0 -15
- data/lib/kind/maybe/result.rb +0 -51
- data/lib/kind/type_checker.rb +0 -73
- data/lib/kind/type_checkers.rb +0 -30
@@ -2,13 +2,15 @@
|
|
2
2
|
|
3
3
|
module Kind
|
4
4
|
module Set
|
5
|
-
extend self,
|
5
|
+
extend self, ::Kind::Object
|
6
6
|
|
7
7
|
def kind; ::Set; end
|
8
8
|
|
9
9
|
def value_or_empty(arg)
|
10
10
|
KIND.value(self, arg, Empty::SET)
|
11
11
|
end
|
12
|
+
|
13
|
+
alias empty_or value_or_empty
|
12
14
|
end
|
13
15
|
|
14
16
|
def self.Set?(*values)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kind/maybe'
|
4
|
+
|
5
|
+
module Kind
|
6
|
+
module Object
|
7
|
+
include Kind::BasicObject
|
8
|
+
include Maybe::Buildable
|
9
|
+
include UnionType::Buildable
|
10
|
+
|
11
|
+
def name
|
12
|
+
kind.name
|
13
|
+
end
|
14
|
+
|
15
|
+
def ===(value)
|
16
|
+
kind === value
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
"Kind::Object<#{name}>"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Object::Instance # :nodoc: all
|
25
|
+
include ::Kind::Object
|
26
|
+
|
27
|
+
ResolveKindName = ->(kind, opt) do
|
28
|
+
name = Try.call!(opt, :[], :name)
|
29
|
+
name || Try.call!(kind, :name)
|
30
|
+
end
|
31
|
+
|
32
|
+
attr_reader :kind, :name
|
33
|
+
|
34
|
+
def initialize(kind, opt)
|
35
|
+
name = ResolveKindName.(kind, opt)
|
36
|
+
|
37
|
+
@name = STRICT.kind_of(::String, name)
|
38
|
+
@kind = KIND.respond_to!(:===, kind)
|
39
|
+
end
|
40
|
+
|
41
|
+
private_constant :ResolveKindName
|
42
|
+
end
|
43
|
+
|
44
|
+
# Kind[]
|
45
|
+
def self.[](kind, opt = Empty::HASH)
|
46
|
+
Object::Instance.new(kind, opt)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Kind::Of()
|
50
|
+
def self.Of(*args)
|
51
|
+
warn '[DEPRECATION] Kind::Of() is deprecated; use Kind[] instead. ' \
|
52
|
+
'It will be removed on next major release.'
|
53
|
+
|
54
|
+
self[*args]
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kind
|
4
|
+
class RespondTo
|
5
|
+
include Kind::BasicObject
|
6
|
+
|
7
|
+
def self.[](*args)
|
8
|
+
args.each { |arg| STRICT.kind_of(::Symbol, arg) }
|
9
|
+
|
10
|
+
new(args)
|
11
|
+
end
|
12
|
+
|
13
|
+
private_class_method :new
|
14
|
+
|
15
|
+
attr_reader :inspect
|
16
|
+
|
17
|
+
def initialize(method_names)
|
18
|
+
@method_names = method_names
|
19
|
+
@inspect = "Kind::RespondTo#{@method_names}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def ===(value)
|
23
|
+
KIND.interface?(@method_names, value)
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :call, :===
|
27
|
+
|
28
|
+
alias_method :name, :inspect
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kind
|
4
|
+
class UnionType
|
5
|
+
include Kind::BasicObject
|
6
|
+
|
7
|
+
Interface = Kind::RespondTo[:name, :===]
|
8
|
+
|
9
|
+
singleton_class.send(:alias_method, :[], :new)
|
10
|
+
|
11
|
+
attr_reader :inspect
|
12
|
+
|
13
|
+
def initialize(kind)
|
14
|
+
@kinds = Array(kind)
|
15
|
+
@inspect = "(#{@kinds.map(&:name).join(' | ')})"
|
16
|
+
end
|
17
|
+
|
18
|
+
def |(kind)
|
19
|
+
self.class.new(@kinds + [Interface[kind]])
|
20
|
+
end
|
21
|
+
|
22
|
+
def ===(value)
|
23
|
+
@kinds.any? { |kind| kind === value }
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :name, :inspect
|
27
|
+
|
28
|
+
module Buildable
|
29
|
+
def |(another_kind)
|
30
|
+
__union_type | another_kind
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def __union_type
|
36
|
+
@__union_type ||= UnionType[self]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private_constant :Interface
|
41
|
+
end
|
42
|
+
|
43
|
+
RespondTo.send(:include, UnionType::Buildable)
|
44
|
+
end
|
data/lib/kind/presence.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'kind/basic'
|
4
|
+
|
3
5
|
module Kind
|
4
6
|
module Presence
|
5
7
|
extend self
|
6
8
|
|
7
9
|
def call(object)
|
8
|
-
return
|
10
|
+
return if KIND.nil_or_undefined?(object)
|
9
11
|
|
10
|
-
return object
|
12
|
+
return object.blank? ? nil : object if object.respond_to?(:blank?)
|
11
13
|
|
12
14
|
return blank_str?(object) ? nil : object if String === object
|
13
15
|
|
data/lib/kind/result.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kind/basic'
|
4
|
+
|
5
|
+
module Kind
|
6
|
+
module Result
|
7
|
+
require 'kind/result/abstract'
|
8
|
+
require 'kind/result/monad'
|
9
|
+
require 'kind/result/failure'
|
10
|
+
require 'kind/result/success'
|
11
|
+
require 'kind/result/methods'
|
12
|
+
|
13
|
+
extend self
|
14
|
+
|
15
|
+
def new(value)
|
16
|
+
Success[value]
|
17
|
+
end
|
18
|
+
|
19
|
+
alias_method :[], :new
|
20
|
+
|
21
|
+
def self.from
|
22
|
+
result = yield
|
23
|
+
|
24
|
+
Result::Monad === result ? result : Result::Success[result]
|
25
|
+
rescue StandardError => e
|
26
|
+
Result::Failure[:exception, e]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
extend Result::Methods
|
31
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kind
|
4
|
+
module Result::Abstract
|
5
|
+
def failure?
|
6
|
+
false
|
7
|
+
end
|
8
|
+
|
9
|
+
def failed?
|
10
|
+
failure?
|
11
|
+
end
|
12
|
+
|
13
|
+
def success?
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
def succeeded?
|
18
|
+
success?
|
19
|
+
end
|
20
|
+
|
21
|
+
def on(&block)
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_success(types = Undefined, matcher = Undefined)
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
def on_failure(types = Undefined, matcher = Undefined)
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
def result?(types, matcher)
|
34
|
+
undef_t = Undefined == (t = types)
|
35
|
+
undef_m = Undefined == (m = matcher)
|
36
|
+
|
37
|
+
return true if undef_t && undef_m
|
38
|
+
|
39
|
+
if !undef_t && undef_m && !(Array === types || Symbol === types)
|
40
|
+
m, t = types, matcher
|
41
|
+
|
42
|
+
undef_m, undef_t = false, true
|
43
|
+
end
|
44
|
+
|
45
|
+
is_type = undef_t || (::Array === t ? t.empty? || t.include?(type) : t == type)
|
46
|
+
is_type && (undef_m || m === value)
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_ary
|
50
|
+
[type, value]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kind
|
4
|
+
class Result::Failure < Result::Monad
|
5
|
+
DEFAULT_TYPE = :error
|
6
|
+
|
7
|
+
def failure?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def value_or(default = UNDEFINED, &block)
|
12
|
+
Error.invalid_default_arg! if UNDEFINED == default && !block
|
13
|
+
|
14
|
+
UNDEFINED != default ? default : block.call
|
15
|
+
end
|
16
|
+
|
17
|
+
def map(_ = UNDEFINED, &_fn)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
alias_method :|, :map
|
22
|
+
alias_method :>>, :map
|
23
|
+
alias_method :map!, :map
|
24
|
+
alias_method :then, :map
|
25
|
+
alias_method :then!, :map
|
26
|
+
alias_method :and_then, :map
|
27
|
+
alias_method :and_then!, :map
|
28
|
+
|
29
|
+
def inspect
|
30
|
+
'#<%s type=%p value=%p>' % ['Kind::Failure', type, value]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kind
|
4
|
+
module Result::Methods
|
5
|
+
def Failure(arg1 = UNDEFINED, arg2 = UNDEFINED)
|
6
|
+
Result::Failure[arg1, arg2]
|
7
|
+
end
|
8
|
+
|
9
|
+
def Success(arg1 = UNDEFINED, arg2 = UNDEFINED)
|
10
|
+
Result::Success[arg1, arg2]
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.send(:private, :Success, :Failure)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kind
|
4
|
+
class Result::Monad
|
5
|
+
include Result::Abstract
|
6
|
+
|
7
|
+
require 'kind/empty'
|
8
|
+
require 'kind/result/monad/wrapper'
|
9
|
+
|
10
|
+
attr_reader :type, :value
|
11
|
+
|
12
|
+
def self.[](arg1 = UNDEFINED, arg2 = UNDEFINED, opt = Empty::HASH) # :nodoc:
|
13
|
+
value_must_be_a = opt[:value_must_be_a]
|
14
|
+
|
15
|
+
type = UNDEFINED == arg2 ? self::DEFAULT_TYPE : STRICT.kind_of(::Symbol, arg1)
|
16
|
+
|
17
|
+
Error.wrong_number_of_args!(given: 0, expected: '1 or 2') if UNDEFINED == arg1
|
18
|
+
|
19
|
+
value = UNDEFINED == arg2 ? arg1 : arg2
|
20
|
+
|
21
|
+
new(type, (value_must_be_a ? STRICT.kind_of(value_must_be_a, value) : value))
|
22
|
+
end
|
23
|
+
|
24
|
+
private_class_method :new
|
25
|
+
|
26
|
+
def initialize(type, value)
|
27
|
+
@type = type
|
28
|
+
@value = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def value_or(_method_name = UNDEFINED, &block)
|
32
|
+
raise NotImplementedError
|
33
|
+
end
|
34
|
+
|
35
|
+
def map(_ = UNDEFINED, &_fn)
|
36
|
+
raise NotImplementedError
|
37
|
+
end
|
38
|
+
|
39
|
+
alias_method :|, :map
|
40
|
+
alias_method :>>, :map
|
41
|
+
alias_method :map!, :map
|
42
|
+
alias_method :then, :map
|
43
|
+
alias_method :then!, :map
|
44
|
+
alias_method :and_then, :map
|
45
|
+
alias_method :and_then!, :map
|
46
|
+
|
47
|
+
def on
|
48
|
+
monad = Wrapper.new(self)
|
49
|
+
|
50
|
+
yield(monad)
|
51
|
+
|
52
|
+
monad.output
|
53
|
+
end
|
54
|
+
|
55
|
+
def on_success(types = Undefined, matcher = Undefined)
|
56
|
+
yield(value) if success? && result?(types, matcher)
|
57
|
+
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def on_failure(types = Undefined, matcher = Undefined)
|
62
|
+
yield(value) if failure? && result?(types, matcher)
|
63
|
+
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def ===(m)
|
68
|
+
return false unless Result::Abstract === m
|
69
|
+
return false unless (self.success? && m.success?) || (self.failure? && m.failure?)
|
70
|
+
|
71
|
+
self.type == m.type && self.value === m.value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|